• uniapp H5生成画布,插入网络图片。下载画布


    因为网络图片不能直接使用ctx.drawImage()插入。得使用uni.getImageInfo()方法下载后插入。
    但是当画布中存在多张网络图片时,必须等待uni.getImageInfo()下载完成后才行。这样得下载套下载。太过于繁琐。所以定义了一个递归下载方法。同时避免下载图片异步,画布不显示的结果。

     

    一、引用函数

    1. /**
    2. * canvas文本自动换行,注意调用前要设置字体,例如: ctx.font = '12px Arial'
    3. * @param {*} ctx CanvasRenderingContext2D
    4. * @param {*} text 文本
    5. * @param {*} x
    6. * @param {*} y
    7. * @param {*} lw 所占宽度
    8. * @param {*} lh 行高
    9. * return 绘制文本所需的高度
    10. */
    11. const fillTextLineBreak = (ctx, text, x, y, lw, lh, color = '#000', font = '14') => {
    12. var i = 0;
    13. var n = 0;
    14. var r = -1;
    15. var initHeight = 0;
    16. ctx.font = "" + font + "px Arial"; //字体大小
    17. ctx.fillStyle = color; //字体颜色
    18. while (i < text.length) {
    19. while (ctx.measureText(text.substring(n, i)).width < lw && i < text.length) {
    20. i++
    21. }
    22. r++
    23. ctx.fillText(text.substring(n, i), x, y + lh * r)
    24. n = i
    25. }
    26. initHeight = lh * r;
    27. wx.setStorageSync('initHeight', initHeight);
    28. }
    29. /**
    30. * 自定义函数roundRect
    31. * 画圆弧
    32. * ctx >> 画布
    33. *bg_x 图片的x坐标
    34. *bg_y 图片的y坐标
    35. *bg_w 图片宽度
    36. *bg_h 图片高度
    37. *bg_r 图片圆角
    38. *
    39. */
    40. function roundRect(ctx, img, bg_x, bg_y, bg_w, bg_h, bg_r) {
    41. // 开始绘制
    42. ctx.save();
    43. ctx.beginPath();
    44. ctx.arc(bg_x + bg_r, bg_y + bg_r, bg_r, Math.PI, Math.PI * 1.5);
    45. ctx.arc(bg_x + bg_w - bg_r, bg_y + bg_r, bg_r, Math.PI * 1.5, Math.PI * 2);
    46. ctx.arc(bg_x + bg_w - bg_r, bg_y + bg_h - bg_r, bg_r, 0, Math.PI * 0.5);
    47. ctx.arc(bg_x + bg_r, bg_y + bg_h - bg_r, bg_r, Math.PI * 0.5, Math.PI);
    48. ctx.clip();
    49. ctx.drawImage(img, bg_x, bg_y, bg_w, bg_h);
    50. // 恢复之前保存的绘图上下文
    51. ctx.restore();
    52. }
    53. /*
    54. * 画布网络图片预处理
    55. */
    56. function canvasImage(that, Datas = {}, callback = null) {
    57. var i = Datas.i ? Datas.i : 0;
    58. var callback_Datas = Datas.callback_Datas ? Datas.callback_Datas : [];
    59. var data = Datas.data ? Datas.data : [];
    60. uni.getImageInfo({
    61. src: data[i],
    62. success(res) {
    63. i++;
    64. callback_Datas.push(res.path)
    65. if (i == data.length) {
    66. //回调函数
    67. if (callback) {
    68. callback(that, callback_Datas);
    69. return;
    70. }
    71. } else {
    72. //递归执行下一个上传
    73. canvasImage(that, {
    74. i,
    75. callback_Datas,
    76. data,
    77. }, callback);
    78. }
    79. },
    80. fail(e) {
    81. wx.hideLoading();
    82. //关闭画布弹窗
    83. that.posterHideCanvas();
    84. setTimeout(function() {
    85. wx.showToast({
    86. title: '生成失败,稍后再试',
    87. icon: 'none',
    88. })
    89. }, 0)
    90. }
    91. });
    92. }
    93. /**
    94. * 自定义函数roundRect
    95. * 画圆弧背景
    96. * ctx >> 画布
    97. *bg_x 背景的x坐标
    98. *bg_y 背景的y坐标
    99. *bg_w 背景宽度
    100. *bg_h 背景高度
    101. *bg_r 背景圆角
    102. *
    103. */
    104. function roundRectKuang(ctx, bg_x, bg_y, bg_w, bg_h, bg_r, color = '#fff') {
    105. // 开始绘制
    106. ctx.save();
    107. ctx.beginPath();
    108. ctx.arc(bg_x + bg_r, bg_y + bg_r, bg_r, Math.PI, Math.PI * 1.5);
    109. ctx.arc(bg_x + bg_w - bg_r, bg_y + bg_r, bg_r, Math.PI * 1.5, Math.PI * 2);
    110. ctx.arc(bg_x + bg_w - bg_r, bg_y + bg_h - bg_r, bg_r, 0, Math.PI * 0.5);
    111. ctx.arc(bg_x + bg_r, bg_y + bg_h - bg_r, bg_r, Math.PI * 0.5, Math.PI);
    112. ctx.clip();
    113. ctx.fillStyle = color;
    114. ctx.fillRect(bg_x, bg_y, bg_w, bg_h);
    115. // 恢复之前保存的绘图上下文
    116. ctx.restore();
    117. }

     二、index.vue

    1. <view v-show="posterDatas.hidden" @touchmove="posterTouchMove" class="canvasMain flex center">
    2. <view class="box flex center column">
    3. <canvas :canvas-id="canvasId" :style="canvasStyle" class="canvas">canvas>
    4. <button v-if="posterDatas.buttonType==1" class="btn" @click="posterDownImage">点击保存图片到相册button>
    5. <button v-else-if="posterDatas.buttonType==2" class="btn">已保存到相册,快去分享吧button>
    6. <button v-else-if="posterDatas.buttonType==3" class="btn" open-type="openSetting"
    7. bindopensetting="posterOpenSetting">进入设置页,开启“保存到相册”button>
    8. <text class="iconfont icon-x" @click="posterHideCanvas">text>
    9. view>
    10. view>
    11. <style>
    12. /* 海报 */
    13. .canvasMain {
    14. position: fixed;
    15. left: 0;
    16. top: 0;
    17. width: 100%;
    18. height: 100%;
    19. background-color: rgba(0, 0, 0, 0.6);
    20. z-index: 9999;
    21. }
    22. .canvasMain.hidden {
    23. top: 100%;
    24. left: 100%;
    25. }
    26. .canvasMain .box {
    27. position: relative;
    28. }
    29. .canvasMain .box .canvas {
    30. margin: 0;
    31. }
    32. .canvasMain .box .btn {
    33. height: 40px;
    34. width: 280px;
    35. background-color: rgba(0, 0, 0, 0.3);
    36. border-radius: 40px;
    37. color: #fff;
    38. font-size: 15px;
    39. }
    40. .canvasMain .box .btn {
    41. margin: 10px 0;
    42. padding-left: 0;
    43. padding-right: 0;
    44. }
    45. .canvasMain .box .iconfont {
    46. font-size: 46rpx;
    47. color: #fff;
    48. }
    49. style>

    三、index.js

    1. data() {
    2. return {
    3. posterDatas: {
    4. width: 285, //画布宽度
    5. height: 406, //画布高度
    6. buttonType: 1,
    7. hidden: false, // 是否隐藏海报弹窗
    8. success: false, // 是否成功生成过海报
    9. },
    10. canvasId: 'firstCanvas',
    11. canvasStyle: 'width: 285px; height: 406px;', // 根据实际需要设置 canvas 的宽高
    12. };
    13. },
    14. //海报生成配置
    15. posterSetCanvas() {
    16. var that = this
    17. var posterDatas = that.posterDatas;
    18. var tempConfig = that.tempConfig;
    19. //展示海报弹窗
    20. that.posterDatas.hidden = true;
    21. util.showLoading('生成中');
    22. var userInfo = wx.getStorageSync('userInfo') || {};
    23. var Datas = {};
    24. Datas.i = 0;
    25. Datas.callback_Datas = [];
    26. Datas.data = [];
    27. Datas.data[0] = userInfo.touimg; //头像
    28. Datas.data[1] = app.globalData.swtCircle + "/mp_ewm_v2.php?act=getwxacode&tjrhao=" + (userInfo
    29. .tjrhao || '') + "&url=pages/home/home"; //小程序码
    30. util.canvasImage(that, Datas, function(that, canvasImage_arr) {
    31. //要延时执行的代码
    32. setTimeout(function() {
    33. //预处理画布网络地址图片
    34. var ctx = uni.createCanvasContext(that.canvasId, that);
    35. // 清除背景
    36. //ctx.clearRect(0, 0, posterDatas.width, posterDatas.height);
    37. // 绘制背景
    38. // ctx.fillStyle = "#fff";
    39. // ctx.fillRect(0, 0, posterDatas.width, posterDatas.height);
    40. var bgImg = '/static/images/yao_bj.png';
    41. // 绘制背景图
    42. ctx.drawImage(bgImg, 0, 0, posterDatas.width, posterDatas.height);
    43. //简介
    44. util.fillTextLineBreak(ctx, "邀请您使用" + tempConfig.appMain.name + "小程序", 100, 81, 150,
    45. 20, '#fff',
    46. 13);
    47. //标题文字
    48. ctx.font = "bold 18px PingFang SC";
    49. ctx.fillStyle = "#fff";
    50. ctx.textAlign = "start";
    51. ctx.fillText(userInfo.nickName_hai, 100, 60);
    52. util.roundRect(ctx, canvasImage_arr[0], 30, 35, 56, 56, 28);
    53. ctx.font = "bold 18px PingFang SC";
    54. ctx.fillStyle = "#0D7239";
    55. ctx.textAlign = "start";
    56. ctx.fillText('分享有礼 荐者有份', 70, 170);
    57. ctx.drawImage(canvasImage_arr[1], 65, 200, 160, 160);
    58. ctx.draw();
    59. wx.hideLoading();
    60. }, 200)
    61. });
    62. },
    63. //海报下载图片
    64. posterDownImage: function() {
    65. var that = this
    66. util.showLoading('保存中');
    67. var posterDatas = that.posterDatas
    68. uni.canvasToTempFilePath({
    69. canvasId: "firstCanvas",
    70. success(res) {
    71. console.log(res)
    72. wx.showToast({
    73. icon: 'none',
    74. title: '已保存到相册,快去分享吧',
    75. })
    76. posterDatas["buttonType"] = 2;
    77. that.posterDatas = posterDatas;
    78. // 在 h5 中,res.tempFilePath 返回的是 base64 类型要处理,通过 a 标签的形式下载
    79. var arr = res.tempFilePath.split(',');
    80. var bytes = atob(arr[1]);
    81. let ab = new ArrayBuffer(bytes.length);
    82. let ia = new Uint8Array(ab);
    83. for (let i = 0; i < bytes.length; i++) {
    84. ia[i] = bytes.charCodeAt(i);
    85. }
    86. var blob = new Blob([ab], {
    87. type: 'application/octet-stream'
    88. });
    89. var url = URL.createObjectURL(blob);
    90. var a = document.createElement('a');
    91. a.href = url;
    92. a.download = new Date().valueOf() + ".png";
    93. var e = document.createEvent('MouseEvents');
    94. e.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false,
    95. false, 0, null);
    96. a.dispatchEvent(e);
    97. URL.revokeObjectURL(url);
    98. },
    99. fail(e) {
    100. console.log(e, "fail");
    101. util.showToast('保存失败,稍后再试”', 'none');
    102. that.posterHideCanvas();
    103. }
    104. })
    105. },
    106. //海报隐藏弹窗
    107. posterHideCanvas: function() {
    108. var that = this;
    109. that.posterDatas.buttonType = 1;
    110. that.posterDatas.hidden = false;
    111. },
    112. //海报弹窗禁止屏幕滚动
    113. posterTouchMove: function() {
    114. //在蒙层加上 catchtouchmove 事件
    115. //这里什么都不要放
    116. },

    四、最终结果

  • 相关阅读:
    Unity UI Toolkit学习笔记-EditorWindow
    第一章 教育基础(05 小学教育研究)
    cv面试百问day3
    代替forever下一个部署node的持久化工具---pm2
    python3.9 处理excel来实现类似excel中的vlookup功能
    Vue指令综合案例——汽车品牌管理
    Python——LRU_Cache
    [免费专栏] ATTACK安全之Android车机证书攻击(入侵)场景检测【一】
    gin框架再探
    Git入门
  • 原文地址:https://blog.csdn.net/weixin_44936767/article/details/132838452