微信小程序基于Canvas實現頭像圖片裁剪(上)

序言

嘿,打工人混跡職場這么久,圖片處理肯定都沒少碰。不過咱說實話,大部分時候都是直接 “抄近道”,用現成的三方組件😏。就像我,主打一個會用工具,畢竟善用工具可是咱人類的 “超能力”,不會用那可就真成 “原始人” 啦🤣。最近在搞微信小程序開發時,遇到個需求:用戶上傳圖片得能裁剪。我瞅了瞅 UI 給的效果圖,好家伙,找遍了都沒發現合適的組件,這下沒辦法,社畜的 “使命感” 上身,只能自己動手,豐衣足食咯😅。

UI圖

在這里插入圖片描述

咱來拆解一下在微信小程序里實現這功能的流程。首先從上個頁面調用小程序選擇圖片的 API——chooseMedia,這就好比打開了一個 “圖片寶庫”,通過它能拿到用戶選好圖片后的臨時路徑(下面咱就簡稱 path 啦)。接著帶著這個 path “奔赴” 當前頁面,然后用Canvas這個神奇的 “畫布” 把圖片畫出來,之后還要讓圖片能實現移動、縮放這些 “炫酷操作”。

使用 Canvas 畫出圖片

選擇圖片這塊咱就不細究啦,不是本文的 “主角”,咱直接從拿到 path 之后講起。

第一步得初始化 Canvas,給它設定寬高。在頁面加載完畢時,利用createSelectorQuery這個 “小助手”,拿到 Canvas 的寬高以及 node,然后把這些數據存好,后續其他功能計算時可得靠它們 “大顯身手”。

初始化 Canvas
<canvas id="canvas" type="2d" style="width: 100%; height: 100%;"></canvas>
initCanvas() {return new Promise((resolve, reject) => {const query = wx.createSelectorQuery()query.select('#canvas').fields({ node: true, size: true }).exec((res) => {const { node, width, height } = res[0]node.width = widthnode.height = heightconst ctx = node.getContext('2d')this.setData({ 'canvas.target': node,'canvas.ctx': ctx,'canvas.width': width,'canvas.height': height})resolve()})})},

可能有的小伙伴要問了:已經設了寬高 100%,為啥還要再設置 node 呢🧐?這是因為不明確設置寬高屬性,它就會用默認值,這就像你沒給導航設定目的地,它可能就帶你去 “奇怪的地方”,繪圖效果自然就 “跑偏” 了。但 Canvas 尺寸又不是固定不變的,沒法直接簡單設置,所以初始化時這一步很關鍵哦。

初始化圖片到Canvas

接下來把圖片 “請” 到 Canvas 上。注意啦,圖片得在 Canvas 正中間,還得完整地展示在可見區域,可不能按原圖尺寸隨意 “擺放”,所以得做些簡單的 “數學運算”。

initImage() {return new Promise((resolve, reject) => {const { path, canvas: { target: canvas } } = this.datalet image = canvas.createImage();image.src = pathimage.onload = () => {const { ctx, width: canvasWidth, height: canvasHeight } = this.data.canvasconst scale = image.width / image.heightlet width = canvasWidthlet height = canvasWidth / scaleif (height > canvasHeight) {height = canvasHeightwidth = canvasHeight * scale}const x = (canvasWidth - width) / 2;const y = (canvasHeight - height) / 2;ctx.drawImage(image, x, y, width, height);this.setData({'image.target': image,'image.width': width,'image.height': height,'image.x': x,'image.y': y,'image.scale': scale})resolve()}})},

先用 Canvas 對象創建一個圖片對象,再把 path “賦予” 它。等圖片加載好,就能獲取到圖片尺寸,進而算出寬高比。因為要完整展示圖片,所以圖片高度最大就是 Canvas 的高度,寬度最大是 Canvas 的寬度。通過寬高比,就能算出當繪制寬度是 Canvas 寬度時對應的高度。然后把這個計算出的高度和 Canvas 高度對比,如果超了,就以 Canvas 高度為繪制高度,再算出相應寬度。

尺寸確定好后,最后算圖片繪制的中心位置。以 Canvas 左上角為 (0,0),X 軸坐標就是 Canvas 寬度減去圖片寬度再除以 2,Y 軸坐標同理。最后調用drawImage方法,圖片就 “乖乖” 初始化繪制好啦。別忘了把圖片相關數據存起來,后續功能還得靠它們 “幫忙” 呢。

繪制裁剪區域

再接著就是繪制裁剪區域,從 UI 圖能看出,裁剪區域是正中心的一個長方形。咱先確定好這個長方形尺寸并存起來,然后利用這個尺寸在 Canvas 四周畫上四個黑色遮罩長方形,這招就像 “圍點打援”,簡單又有效😎。

// 裁剪區域的相關數據
crop: {scale: 5 / 7,width: 200,height: 0,x: 0,y: 0,
},
// 裁剪區域尺寸等信息
getCropInfo() {const {canvas: { width: canvasWidth, height: canvasHeight },crop: { width: cropWidth, scale: cropScale }} = this.dataconst result = {scale: cropScale,width: cropWidth,height: cropWidth / cropScale,x: (canvasWidth - cropWidth) / 2,y: (canvasHeight - cropWidth / cropScale) / 2}this.setData({'crop.height': cropWidth / cropScale,'crop.x': (canvasWidth - cropWidth) / 2,'crop.y': (canvasHeight - cropWidth / cropScale) / 2,})return result},// 繪制裁剪區域drawCrop() {const { ctx, width: canvasWidth, height: canvasHeight } = this.data.canvasconst { width: cropWidth, height: cropHeight, x, y} = this.data.crop// 該方式會出現 一次繪制成功一次繪制不成功的情況// ctx.rect(0, 0, canvasWidth, canvasHeight);// ctx.rect(x, y, cropWidth, cropHeight);// ctx.fillStyle = 'rgba(0, 0, 0, 0.7)';// ctx.fill('evenodd');ctx.rect(0, 0, canvasWidth, y);ctx.rect(0, y + cropHeight, canvasWidth, y);ctx.rect(0, y, x, cropHeight);ctx.rect(x + cropWidth, y, x, cropHeight);ctx.fillStyle = 'rgba(0, 0, 0, 0.7)';ctx.fill()},

到這兒,基本雛形已經有啦。不過關于拖拽、縮放這些更精彩的操作,由于篇幅限制,咱下篇再繼續 “揭秘”😜。

在這里插入圖片描述

🦀🦀感謝看官看到這里,如果覺得文章不錯的話🙌,點個關注不迷路?。
誠邀您加入我的微信技術交流群🎉,群里都是志同道合的開發者👨?💻,大家能一起交流分享摸魚🐟。期待與您在群里相見🚀,咱們攜手在開發路上共同進步? !
👉點我

感謝各位大俠一路相伴,實在感激! 不瞞您說,在下還有幾個開源項目 📦,它們就像精心培育的幼苗 🌱,急需您的澆灌。要是您瞧著還不錯,麻煩動動手指,給它們點亮幾顆 Star ?,您的支持就是它們成長的最大動力,在此謝過各位大俠啦!

  • Nova UI組件庫:https://github.com/gmingchen/nova-ui
  • 基于 Vue3 + Element-plus 管理后臺基礎功能框架
  • 預覽:https://admin.gumingchen.icu
    • Github:https://github.com/gmingchen/agile-admin
    • Gitee:https://gitee.com/shychen/agile-admin
    • 基礎版后端:https://github.com/gmingchen/java-spring-boot-admin
    • 文檔:http://admin.gumingchen.icu/doc/
  • 基于 Vue3 + Element-plus + websocket 即時聊天系統
    • 預覽:https://chatterbox.gumingchen.icu/
    • Github:https://github.com/gmingchen/chatterbox
    • Gitee:https://gitee.com/shychen/chatterbox
  • 基于 node 開發的后端服務:https://github.com/gmingchen/node-server

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/74768.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/74768.shtml
英文地址,請注明出處:http://en.pswp.cn/web/74768.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

[特殊字符] 使用 Handsontable 構建一個支持 Excel 公式計算的動態表格

在 Web 應用中&#xff0c;處理表格數據并提供 Excel 級的功能&#xff08;如公式計算、數據導入導出&#xff09;一直是個挑戰。今天&#xff0c;我將帶你使用 React Handsontable 搭建一個強大的 Excel 風格表格&#xff0c;支持 公式計算、Excel 文件導入導出&#xff0c;并…

0302useState-hooks-react-仿低代碼平臺項目

文章目錄 1 useState1.1 說明返回 1.2 示例1.3 數據類型 2 state2.1 概述2.2 state特點 3 state重構問卷4 immer結語 1 useState useState 是一個 React Hook&#xff0c;它允許你向組件添加一個 狀態變量。 1.1 說明 語法 const [state, setState] useState(initialState…

前端實現單點登錄(SSO)的方案

概念&#xff1a;單點登錄&#xff08;Single Sign-On, SSO&#xff09;主要是在多個系統、多個瀏覽器或多個標簽頁之間共享登錄狀態&#xff0c;保證用戶只需登錄一次&#xff0c;就能訪問多個關聯應用&#xff0c;而不需要重復登錄。 &#x1f4a1; 方案分類 1. 前端級別 SS…

zabbix監控網站(nginx、redis、mysql)

目錄 前提準備&#xff1a; zabbix-server主機配置&#xff1a; 1. 安裝數據庫 nginx主機配置&#xff1a; 1. 安裝nginx redis主機配置&#xff1a; 1. 安裝redis mysql主機配置&#xff1a; 1. 安裝數據庫 zabbix-server&#xff1a; 1. 安裝zabbix 2. 編輯配置文…

無人機等非合作目標公開數據集2025.4.3

一.無人機遙感數據概述 1.1 定義與特點 在遙感技術的不斷發展中&#xff0c;無人機遙感數據作為一種新興的數據源&#xff0c;正逐漸嶄露頭角。它是通過無人駕駛飛行器&#xff08;UAV&#xff09;搭載各種傳感器獲取的地理空間信息&#xff0c;具有 覆蓋范圍大、綜合精度高、…

大數據時代的隱私保護:區塊鏈技術的創新應用

一、引言 在當今數字化時代&#xff0c;大數據已經成為推動社會發展的關鍵力量。從商業決策到社會治理&#xff0c;從醫療健康到金融服務&#xff0c;數據的價值日益凸顯。然而&#xff0c;隨著數據的大量收集和廣泛使用&#xff0c;隱私保護問題也日益突出。如何在充分利用大…

LeetCode 2442:統計反轉后的不同整數數量

目錄 核心思想&#xff1a;數字的“拆分”與“重組” 分步拆解&#xff08;以輸入 123 為例&#xff09; 關鍵操作詳解 為什么能處理中間或末尾的0&#xff1f; 數學本質 總結 題目描述 解題思路 代碼實現 代碼解析 復雜度分析 示例演示 總結 核心思想&#xff1a;…

Python爬蟲第3節-會話、Cookies及代理的基本原理

目錄 一、會話和Cookies 1.1 靜態網頁和動態網頁 1.2 無狀態HTTP 1.3 常見誤區 二、代理的基本原理 2.1 基本原理 2.2 代理的作用 2.3 爬蟲代理 2.4 代理分類 2.5 常見代理設置 一、會話和Cookies 大家在瀏覽網站過程中&#xff0c;肯定經常遇到需要登錄的場景。有些…

Flutter項目之登錄注冊功能實現

目錄&#xff1a; 1、頁面效果2、登錄兩種狀態界面3、中間按鈕部分4、廣告區域5、最新資訊6、登錄注冊頁聯調6.1、網絡請求工具類6.2、注冊頁聯調6.3、登錄問題分析6.4、本地緩存6.5、共享token6.6、登錄頁聯調6.7、退出登錄 1、頁面效果 import package:flutter/material.dart…

木馬學習記錄

一句話木馬是什么 一句話木馬就是僅需要一行代碼的木馬&#xff0c;很簡短且簡單&#xff0c;木馬的函數將會執行我們發送的命令 如何發送命令&#xff06;發送的命令如何執行? 有三種方式&#xff1a;GET&#xff0c;POST&#xff0c;COOKIE&#xff0c;一句話木馬中用$_G…

(C語言)單鏈表(1.0)(單鏈表教程)(數據結構,指針)

目錄 1. 什么是單鏈表&#xff1f; 2. 單鏈表的代碼表示 3. 單鏈表的基本操作 3.1 初始化鏈表 3.2 插入結點&#xff08;頭插法&#xff09; 3.3 插入結點&#xff08;尾插法&#xff09; 3.4 遍歷鏈表 4. 單鏈表的優缺點 代碼&#xff1a;*L(LinkList)malloc(sizeof(…

Sentinel-自定義資源實現流控和異常處理

目錄 使用SphU的API實現自定義資源 BlockException 使用SentinelResource注解定義資源 SentinelResourceAspect 使用Sentinel實現限流降級等效果通常需要先把需要保護的資源定義好&#xff0c;之后再基于定義好的資源為其配置限流降級等規則。 Sentinel對于主流框架&#…

Linux信號處理解析:從入門到實戰

Linux信號處理全解析&#xff1a;從入門到實戰 一、初識Linux信號&#xff1a;系統級的"緊急電話" 信號是什么&#xff1f; 信號是Linux系統中進程間通信的"緊急通知"&#xff0c;如同現實中的交通信號燈。當用戶按下CtrlC&#xff08;產生SIGINT信號&…

Java的Selenium的特殊元素操作與定位之select下拉框

如果頁面元素是一個下拉框&#xff0c;我們可以將此web元素封裝為Select對象 Select selectnew Select(WebElement element); Select對象常用api select.getOptions();//獲取所有選項select.selectBylndex(index);//根據索引選中對應的元素select.selectByValue(value);//選…

藍橋云客 刷題統計

刷題統計 問題描述 小明決定從下周一開始努力刷題準備藍橋杯競賽。他計劃周一至周五每天做 a 道題目&#xff0c;周六和周日每天做 b 道題目。請你幫小明計算&#xff0c;按照計劃他將在第幾天實現做題數大于等于 n 題&#xff1f; 輸入格式 輸入一行包含三個整數 a, b 和 …

三防筆記本有什么用 | 三防筆記本有什么特別

在現代社會&#xff0c;隨著科技的不斷進步&#xff0c;筆記本電腦已經成為人們工作和生活的重要工具。然而&#xff0c;在一些特殊的工作環境和極端條件下&#xff0c;普通筆記本電腦往往難以滿足需求。這時&#xff0c;三防筆記本以其獨特的設計和卓越的性能&#xff0c;成為…

智能體和RPA都需要程序思維,如何使用影刀的變量?

歡迎來到濤濤聊AI&#xff0c; 不管AI還是RPA&#xff0c;都需要用到編程思想才能完成批量工作。今天研究了下影刀的變量。 變量類型 根據變量值選擇相應的類型&#xff0c;可選擇任意一種影刀所支持的數據類型 變量值 指定變量中保存的值&#xff0c;會根據不同的類型設置…

【藍橋杯】算法筆記3

1. 最長上升子序列(LIS) 1.1. 題目 想象你有一排數字,比如:3, 1, 2, 1, 8, 5, 6 你要從中挑出一些數字,這些數字要滿足兩個條件: 你挑的數字的順序要和原來序列中的順序一致(不能打亂順序) 你挑的數字要一個比一個大(嚴格遞增) 問:最多能挑出多少個這樣的數字? …

性能測試之jmeter的基本使用

簡介 Jmeter是Apache的開源項目&#xff0c;基于Java開發&#xff0c;主要用于進行壓力測試。 優點&#xff1a;開源免費、支持多協議、輕量級、功能強大 官網&#xff1a;https://jmeter.apache.org/index.html 安裝 安裝步驟&#xff1a; 下載&#xff1a;進入jmeter的…

【NLP 面經 7、常見transformer面試題】

目錄 1. 為何使用多頭注意力機制&#xff1f; 2. Q和K使用不同權重矩陣的原因 3. 選擇點乘而非加法的原因 4. Attention進行scaled的原因 5. 對padding做mask操作 6. 多頭注意力降維原因 7. Transformer Encoder模塊簡介 8. 乘以embedding size的開方的意義 9. 位置編碼 10. 其…