uni生成canvas海报 / wx同理
如果发现绘制不出来的情况,初始化要加参数:
XML/HTML Code复制内容到剪贴板
- this.poster.context = uni.createCanvasContext(this.poster.id,this);
如果绘制最后一步发现报错:canvasToTempFilePath:fail fail canvas is empty
因为在自定义组件中使用canvas 需要添加this参数
uni.canvasToTempFilePath({
...
},this)
使用canvas组件:
XML/HTML Code复制内容到剪贴板
- <gui-poster ref="posterRef" id="canvas1" :posterDetail="posterDetail"></gui-poster>
- <script>
- export default {
- data() {
- return {
- posterDetail: {
- id: '',
- title: '',
- titlepic: '',
- name: '',
- avatar: '',
- qrcode: ''
- }
- }
- },
- created() {
- this.posterDetail = {
- title: ele.title,
- titlepic: ele.cover,
- name: this.hasLogin ? this.provider.nickname : '',
- avatar: this.hasLogin ? this.provider.avatar : '',
- qrcode: this.apiBaseUrl + 'road/poster-qrcode?id=' + ele.id
- }
- this.$refs.posterRef.getPoster()
- },
组件化:
XML/HTML Code复制内容到剪贴板
- <template>
- <canvas
- :style="{
- width:poster.widthIn+'px',
- height:poster.heightIn+'px',
- boxShadow: '0 0 15px #cccccc'
- }"
- :canvas-id="id" @longpress="longpress"></canvas>
- </template>
- <script>
- export default {
- props: {
- id: {
- type: String,
- default: 'Canvas1'
- },
- posterDetail: {
- type: Object,
- default() {
- return {
- title: '',
- titlepic: '',
- name: '',
- avatar: '',
- qrcode: ''
- }
- }
- }
- },
- data() {
- return {
- poster: {
- context : null, // canvas内容
- width : 700, // 画布宽度,单位 rpx
- height : 1000, // 画布高度
- widthIn : 300, // 自动计算转换为 px
- heightIn : 0, // 自动计算转换为 px
- bgColor : '#ffffff', // 背景颜色
- imgSrc : null,
- multiple : 1 // 将画布放大 2.0 - 2.9 倍(支持小数,过大app端会出现无法渲染的问题),保存的图片更清晰
- }
- }
- },
- // created() {
- // this.init()
- // console.log(this.item)
- // },
- methods: {
- // 生成海报
- getPoster() {
- if(this.poster.imgSrc) {
- return
- }
- uni.showLoading({title:'loading ...'});
- this.posterInitSize();
- // 画布初始化
- this.poster.context = uni.createCanvasContext(this.id,this);
- // console.log('context id', this.id)
- // this.poster.context.setFillStyle(this.poster.bgColor)
- // this.poster.context.fillRect(10, 10, 150, 75)
- // this.poster.context.draw()
- //延迟500毫秒等待画布创建
- setTimeout(()=>{
- this.posterDraw();
- uni.hideLoading();
- }, 500);
- },
- // 画布初始化
- posterInitSize : function () {
- // 将rpx单位值转换成px
- this.poster.widthIn = uni.upx2px(this.poster.width) * this.poster.multiple;
- this.poster.heightIn = uni.upx2px(this.poster.height) * this.poster.multiple;
- console.log('posterInitSize', this.poster.widthIn, this.poster.heightIn);
- },
- // 海报绘制代码
- posterDraw : function(){
- // 步骤 01. 绘制背景颜色
- this.step01();
- // 步骤 02. 绘制标题
- this.step02();
- // 步骤 03. 绘制发布人
- this.step03();
- // 步骤 04. 绘制最下面一行tips
- this.step04();
- // 步骤 05. 绘制图片等
- this.step05();
- },
- // 步骤 01 : 绘制背景颜色
- step01 : function () {
- // 设置填充色
- this.poster.context.setFillStyle(this.poster.bgColor);
- // 用fillRect(x, y, width, height)方法画一个矩形
- this.poster.context.fillRect(0,0,this.poster.widthIn, this.poster.heightIn);
- // 测试绘制矩形
- // this.poster.context.draw()
- },
- step02 : function () {
- // 文本内容,
- // x,
- // y,
- // 颜色,
- // 文本大小,
- // 横向对齐方式
- /**
- * 左侧空出30 px,顶部banner,260高度 + 20空隙
- */
- this.drawText(
- this.posterDetail.title,
- 30,
- 280,
- '#000000',
- 16 * this.poster.multiple,
- 'left'
- );
- },
- step03 : function () {
- // 文本内容,发布人,
- // x,
- // y,
- // 颜色,
- // 文本大小,
- // 横向对齐方式
- /**
- * 左侧空出30 px + 头像 50px ,顶部banner,260高度 + 20空隙
- * 底部空出30px + 一行字留白 40px
- */
- this.drawText(
- this.posterDetail.name,
- 80,
- this.poster.heightIn - 140,
- '#000000',
- 16 * this.poster.multiple,
- 'left'
- );
- },
- step04 : function () {
- // 文本内容,
- // x,
- // y,
- // 颜色,
- // 文本大小,
- // 横向对齐方式
- /**
- * 左侧空出30 px + 头像 50px ,顶部banner,260高度 + 20空隙
- * 底部空出30px + 一行字留白 40px
- */
- this.drawText(
- '长按小程序码进入探路官小程序查看更多精彩',
- 30,
- this.poster.heightIn - 50,
- '#666666',
- 13 * this.poster.multiple,
- 'left'
- );
- },
- async step05() {
- await this.drawBanner()
- await this.drawAvatar()
- await this.drawQrcode()
- // 在最后一步执行 drawIt 完整最终的绘制
- this.drawIt();
- },
- drawBanner() {
- const _this = this
- return new Promise(function (resolve) {
- // 绘制banner图
- uni.downloadFile({
- // 请使用自己的后端来实现二维码的生成
- url: _this.posterDetail.titlepic,
- success: (res) => {
- if (res.statusCode === 200) {
- /**
- * imageResource String 所要绘制的图片资源
- * x Number 图像左上角的x坐标
- * y Number 图像左上角的y坐标
- * width Number 图像宽度
- * height Number 图像高度
- */
- _this.poster.context.drawImage(res.tempFilePath, 0, 0, _this.poster.widthIn, 240);
- resolve();
- }
- },
- fail:function(e){console.log(e);}
- });
- })
- },
- drawAvatar() {
- const _this = this
- return new Promise(function (resolve) {
- // 绘制头像
- uni.downloadFile({
- // 请使用自己的后端来实现二维码的生成
- url: _this.posterDetail.avatar,
- success: (res) => {
- if (res.statusCode === 200) {
- /**
- * imageResource String 所要绘制的图片资源
- * x Number 图像左上角的x坐标
- * y Number 图像左上角的y坐标
- * width Number 图像宽度
- * height Number 图像高度
- */
- _this.poster.context.drawImage(res.tempFilePath, 30, _this.poster.heightIn - 170, 40, 40);
- resolve();
- }
- },
- fail:function(e){console.log(e);}
- });
- })
- },
- drawQrcode() {
- const _this = this
- return new Promise(function (resolve) {
- // 绘制二维码
- uni.downloadFile({
- url: _this.posterDetail.qrcode,
- header: {
- 'token': _this.gRequest.token
- },
- success: (res) => {
- if (res.statusCode === 200) {
- /**
- * imageResource String 所要绘制的图片资源
- * x Number 图像左上角的x坐标
- * y Number 图像左上角的y坐标
- * width Number 图像宽度
- * height Number 图像高度
- */
- _this.poster.context.drawImage(res.tempFilePath, _this.poster.widthIn - 180, _this.poster.heightIn - 250, 150, 150);
- resolve();
- }
- },
- fail:function(e){console.log(e);}
- });
- })
- },
- // 绘制文本, 参数 : 文本内容,x,y,颜色,文本大小,横向对齐方式
- drawText:function(content, x, y, color, size, align){
- const ctx = this.poster.context
- ctx.setFontSize(size);
- ctx.setFillStyle(color);
- ctx.setTextAlign(align);
- // this.poster.context.fillText(content,x,y);
- var lineWidth = 0;
- var canvasWidth = this.poster.widthIn - 60;//计算canvas的宽度,要留下两边的60
- var initHeight=y;//绘制字体距离canvas顶部初始的高度
- var lastSubStrIndex= 0; //每次开始截取的字符串的索引
- for(let i=0;i<content.length;i++){
- lineWidth+=ctx.measureText(content[i]).width;
- if(lineWidth>canvasWidth){
- ctx.fillText(content.substring(lastSubStrIndex,i),x,initHeight);//绘制截取部分
- initHeight+=20;//20为字体的高度
- lineWidth=0;
- lastSubStrIndex=i;
- }
- if(i==content.length-1){//绘制剩余部分
- ctx.fillText(content.substring(lastSubStrIndex,i+1),x,initHeight);
- }
- }
- },
- // 最终绘制函数
- drawIt : function(){
- this.poster.context.draw(true, ()=>{
- uni.canvasToTempFilePath({
- x: 0,
- y: 0,
- width: this.poster.widthIn,
- height: this.poster.heightIn,
- destWidth: this.poster.widthIn,
- destHeight: this.poster.heightIn,
- canvasId: this.id,
- success:(res)=>{
- // 在H5平台下,tempFilePath 为 base64
- this.poster.imgSrc = res.tempFilePath;
- },
- fail:(error) => {
- console.log('生成canvas失败', error)
- }
- },this);
- });
- },
- // 长按事件
- longpress : function () {
- uni.saveImageToPhotosAlbum({
- filePath: this.poster.imgSrc,
- success:()=>{
- // console.log('save success');
- uni.showToast({
- title:"图片已经保存到您的相册~"
- })
- }
- });
- }
- }
- }
- </script>
- <style>
- </style>
XML/HTML Code复制内容到剪贴板
- <template>
- <view>
- <view @click="open3">点我打开</view>
- <gui-popup ref="guipopup3" position="bottom">
- <view class="gui-relative gui-box-shadow gui-bg-gray" style="padding: 60rpx 20rpx;">
- <canvas
- :style="{
- width:poster.widthIn+'px',
- height:poster.heightIn+'px',
- boxShadow: '0 0 15px #cccccc'
- }"
- canvas-id="canvas1" @longpress="saveQrcode"></canvas>
- <!-- iphone 底部操作按钮躲避 -->
- <gui-iphone-bottom></gui-iphone-bottom>
- <!-- 关闭按钮 -->
- <text class="gui-block-text demo-close iconfont gui-color-white gui-absolute-rt"
- @tap.stop="close3"></text>
- </view>
- </gui-popup>
- <!-- <canvas
- :style="{
- width:poster.widthIn+'px',
- height:poster.heightIn+'px',
- boxShadow: '0 0 15px #cccccc'
- }"
- canvas-id="canvas1" @longpress="saveQrcode"></canvas> -->
- </view>
- </template>
- <script>
- export default {
- props: {
- posterDetail: {
- type: Object,
- default() {
- return {
- id: '',
- title: '海南中线骑行',
- titlepic: 'https://wxapp.tanluguan.cn/api/static/map.jpg',
- name: '我是张三',
- avatar: 'https://wxapp.tanluguan.cn/api/static/map.jpg',
- qrcode: 'https://wxapp.tanluguan.cn/api/road/poster-qrcode?id=1'
- }
- }
- }
- },
- data() {
- return {
- // "xingchengliangdian": []
- poster: {
- id: 'canvas1',
- context : null, // canvas内容
- width : 700, // 画布宽度,单位 rpx
- height : 1000, // 画布高度
- widthIn : 300, // 自动计算转换为 px
- heightIn : 0, // 自动计算转换为 px
- bgColor : '#ffffff', // 背景颜色
- imgSrc : null,
- multiple : 1 // 将画布放大 2.0 - 2.9 倍(支持小数,过大app端会出现无法渲染的问题),保存的图片更清晰
- }
- }
- },
- created() {
- // this.$nextTick(() => {
- // this.getPoster()
- // })
- },
- methods: {
- //03 底部弹出模式
- open3 : function () {
- if(!this.poster.imgSrc) {
- this.$refs.guipopup3.open();
- setTimeout(() => {
- this.getPoster()
- },500)
- }else{
- this.$refs.guipopup3.open();
- }
- },
- close3 : function () {this.$refs.guipopup3.close();},
- // 生成海报
- getPoster() {
- uni.showLoading({title:'loading ...'});
- this.posterInitSize();
- // 画布初始化
- this.poster.context = uni.createCanvasContext(this.poster.id, this);
- //延迟500毫秒等待画布创建
- setTimeout(()=>{
- this.posterDraw();
- uni.hideLoading();
- }, 500);
- },
- // 画布初始化
- posterInitSize : function () {
- // 将rpx单位值转换成px
- this.poster.widthIn = uni.upx2px(this.poster.width) * this.poster.multiple;
- this.poster.heightIn = uni.upx2px(this.poster.height) * this.poster.multiple;
- console.log('posterInitSize', this.poster.widthIn, this.poster.heightIn);
- },
- // 海报绘制代码
- posterDraw : function(){
- // 步骤 01. 绘制背景颜色
- this.step01();
- // 步骤 02. 绘制标题
- this.step02();
- // 步骤 03. 绘制发布人
- this.step03();
- // 步骤 04. 绘制最下面一行tips
- this.step04();
- // 步骤 05. 绘制图片等
- this.step05();
- },
- // 步骤 01 : 绘制背景颜色
- step01 : function () {
- // 设置填充色
- this.poster.context.setFillStyle(this.poster.bgColor);
- // 用fillRect(x, y, width, height)方法画一个矩形
- this.poster.context.fillRect(0,0,this.poster.widthIn, this.poster.heightIn);
- // 测试绘制矩形
- // this.poster.context.draw()
- },
- step02 : function () {
- // 文本内容,
- // x,
- // y,
- // 颜色,
- // 文本大小,
- // 横向对齐方式
- /**
- * 左侧空出30 px,顶部banner,260高度 + 20空隙
- */
- this.drawText(
- this.posterDetail.title,
- 30,
- 280,
- '#000000',
- 16 * this.poster.multiple,
- 'left'
- );
- },
- step03 : function () {
- // 文本内容,
- // x,
- // y,
- // 颜色,
- // 文本大小,
- // 横向对齐方式
- /**
- * 左侧空出30 px + 头像 50px ,顶部banner,260高度 + 20空隙
- * 底部空出30px + 一行字留白 40px
- */
- this.drawText(
- this.posterDetail.name,
- 80,
- this.poster.heightIn - 170,
- '#000000',
- 16 * this.poster.multiple,
- 'left'
- );
- },
- step04 : function () {
- // 文本内容,
- // x,
- // y,
- // 颜色,
- // 文本大小,
- // 横向对齐方式
- /**
- * 左侧空出30 px + 头像 50px ,顶部banner,260高度 + 20空隙
- * 底部空出30px + 一行字留白 40px
- */
- this.drawText(
- '长按小程序码进入探路官小程序查看更多精彩',
- 30,
- this.poster.heightIn - 50,
- '#666666',
- 16 * this.poster.multiple,
- 'left'
- );
- },
- async step05() {
- await this.drawBanner()
- await this.drawAvatar()
- await this.drawQrcode()
- // 在最后一步执行 drawIt 完整最终的绘制
- this.drawIt();
- },
- drawBanner() {
- const _this = this
- return new Promise(function (resolve) {
- // 绘制banner图
- uni.downloadFile({
- // 请使用自己的后端来实现二维码的生成
- url: _this.posterDetail.titlepic,
- success: (res) => {
- if (res.statusCode === 200) {
- /**
- * imageResource String 所要绘制的图片资源
- * x Number 图像左上角的x坐标
- * y Number 图像左上角的y坐标
- * width Number 图像宽度
- * height Number 图像高度
- */
- _this.poster.context.drawImage(res.tempFilePath, 0, 0, _this.poster.widthIn, 240);
- resolve();
- }
- },
- fail:function(e){console.log(e);}
- });
- })
- },
- drawAvatar() {
- const _this = this
- return new Promise(function (resolve) {
- // 绘制头像
- uni.downloadFile({
- // 请使用自己的后端来实现二维码的生成
- url: _this.posterDetail.avatar,
- success: (res) => {
- if (res.statusCode === 200) {
- /**
- * imageResource String 所要绘制的图片资源
- * x Number 图像左上角的x坐标
- * y Number 图像左上角的y坐标
- * width Number 图像宽度
- * height Number 图像高度
- */
- _this.poster.context.drawImage(res.tempFilePath, 30, _this.poster.heightIn - 200, 40, 40);
- resolve();
- }
- },
- fail:function(e){console.log(e);}
- });
- })
- },
- drawQrcode() {
- const _this = this
- return new Promise(function (resolve) {
- // 绘制二维码
- uni.downloadFile({
- url: _this.posterDetail.qrcode,
- success: (res) => {
- if (res.statusCode === 200) {
- /**
- * imageResource String 所要绘制的图片资源
- * x Number 图像左上角的x坐标
- * y Number 图像左上角的y坐标
- * width Number 图像宽度
- * height Number 图像高度
- */
- _this.poster.context.drawImage(res.tempFilePath, _this.poster.widthIn - 180, _this.poster.heightIn - 250, 150, 150);
- resolve();
- }
- },
- fail:function(e){console.log(e);}
- });
- })
- },
- // 绘制文本, 参数 : 文本内容,x,y,颜色,文本大小,横向对齐方式
- drawText:function(content, x, y, color, size, align){
- const ctx = this.poster.context
- ctx.setFontSize(size);
- ctx.setFillStyle(color);
- ctx.setTextAlign(align);
- // this.poster.context.fillText(content,x,y);
- var lineWidth = 0;
- var canvasWidth = this.poster.widthIn - 60;//计算canvas的宽度,要留下两边的60
- var initHeight=y;//绘制字体距离canvas顶部初始的高度
- var lastSubStrIndex= 0; //每次开始截取的字符串的索引
- for(let i=0;i<content.length;i++){
- lineWidth+=ctx.measureText(content[i]).width;
- if(lineWidth>canvasWidth){
- ctx.fillText(content.substring(lastSubStrIndex,i),x,initHeight);//绘制截取部分
- initHeight+=20;//20为字体的高度
- lineWidth=0;
- lastSubStrIndex=i;
- }
- if(i==content.length-1){//绘制剩余部分
- ctx.fillText(content.substring(lastSubStrIndex,i+1),x,initHeight);
- }
- }
- },
- // 最终绘制函数
- drawIt : function(){
- this.poster.context.draw(true, ()=>{
- uni.canvasToTempFilePath({
- x: 0,
- y: 0,
- width: this.poster.widthIn,
- height: this.poster.heightIn,
- destWidth: this.poster.widthIn,
- destHeight: this.poster.heightIn,
- canvasId: this.poster.id,
- success:(res)=>{
- // 在H5平台下,tempFilePath 为 base64
- this.poster.imgSrc = res.tempFilePath;
- uni.hideLoading();
- }
- },this);
- });
- },
- // 长按事件
- longpress : function () {
- uni.saveImageToPhotosAlbum({
- filePath: this.poster.imgSrc,
- success:()=>{
- console.log('save success');
- uni.showToast({
- title:"图片已经保存到您的相册~"
- })
- }
- });
- }
- }
- }
- </script>
- <style>
- </style>