uniapp 图片添加水印代码封装(优化版、图片上传压缩、生成文字根据页面自适应比例、增加文字背景色

本文主要是介绍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>

这篇关于uniapp 图片添加水印代码封装(优化版、图片上传压缩、生成文字根据页面自适应比例、增加文字背景色的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/983546

相关文章

禁止HTML页面滚动的操作方法

《禁止HTML页面滚动的操作方法》:本文主要介绍了三种禁止HTML页面滚动的方法:通过CSS的overflow属性、使用JavaScript的滚动事件监听器以及使用CSS的position:fixed属性,每种方法都有其适用场景和优缺点,详细内容请阅读本文,希望能对你有所帮助... 在前端开发中,禁止htm

C++使用栈实现括号匹配的代码详解

《C++使用栈实现括号匹配的代码详解》在编程中,括号匹配是一个常见问题,尤其是在处理数学表达式、编译器解析等任务时,栈是一种非常适合处理此类问题的数据结构,能够精确地管理括号的匹配问题,本文将通过C+... 目录引言问题描述代码讲解代码解析栈的状态表示测试总结引言在编程中,括号匹配是一个常见问题,尤其是在

Java调用DeepSeek API的最佳实践及详细代码示例

《Java调用DeepSeekAPI的最佳实践及详细代码示例》:本文主要介绍如何使用Java调用DeepSeekAPI,包括获取API密钥、添加HTTP客户端依赖、创建HTTP请求、处理响应、... 目录1. 获取API密钥2. 添加HTTP客户端依赖3. 创建HTTP请求4. 处理响应5. 错误处理6.

使用 sql-research-assistant进行 SQL 数据库研究的实战指南(代码实现演示)

《使用sql-research-assistant进行SQL数据库研究的实战指南(代码实现演示)》本文介绍了sql-research-assistant工具,该工具基于LangChain框架,集... 目录技术背景介绍核心原理解析代码实现演示安装和配置项目集成LangSmith 配置(可选)启动服务应用场景

Python中顺序结构和循环结构示例代码

《Python中顺序结构和循环结构示例代码》:本文主要介绍Python中的条件语句和循环语句,条件语句用于根据条件执行不同的代码块,循环语句用于重复执行一段代码,文章还详细说明了range函数的使... 目录一、条件语句(1)条件语句的定义(2)条件语句的语法(a)单分支 if(b)双分支 if-else(

浅析如何使用Swagger生成带权限控制的API文档

《浅析如何使用Swagger生成带权限控制的API文档》当涉及到权限控制时,如何生成既安全又详细的API文档就成了一个关键问题,所以这篇文章小编就来和大家好好聊聊如何用Swagger来生成带有... 目录准备工作配置 Swagger权限控制给 API 加上权限注解查看文档注意事项在咱们的开发工作里,API

Deepseek使用指南与提问优化策略方式

《Deepseek使用指南与提问优化策略方式》本文介绍了DeepSeek语义搜索引擎的核心功能、集成方法及优化提问策略,通过自然语言处理和机器学习提供精准搜索结果,适用于智能客服、知识库检索等领域... 目录序言1. DeepSeek 概述2. DeepSeek 的集成与使用2.1 DeepSeek API

Python利用PIL进行图片压缩

《Python利用PIL进行图片压缩》有时在发送一些文件如PPT、Word时,由于文件中的图片太大,导致文件也太大,无法发送,所以本文为大家介绍了Python中图片压缩的方法,需要的可以参考下... 有时在发送一些文件如PPT、Word时,由于文件中的图片太大,导致文件也太大,无法发送,所有可以对文件中的图

MySQL数据库函数之JSON_EXTRACT示例代码

《MySQL数据库函数之JSON_EXTRACT示例代码》:本文主要介绍MySQL数据库函数之JSON_EXTRACT的相关资料,JSON_EXTRACT()函数用于从JSON文档中提取值,支持对... 目录前言基本语法路径表达式示例示例 1: 提取简单值示例 2: 提取嵌套值示例 3: 提取数组中的值注意

java获取图片的大小、宽度、高度方式

《java获取图片的大小、宽度、高度方式》文章介绍了如何将File对象转换为MultipartFile对象的过程,并分享了个人经验,希望能为读者提供参考... 目China编程录Java获取图片的大小、宽度、高度File对象(该对象里面是图片)MultipartFile对象(该对象里面是图片)总结java获取图片