一、整体步骤流程:
1、用小程序的页面把想要的海报格式渲染出来(有海报设计稿的话此处可以不用)。
我的海报组成:上面一张背景图,背景图的左下方是说明文字,说明文字可以随意编辑,右下方是一张固定的二维码图片,这三部分组成
2、在第一步的页面上放一个按钮“生成海报”,加一个点击事件,点击按钮后跳转到海报页面
第一步渲染的页面上,我需要把图片地址和录入的文字信息传到海报的页面,所以跳转时带了两个参数:一个地址,一个文字标题
saveImage() {
//跳转到海报页面
uni.navigateTo({
url: '/pages/canTest/canTest?url=' + this.url + '&title=' + this.title
})
},
3、新的海报页面,通过canvas把海报画出来。
4、点击新生成的海报链接,预览海报,再把海报保存到手机相册
难点:canvas不会用,不知道怎么画。
二、操作过程:
1、海报页面写一个canvas组件
上面第2步点击“生成海报”,跳转到画海报的页面,页面上写一个canvas组件,然后给canvas一个点击事件 ,点击后可以预览画布画的图片。
style里面设置的是画布的宽度和高度
<template>
<view class="demo">
<canvas :style="{ width: canvasW + 'px', height: canvasH + 'px' }" canvas-id="myCanvas" id="myCanvas"
@click="saveHB"></canvas>
</view>
</template>
2、获取设备的信息和照片的信息,
(我的背景图用的是网络图片:this.url)
2.1获得屏幕的宽和高
//获取设备信息
this.SystemInfo = await this.getSystemInfo();
获得了设备的宽和高就是获得了画布的宽和高,如果画布高度不需要整个屏幕高,则可以减掉一部分,至于具体减掉多少自己调试就行,我减掉了150高度。
this.canvasW = this.SystemInfo.windowWidth; // 画布宽度
this.canvasH = this.SystemInfo.windowHeight - 150; //画布高度
2.2获得背景图片的实际宽和实际高
this.goodsImg = await this.getImageInfo(this.url); //获取照片信信息
2.3计算背景图片画在画布上时应该画的宽度和高度
这个在画布上需要画的背景图片的宽度,我的设计稿左右padding :20rpx,所以实际画的宽度是屏幕的宽度减掉两边一起20的宽度
this.picWidth = this.canvasW - 20
背景图片的在画布上的宽度确认后,要保证原图的缩放比,所以高度需要计算下:
原图宽 / 原图高=实际画的宽 / 实际画的高,
原图的宽和高通过getImageInfo得到了,新需要画的宽在上面一步得到了,所以实际需要的高为:实际画的宽*原图的高/原图的宽
this.picHight = this.picWidth * this.goodsImg.height / this.goodsImg.width
3.准备二维码图片
我没有自动生成二维码,直接准备了一张二维码图片
//二维码的信息
this.ewmImg = '/static/erweima.png';
4.画背景图
// 如果主图,二维码图片,设备信息都获取成功,开始绘制海报,这里需要用setTimeout延时绘制,否则可能会出现图片不显示。
//检查系统信息,图片信息都正常返回了
if (this.goodsImg.errMsg == 'getImageInfo:ok' && this
.SystemInfo.errMsg == 'getSystemInfo:ok') {
// console.log('ok')
//弹出提示,海报绘制中
uni.showToast({
icon: 'loading',
mask: true,
// duration: 5000,
title: '海报绘制中',
});
setTimeout(() => {
//准备ctx画布
var ctx = uni.createCanvasContext('myCanvas', this);
// 填充画布的背景色为白色
ctx.setFillStyle('#fff'); // 默认白色
//设置的画布的高度与宽度和2.1章节的屏幕宽高保持一致
ctx.fillRect(0, 0, this.canvasW, this.canvasH) // fillRect(x,y,宽度,高度)
// 绘制主背景图,因为有20rpx的padding,所以起始坐标是10,10,
//后面两个参数是图片需要画的宽度和高度
ctx.drawImage(this.goodsImg.path, 10, 10, this.picWidth, this.picHight)
5、绘制二维码
//如果有设计图,直接量设计图即可,
//没有设计图就慢慢调试
//我的x坐标是设备的宽度减掉前面文字组件的大概宽度:this.canvasW - 110
//我的Y坐标是上面背景图的高度加上中间隔离的高度:this.picHight + 45
//后面两个参数就是需要画的二维码的宽和高: this.ewmW
ctx.drawImage(this.ewmImg, this.canvasW - 110, this.picHight + 45, this.ewmW, this.ewmW)
// 6、绘制文字标题,多余文字自动换行
ctx.setFontSize(18); // setFontSize() 设置字体字号
ctx.setFillStyle('#000000'); // setFillStyle() 设置字体颜色
//canvas不能自动换行,需要自行计算 ,直接copy过去用
let _strlineW = 0;
let _strLastIndex = 0; //每次开始截取的字符串的索引
// let _strHeight = this.canvasW * rant + 30; //绘制字体距离canvas顶部的初始高度
let _strHeight = this.picHight + 70;
let _num = 1;
for (let i = 0; i < this.title.length; i++) {
_strlineW += ctx.measureText(this.title[i]).width;
// if (_strlineW > this.canvasW * rant - 155) {
if (_strlineW > this.canvasW - 155) {
if (_num == 4 && 4) {
//文字换行数量大于4进行省略号处理,想几行就改下上面的数字
ctx.fillText(this.title.substring(_strLastIndex, i - 5) + '...', 10,
_strHeight);
_strlineW = 0;
_strLastIndex = i;
_num++;
break;
} else {
ctx.fillText(this.title.substring(_strLastIndex, i), 20, _strHeight);
_strlineW = 0;
_strHeight += 20;
_strLastIndex = i;
_num++;
}
} else if (i == this.title.length - 1) {
ctx.fillText(this.title.substring(_strLastIndex, i + 1), 20, _strHeight);
_strlineW = 0;
}
}
/* end */
以下内容就比较容易了,直接照抄即可
ctx.draw(true, (ret) => { // draw方法 把以上内容画到 canvas 中。
uni.showToast({
icon: 'success',
mask: true,
title: '绘制完成',
});
uni.canvasToTempFilePath({ // 保存canvas为图片
canvasId: 'myCanvas',
quality: 1,
complete: (res) => {
this.hbUrl.push(res.tempFilePath)
},
})
});
}, 1000)
} else {
console.log('err')
}
7.给canvas绑定一个点击事件,点击后,可以预览图片,预览时可以长按图片进行转发和保存了
//预览图片接口,urls参数为数组,上面绘图得到的地址push到 this.hbUrl,就可以预览了
saveHB() {
// console.log('点击了图片')
uni.previewImage({
urls: this.hbUrl
})
},
下面时获取图片信息和获取系统信息的方法
// 获取图片信息
getImageInfo(image) {
return new Promise((req, rej) => {
uni.getImageInfo({
src: image,
success: (res) => {
req(res)
},
});
})
},
// 获取设备信息
getSystemInfo() {
return new Promise((req, rej) => {
uni.getSystemInfo({
success: function(res) {
req(res)
}
});
})
},
通过以上的方式,就可以生成海报图片了,点击海报也能预览,在预览页面长按就能把图片转发或者保存到电脑了,后面的操作无需任何方法。
整体页面的代码如下,直接复制过去,稍微调试下就能使用。
<template>
<view class="demo">
<canvas :style="{ width: canvasW + 'px', height: canvasH + 'px' }" canvas-id="myCanvas" id="myCanvas"
@click="saveHB"></canvas>
</view>
</template>
<script>
export default {
components: {},
data() {
return {
canvasW: 0, // 画布宽
canvasH: 0, // 画布高
picWidth: '', //图片宽
picHight: 260, //图片高
SystemInfo: {}, // 设备信息
goodsImg: {}, // 主图
ewmImg: {}, // 二维码图片
ewmW: 100, // 二维码大小
title: '营销是做一切的事情,让客户来找我;销售是做一切的事情,我去找客户。',
name: '周希奇', // 推荐人
hbUrl: [], //储存生成的图片地址
}
},
async onLoad(params) {
//获取从上衣页面传过来的图片参数
this.title = params.title
this.url = params.url
// 获取设备信息,获取设备的宽高,画布做一样的高度
this.SystemInfo = await this.getSystemInfo();
console.log('this.SystemInfo', this.SystemInfo)
this.canvasW = this.SystemInfo.windowWidth; // 画布宽度
this.canvasH = this.SystemInfo.windowHeight - 150; //画布高度
//获取背景图片的长与宽,按画布的比例进行缩放
this.goodsImg = await this.getImageInfo(this.url);
console.log('this.goodsImg', this.goodsImg)
//图片的宽度等于整个宽度减掉两边的padding
this.picWidth = this.canvasW - 20
//图片的高度= this.picWidth * 实际的宽度/原来的高度
this.picHight = this.picWidth * this.goodsImg.height / this.goodsImg.width
console.log('画的图片宽度为:', this.picWidth)
console.log('画的图片高度为:', this.picHight)
//二维码的信息
this.ewmImg = '/static/erweima.png';
// 如果主图,二维码图片,设备信息都获取成功,开始绘制海报,这里需要用setTimeout延时绘制,否则可能会出现图片不显示。
if (this.goodsImg.errMsg == 'getImageInfo:ok' && this
.SystemInfo.errMsg == 'getSystemInfo:ok') {
// console.log('ok')
uni.showToast({
icon: 'loading',
mask: true,
// duration: 5000,
title: '海报绘制中',
});
setTimeout(() => {
var ctx = uni.createCanvasContext('myCanvas', this);
// 填充背景色,白色
ctx.setFillStyle('#fff'); // 默认白色
ctx.fillRect(0, 0, this.canvasW, this.canvasH) // fillRect(x,y,宽度,高度)
// 绘制商品主图,二维码
ctx.drawImage(this.goodsImg.path, 10, 10, this.picWidth, this.picHight)
ctx.drawImage(this.ewmImg, this.canvasW - 110, this.picHight + 45, this.ewmW, this.ewmW)
// 3、绘制商品标题,多余文字自动换行
ctx.setFontSize(18); // setFontSize() 设置字体字号
ctx.setFillStyle('#000000'); // setFillStyle() 设置字体颜色
/* str 这段代码是我百度找的,参考别人的。canvas不能自动换行,需要自行计算 */
let _strlineW = 0;
let _strLastIndex = 0; //每次开始截取的字符串的索引
// let _strHeight = this.canvasW * rant + 30; //绘制字体距离canvas顶部的初始高度
let _strHeight = this.picHight + 70;
let _num = 1;
for (let i = 0; i < this.title.length; i++) {
_strlineW += ctx.measureText(this.title[i]).width;
// if (_strlineW > this.canvasW * rant - 155) {
if (_strlineW > this.canvasW - 155) {
if (_num == 4 && 4) {
//文字换行数量大于二进行省略号处理
ctx.fillText(this.title.substring(_strLastIndex, i - 5) + '...', 10,
_strHeight);
_strlineW = 0;
_strLastIndex = i;
_num++;
break;
} else {
ctx.fillText(this.title.substring(_strLastIndex, i), 20, _strHeight);
_strlineW = 0;
_strHeight += 20;
_strLastIndex = i;
_num++;
}
} else if (i == this.title.length - 1) {
ctx.fillText(this.title.substring(_strLastIndex, i + 1), 20, _strHeight);
_strlineW = 0;
}
}
/* end */
ctx.draw(true, (ret) => { // draw方法 把以上内容画到 canvas 中。
uni.showToast({
icon: 'success',
mask: true,
title: '绘制完成',
});
uni.canvasToTempFilePath({ // 保存canvas为图片
canvasId: 'myCanvas',
quality: 1,
complete: (res) => {
this.hbUrl.push(res.tempFilePath)
},
})
});
}, 1000)
} else {
console.log('err')
}
uni.showShareMenu({
withShareTicket: true,
menus: ["shareAppMessage", "shareTimeline"]
})
},
methods: {
saveHB() {
// console.log('点击了图片')
uni.previewImage({
urls: this.hbUrl
})
},
// 获取图片信息
getImageInfo(image) {
return new Promise((req, rej) => {
uni.getImageInfo({
src: image,
success: (res) => {
req(res)
},
});
})
},
// 获取设备信息
getSystemInfo() {
return new Promise((req, rej) => {
uni.getSystemInfo({
success: function(res) {
req(res)
}
});
})
},
//保存相片到本地
savePicture() {
uni.saveImageToPhotosAlbum({
filePath: this.hbUrl,
})
},
//分享相片
sharePicture() {
uni.share({
provider: 'weixin',
imageUrl: this.hbUrl,
type: 2,
scene: 'WXSceneTimeline'
})
},
},
}
</script>
<style lang="scss">
.button-container {
display: flex;
justify-content: center;
position: fixed;
top: 80%;
height: 100rpx;
width: 100%;
button {
width: 40%;
background-color: #0055ff;
}
}
</style>