50字范文,内容丰富有趣,生活中的好帮手!
50字范文 > 小程序保存海报 canvas绘制然后保存到相册 canvas文字换行计算

小程序保存海报 canvas绘制然后保存到相册 canvas文字换行计算

时间:2018-09-26 01:46:48

相关推荐

小程序保存海报 canvas绘制然后保存到相册 canvas文字换行计算

一、小程序保存海报,canvas绘制然后保存到相册

1.wxml

<view class="box-canvas"><canvas canvas-id='myCanvas' class='myCanvas'></canvas></view><view class='myPage'><view class='myPage-title'>{{myPageTitle}}</view><image class='myPage-img' src='{{myPageImg}}'></image><view class='myPage-time'>{{myPageTime}}</view><view class='myPage-msg'>{{myPageMsg}}</view><view class='myPage-author'>{{myPageAuthor}}</view></view><!-- 涉及授权,须用按钮 --><button bindtap='tosave' class='saveBtn'>保存</button>

2.wxss

/* 如果需要海报隐藏,可以给canvas套一个盒子,给这个盒子宽高置为零同时添加 overflow: hidden*//***如果不添加,在编辑器中是好的,但在手机中,canvas的层级会盖住自己原来的页面**/.box-canvas {width: 0;height: 0;overflow: hidden;}.myCanvas {width: 375px;height: 667px;position:fixed;left:9000px;}.myPage {padding: 0 25rpx;color: #ffe1c3;}.myPage-title{width: 100%;text-align: center;font-size: 46rpx;line-height: 80rpx;margin: 10rpx 0;}.myPage-img{width: 100%;}.myPage-time{width: 100%;font-size: 46rpx;margin: 10rpx 0;}.myPage-msg{width: 100%;font-size: 36rpx;line-height: 60rpx;}.myPage-author{width: 100%;font-size: 46rpx;text-align: right;margin: 10rpx 0;}.saveBtn{width: 200rpx;height: 50rpx;line-height: 50rpx;text-align: center;font-size: 30rpx;background-color: orange;color: #fff;border-radius: 50rpx;margin: 50rpx auto 0;}

3.js

var that;var myPageTitle = "我是标题";var myPageImg = "http://img-//12101159198567.png";var myPageTime = ".12.24";var myPageMsg = "这是段落这是段落这是段落这是段落这是段落这是段落这是段落 这是段落这是段落这是段落这是段落这是段落这是段落这是段落 这是段落这是段落这是段落这是段落这是段落这是段落这是段落";var myPageAuthor = "出处";Page({/*** 页面的初始数据*/data: {//iscreating,是否正在画图iscreating: false,canvasPath: ''},/*** 生命周期函数--监听页面加载*/onLoad: function (options) {that = this;that.setData({"myPageTitle": myPageTitle,"myPageImg": myPageImg,"myPageTime": myPageTime,"myPageMsg": myPageMsg,"myPageAuthor": myPageAuthor});},/*** 如果有过生成,那就保存* 如果没生成过,那就先生成,再保存* **/tosave: function () {if (that.data.canvasPath) {that.redrawCanvasImage();} else {that.drawCanvasImage(myPageImg);}},//重新保存图片redrawCanvasImage: function () {/**检测用户是否授权**/wx.getSetting({success: function (res) {/**授权,则调用相册**/if (res.authSetting["scope.writePhotosAlbum"] == true) {that.saveimg();} else if (res.authSetting["scope.writePhotosAlbum"] === false) {/**未授权,则打开授权页面,让用户授权**/wx.openSetting({success: (res) => {/**授权成功,则保存图片,失败则不保存**/if (res.authSetting["scope.writePhotosAlbum"] == true) {that.saveimg();}}})} else {that.saveimg();}},fail: function (res) {console.log("打开设置失败", res)}})},// 画图drawCanvas: function () {// 画图that.setData({"iscreating": true});// 获取画布var ctx = wx.createCanvasContext("myCanvas");ctx.clearRect(0, 0, 0, 0);//固定宽高var WIDTH = 750 / 2;var HEIGHT = 1334 / 2;/*** 如果需要底图,背景图,bgimg为底图的路径* ctx.drawImage(bgimg, 0, 0, WIDTH, HEIGHT);* **///绘制文章标题ctx.setFontSize(46 / 2);ctx.setFillStyle('#ffe1c3');ctx.setTextAlign('center');ctx.fillText(myPageTitle, 750 / 2 / 2, 30);// 画图片ctx.drawImage(that.data.myPageImg, 12.5, 50, 350, 240);//绘制文章时间ctx.setFontSize(46 / 2);ctx.setFillStyle('#ffe1c3');ctx.setTextAlign('left');ctx.fillText(myPageTime, 12.5, 320);//绘制文章正文// 正文 单行显示字符长度var textChangeLength = 39;//es6写法let [contentLeng, contentArray, contentRows] = that.textChangeLine(myPageMsg, textChangeLength);ctx.setTextAlign('left')ctx.setFontSize(36 / 2);let contentHh = 36 / 2 * 1.3;for (let m = 0; m < contentArray.length; m++) {ctx.fillText(contentArray[m], 12.5, 350 + contentHh * m);}// 绘制 出处ctx.setTextAlign('right')ctx.setFontSize(46 / 2);ctx.fillText(myPageAuthor, 360, (350 + contentHh * contentArray.length + 10));/*** 通过回调的方式,同时给一个小的延时,保证画布将图片完全画完* 确保生成图片时canvas绘制已完成* **/ctx.draw(false, setTimeout(function () {/*** 将画布内容转为图片* **/wx.canvasToTempFilePath({canvasId: 'myCanvas',fileType: 'jpg',quality: 1,success(res) {/*** 如果页面需要用到生成的图片路径,通过res.tempFilePath可以取到* **/that.setData({canvasPath: res.tempFilePath,iscreating: false});that.saveimg();},fail: function (res) {console.log("截取图片失败", res);}})}, 500));},//保存图片到相册saveimg: function () {wx.saveImageToPhotosAlbum({filePath: that.data.canvasPath,success(res) {wx.showToast({title: '已保存到相册'});},fail(res) {}})},// 截字// text为传入的文本 num为单行显示的字节长度textChangeLine: function (text, num) {// text byte lengthlet strLength = 0;let rows = 1;let str = 0;let arr = [];for (let j = 0; j < text.length; j++) {if (text.charCodeAt(j) > 255) {strLength += 2;if (strLength > rows * num) {strLength++;arr.push(text.slice(str, j));str = j;rows++;}} else {strLength++;if (strLength > rows * num) {arr.push(text.slice(str, j));str = j;rows++;}}}arr.push(text.slice(str, text.length));return [strLength, arr, rows] // [处理文字的总字节长度,每行显示内容的数组,行数]},// 把网络图片变为本地资源drawCanvasImage: function (url) {if (typeof url === 'string') {// 小程序获取图片信息APIwx.getImageInfo({src: url,success: function (res) {console.log(res)that.setData({myPageImg: res.path});//画图that.drawCanvas();},fail(err) {console.log(err)}})}},})

4.效果(授权成功,会保存海报)

5.说明

5.1有部分代码来自:/WangYangsea/article/details/79953346

(其中的截取字符,换行部分);

5.2对于字体

官网:https://developers./miniprogram/dev/api/canvas/CanvasContext.fillText.html

(1)CanvasContext.fillText(文本, 左上角 x 坐标位置, 左上角 y 坐标位置, 需要绘制的最大宽度【可选】)

(2)若字体需要居中,可使用

ctx.setTextAlign('center')ctx.fillText('万科金域东方', 750 / 2 / 2, 80);

让字体居中对齐,设置从中轴线画,居中即可https://developers./miniprogram/dev/api/canvas/CanvasContext.fillText.html

(3)如果字体不设置最大宽度maxWidth,会一直往后写,不换行,字体大小不变,超出隐藏;如果设置了最大宽,会全部挤一块,字体自动缩小,如果字特别多,就会挤得看不清了;

5.3createCanvasContext

wx.createCanvasContext('myCanvas');

(myCanvas为)

官网:https://developers./miniprogram/dev/api/canvas/wx.createCanvasContext.html?search-key=createCanvasContext

5.4ctx.drawImage(图片路径, 起始x坐标, 起始y坐标, 宽度, 高度)

官网:https://developers./miniprogram/dev/api/canvas/CanvasContext.drawImage.html?search-key=drawImage

5.5CanvasContext.draw(本次绘制是否接着上一次绘制, 绘制完成后执行的回调函数)

官网:https://developers./miniprogram/dev/api/canvas/CanvasContext.draw.html

5.6wx.canvasToTempFilePath

(1)代码

wx.canvasToTempFilePath({//<canvas> 组件的 canvas-idcanvasId: 'myCanvas',//图片类型,jpg和pngfileType: 'jpg',//图片的质量,目前仅对 jpg 有效。取值范围为 (0, 1]quality: 1,success(res) {/*** 如果页面需要用到生成的图片路径,通过res.tempFilePath可以取到* **/},fail: function (res) {console.log("截取图片失败", res);}})

(2)简单说明:

①更详细见官网:https://developers./miniprogram/dev/api/wx.canvasToTempFilePath.html?search-key=canvasToTempFilePath

②如果对输出的图片大小有要求可通过destWidth和destHeight来设置,如果对画布区域的宽度和高度有要求可以通过width和height来设置,官网中有详细说明;

5.7wx.saveImageToPhotosAlbum

(1)代码

wx.saveImageToPhotosAlbum({//生成的图片路径filePath: that.data.canvasPath,success(res) {wx.showToast({title: '已保存到相册'});},fail(res) {}})

(2)官网:https://developers./miniprogram/dev/api/media/image/wx.saveImageToPhotosAlbum.html?search-key=wx.saveImageToPhotosAlbum

5.8wx.getSetting(https://developers./miniprogram/dev/api/wx.getSetting.html?search-key=getSetting)

wx.getSetting({success(res) {console.log(res.authSetting)// res.authSetting = {// "scope.userInfo": true,// "scope.userLocation": true// }//可以拿到用户是否授权过相册的使用权限//res.authSetting["scope.writePhotosAlbum"]}})

5.9wx.openSetting

(1)https://developers./miniprogram/dev/api/open-api/setting/wx.openSetting.html?search-key=wx.openSetting

(2)调起客户端小程序设置界面,返回用户设置的操作结果;

(3)代码

wx.openSetting({success (res) {console.log(res.authSetting)// res.authSetting = {// "scope.userInfo": true,// "scope.userLocation": true// }}})

5.10wx.getImageInfo

(1)代码

wx.getImageInfo({//网络图片路径src: url,success: function (res) {console.log(res)//res.path可以拿到本地图片路径//that.setData({//myPageImg: res.path//});},fail(err) {console.log(err)}})

(2)获取图片信息。网络图片需先配置download域名才能生效。

(3)https://developers./miniprogram/dev/api/wx.getImageInfo.html?search-key=wx.getImageInfo

6.几点说明

(1)画布完成之后才能转图片,转图片应该放在draw的回调之后,最好再加一个小的延时;

(2)画布没有text-align: center;,如果想要文字居中可以找到中轴线,从中轴线画文字即可;

(3)画布上的文字不会自动换行,如果不设置最大宽,他会文字大小不变自动超出,超出部分隐藏;如果设置了最大宽度,文字会挤在一起,字体自动缩小,但如果文字特别多的时候,会惨不忍睹(你可以自己试试哈);所以如果设置了最大宽,建议填充的文字被超出太多;

(3)当文字比较多,就必须用到换行,也能换,字体大小固定以后可以看看一行能放多少个字,然后把需要填充的文字按照数组最大存放量截成数组,使用循环把数组的每项一个一个画,在每个数组的高度上递增,即可达到换行的视觉效果;

(4)画布中不能使用网络资源,如果必须用到网络资源,首先通过wx.getImageInfo把网络资源转为本地资源才能使用,并且该网络图片资源必须为可以下载的,否则还是不能使用(官网中也有提到);

(5)保存海报,需要用到用户的相册权限,只有当用户授权成功才能使用,否则无法保存,所以在用户点击保存时,需要检测相册授权wx.getSetting的(res.authSetting["scope.writePhotosAlbum"] == true);如果用户没授权则需要打开授权wx.openSetting;

(6)有些时候,在页面弄两个按钮,一个保存图片,一个再次保存(说白了,该按钮就是打开授权);这样还比较繁琐,用一个按钮就好,每次点击都判断是否对相册授权,授权了就保存,没授权就打开授权页面让用户授权,如果用户还是不授权,n那么再次点击按钮还是打开授权(这里可能会感觉,不太好,但是你自己想想,我保存海报就是要用到相册授权,你就是不授权,你还想保存海报,这怎么可能,所以不授权就不能保存,逻辑上也是说得通的);

(7)在保存的时候,先判断是否存在图片路径,如果存在图片路径(则说明已经经历了画布绘制,画布转为图片地址的过程)我们就可以直接保存了,如果不存在图片路径(则说明没有经历画布绘制,更不存在画布转为图片地址)我们就需要先绘制再保存。(当然了,这只是一个小技巧,如果你再绘制生成一次也没错,但是不需要(你既然生成过了,就可以直接保存呗));

(8)在使用画布保存时,可以控制输出大小,如果在页面存在多处使用,可以按照需要选择不同的尺寸;

(9)canvas组件是小程序自带的,它的层级是最高的,如果想让它隐藏在视口中(你直接通过position: absolute;z-index: -100;在编辑器中确实隐藏了,但到了手机中,它又跑出来了),可以给canvas外包裹一个盒子,给这个盒子设置{width: 0;height: 0;overflow: hidden;}即可,如果此法不行可以通过<canvas canvas-id='canOne' class='canOne' style='width:1080px;height:1643px;position:fixed;left:9000px;'></canvas>来实现(此法比较好用,同时兼容安卓和ios);

二、canvas文字换行计算

/**** 文本换行处理方法* * context:canvas对象 * fontsize:需绘制文本的字体大小 * text:需绘制文本内容 * context_width:需绘制文本区域宽度 * row_num:需绘制文本的行数* ****/breakLinesForCanvas: function (context, fontsize, text, context_width, row_num) {var that = this;// pxtorpx:比例(视缩放比而定:如果等比画布,则按画布设计稿比例;如果固定,则不变)that.data.pxtorpx = 750 / 750; context.setFontSize(fontsize);// 对于接口返回的强制换行符处理('\r\n'处理换行符)var textArray = text.split('\r\n');var row = [];for (let i = 0; i < textArray.length; i++) {var chr = textArray[i].split("");var temp = "";for (var j = 0; j < chr.length; j++) {if (context.measureText(temp + chr[j]).width < context_width) {temp += chr[j];} else {row.push(temp);temp = chr[j];}}row.push(temp);}// 如果数组长度大于所需长度(row_num) 则截所需长度(row_num之前的部分)if (row.length > row_num) {var row_cut = row.slice(0, row_num);var row_part = row_cut[row_num - 1];var test = "";var empty = [];var ellipsis_length = 20 * that.data.pxtorpx;for (var k = 0; k < row_part.length; k++) {if (context.measureText(test + row_part[k]).width < context_width - ellipsis_length) {test += row_part[k];} else {break;}}empty.push(test);var group = empty[0] + "..."; //这里只显示两行,超出的用...表示row_cut.splice(row_num - 1, 1, group);row = row_cut;}return row;},get_row() {var calc_row = that.breakLinesForCanvas(context, fontsize, text, context_width, 2);}

7.参考推荐博客

参考博客:/WangYangsea/article/details/79953346

参考博客:/q/1010000013885641

推荐:/cdj61/p/9507192.html(有动态的思路,如果宽度想自适应,可以参考一下)

推荐:/zzgyq/p/8882995.html

推荐:/p/374e5b5376d7(有动态思路,可以参考,推荐)

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。