前言
在帮客户开发一个关于生成证书的功能!需要把图片合成,然后在指定的位置添加上文字,最后把图片合成让用户保存到相册里面!
这就是效果图
其中,爱呵呵,小程序二维码,比赛名称,项目,都是会动态替换的文字!
碰到的所有问题
总体来说就是开发的时候容易钻牛角尖
- 问题1:小程序使用canvas怎么隐藏
- 问题2:保存到用户手机相册需要更新用户隐私协议
- 问题3: 配置下载域名,
- 问题4:下载太慢了
解决的办法
其实解决办法就没用canvas!
哈哈哈,并不是没用使用,是中间有一个步骤没想明白!客户着急要,最后使用了sharp在服务端去合成的然后返回链接下载,保存
因为一开始,我希望原图下载,我就使用了2481px * 3580px 这个宽高比例 然后去生成 出来的图片1.5mb差不多,感觉没问题,但不知道为什么上传到服务器,图片突然变成了10mb 特别是不同手机好像出来的还不一样。我的代码是
javascript
download() {
if (this.isDownloading) {
return
console.log('下载中')
}
this.isDownloading = true
uni.getSetting({
success: res => {
if (!res.authSetting['scope.writePhotosAlbum']) {
uni.showModal({
title: '提示',
content: '需要获取图片权限哦',
success: r => {
console.log('同意')
this.downloadImages()
uni.openSetting({
success: res => {
console.log(res)
},
fail: er => {
console.log(er)
}
})
}
})
} else {
console.log('授权了的')
this.downloadImages()
}
}
})
}
下载之前 先去 判断是否授权了,没有就去授权, 然后就去执行 downloadImages 下载图片
kotlin
async downloadImages() {
try {
uni.showLoading({
title: '正在颁发中...',
})
const [imageRes, logoRes] = await Promise.all([
this.downloadFilePromise(this.bgUrl),
this.downloadFilePromise(this.logoUrl)
])
if (imageRes.statusCode === 200 && logoRes.statusCode === 200) {
this.localImagePath = imageRes.tempFilePath
this.localImageLogo = logoRes.tempFilePath
// 绘制图片到 canvas 并保存
console.log('图片', this.localImageLogo,this.localImagePath)
this.drawAndSaveImage()
} else {
console.error('下载图片失败')
}
} catch (error) {
console.error('下载图片失败', error)
this.isDownloading = false
}
},
javascript
downloadFilePromise(url) {
return new Promise((resolve, reject) => {
uni.downloadFile({
url,
success: resolve,
fail: reject
})
})
},
这里就是去下载图片,然后去开始使用canvas绘画,
到了绘画哪里 就是使用canvas 获取,在小程序里面 使用:
kotlin
const ctx = uni.createCanvasContext('myCanvas', this)
在template 需要去所明一个:
css
<canvas canvas-id="myCanvas" style="position: fixed; left: 100%;"></canvas>
这里就是canvas在绘画的时候,会在页面出现,特别是我这个宽高特别丑,关于隐藏!首先排除v-if 然后使用display:none 这个也是不可以的,v-show 同样不可以, visibility: hidden; 我也使用了,测试的时候可以,但一到真机上,我发现还是会出现!
最后可以的办法就是使用:position: fixed; left: 100%; 只能说 CSS YYDS
kotlin
drawAndSaveImage() {
// 设置画布宽高
const canvasWidth = 827
// const canvasWidth = 2481
const canvasHeight = 1169
// const canvasHeight = 3580
const ctx = uni.createCanvasContext('myCanvas', this)
// 填背景图
ctx.drawImage(this.localImagePath, 0, 0, canvasWidth, canvasHeight)
// 添加姓名
ctx.setFontSize(50)
ctx.setFillStyle('#555500')
ctx.setTextAlign('center')
ctx.fillText(this.name, 420, 680)
// 添加内容
ctx.setFontSize(24)
ctx.setFillStyle('#111')
ctx.setTextAlign('center')
ctx.fillText(this.title, 460, 765)
ctx.setTextAlign('center')
ctx.fillText(this.subtitle, 300, 805)
// 添加小程序logo
ctx.drawImage(this.localImageLogo, 330, 900, 150, 150)
uni.hideLoading()
ctx.draw(false, () => {
uni.showLoading({
title: '正在加载图片'
})
// 开始绘制
uni.canvasToTempFilePath({
canvasId: 'myCanvas',
quality: 0.7,
success: res => {
},
fail: err => {}
})
}
}
这里我一开始就是把这里的图片直接使用uni.saveImageToPhotosAlbum 保存到了 用户手机相册,但是我报了下载域不在配置名单的错误,因此,我就只能上传到我的服务器 也是这里上传的时候,我莫名其妙发现res.tempFilePath 上传到服务器 我手机上传是1.49MB, 其他人的手机每一个上传的大小都不一样,还有的到10MB, 导致的结果就是 太慢了 几十秒 根本不可能等待! 于是我的第一个解决办法就是把 canvas的宽高但除 3 然后一样的步骤去操作
我发现还是不可以!一样的问题!太大了,我百思不得其解,为什么图片体积增大了
我去查了文档 看了下 uni.canvasToTempFilePath 这个方法的介绍
destWidth | Number | 否 | 输出图片宽度(默认为 width * 屏幕像素密度) |
---|---|---|---|
destHeight | Number | 否 | 输出图片高度(默认为 height * 屏幕像素密度) |
感觉这里是图片可能变化的问题,但我不确定,这个东西着急要,我不能拖着!
于是我放弃了之前的做法,我直接在服务端生成图片,让小程序端下载,然后保存就可以了,前端只需要提供我需要的三个参数就可以了!
于是在服务端使用sharp 完成了代码!然后返回前端一个链接,
javascript
// 这就是服务端处理好的图片url: fillUrl
uni.downloadFile({
url: fillUrl,
success: downloadRes => {
if (downloadRes.statusCode === 200) {
console.log('图片下载成功')
// 将图片保存到相册
uni.hideLoading()
uni.saveImageToPhotosAlbum({
filePath: downloadRes.tempFilePath,
success: saveRes => {
uni.showToast({
title: '图片保存成功',
icon: 'none'
})
this.isDownloading = false
},
fail: saveErr => {
uni.showToast({
title: `保存失败${saveErr}`,
icon: 'none'
})
this.isDownloading = false
}
})
} else {
this.isDownloading = false
console.error('图片下载失败', downloadRes)
}
},
fail: err => {
console.error(err)
uni.hideLoading()
uni.showToast({
title: '下载失败',
icon: 'none'
})
this.isDownloading = false
}
})
速度大概几百毫秒把!体积也才100kb 左右使用的webp 画质也不错!
下面是服务端的代码:
ini
const sharp = require('sharp')
const path = require('path')
const fs = require('fs')
async generateImage(ctx) {
const { name, title, subtitle } = ctx.request.body
const width = 827
const height = 1169
const x = width / 2
// const y = 680
const fontFamily = 'Microsoft YaHei'
const fontSize = 40
const color = 'black'
const stroke = 'transparent'
const nameImage = Buffer.from(`
<svg width="${width}px" height="${height}px" xmlns="http://www.w3.org/2000/svg">
<text
text-anchor="middle"
y="680" x="${x}"
font-family="${fontFamily}"
font-size="${fontSize}px"
fill="red"
stroke="${stroke}"
>${name}</text>
</svg>`)
const titleImage = Buffer.from(
`<svg width="${width}px" height="${height}px" xmlns="http://www.w3.org/2000/svg">
<text
text-anchor="middle"
y="765" x="460"
font-family="${fontFamily}"
font-size="24px"
stroke="${stroke}"
fill="${color}"
>${title}</text>
</svg>`
)
const subImage = Buffer.from(
`<svg width="${width}px" height="${height}px" xmlns="http://www.w3.org/2000/svg">
<text
text-anchor="middle"
y="805" x="300"
font-family="${fontFamily}"
font-size="24px"
stroke="${stroke}"
fill="${color}"
>${subtitle}</text>
</svg>`
)
try {
// 读取原始图像
const image = await sharp('public/img/logo.webp')
// 缩放至指定尺寸
.resize(827, 1169)
// 添加文字水印
.composite([
{ input: nameImage },
{ input: titleImage },
{ input: subImage },
{
input: 'public/img/logo.png',
top: 900,
left: 330,
},
])
// 输出为 WebP 格式,质量设置为 90%
.webp({ quality: 90 })
// 将处理后的图像转换为 Buffer
.toBuffer()
// 保存图片到服务器指定路径
const fileName = Date.now().toString() + 'zs.webp'
const DIST_FOLDER_PATH = path.join(__dirname, '..', '..', 'uploadFiles')
const distFilePath = path.join(DIST_FOLDER_PATH, fileName) //目的地
fs.writeFileSync(distFilePath, image)
// 发送处理后的图像给前端
ctx.body = new SuccessModel({ data: `/${fileName}` })
} catch (error) {
// 如果处理过程中出现错误,返回错误信息给前端
console.log(error)
ctx.status = 500
ctx.body = new ErrorModel({ status: 500, message: 'Internal Server Error' })
}
}
npm install sharp 就可以,记得确保你的环境是windows还是linux服务端还是mac 好像不太一样,文档有比较仔细的教程!
不清晰的地方
- 关于图片尺寸为什么在上传的时候变大,我为此还以为是我的服务上传代码配置问题,后面排查了很多次,才发现是我的平台尺寸问题,上传就一直失败,百思不得其解 ~
- 为什么visibility: hidden; 在电脑上测试可以,到真机上就不可以了会显示出来,除此之外我还试了用 view去包裹 canvas 然后 view 设置了width:0px;height:0px;overflow:hidden; 可是一样不可以没有效果,canvas在渲染的时候还是会出现!
反馈总结
记录这次使用uni-app开发小程序中,使用canvas的问题,虽然最后还是没有使用这个方法,哈哈哈。 sharp确实好用