微信小程序-海报制作(canvas)
Posted yw00yw
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了微信小程序-海报制作(canvas)相关的知识,希望对你有一定的参考价值。
文档
- https://developers.weixin.qq.com/miniprogram/dev/api/canvas/wx.createOffscreenCanvas.html
- 以下是按照1倍图画的,可以先画出来再调整合适的倍图
- 以下宽度、文字间距等可以使用变量代替
wxml
<view class="canvas-container">
<canvas
canvas-id="myCanvas"
class="myCanvas"
style="width: canvasWidthpx; height: canvasHeightpx;">
</canvas>
<view class="btn-save" bindtap="savePoster">保存到相册</view>
</view>
wxss
.myCanvas
display: block;
margin: 0 auto;
.btn-save
margin: 20rpx;
padding: 10rpx;
border: 1rpx solid #eee;
text-align: center;
font-size: 24rpx;
border-radius: 4rpx;
js
// pages/canvas/canvas.js
Page(
/**
* 页面的初始数据
*/
data:
canvasWidth: 296, // 绘图区域宽度
canvasHeight: 426, // 绘图区域高度
bgUrl: 'https://img-crs.vchangyi.com/standard/new_buy_poster_bg2.png',
goodsUlr: 'https://img-crs.vchangyi.com/goods16233105466440.jpg',
card_url: '' // 生成图片的id
,
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options)
const canvasWidth, canvasHeight, bgUrl, goodsUlr = this.data;
// 定义画布对象
const ctx = wx.createCanvasContext("myCanvas", this);
// 获取图片
Promise.all([
this.getCode(bgUrl),
this.getCode(goodsUlr)
]).then(res =>
// 背景图
ctx.drawImage(res[0].tempFilePath, 0, 0, canvasWidth, canvasHeight);
// 白背景
this.roundedRect(
ctx,
10,
56,
275,
360,
5,
5,
5,
5
);
ctx.fillStyle = "#ffffff";
ctx.fill();
// 商品图
ctx.drawImage(res[1].tempFilePath, 20, 66, 255, 255);
// 标题
this.drawText(ctx,
x: 20,
y: 255 + 66 + 20,
color: "#333333",
size: 14,
// isCenter: true,
text: '哈哈哈,大傻瓜,哈哈哈,大傻瓜哈哈哈',
width: "",
bold: true
);
this.drawText(ctx,
x: 20,
y: 255 + 66 + 40,
color: "#333333",
size: 14,
isCenter: true,
text: '哈哈哈,大傻瓜,哈哈哈',
width: 255,
bold: true
);
// 价格
this.drawText(ctx,
x: 20,
y: 390,
color: "#FA4046",
size: 16,
isCenter: true,
text: "¥",
width: "",
bold: true
);
// 元
this.drawText(ctx,
x: 20 + this.measureText('¥'),
y: 378,
color: "#FA4046",
size: 32,
isCenter: true,
text: 2,
width: "",
bold: true
);
// 角分
this.drawText(ctx,
x: 20 + 3 + this.measureText('¥') + this.measureText('2', 32),
y: 390,
color: "#FA4046",
size: 16,
isCenter: true,
text: "." + '02',
width: "",
bold: true
);
// 划线价
this.drawText(ctx,
x: 20 + 3 + 10 + this.measureText('¥') + this.measureText('2', 32) + this.measureText('.02', 16),
y: 394,
color: "#a6a6a6",
size: 12,
isCenter: true,
text: '¥7.99',
width: "",
bold: true
);
// 划线
this.lineation(ctx,
sx: 20 + 3 + 10 + this.measureText('¥') + this.measureText('2', 32) + this.measureText('.02', 16),
sy: 399,
ex: 20 + 3 + 5 + 10 + this.measureText('¥') + this.measureText('2', 32) + this.measureText('.02', 16) + this.measureText('¥7.99', 12),
ey: 399,
lineWidth: "",
color: "#a6a6a6"
);
ctx.draw();
setTimeout(() =>
console.log('生成', '....')
this.exportImg("myCanvas", 296, 426);
, 1000);
)
,
//把网路图片下载成本地图片
getCode(img)
return new Promise((resolve, reject) =>
wx.downloadFile(
url: img,
success: (res) =>
resolve(res)
)
)
,
// 生成指定的图片
exportImg(idn, w, h)
console.log(idn, w, h)
let that = this;
wx.canvasToTempFilePath(
x: 0,
y: 0,
width: w,
height: h,
destWidth: w,
destHeight: h,
canvasId: idn,
success: function(res)
console.log(res)
wx.getImageInfo(
src: res.tempFilePath,
success: function(res)
console.log(that, '.......');
// 生成的canvas图片路径
that.setData(
card_url: res.path
)
);
,
fail(err)
console.error(err);
,
complete()
,
this
);
,
// 保存海报
savePoster()
// 将图片保存到相册
wx.saveImageToPhotosAlbum(
filePath: this.data.card_url,
success(res)
wx.showToast(
title: '成功',
icon: 'success',
duration: 2000
)
,
fail()
// 判断是否获得了用户保存相册授权
wx.getSetting(
success: auth =>
if (!auth.authSetting["scope.writePhotosAlbum"])
wx.showToast(
title: '请开启相册授权',
icon: 'error',
duration: 2000
)
);
);
,
/**
* 工具 圆角矩形
* x, y 坐标
* width, height 宽高
* 圆角: 左下, 右下, 右上, 左上
*/
roundedRect(
ctx,
x,
y,
width,
height,
RTradius,
RBradius,
LBradius,
LTradius
)
// ctx.strokeStyle = "#fffbff";
ctx.beginPath();
// 右上
ctx.moveTo(x, y + RTradius);
ctx.lineTo(x, y + height - RTradius);
ctx.quadraticCurveTo(x, y + height, x + RTradius, y + height);
// 右下
ctx.lineTo(x + width - RBradius, y + height);
ctx.quadraticCurveTo(
x + width,
y + height,
x + width,
y + height - RBradius
);
// 左下
ctx.lineTo(x + width, y + LBradius);
ctx.quadraticCurveTo(x + width, y, x + width - LBradius, y);
// 左上
ctx.lineTo(x + LTradius, y);
ctx.quadraticCurveTo(x, y, x, y + LTradius);
// ctx.stroke();
ctx.closePath();
,
/**
* 文本填充方法
* @param String ctx 画布实例对象名
* @param Object obj 文本属性
* obj =
x: 绘制文本的左上角 x 坐标位置,如果这个文本要基于一个盒子水平居中,此值应该写盒子的左上角 x 坐标位置,
y: 绘制文本的左上角 y 坐标位置,
color: 绘制文本的颜色,
size: 绘制文本的字体大小,
isCenter: 文字的水平对齐方式(true,false),
text: 在画布上输出的文本内容,
width: 展示当前文本盒子的宽度,在文本需要水平居中是要加这个参数,
bold: 字体是否需要加粗(true、false)
*/
drawText(ctx, obj)
ctx.save();
ctx.fillStyle = obj.color;
ctx.setTextBaseline("top");
if (obj.bold)
ctx.font = `normal bold $obj.sizepx PingFangSC-Regular`;
else
ctx.font = `normal 100 $obj.sizepx PingFangSC-Regular`;
if (obj.isCenter && obj.width)
ctx.fillText(
obj.text,
obj.x + (obj.width - ctx.measureText(obj.text).width) / 2,
obj.y
);
else
ctx.fillText(obj.text, obj.x, obj.y);
ctx.restore();
ctx.closePath();
,
// 文本宽度计算
measureText(text, fontSize = 10)
let width = 0;
String(text)
.split("")
.forEach(item =>
if (/[a-zA-Z]/.test(item))
width += 7;
else if (/[0-9]/.test(item))
width += 5.5;
else if (/\\./.test(item))
width += 2.7;
else if (/-/.test(item))
width += 3.25;
else if (/[\\u4e00-\\u9fa5]/.test(item))
// 中文匹配
width += 10;
else if (/\\(|\\)/.test(item))
width += 3.73;
else if (/\\s/.test(item))
width += 2.5;
else if (/%/.test(item))
width += 8;
else
width += 10;
);
return (width * fontSize) / 10;
,
/**
* 文本划线
* @param String ctx 画布实例对象名
* @param Object obj
* obj =
sx: 划线的开始位置的 x 坐标位置,
sy: 划线的开始位置的 y 坐标位置,
ex: 划线的结束位置的 x 坐标位置,
ey: 划线的结束位置的 y 坐标位置,
lineWidth: 线条的宽度,
color: 画线的颜色
*/
lineation(ctx, obj)
// 开始一个新的绘制路径
ctx.beginPath();
// 设置线条的宽度
ctx.setLineWidth(1);
// 定义直线的起点坐标为
ctx.moveTo(obj.sx, obj.sy);
// 定义直线的终点坐标为
ctx.lineTo(obj.ex, obj.ey);
// 设置画线的颜色
ctx.strokeStyle = obj.color;
// 沿着坐标点顺序的路径绘制直线
ctx.stroke();
// 关闭当前的绘制路径
ctx.closePath();
)
效果图
以上是关于微信小程序-海报制作(canvas)的主要内容,如果未能解决你的问题,请参考以下文章
uniapp 手写canvas海报(兼容android/ios/h5/微信小程序)