一、定义一个canvas标签,微信小程序的实现方式有所变动
<!-- #ifdef MP-WEIXIN -->
<canvas type="2d" id="upload-canvas" class="uploadCanvas"
:style="{'width':width+'px','height':height+'px','position':'absolute','z-index':'-999','left':'-1000000px'}"></canvas>
<!-- #endif -->
<!-- #ifdef H5 -->
<canvas canvas-id="upload-canvas" class="uploadCanvas"
:style="{'width':width+'px','height':height+'px','position':'absolute','z-index':'-999','left':'-1000000px'}"></canvas>
<!-- #endif -->
二、拿到图片后添加水印
addWatermark(fileUrl) {
let that = this;
return new Promise((resolve, reject) => {
uni.getImageInfo({
src: fileUrl, // 替换为你的图片路径
success: async (res) => {
console.log("res", res);
const imageWidth = res.width;
const imageHeight = res.height;
that.width = imageWidth;
that.height = imageHeight;
await util.sleep(1000);
// #ifdef MP-WEIXIN
const query = wx.createSelectorQuery()
query.select('#upload-canvas')
.fields({
node: true,
size: true
})
.exec((resCanvas) => {
let filePath = res.path;
// 获取文件系统管理器
const fs = uni.getFileSystemManager();
// 读取图片文件为Base64编码
fs.readFile({
filePath: filePath,
encoding: 'base64',
success: function(res) {
const base64Data = res.data;
console.log("base64Data==",base64Data)
const canvas = resCanvas[0].node
canvas.width = that.width;
canvas.height = that.height;
const ctx = canvas.getContext('2d')
let img = canvas
.createImage(); // 注意是使用canvas实例 不是ctx
img.src =
`data:image/png;base64,${base64Data}`
img.onload = () => {
ctx.drawImage(img, 0, 0,that.width,that.height);
ctx.font = '16px',
ctx.fillStyle =
'rgba(0, 0, 0, 1)';
const lineHeight = 20; // 水印文字行高
const lines = that.watermarkText
.split('\n');
const x = 10; // 水印左上角 x 坐标
let y = 20; // 水印左上角 y 坐标
lines.forEach((line) => {
ctx.fillText(line, x,
y);
y += lineHeight;
});
ctx.stroke();
// 保存Canvas绘制结果为临时文件
uni.canvasToTempFilePath({
canvas: canvas,
success: (res) => {
// 将临时文件路径保存到数组中
resolve(res
.tempFilePath
)
},
fail: (error) => {
console.error(
'Failed to save canvas:',
error);
},
});
}
},
fail: function(error) {
console.log("eee", error);
}
});
})
// #endif
// #ifdef H5
const ctx = uni.createCanvasContext('upload-canvas', this);
ctx.drawImage(res.path, 0, 0, imageWidth,
imageHeight);
ctx.setFontSize(16);
ctx.setFillStyle('rgba(0, 0, 0, 1)'); // 设置水印颜色和透明度
const lineHeight = 20; // 水印文字行高
const lines = that.watermarkText
.split('\n');
const x = 10; // 水印左上角 x 坐标
let y = 20; // 水印左上角 y 坐标
lines.forEach((line) => {
ctx.fillText(line, x,
y);
y += lineHeight;
});
ctx.stroke();
ctx.draw(false, () => {
// 保存Canvas绘制结果为临时文件
uni.canvasToTempFilePath({
canvasId: 'upload-canvas',
success: (res) => {
// 将临时文件路径保存到数组中
resolve(res.tempFilePath)
},
fail: (error) => {
console.error('Failed to save canvas:',
error);
},
}, this);
});
// #endif
},
fail: (error) => {
console.error(error);
},
});
})
},
三、改进版本
改进原因:
1、Canvas 2D(新接口)需要显式设置画布宽高,默认:300150,最大:13651365
ios 无法上传较大图片的尺寸,固对超过此尺寸的图片进行了等比缩放的处理;文章来源:https://www.toymoban.com/news/detail-726538.html
2、在页面中设置canvas宽高,导致页面有滚动条;现在采用离屏的canvas,但是离屏的canvas,canvasToTempFilePath方法又不支持,故先把canvas转化为base64,然后存储到本地文件,然后再读一遍文件文章来源地址https://www.toymoban.com/news/detail-726538.html
addWatermark(fileUrl) {
let that = this;
return new Promise((resolve, reject) => {
uni.getImageInfo({
src: fileUrl,
fail: (error) => {}, // 替换为你的图片路径
success: async (res) => {
console.log("res", res);
let radio = 1365 / Math.max(res.width, res.height)
let imageWidth = Math.round(res.width * radio)
let imageHeight = Math.round(res.height * radio)
that.width = imageWidth;
that.height = imageHeight;
// #ifdef MP-WEIXIN
let filePath = res.path;
// 获取文件系统管理器
const canvas = wx.createOffscreenCanvas({
type: '2d',
width: imageWidth,
height: imageHeight
})
let img = canvas.createImage(); // 注意是使用canvas实例 不是ctx
// 等待图片加载
await new Promise(resolve => {
img.onload = resolve
img.src = filePath; // 要加载的图片 url
})
canvas.width = imageWidth;
canvas.height = imageHeight;
const ctx = canvas.getContext('2d')
ctx.drawImage(img, 0, 0, imageWidth,
imageHeight);
ctx.font = '28px arial',
ctx.fillStyle =
'rgba(255, 255, 255, 1.0)';
const lineHeight = 50; // 水印文字行高
const lines = that.watermarkText
.split('\n');
const x = 40; // 水印左上角 x 坐标
let y = imageHeight -
200; // 水印左上角 y 坐标
// 文字添加阴影效果
ctx.shadowColor = 'black';
ctx.shadowBlur = 5;
ctx.shadowOffsetX = 2;
ctx.shadowOffsetY = 2;
// 添加水印图标
lines.forEach((line) => {
ctx.fillText(line, x,
y);
y += lineHeight;
});
// 设置线条颜色和宽度
ctx.strokeStyle = '#fff'; // 设置线条颜色为白色
ctx.lineWidth = 3; // 设置线条宽度为 3 像素
// 绘制竖线
ctx.beginPath(); // 开始路径
ctx.moveTo(20, imageHeight -
220); // 移动到起点坐标 (x, y)
ctx.lineTo(20, imageHeight -
100); // 画一条竖线到终点坐标 (x, y)
ctx.stroke();
// 保存Canvas绘制结果为临时文件
//ios不兼容
if (this.navBarHeight == 44) {
console.log('ios上传');
//if (true) {
//string type
//图片格式,默认为 image/png
//number encoderOptions
//在指定图片格式为 image/jpeg 或 image/webp的情况下,可以从 0 到 1 的区间内选择图片的质量。如果超出取值范围,将会使用默认值 0.92。其他参数会被忽略。
let base64 = canvas.toDataURL("image/png", 0.8);
const time = new Date().getTime();
const imgPath = wx.env.USER_DATA_PATH + "/poster" + time + "upload" +
".png";
//如果图片字符串不含要清空的前缀,可以不执行下行代码.
const imageData = base64.replace(/^data:image\/\w+;base64,/, "");
const fs = wx.getFileSystemManager();
fs.writeFileSync(imgPath, imageData, "base64");
fs.close()
wx.getImageInfo({
src: imgPath,
success: (res) => {
console.log("读取写入的文件", res)
resolve(res.path)
},
fail: (res) => {
console.log("读取写入的文件失败", res)
}
})
} else {
console.log('android 上传');
uni.canvasToTempFilePath({
canvas: canvas,
fileType: "jpg",
success: (res) => {
uni.compressImage({ //图片压缩
src: res
.tempFilePath,
success: (
res) => {
// // 将临时文件路径保存到数组中
resolve(res
.tempFilePath
)
}
})
},
fail: (error) => {
console.error(
'Failed to save canvas:',
error);
},
});
}
}
// #endif
});
})
},
到了这里,关于uni-app 实现图片上传添加水印操作的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!