uniapp 多圖上傳,加水印功能(全平臺通用)

多圖上傳和水印都是比較難得,特別是有的api只支持在小程序用,h5不給用

效果圖
模擬插件
沒加水印

加水印

普通的多圖上傳

// 多圖上傳
// count:最大數量
export function headerUploads0(count = 9, orderNumber = '', watermarkInfo) {return new Promise((resolve, reject) => {let UploadList = []uni.chooseImage({// 最多可以選擇的圖片總數count,success: async res => {let processedFiles = res.tempFilePathsif (watermarkInfo) {// 創建列式水印文本數組const watermarkLines = [`訂單號: ${watermarkInfo.number}`,`買  家: ${watermarkInfo.traderName}`,`賣  家: ${watermarkInfo.sellerTraderName}`,`資金方: ${watermarkInfo.capitalTraderName}`,`時  間: ${format(new Date(), false)}`];// 批量添加水印}//啟動上傳等待中...  uni.showLoading({title: '上傳中',});await Promise.all(processedFiles.map((item, index) => {return new Promise((resolve1, reject1) => {console.log('上傳');uni.uploadFile({// 上傳地址url: BASE_URL + VUE_APP_BASE_API +'/AppBusiness/AppCommon/UploadFile',name: 'file',filePath: processedFiles[index],formData: {FileNameType: 3,FileDir: orderNumber || '',ClassifyType: orderNumber ? 'order' : ''},header: {"Authorization": (store.state.token ||uni.getStorageSync('token')) ?'Bearer ' + (store.state.token ||uni.getStorageSync('token')) :''},success: (resz) => {console.log('后端返回', (JSON.parse(resz.data).data));uni.hideLoading()UploadList.push(JSON.parse(resz.data).data)resolve1()},fail: (resz) => {console.log('失敗返回', resz);uni.hideLoading()reject1()}})});})).then(() => {console.log('循環后', UploadList);resolve(UploadList)}).catch((error) => {console.log('循環后', UploadList);resolve(UploadList)})},complete: compRes => {}});})
}

帶水印的多圖上傳

在組件頁面那需要加個空畫布用來操作

// vue頁面上
<!-- 隱藏的Canvas,用于繪制水印(全端兼容)-->
<canvas canvas-id="watermarkCanvas":style="{position: 'absolute', top: '0', left: '-1000vw', width: canvasWidth + 'px', height: canvasHeight + 'px'}"></canvas>// 引入下面的函數tools.js是我的封裝js,別搞錯了
import {headerUploads, // 多圖上傳
} from "@/utils/tools.js"// data數據中
canvasWidth: 500, // 動態綁定Canvas寬高
canvasHeight: 500// js中調用 
// 參數 多少張圖片3張,攜帶的訂單號(不重要我這邊上傳后端要) Y12345, 訂單信息 this.watermarkInfo, this 用來設置canvasWidth的
headerUploads(3, 'Y12345', this.watermarkInfo, this)

函數–封裝的tools.js中


/*** 跨平臺圖片壓縮(兼容小程序和H5)* @param {string} filePath 原始圖片路徑* @param {number} [quality=0.7] 壓縮質量(0-1)* @param {number} [maxWidth=1024] 最大寬度* @param {number} [maxHeight=1024] 最大高度* @return {Promise<string>} 壓縮后的圖片路徑*/
export function compressImage(filePath, quality = 0.8, maxWidth = 1024, maxHeight = 1024) {return new Promise((resolve, reject) => {// 平臺判斷// #ifdef MP-WEIXIN// 微信小程序使用官方APIwx.compressImage({src: filePath,quality: Math.floor(quality * 100), // 微信使用0-100整數success: (res) => resolve(res.tempFilePath),fail: reject});// #endif// #ifdef H5// H5使用Canvas壓縮const img = new Image();img.crossOrigin = 'anonymous';img.src = filePath;img.onload = () => {const canvas = document.createElement('canvas');const ctx = canvas.getContext('2d');// 計算壓縮尺寸let width = img.width;let height = img.height;if (width > maxWidth) {height *= maxWidth / width;width = maxWidth;}if (height > maxHeight) {width *= maxHeight / height;height = maxHeight;}canvas.width = width;canvas.height = height;// 繪制壓縮圖片ctx.drawImage(img, 0, 0, width, height);console.log(666);// 獲取壓縮結果canvas.toBlob((blob) => {const reader = new FileReader();reader.onload = () => resolve(reader.result);reader.readAsDataURL(blob);},'image/jpeg',quality);};img.onerror = reject;// #endif// 其他平臺(如App)或未處理平臺返回原圖// #ifndef MP-WEIXIN, H5resolve(filePath);// #endif});
}// 多圖上傳(帶水印功能)
export function headerUploads(count = 9, orderNumber = '', watermarkInfo, pageContext) {return new Promise((resolve, reject) => {uni.chooseImage({count,success: async res => {try {const tempFiles = res.tempFilePaths;let processedFiles = tempFiles;// 如果需要加水印if (watermarkInfo && watermarkInfo.number) {const watermarkLines = [`時  間: ${format(new Date(), false)}`,`資金方: ${watermarkInfo.capitalTraderName || ''}`,`賣  家: ${watermarkInfo.sellerTraderName || ''}`,`買  家: ${watermarkInfo.traderName || ''}`,`訂單號: ${watermarkInfo.number}`];// 串行處理水印(確保畫布狀態獨立)processedFiles = [];for (const imgPath of tempFiles) {try {const watermarked = await addWatermarkByContext(imgPath, watermarkLines, pageContext);processedFiles.push(watermarked);} catch (e) {console.error('水印處理失敗,使用原圖:', e);processedFiles.push(imgPath); // 失敗時使用原圖}}}// 上傳所有處理后的文件const UploadList = await uploadAllFiles(processedFiles, orderNumber);resolve(UploadList);} catch (e) {reject(e);}},fail: reject});});
}// 重置畫布狀態(關鍵解決畫布污染問題)
function resetCanvasContext(pageContext) {if (!pageContext) return;// 重置畫布尺寸(避免上一張圖片的尺寸影響)pageContext.canvasWidth = 0;pageContext.canvasHeight = 0;// 清除畫布內容const ctx = uni.createCanvasContext('watermarkCanvas', pageContext);ctx.clearRect(0, 0, pageContext.canvasWidth || 500, pageContext.canvasHeight || 500); // 清除超大區域確保干凈ctx.draw(); // 立即執行清除
}// 具體的加水印
function addWatermarkByContext(imgPath, watermarkLines, pageContext) {// 無需水印直接返回原圖if (!watermarkLines || watermarkLines.length === 0 || !pageContext) {return Promise.resolve(imgPath);}return new Promise((resolve, reject) => {// 1. 先重置畫布狀態(關鍵步驟)resetCanvasContext(pageContext);// 2. 獲取原圖信息uni.getImageInfo({src: imgPath,success: (imgInfo) => {const { width: imgWidth, height: imgHeight } = imgInfo;const dpr = 1// uni.getSystemInfoSync().pixelRatio;let dpr2 = uni.getSystemInfoSync().pixelRatio// 3. 設置畫布尺寸(使用原圖尺寸)pageContext.canvasWidth = imgWidth * dpr;pageContext.canvasHeight = imgHeight * dpr;const maxCanvasSize = 4096; // 大多數設備的限制if (imgWidth * dpr > maxCanvasSize || imgHeight * dpr > maxCanvasSize) {const scale = Math.min(maxCanvasSize/(imgWidth*dpr), maxCanvasSize/(imgHeight*dpr));pageContext.canvasWidth = imgWidth * dpr * scale;pageContext.canvasHeight = imgHeight * dpr * scale;}// 4. 創建畫布上下文const ctx = uni.createCanvasContext('watermarkCanvas', pageContext);ctx.scale(dpr, dpr);// 5. 繪制原圖ctx.drawImage(imgPath, 0, 0, imgWidth, imgHeight);// 6. 繪制水印const fontSize = 28 * dpr2;const lineHeight = fontSize + 8;const margin = 20 * dpr2;ctx.setFontSize(fontSize);ctx.setFillStyle('#3975e2');ctx.setTextAlign('left');ctx.setTextBaseline('bottom');console.log(777);watermarkLines.forEach((line, index) => {const y = imgHeight - margin - (index * lineHeight);ctx.fillText(line, margin, y);});// 7. 延遲確保繪制完成setTimeout(() => {ctx.draw(false, () => {uni.canvasToTempFilePath({canvasId: 'watermarkCanvas',destWidth: imgWidth,destHeight: imgHeight,fileType: 'jpg',quality: 0.9,success: (res) => {// 8. 再次重置畫布(為下一張圖準備)resetCanvasContext(pageContext);resolve(res.tempFilePath);},fail: (err) => {resetCanvasContext(pageContext);reject(new Error(`Canvas轉圖片失敗: ${JSON.stringify(err)}`));}}, pageContext);});}, 300); // 適當延遲確保繪制完成},fail: (err) => {reject(new Error(`獲取圖片信息失敗: ${JSON.stringify(err)}`));}});});
}

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

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

相關文章

【appium】5. Appium WebDriver 支持的常用方法匯總

下面是一個完整的 Appium WebDriver 支持的常用方法匯總&#xff0c;并附上典型用法示例。 一、元素查找方法/元素操作方法 ? 使用 find_element() 和 find_elements() from appium import webdriver from appium.webdriver.common.appiumby import AppiumBy# 單個元素查找 …

FreeRTOS 介紹、使用方法及應用場景

一、FreeRTOS 概述 FreeRTOS 是一款廣泛應用于嵌入式系統的實時操作系統&#xff08;RTOS&#xff09;&#xff0c;具有開源、可移植、可裁剪、輕量級等顯著特點。它最初由 Richard Barry 開發&#xff0c;如今已成為全球開發者在物聯網、工業控制、消費電子等領域的熱門選擇&a…

深度解析 Caffeine:高性能 Java 緩存庫

1. Caffeine 簡介 Caffeine 是一個基于 Java 8 的高性能本地緩存庫&#xff0c;由 Ben Manes 開發&#xff0c;旨在替代 Google Guava Cache&#xff0c;提供更優的緩存策略、更高的吞吐量和更靈活的配置。 核心優勢 ? 卓越的性能&#xff1a;采用優化的數據結構&#xff0…

創客匠人賦能創始人 IP 打造:健康行業知識變現案例深度解析

在知識服務行業蓬勃發展的當下&#xff0c;創始人 IP 打造已成為知識變現的核心驅動力。創客匠人近期披露的陪跑案例顯示&#xff0c;通過系統化的線上線下聯動運營&#xff0c;傳統行業從業者可高效實現 IP 價值轉化。以亓黃中醫科技創始人吳豐言老師為例&#xff0c;其在創客…

64、最小路徑和

題目&#xff1a; 解答&#xff1a; 簡單dp。 定義&#xff1a;dp[i][j]為到達(i,j)所需要的最短路程 初始化&#xff1a;dp[0][0]grid[0][0]&#xff0c;同時對第一行和第一列的&#xff0c;第i個就是前i個之和加上自身 遞歸&#xff1a;dp[i][j]min(dp[i-1][j],dp[i][j-1…

獲取連接通義千問大語言模型配置信息的步驟:api_key、api_url

一、注冊并開通通義千問API服務 1. 注冊阿里云賬號 訪問 阿里云官網點擊右上角"免費注冊"&#xff0c;按指引完成賬號注冊和實名認證 2. 開通通義千問API服務 進入 通義千問API產品頁點擊"立即開通"&#xff0c;按提示完成服務開通&#xff08;部分服務…

汽車加氣站操作工考試題庫含答案【最新】

1.天然氣的主要成分是&#xff08;&#xff09;。 A. 乙烷 B. 乙烯 C. 甲烷 D. 乙炔 答案&#xff1a;C 2.CNG 加氣站中&#xff0c;加氣機的加氣軟管應&#xff08;&#xff09;進行檢查。 A. 每天 B. 每周 C. 每月 D. 每季度 答案&#xff1a;A 3.儲氣罐的安全閥應&#xf…

顯示任何結構的數組對象數據【向上自動滾動】

顯示任何結構的數組對象數據 <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>地圖編輯軟件 - 數…

GPIO模式詳解

一、GPIO的八種模式 GPIO支持4種輸入模式&#xff08;浮空輸入、上拉輸入、下拉輸入、模擬輸入&#xff09;和4種輸出模式&#xff08;開漏輸出、開漏復用輸出、推挽輸出、推挽復用輸出&#xff09;。 GPIO_Mode_AIN模擬輸入GPIO_Mode_IN_FLOATING浮空輸入GPIO_Mode_IPD下拉輸…

django rest_framework 自定義403 Forbidden錯誤頁面

django本來有是可以很方便自定義HTTP錯誤頁面的&#xff0c;網上資料一大把。核心是在項目的urls代碼中增加handler403的定義&#xff0c;比如&#xff1a; handler403 "app.views.your_custom_view" 404&#xff0c;500都是一樣的&#xff0c;重新定義handler404…

Kafka Streams架構深度解析:從并行處理到容錯機制的全鏈路實踐

在流處理技術領域&#xff0c;Kafka Streams以其輕量級架構與Kafka生態的深度整合能力脫穎而出。作為構建在Kafka生產者/消費者庫之上的流處理框架&#xff0c;它通過利用Kafka原生的分區、副本與協調機制&#xff0c;實現了數據并行處理、分布式協調與容錯能力的無縫集成。本文…

【嵌入式硬件實例】-555定時器控制舵機/伺服電機

555定時器控制舵機/伺服電機 文章目錄 555定時器控制舵機/伺服電機1、555定時器介紹2、舵機/伺服電機介紹3、硬件準備與接線使用 555 定時器 IC 的伺服電機控制器和測試儀電路是一個簡單的電路,可用于生成操作伺服電機所需的控制信號。該電路允許我們通過按下按鈕手動驅動/控制…

國產麒麟 安裝可視化數據庫軟件DBeaver(圖解)

目錄 ????????編輯DBeaver介紹 官網 通過強制使用 Ubuntu 模板來修復 add-apt-repository 重新添加 PPA 撤銷更改&#xff08;可選&#xff09; 官網直接下載 DBeaver CE 下載好后安裝軟件 啟動方式一 啟動方式二 啟動成功 在左側右擊新建連接 安裝驅動 測…

線程池 JMM 內存模型

線程池 & JMM 內存模型 文章目錄 線程池 & JMM 內存模型線程池線程池的創建ThreadPoolExecutor 七大參數飽和策略ExecutorService 提交線程任務對象執行的方法&#xff1a;ExecutorService 關閉線程池的方法&#xff1a;線程池最大線程數如何確定&#xff1f; volatile…

[論文閱讀] 軟件工程 + 教學 | 軟件工程項目管理課程改革:從傳統教學到以學生為中心的混合式學習實踐

軟件工程項目管理課程改革&#xff1a;從傳統教學到以學生為中心的混合式學習實踐 論文信息 arXiv:2506.14369 Agile and Student-Centred Teaching of Agile/Scrum Concepts Maria Spichkova Comments: Preprint. Accepted to the 29th International Conference on Knowledg…

Windows系統提示“mfc140u.dll丟失”?詳細修復指南,一鍵恢復程序運行!

當你興致勃勃地打開某個游戲或專業軟件時&#xff0c;突然彈出一條錯誤提示——“MFC140u.dll丟失”&#xff0c;程序直接閃退&#xff0c;讓人無比沮喪。別擔心&#xff01;這個問題并不復雜&#xff0c;通常只需重新安裝運行庫或修復系統文件即可解決。本文將為你提供詳細的修…

云XR(AR/VR)算力底座關鍵特征與技術路徑

云XR&#xff08;AR/VR&#xff09;算力底座是支撐擴展現實技術規模化落地的核心基礎設施&#xff0c;當前發展呈現以下關鍵特征與技術路徑&#xff1a; 一、算力架構&#xff1a;云邊端協同異構融合 分布式部署模式? 云端?&#xff1a;承擔高復雜度渲染與大數據處理&#x…

Android開發常用adb合集

Android開發常用adb合集 Android開發常用adb合集crash日志導出 Android開發常用adb合集 crash日志導出 bugreport: adb bugreportdropbox: adb shell dumpsys dropbox --print > desktop/full_dropbox_logs.txt

LTspice仿真4——exp指數函數波形

參數設置 Vinitial&#xff1a;初始電壓值 Vpulsed&#xff1a;脈沖達到值 Rise Delay&#xff1a;上升延遲時間 Rise Tau&#xff1a;上升指數系數tau Fall Delay&#xff1a;下降延遲時間 Fall Tau&#xff1a;下降指數系數tau tau決定指數波形下降或者上升快慢&#x…

[Java 基礎]集合框架

在 Java 中&#xff0c;我們經常需要存儲和操作一組數據&#xff0c;而集合框架就是為此而生。它提供了一套統一的接口和類&#xff0c;幫助我們高效地管理各種數據集合。 常用的集合框架中的類只有 ArrayList、LinkedList、HashSet、HashMap 這 4 個&#xff0c;這些類的繼承…