微信小程序分享图片的简易canvas工具类

在微信小程序中生成一张海报以便用户可以分享到朋友圈的功能在很多微信小程序中都有,今天分享一个自己写的简易canvas工具类

如有需要请自取:GitHub微信小程序保存图片分享的 canvas 简易自用工具类

demo.jpg

所有参数按顺序传,没有默认值的必须传,如果需要修改最后一个参数,所有参数都需要传。。。(js小白,不知道怎么解决)

下面将大部分功能贴在下方

首先,一个将rpx转成px的方法,canvas使用px作为单位,(我这里UI使用750px宽做设计图,使用的时候将标注软件的px改成rpx就是我们需要的)这个方法我直接写在app.js里面,因为用到的地方很多,比如还有OSS
  onLaunch: function () {
    wx.getSystemInfo({
      success: res => {
        //获取屏幕宽度,然后根据宽度图获取图片
        this.globalData.screenWidth = res.screenWidth;
        this.globalData.pixelRatio = res.pixelRatio;
        this.globalData.factor = res.screenWidth / 750;
      },
    })
  },

  globalData: {
    userInfo: null,
    factor: 0.5,
    screenWidth: 375,
    pixelRatio: 2
  },
 
  toPx: function (rpx) {
    //这里的 2 可以改成 动态的 pixelRatio
    //设成固定的是为了在不同设备生成的图片可以在同一级分辨率 
    return rpx * this.globalData.factor * 2;
  }
1、绘制纯色背景

最开始没有写这个,但是安卓真机上需要所以加上了, 这个其实就是画一个矩形,记得宽高要超过你需要绘制的宽高

/**
 * @author 赵勇
 * @desc canvas 画纯色背景 (在iOS上不画默认白色,安卓上不画默认是透明色)
 * 
 *  @param ctx canvas上下文
 *  @param color 背景颜色
 *  @param width  背景宽
 *  @param height 背景高
 *  @param x 轴 坐标
 *  @param y 轴 坐标
 *
 */
function drawBackground(ctx, color = 'white', width = 1000, height = 3000, x = 0, y = 0) {
    ctx.rect(x, y, width, height)
    ctx.setFillStyle(color)
    ctx.fill()
}
使用

如果默认值满足,也可以只传一个参数即:canvas的上下文

canvasUtil.drawBackground(ctx);

要修改颜色可以

canvasUtil.drawBackground(ctx, '#999999');
2、绘制文字

这个是为了方便设置字体,字号,同时返回了最终的x轴坐标,是为了适应某些需要拼接文字的需求(比如价格拼接单位,但是单位字号不一样)

/**
 * @author 赵勇
 * @desc canvas 画文字
 * 
 *  @param ctx canvas上下文
 *  @param text 需要绘制的文字文字
 *  @param x 轴 坐标
 *  @param y 轴 坐标
 *  @param size 字体大小
 *  @param align 字体对齐方式
 *  @param color 字体颜色
 *  @param baseline 字体基线对齐方式
 *  @param fontWeight 字体粗细
 *
 *  @return 绘制完的 x轴 坐标值
 */
function drawText(ctx, text, x, y, size = '18', align = 'left', color = '#333333', baseline = 'top', fontWeight = 'normal') {
    size = parseInt(size)
    let font = `${fontWeight} ${size}px sans-serif`;
    ctx.font = font;

    ctx.setTextAlign(align);
    ctx.setFillStyle(color);
    ctx.setTextBaseline(baseline);
    ctx.fillText(text, x, y);
    let m = ctx.measureText("" + text)
    return m.width + x;
}
注意点:

(1)size 转成整数是因为字号设置是用rpx转px的,会出现小数的情况,而在canvas里面。。。一不小心就报错了 (2)ctx.measureText();可以测量字符串的长度,但是不能是数字、、、我这里就踩坑了,所以转成字符串

使用:

只传部分参数

canvasUtil.drawBreakText(ctx, "text", app.toPx(50), app.toPx(350));

所有参数都用上

  canvasUtil.drawBreakText(ctx, "text", app.toPx(50), app.toPx(350), app.toPx(38), app.toPx(40), app.toPx(650), 'left', '#999999', 'top', 'bold');
3、绘制换行文字

这个需求也算是常见了吧,这里将返回值改成最后的y坐标值,相信大家也是能理解的啦

/**
 * @author  赵勇
 * @desc  canvas画文字带换行 单位(px)
 * 
 * @param ctx canvas上下文
 * @param text 需要绘制的文字文字
 * @param x x轴 坐标值    
 * @param y y轴 坐标值
 * @param lineHeight 行高
 * @param maxW  文字最宽值
 * @param align 文字对齐方式
 * @param color 字体颜色
 * @param baseline 字体基线对齐方式
 * @param fontWeight 字体粗细
 *
 * @return 最后一行的底部 y轴 坐标值
 */
function drawBreakText(ctx, text, x, y, size, lineHeight, maxW, align = 'left', color = '#333333', baseline = 'top', fontWeight = 'normal') {
    size = parseInt(size)
    let font = `${fontWeight} ${size}px sans-serif`;
    ctx.font = font;
    ctx.setTextAlign(align);
    ctx.setFillStyle(color);
    ctx.setTextBaseline(baseline);

    let textArr = text.split("");
    const count = textArr.length;
    let tempText = "";
    let row = [];
    for (let i = 0; i < count; i++) {
        if (ctx.measureText(tempText).width < maxW) {
            tempText += textArr[i];
        } else {
            I--;
            row.push(tempText);
            tempText = "";
        }
    }
    row.push(tempText);

    let i = 0;
    for (i; i < row.length; i++) {
        ctx.fillText(row[i], x, y + i * lineHeight, maxW);
    }

    return y + i * lineHeight;
}

具体实现逻辑就是循环所有字符,然后去判断长度,看的不是很明白的可以cue我

4、绘制图片,但是保持比例填充

我想在小程序里面,只有mode:aspectFill才是我们真的用的最多的吧!

/**
 * @author 赵勇
 * @desc canvas 绘制图  mode:aspectFill 保持比例填充
 *
 * @param ctx canvas上下文
 * @param imagePath 图片url
 * @param sWidth 原图宽
 * @param sHeight 原图高
 * @param dx canvas x轴 坐标
 * @param dy canvas y轴 坐标
 * @param dWidth canvas 宽
 * @param dHeight canvas 高
 */
function drawImageAspectFill(ctx, imagePath, sWidth, sHeight, dx, dy, dWidth, dHeight) {
    //canvas与图片宽高比
    var wRatio = dWidth / sWidth;
    var hRatio = dHeight / sHeight;
    //裁剪图片中间部分
    if (sWidth >= dWidth && sHeight >= dHeight || sWidth <= dWidth && sHeight <= dHeight) {
        if (wRatio > hRatio) {
            ctx.drawImage(imagePath, 0, (sHeight - dHeight / wRatio) / 2, sWidth, dHeight / wRatio, dx, dy, dWidth, dHeight);
        } else {
            ctx.drawImage(imagePath, (sWidth - dWidth / hRatio) / 2, 0, dWidth / hRatio, sHeight, dx, dy, dWidth, dHeight);
        }
    }
    //拉伸图片
    else {
        if (sWidth <= dWidth) {
            ctx.drawImage(imagePath, 0, (sHeight - dHeight / wRatio) / 2, sWidth, dHeight / wRatio, dx, dy, dWidth, dHeight);
        } else {
            ctx.drawImage(imagePath, (sWidth - dWidth / hRatio) / 2, 0, dWidth / hRatio, sHeight, dx, dy, dWidth, dHeight);
        }
    }
}

这个具体看例子吧。。我懒得写了

5、绘制图片,但是保持比例填充,同时还要圆角

(1)绘制圆角的方法,网上很多,我抄的,所以也就不做解释了

/**
 * @author 赵勇
 * @desc canvas 绘制圆角视图
 *
 * @param ctx canvas上下文
 * @param x canvas x轴 坐标
 * @param y canvas y轴 坐标
 * @param w 宽
 * @param h 高
 * @param r 圆角半径
 * @param fill 填充 true  边框 false
 */
function drawRoundRect(ctx, x, y, w, h, r, fill = true) {
    //开始绘制
    ctx.beginPath();
    // 因为边缘描边存在锯齿,最好指定使用 transparent 填充
    // 这里是使用 fill 还是 stroke都可以,二选一即可
    if (fill) {
        ctx.setFillStyle('transparent')
    } else {
        ctx.setStrokeStyle('transparent')
    }

    // 左上角
    ctx.arc(x + r, y + r, r, Math.PI, Math.PI * 1.5)

    // border-top
    ctx.lineTo(x + w - r, y)

    // 右上角
    ctx.arc(x + w - r, y + r, r, Math.PI * 1.5, Math.PI * 2)

    // border-right
    ctx.lineTo(x + w, y + h - r)

    // 右下角
    ctx.arc(x + w - r, y + h - r, r, 0, Math.PI * 0.5)

    // border-bottom
    ctx.lineTo(x + r, y + h)

    // 左下角
    ctx.arc(x + r, y + h - r, r, Math.PI * 0.5, Math.PI)

    // border-left
    ctx.lineTo(x, y + r)

    // 这里是使用 fill 还是 stroke都可以,二选一即可,但是需要与上面对应
    if (fill) {
        ctx.fill()
    } else {
        ctx.stroke()
    }

    ctx.closePath()
}

(2)最后调用绘制圆角和绘制图片的方法

/**
 * @author 赵勇
 * @desc canvas 绘制圆角图  mode:aspectFill 保持比例填充
 *
 * @param ctx canvas上下文
 * @param imagePath 图片url
 * @param sWidth 原图宽
 * @param sHeight 原图高
 * @param dx canvas x轴 坐标
 * @param dy canvas y轴 坐标
 * @param dWidth canvas 宽
 * @param dHeight canvas 高
 * @param radius 圆角半径
 */
function drawImageAspectFillWidthCorner(ctx, imagePath, sWidth, sHeight, dx, dy, dWidth, dHeight, radius = 0) {
    ctx.save();
    drawRoundRect(ctx, dx, dy, dWidth, dHeight, radius);
    // 剪切
    ctx.clip()
    drawImageAspectFill(ctx, imagePath, sWidth, sHeight, dx, dy, dWidth, dHeight);
    ctx.restore();
}

这里需要注意的就是这三个方法的调用时机啦

    ctx.save();
    ctx.clip()
    ctx.restore();
最后一个,下载图片。。。what?下载图片和canvas有啥关系、、、当我需要绘制很多图片时,当图片数量不固定时。。。我就需要他了
/**
 * @author 赵勇
 * @desc 下载图片数组
 *
 * @param images 图片url数组
 * @param success 成功回调
 * 
 */
function downloadImages(images, success, info = [], i = 0) {
    const wxGetImageInfo = utils.wxPromisify(wx.getImageInfo);
    wxGetImageInfo({
        src: images[I]
    }).then(res => {
        info = [...info, res];
        I++;
        if (i < images.length) {
            downloadImages(images, success, info, i);
        } else {
            success(info);
        }
    }).catch(err => {
        console.log(err)

    })
}

写了一个简单的demo,需要的就自取啦:GitHub微信小程序保存图片分享的 canvas 简易自用工具类

当然,欢迎star~~~~

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏编程

java基础知识,font属性css写法,代码详解!

CSS属性值 字体与文本 网页设计中有很多的文字要去处理,标题、段落、文章、列表以及表单中的文本。这一篇章我们讨论一下HTML中的字体与文本 字体 首先要有一...

1998
来自专栏LeoXu的博客

布局和容器 原

1463
来自专栏技术墨客

React——Fragments特性 转

在我们使用React开发组件的时候,每个React组件都必须返回一个根元素。例如下面这样:

951
来自专栏進无尽的文章

绘图-视图遮罩MaskView的使用

可以这样理解,是将maskView每个point的alpha赋值给View的重叠部分相对应的point,这样view的重叠每个point都有个alpha值了,v...

1392
来自专栏androidBlog

Android 正 N 边形圆角头像的实现

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/gdutxiaoxu/article/de...

1101
来自专栏企鹅号快讯

前端学习自学笔记:day10

今天是第十天的笔记,主要是HTML和CSS的,希望大家支持~ ? 在此之前先为大家显示下前端工程师的路线图: 第十天的笔记:HTML AND CSS: 响应式设...

2027
来自专栏守候书阁

canvas入门实战--邀请卡生成与下载

写了很多的javascript和css3的文章,是时候写一篇canvas的了。canvas是html5提供的一个新的功能!至于作用,就是一个画布。然后画笔就是j...

1153
来自专栏有趣的django

博客园美化大全

3080
来自专栏Coding01

推荐一款快速生成海报的微信小插件

现在很多小程序都有生成海报,分享海报的功能。我们自己的几个小程序 (如:爸妈搜商城、爸妈搜云课堂、幼师大学、跟着外教学英语等) 也都有生成海报的功能。因此技术团...

5203
来自专栏小白安全

给网站顶部添加一个彩色横条

效果图片 开始  首先,我们需要图片,直接贴出来吧,需要的请直接右键另存为。 GIF滚动优化版   接着,在网站顶部适当位置添加一个Div,自...

2845

扫码关注云+社区

领取腾讯云代金券