uniapp 圖片添加水印代碼封裝(優化版、圖片上傳壓縮、生成文字根據頁面自適應比例、增加文字背景色

uniapp 圖片添加水印代碼封裝(優化版、圖片上傳壓縮、生成文字根據頁面自適應比例、增加文字背景色

多張照片上傳封裝

<template><view class="image-picker"><uni-file-picker v-model="imageValue" :auto-upload="false" :title="title" :limit="limit":image-styles="imageStyles" :file-mediatype="fileMediatype" :mode="mode" @select="select"><view v-if="loading" class="form-item-column-center"><u-loading-icon text="上傳中" textSize="12" :vertical="true"></u-loading-icon></view><view v-else class="form-item-column-center"><u-icon name="camera" size="28"></u-icon><view :style="{ marginTop: '5px'}">上傳照片</view></view></uni-file-picker><view class="watermark-canvas"><canvas id="watermark-canvas" :style="{ width: canvasWidth, height: canvasHeight }"canvas-id="watermark-canvas" v-if="flag" /></view></view>
</template><script>import {imageUpload,} from '@/api/system/applet.js' //圖片上傳import {imageChoose, //拿到后臺圖片上傳鏈接} from '@/utils/public.js'export default {name: 'ImageWatermarkPicker',props: {limit: {type: [Number, String],default: 1,},title: {type: String,default: null,},mode: {type: String,default: 'grid',},fileMediatype: {type: String,default: 'image',},imageStyles: {type: Object,default: null,},watermark: {type: Boolean,default: true,},// #ifdef VUE3modelValue: {type: Array,default () {return []},},// #endif// #ifndef VUE3value: {type: Array,default () {return []},},// #endif},emits: ['input', 'update:modelValue'],data() {return {flag: false, //繪制顯示imageValue: [],canvasWidth: '1080px',canvasHeight: '2160px',longitude: '', //坐標latitude: '', //y坐標addressName: '', //傳入公司地址loading: false,oldImageslength: null, //上傳時照片個數}},watch: {imageValue(newVal) {// #ifdef VUE3this.$emit('update:modelValue', newVal)// #endif// #ifndef VUE3this.$emit('input', newVal)// #endifthis.$emit('change', newVal)},// #ifndef VUE3value: {handler(newVal) {this.imageValue = newVal},immediate: true,},// #endif// #ifdef VUE3modelValue: {handler(newVal) {this.imageValue = newVal},immediate: true,},// #endif},methods: {// 檢測圖片,確保圖片存在checkImage(url) {const checkNum = 5let currentCheckNum = 1return new Promise((resolve, reject) => {process()function process() {uni.getImageInfo({src: url,success: function(image) {resolve(image)},fail: function(err) {if (checkNum <= currentCheckNum) {uni.showToast({title: '圖片上傳失敗',icon: 'none'})reject(err)} else {currentCheckNum++const timer = setTimeout(() => {clearTimeout(timer)process()}, 300)}},})}})},async select(e) {this.oldImageslength = e.tempFiles.lengthfor (let tempFile of e.tempFiles) {await this.watermarkProcess(tempFile)}},async watermarkProcess(tempFile) {const {name,size,extname,uuid,path} = tempFilelet url = nulllet photo = null// 添加水印if (this.watermark) {url = await this.addWatermark(path)}// 上傳圖片url = await this.uploadFile(url)// 檢測圖片,確保圖片存在await this.checkImage(url)this.imageValue = [...this.imageValue,{name,extname,url,photo,size,uuid,},]},getHeightOffset(height, index, fontSize) {return index == 0 ? (height - fontSize) : (height - (index * fontSize) - fontSize) - (index * (fontSize /3))},// 異步添加水印async addWatermark(tempFilePath) {// #ifdef MP-WEIXINthis.addressName = '測試位置'this.latitude = 119.651this.longitude = 80.654// #endifthis.flag = trueif (this.loading == true) {uni.showLoading({title: "上傳圖片",mask: true,})}return new Promise((resolve, reject) => {uni.getImageInfo({src: tempFilePath,success: async (res) => {// 設置畫布高度和寬度this.canvasWidth = `${res.width}px`this.canvasHeight = `${res.height}px`await this.sleep(200) // 某些平臺 canvas 渲染慢,需要等待const ctx = uni.createCanvasContext('watermark-canvas', this)ctx.clearRect(0, 0, res.width, res.height)ctx.beginPath()ctx.drawImage(tempFilePath, 0, 0)// 第一個參數是圖片 第二、三是圖片在畫布位置 第四、五是將圖片繪制成多大寬高(不寫四五就是原圖寬高)let size// 根據圖片縱橫比設置字體大小,背景色相比一般ctx.fillStyle = 'rgba(0,0,0,0.1)'; // 設置背景色if (res.width / res.height > 1) {size = Math.floor(res.height / 26)//這個背景不一定適用,自行調整ctx.fillRect(0, res.height - (size*6), res.width, size*6); // 填充整個 Canvas 區域	} else {size = Math.floor(res.width / 26)ctx.fillRect(0, res.height - (size*7), res.width, size*7); // 填充整個 Canvas 區域	}let fontSize = sizectx.setFontSize(fontSize)ctx.shadowColor = "rgba(0,0,0,1.0)";//設置字體陰影,真機未生效ctx.shadowOffsetX = 5ctx.shadowOffsetY = 5let max = (res.width - fontSize) / fontSize //圖片上一行能顯示的最大字數let marks = []let address = "地址:" + this.addressNamelet location = "坐標:" + this.latitude + ',' + this.longitudelet fillTexts = [address, location, time]fillTexts.forEach((mark, index) => {//測量出最長文字的寬// console.log('文字寬:'+ctx.measureText(mark).width)if (mark.length <= max) {marks.push({mark: mark, //水印文字start: fontSize / 2 //第一個字的起點位置})} else {marks.push({mark: mark.substring(max),start: fontSize / 2 + fontSize *3 //第一個字的起點位置,+fontSize*3是因為此水印為當前mark的換行,因此縮進3字符})marks.push({mark: mark.substring(0, max),start: fontSize / 2 //第一個字的起點位置})}})// 繪制水印背景另外寫法,實測不太好用// ctx.fillStyle = 'rgba(0,0,0,0.1)'; // 設置背景色// ctx.fillRect(0, this.getHeightOffset(res.height, 4, fontSize), res.width,this.getHeightOffset(res.height, 4, fontSize)); // 填充整個 Canvas 區域	//繪制水印文字marks.forEach((mark, index) => {ctx.setFillStyle("rgba(250, 250, 250,1.0)")ctx.fillText(mark.mark, mark.start, this.getHeightOffset(res.height, index, fontSize))});ctx.draw(false, async () => {await this.sleep(500) // 某些平臺 canvas 渲染慢,需要等待uni.canvasToTempFilePath({canvasId: 'watermark-canvas',destWidth: res.width,destHeight: res.height,fileType: 'jpg',quality: 0.8,success: (fileRes) => {this.flag = falseresolve(fileRes.tempFilePath)},fail: (err) => {console.log('[Error draw]', err)uni.showToast({title: err.errMsg,icon: 'none'})reject()},},this,)})},fail: (err) => {console.log('[Error getImageInfo]', err)uni.showToast({title: err.errMsg,icon: 'none'})reject()},})})},//此位置為我上傳后臺的寫法,具體可按照自己的填寫async uploadFile(path) {let image = imageChoose(path)const res = await imageUpload(image).then(response => {this.oldImageslength--this.loading = this.oldImageslength == 0 ? false : truethis.oldImageslength == 0 ? uni.hideLoading() : ''return response.data.url})return res},sleep(millisecond) {return new Promise((resolve) => {setTimeout(resolve, millisecond)})},},}
</script><style lang="scss" scoped>canvas {position: absolute;left: 2000upx;}.image-picker {position: relative;.form-item-column-center {display: flex;align-items: center;justify-content: center;flex: 1;flex-direction: column;}.watermark-canvas {position: absolute;top: 5px;left: 5px;width: 1px;height: 1px;overflow: hidden;}}
</style>

應用實例

照片上傳實例
<template><view><photoList   v-model="baseFormData.faceImgsFirst"  :limit="1"/></view>
</template>
<script>
import photoOne from '@/pages/public/photoOne/photoOne.vue'
export default{components: {photoOne},data(){return{baseFormData:{}}},methods:{}
}
</script>

動態表單照片添加水印(直接使用)

注意imagelists必填,避免出現刪除不一致現象,發送為父級數據


<template><view><uni-forms><uni-forms-item label="照片" required :rules="[{required: true,errorMessage: '最少一張照片'}]":name="['inspectionCustodyWorkLogDetailBoList',index,'imagelist']" label-width="100rpx"><view class="form-item"><photoList   v-model="baseFormData.faceImgsFirst"  :limit="1"/></view></uni-forms-item></uni-forms></view>
</template>
<script>
import photoOne from '@/pages/public/photoOne/photoOne.vue'
export default{components: {photoOne},data(){// 基礎表單數據baseFormData: {inspectionCustodyWorkLogDetailBoList: [], },},methods:{}
}
</script>

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

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

相關文章

關于服務端接口知識的匯總

大家好&#xff0c;今天給大家分享一下之前整理的關于接口知識的匯總&#xff0c;對于測試人員來說&#xff0c;深入了解接口知識能帶來諸多顯著的好處。 一、為什么要了解接口知識&#xff1f; 接口是系統不同模塊之間交互的關鍵通道。只有充分掌握接口知識&#xff0c;才能…

http-server實現本地服務器

要實現一個本地服務器&#xff0c;你可以使用Node.js的http-server模塊。首先&#xff0c;確保你已經安裝了Node.js和npm。然后&#xff0c;按照以下步驟操作&#xff1a; 打開終端或命令提示符&#xff0c;進入你想要作為服務器根目錄的文件夾&#xff1b;運行以下命令安裝ht…

Axure PR 10 制作頂部下拉三級菜單和側邊三級菜單教程和源碼

在線預覽地址&#xff1a;Untitled Document 2.側邊三級下拉菜單 在線預覽地址&#xff1a;Untitled Document 文件包和教程下載地址&#xff1a;https://pan.quark.cn/s/77e55945bfa4 程序員必備資源網站&#xff1a;天夢星服務平臺 (tmxkj.top)

Linux x86_64 dump_stack()函數基于FP棧回溯

文章目錄 前言一、dump_stack函數使用二、dump_stack函數源碼解析2.1 show_stack2.2 show_stack_log_lvl2.3 show_trace_log_lvl2.4 dump_trace2.5 print_context_stack 參考資料 前言 Linux x86_64 centos7 Linux&#xff1a;3.10.0 一、dump_stack函數使用 dump_stack函數…

Unity開發中導彈路徑散射的原理與實現

Unity開發中導彈路徑散射的原理與實現 前言邏輯原理代碼實現導彈自身腳本外部控制腳本 應用效果結語 前言 前面我們學習了導彈的追蹤的效果&#xff0c;但是在動畫或游戲中&#xff0c;我們經常可以看到導彈發射后的彈道是不規則的&#xff0c;扭扭曲曲的飛行&#xff0c;然后擊…

數字生態系統的演進與企業API管理的關鍵之路

數字生態系統的演進與企業API管理的關鍵之路 在數字化時代&#xff0c;企業正經歷著一場轉型的浪潮&#xff0c;而API&#xff08;應用程序編程接口&#xff09;扮演著至關重要的角色。API如同一座橋梁&#xff0c;將組織內部的價值轉化為可市場化的產品&#xff0c;從而增強企…

韓國站群服務器在全球網絡架構中的重要作用?

韓國站群服務器在全球網絡架構中的重要作用? 在全球互聯網的蓬勃發展中&#xff0c;站群服務器作為網絡架構的核心組成部分之一&#xff0c;扮演著至關重要的角色。韓國站群服務器以其卓越的技術實力、優越的地理位置、穩定的網絡基礎設施和強大的安全保障能力&#xff0c;成…

LeetCode 題目 118:楊輝三角

題目描述 給定一個非負整數 numRows&#xff0c;生成楊輝三角的前 numRows 行。在楊輝三角中&#xff0c;每個數是它左上方和右上方的數的和。 楊輝三角解析 在這個詳解中&#xff0c;我們將使用 ASCII 圖形來說明楊輝三角的構建過程&#xff0c;包括逐行添加新的行的過程。…

250 基于matlab的5種時頻分析方法((短時傅里葉變換)STFT

基于matlab的5種時頻分析方法&#xff08;(短時傅里葉變換)STFT,Gabor展開和小波變換,Wigner-Ville&#xff08;WVD&#xff09;,偽Wigner-Ville分布(PWVD),平滑偽Wigner-Ville分布&#xff08;SPWVD&#xff09;,每條程序都有詳細的說明&#xff0c;設置仿真信號進行時頻輸出。…

Parted分區大容量磁盤

創建了新的虛擬磁盤10T , 掛載后分區格式化一.fdisk無法創建大容量的分區 Fileserver:~ # fdisk /dev/sdb Welcome to fdisk (util-linux 2.29.2). Changes will remain in memory only, until you decide to write them. Be careful before using the write command. Device …

使用html和css實現個人簡歷表單的制作

根據下列要求&#xff0c;做出下圖所示的個人簡歷&#xff08;表單&#xff09; 表單要求 Ⅰ、表格整體的邊框為1像素&#xff0c;單元格間距為0&#xff0c;表格中前六列列寬均為100像素&#xff0c;第七列 為200像素&#xff0c;表格整體在頁面上居中顯示&#xff1b; Ⅱ、前…

git提交代碼異常報錯error:bad signature 0x00000000

報錯信息 error:bad signature 0x00000000 異常原因 git 提交過程中異常關機或重啟&#xff0c;造成當前項目工程中的.git/index 文件損壞&#xff0c;無法提交 解決步驟 刪除.git/index文件 rm -f .git/index 重啟git git reset

Java 【數據結構】 哈希(Hash超詳解)HashSetHashMap【神裝】

登神長階 第十神裝 HashSet 第十一神裝 HashMap 目錄 &#x1f454;一.哈希 &#x1f9e5;1.概念 &#x1fa73;2.Object類的hashCode()方法: &#x1f45a;3.String類的哈希碼: &#x1f460;4.注意事項: &#x1f3b7;二.哈希桶 &#x1fa97;1.哈希桶原理 &#x…

Bert基礎(二十二)--Bert實戰:對話機器人

一 、概念簡介 1.1 生成式對話機器人 1.1.1什么是生成式對話機器人? 生成式對話機器人是一種能夠通過自然語言交互來理解和生成響應的人工智能系統。它們能夠進行開放域的對話,即在對話過程中,機器人可以根據用戶的需求和上下文信息,自主地生成新的、連貫的回復,而不僅…

如何使用CertCrunchy從SSL證書中發現和識別潛在的主機名稱

關于CertCrunchy CertCrunchy是一款功能強大的網絡偵查工具&#xff0c;該工具基于純Python開發&#xff0c;廣大研究人員可以利用該工具輕松從SSL證書中發現和識別潛在的主機信息。 支持的在線源 該工具支持從在線源或給定IP地址范圍獲取SSL證書的相關數據&#xff0c;并檢索…

大數據測試

1、前言 大數據測試是對大數據應用程序的測試過程&#xff0c;以確保大數據應用程序的所有功能按預期工作。大數據測試的目標是確保大數據系統在保持性能和安全性的同時&#xff0c;平穩無差錯地運行。 大數據是無法使用傳統計算技術處理的大型數據集的集合。這些數據集的測試涉…

Foxmail使用經驗總結

本篇博客將詳盡講解如何利用Foxmail進行高效的郵件管理&#xff0c;以及一些實用的使用技巧&#xff0c;讓郵件管理變得更為高效和有序。 1. 賬戶設置與管理 多賬戶整合&#xff1a;Foxmail支持多個郵件賬戶同時管理&#xff0c;用戶可以將個人和工作郵箱整合在同一個界面&am…

實戰中使用 QEMU 進行內網穿透

前言 閱讀 https://xz.aliyun.com/t/14052 《使用 QEMU 進行內網穿透&#xff1f;》 https://securelist.com/network-tunneling-with-qemu/111803/ 《Network tunneling with… QEMU?》 我將此項技術應用到實戰中&#xff0c;取得不錯的效果&#xff0c;但是也遇到很多坑&am…

機器學習算法應用——樸素貝葉斯分類器

樸素貝葉斯分類器 樸素貝葉斯分類器&#xff08;Naive Bayes Classifier&#xff09;是一種基于貝葉斯定理和特征條件獨立假設的分類方法。它適用于分類任務&#xff0c;特別是文本分類、垃圾郵件識別等領域。 原理 樸素貝葉斯分類器基于以下兩個主要假設&#xff1a; 特征條…

JS_ES6(1)

作用域鏈&#xff1a; 作用域鏈是底層變量查找的機制&#xff1a;當函數執行時&#xff0c;優先查找當前函數作用域中有無需要用到的變量&#xff0c;如果找不到&#xff0c;逐級查找父級&#xff0c;直到全局 > 嵌套關系形成作用域鏈&#xff0c;同一作用域鏈從小到大查找…