微信小程序-CANVAS写入图片素材、文字等数据生成图片

news2024/12/24 2:26:05

微信小程序中,CANVAS写入图片素材、文字等数据生成图片,最终可将生成的 base64 格式图片保存至相册操作

Tips:

1、canvas 标签默认宽度 300px、高度 150px
canvas 生成图片时,写入图片素材、文字等数据前,需要根据实际需求,设置 canvas 宽、高,
如以下示例中 设置 posterCanvas.width 及 posterCanvas.height

2、同一页面中的 canvas-id 不可重复,如果使用一个已经出现过的 canvas-id,该 canvas 标签对应的画布将被隐藏并不再正常工作
canvas 不可设置隐藏,否则不能正常工作,若不希望其显示的话,可以 如以下示例中 设置 CSS样式,
makeResCanvasW 、 makeResCanvasH 都设置为 0 ,
- 原生开发:
style="width: {{makeResCanvasW}}rpx;height: {{makeResCanvasH}}rpx;"

- uniapp开发:
:style="'width: ' + makeResCanvasW + 'rpx;height: ' + makeResCanvasH + 'rpx;'"

3、多次生成操作时,清除之前写入数据即可,不需要设置多个 canvas
如以下示例中 setCanvasCtx 方法设置
判断是否已有 Canvas 对象,无则设置 Canvas 对象 及 Canvas 绘制上下文 ctx,有则清除之前写入的数据

4、写入图片素材、文字等数据,与普通H5操作一致
写入图片设置:
注:使用网络图片时,使用 downloadFile 方法,下载文件资源到本地进行处理(返回文件的本地临时路径 (本地路径),单次下载允许的最大文件为 200MB)
如以下示例中 步骤:
- posterCanvas.createImage() 创建一个图片对象
- .src 设置图片的 URL
- .onload 图片加载完成后触发的回调函数,这里可以获取到此图片对象的宽高等数据
- .drawImage 画入图片数据
- 其他写入数据:与H5中处理基本一致

5、生成图片(base64 格式图片)
如以下示例中 posterCanvas.toDataURL('image/png') ,生成图片后,可使用 小程序预览图片方法 previewImage 方法查看生成的图片

6、base64 格式图片保存至相册
如以下示例中 base64ImageHandle 方法设置,
步骤:
- .env.USER_DATA_PATH : 指定图片的临时路径【.env 环境变量 .USER_DATA_PATH 文件系统中的用户目录路径 (本地路径)】
- getFileSystemManager : 获取小程序的文件系统(小程序获取全局唯一的文件管理器方法)
- .writeFile : 把arraybuffer数据写入到临时目录中(写文件)
- 使用小程序保存图片到系统相册方法 saveImageToPhotosAlbum,把临时路径下的图片,保存图片到相册

微信小程序-原生开发,处理代码如下:

wxml:

<canvas type="2d" id="makeResCanvas" style="width: {{makeResCanvasW}}rpx;height: {{makeResCanvasH}}rpx;"></canvas>

data中参数:

data: {
  makeResCanvasW : 0,
  makeResCanvasH : 0,
},

调用方法生成图片

this.makeResImg();

处理方法:

/**
 * CANVAS画布生成图片
 */
makeResImg() {
  wx.showLoading({
    title: "生成中",
    mask: true
  });
  this.setCanvasCtx(()=>{
    this.makeResImgAfter();
  })
},
// 
setCanvasCtx(callback){
  if(this.data.posterCanvas){
    console.log(222)
    this.data.posterCtx.clearRect(0, 0, this.data.posterCanvas.width, this.data.posterCanvas.height);
    callback && callback();
  }else{
    console.log(111)
    const query = wx.createSelectorQuery();
    query.select('#makeResCanvas')
    .fields({
      node: true,
      size: true
    })
    .exec((res) => {
      // console.log(res);
      this.setData({
        posterCanvas : res[0].node
      })
      this.setData({
        posterCtx : this.data.posterCanvas.getContext('2d')
      })
      this.data.posterCtx.clearRect(0, 0, this.data.posterCanvas.width, this.data.posterCanvas.height);
      callback && callback();
    })
  }
},
// 
makeResImgAfter(){
  // 写入 生成图片 背景图片
  const posterBgImg = this.data.posterCanvas.createImage();
  posterBgImg.src = '../../images/poster_bg.png';
  // this.getDownloadFile('https://xxxxxxxxx/poster_bg.png',(formimgTempFilePath)=>{
    // posterBgImg.src = formimgTempFilePath;
    posterBgImg.onload = () => {
      console.log('背景图实际宽高', posterBgImg.width, posterBgImg.height);
      this.data.posterCanvas.width = posterBgImg.width;
      this.data.posterCanvas.height = posterBgImg.height;
      this.setData({
        makeResCanvasW:0,
        makeResCanvasH:0,
      })
      // 画入背景图片
      this.data.posterCtx.drawImage(posterBgImg, 0, 0, posterBgImg.width, posterBgImg.height);
      
      // 写入 生成图片 勾选标识图片
      const checkImg = this.data.posterCanvas.createImage();
      checkImg.src = '../../images/check.png';
      // this.getDownloadFile('https://xxxxxxxxx/check.png',(checkTempFilePath)=>{
        // checkImg.src = checkTempFilePath;
        checkImg.onload = () => {
          // 画入勾选标识图片
          this.data.posterCtx.drawImage(checkImg, 20, 188, 32, 24);
          this.data.posterCtx.drawImage(checkImg, 20 + 42, 188, 32, 24);
          this.data.posterCtx.drawImage(checkImg, 20 + 42 + 42, 188, 32, 24);
          this.data.posterCtx.drawImage(checkImg, 20 + 42 + 42 + 42, 188, 32, 24);
          this.data.posterCtx.drawImage(checkImg, 20 + 42 + 42 + 42 + 42, 188, 32, 24);
          this.data.posterCtx.drawImage(checkImg, 20 + 42 + 42 + 42 + 42 + 42, 188, 32, 24);
          // 写入文本
          this.data.posterCtx.fillStyle = '#000000';
          this.data.posterCtx.textAlign = 'left';
          this.data.posterCtx.textBaseline = 'top';
          this.data.posterCtx.font = '26px "PingFangSC-Regular","STHeitiSC-Light","微软雅黑","Microsoft YaHei","sans-serif"';
          // 写入单行文本
          this.data.posterCtx.fillText('写入单行文本',10,60);
          // 写入多行文本
          this.writeTextOnCanvas(this.data.posterCtx, 36, 40, '写入多行文本写入多行文本写入多行文本写入多行文本写入多行文本写入多行文本' ,10, 100);
          // 生成图片
          this.setData({
            posterUrl: this.data.posterCanvas.toDataURL('image/png'),
          })
          
          // 查看生成的图片
          setTimeout(()=>{
            wx.previewImage({
              current: this.data.posterUrl,
              urls: [this.data.posterUrl]
            });
          },10)
          wx.hideLoading();
          
          // base64图片保存至相册
          setTimeout(()=>{
            this.base64ImageHandle(this.data.posterUrl);
          },10)
        }
      // })
    }
  // })
},
// 写入多行文本
writeTextOnCanvas(ctx_2d, lineheight, bytelength, text ,startleft, starttop){
  function getTrueLength(str){
    var len = str.length, truelen = 0;
    for(var x = 0; x < len; x++){
      if(str.charCodeAt(x) > 128){
        truelen += 2;
      }else{
        truelen += 1;
      }
    }
    return truelen;
  }
  function cutString(str, leng){
    var len = str.length, tlen = len, nlen = 0;
    for(var x = 0; x < len; x++){
      if(str.charCodeAt(x) > 128){
        if(nlen + 2 < leng){
          nlen += 2;
        }else{
          tlen = x;
          break;
        }
      }else{
        if(nlen + 1 < leng){
          nlen += 1;
        }else{
          tlen = x;
          break;
        }
      }
    }
    return tlen;
  }
  for(var i = 1; getTrueLength(text) > 0; i++){
    var tl = cutString(text, bytelength);
    ctx_2d.fillText(text.substr(0, tl).replace(/^\s+|\s+$/, ""), startleft, (i-1) * lineheight + starttop);
    text = text.substr(tl);
  }
},
// 下载网络图片
getDownloadFile(img,callback){
  wx.downloadFile({
    url: img,
    success (res) {
      if (res.statusCode === 200) {
        callback && callback(res.tempFilePath)
      }
    }
  })
},
// base64图片保存至相册
base64ImageHandle(base64) {
  // 指定图片的临时路径
  const path = `${wx.env.USER_DATA_PATH}/reportformImg.png`
  // 获取小程序的文件系统
  const fsm = wx.getFileSystemManager()
  // 把arraybuffer数据写入到临时目录中
  fsm.writeFile({
    filePath: path,
    data: base64.replace(/^data:image\/\w+;base64,/, ''),
    encoding: 'base64',
    success: () => {
      wx.hideLoading();
      wx.showModal({
        title: '保存图片',
        content: '保存数据报表图片至手机相册?',
        success: (result) => {
          if (result.confirm) {
            // 把临时路径下的图片,保存至相册
            wx.saveImageToPhotosAlbum({
              filePath: path,
              success: () => {
                wx.showToast({
                title: '保存海报成功',
                icon: 'success',
                duration: 2000
                })
              }
            })
          }
        }
      })
    }
  })
},

微信小程序-uniapp开发,处理代码如下:

.vue:

<canvas type="2d" id="makeResCanvas" :style="'width: ' + makeResCanvasW + 'rpx;height: ' + makeResCanvasH + 'rpx;'"></canvas>

data中参数:

data() {
  return {
    makeResCanvasW:0,
    makeResCanvasH:0,
  };
},

调用方法生成图片

this.makeResImg();

处理方法:

/**
 * CANVAS画布生成图片
 */
makeResImg() {
  uni.showLoading({
    title: "生成中",
    mask: true
  });
  this.setCanvasCtx(()=>{
    this.makeResImgAfter();
  })
},
// 
setCanvasCtx(callback){
  if(this.posterCanvas){
    console.log(222)
    this.posterCtx.clearRect(0, 0, this.posterCanvas.width, this.posterCanvas.height);
    callback && callback();
  }else{
    console.log(111)
    const query = uni.createSelectorQuery();
    query.select('#makeResCanvas')
    .fields({
      node: true,
      size: true
    })
    .exec((res) => {
      // console.log(res);
      this.posterCanvas = res[0].node;
      this.posterCtx = this.posterCanvas.getContext('2d');
      this.posterCtx.clearRect(0, 0, this.posterCanvas.width, this.posterCanvas.height);
      callback && callback();
    })
  }
},
// 
makeResImgAfter(){
  // 写入 生成图片 背景图片
  const posterBgImg = this.posterCanvas.createImage();
  posterBgImg.src = '/static/images/xjshop/poster_bg.png';
  // this.getDownloadFile('https://xxxxxxxxx/poster_bg.png',(formimgTempFilePath)=>{
    // posterBgImg.src = formimgTempFilePath;
    posterBgImg.onload = () => {
      // console.log('背景图实际宽高', posterBgImg.width, posterBgImg.height);
      this.posterCanvas.width = posterBgImg.width;
      this.posterCanvas.height = posterBgImg.height;
      this.makeResCanvasW = 0;
      this.makeResCanvasH = 0;
      // 画入背景图片
      this.posterCtx.drawImage(posterBgImg, 0, 0, posterBgImg.width, posterBgImg.height);
      
      // 写入 生成图片 勾选标识图片
      const checkImg = this.posterCanvas.createImage();
      // checkImg.src = '/static/images/xjshop/check.png';
      this.getDownloadFile('https://xxxxxxxxx/check.png',(checkTempFilePath)=>{
        checkImg.src = checkTempFilePath;
        checkImg.onload = () => {
          // 画入勾选标识图片
          this.posterCtx.drawImage(checkImg, 20, 188, 32, 24);
          this.posterCtx.drawImage(checkImg, 20 + 42, 188, 32, 24);
          this.posterCtx.drawImage(checkImg, 20 + 42 + 42, 188, 32, 24);
          this.posterCtx.drawImage(checkImg, 20 + 42 + 42 + 42, 188, 32, 24);
          this.posterCtx.drawImage(checkImg, 20 + 42 + 42 + 42 + 42, 188, 32, 24);
          this.posterCtx.drawImage(checkImg, 20 + 42 + 42 + 42 + 42 + 42, 188, 32, 24);
          // 写入文本
          this.posterCtx.fillStyle = '#000000';
          this.posterCtx.textAlign = 'left';
          this.posterCtx.textBaseline = 'top';
          this.posterCtx.font = '26px "PingFangSC-Regular","STHeitiSC-Light","微软雅黑","Microsoft YaHei","sans-serif"';
          // 写入单行文本
          this.posterCtx.fillText('写入单行文本',10,60);
          // 写入多行文本
          this.writeTextOnCanvas(this.posterCtx, 36, 40, '写入多行文本写入多行文本写入多行文本写入多行文本写入多行文本写入多行文本' ,10, 100);
          // 生成图片
          this.posterUrl = this.posterCanvas.toDataURL('image/png')
          
          // 查看生成的图片
          setTimeout(()=>{
            uni.previewImage({
              current: this.posterUrl,
              urls: [this.posterUrl]
            });
          },10)
          uni.hideLoading();
          
          // base64图片保存至相册
          setTimeout(()=>{
            this.base64ImageHandle(this.posterUrl);
          },10)
        }
      })
    }
  // })
},
// 写入多行文本
writeTextOnCanvas(ctx_2d, lineheight, bytelength, text ,startleft, starttop){
  function getTrueLength(str){
    var len = str.length, truelen = 0;
    for(var x = 0; x < len; x++){
      if(str.charCodeAt(x) > 128){
        truelen += 2;
      }else{
        truelen += 1;
      }
    }
    return truelen;
  }
  function cutString(str, leng){
    var len = str.length, tlen = len, nlen = 0;
    for(var x = 0; x < len; x++){
      if(str.charCodeAt(x) > 128){
        if(nlen + 2 < leng){
          nlen += 2;
        }else{
          tlen = x;
          break;
        }
      }else{
        if(nlen + 1 < leng){
          nlen += 1;
        }else{
          tlen = x;
          break;
        }
      }
    }
    return tlen;
  }
  for(var i = 1; getTrueLength(text) > 0; i++){
    var tl = cutString(text, bytelength);
    ctx_2d.fillText(text.substr(0, tl).replace(/^\s+|\s+$/, ""), startleft, (i-1) * lineheight + starttop);
    text = text.substr(tl);
  }
},
// 下载网络图片
getDownloadFile(img,callback){
  uni.downloadFile({
    url: img,
    success (res) {
      if (res.statusCode === 200) {
        callback && callback(res.tempFilePath)
      }
    }
  })
},
// base64图片保存至相册
base64ImageHandle(base64) {
  // 指定图片的临时路径
  const path = `${uni.env.USER_DATA_PATH}/reportformImg.png`
  // 获取小程序的文件系统
  const fsm = uni.getFileSystemManager()
  // 把arraybuffer数据写入到临时目录中
  fsm.writeFile({
    filePath: path,
    data: base64.replace(/^data:image\/\w+;base64,/, ''),
    encoding: 'base64',
    success: () => {
      uni.hideLoading();
      uni.showModal({
        title: '保存图片',
        content: '保存数据报表图片至手机相册?',
        success: (result) => {
          if (result.confirm) {
            // 把临时路径下的图片,保存至相册
            uni.saveImageToPhotosAlbum({
              filePath: path,
              success: () => {
                uni.showToast({
                title: '保存海报成功',
                icon: 'success',
                duration: 2000
                })
              }
            })
          }
        }
      })
    }
  })
},

素材图片

原生开发 生成图片

uniapp开发 生成图片

 下载图片提示

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1942443.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

git的一些使用技巧(git fetch 和 git pull的区别,git merge 和 git rebase的区别)

最近闲来无聊&#xff0c;虽然会使用git操作&#xff0c;但是 git fetch 和 git pull 的区别&#xff0c;git merge 和 git rebase的区别只是一知半解&#xff0c;稍微研究一下&#xff1b; git fetch 和 git pull 的区别 git fetch git fetch 是将远程仓库中的改动拉到本地…

鸿蒙仓颉语言【扩展Redis仓颉语言客户端】

2. 扩展Redis仓颉语言客户端 2.1 Redis命令处理模块的架构 Redis命令处理的架构图如下&#xff1a; RedisCommand类 Redis命令的实现类 包含以下成员&#xff1a; commandType: Redis命令的名称 commandArgs: Redis命令的参数列表 response: Redis命令的响应消息&#xff…

【学习笔记】无人机系统(UAS)的连接、识别和跟踪(十)-无人机A2X服务

引言 3GPP TS 23.256 技术规范&#xff0c;主要定义了3GPP系统对无人机&#xff08;UAV&#xff09;的连接性、身份识别、跟踪及A2X&#xff08;Aircraft-to-Everything&#xff09;服务的支持。 3GPP TS 23.256 技术规范&#xff1a; 【免费】3GPPTS23.256技术报告-无人机系…

当当网数据采集:Scrapy框架的异步处理能力

在互联网数据采集领域&#xff0c;Scrapy框架以其强大的异步处理能力而著称。Scrapy利用了Python的异步网络请求库&#xff0c;如twisted&#xff0c;来实现高效的并发数据采集。本文将深入探讨Scrapy框架的异步处理能力&#xff0c;并展示如何在当当网数据采集项目中应用这一能…

npm 安装报错(已解决)+ 运行 “wue-cli-service”不是内部或外部命令,也不是可运行的程序(已解决)

首先先说一下我这个项目是3年前的一个项目了&#xff0c;中间也是经过了多个人的修改惨咋了布置多少个人的思想&#xff0c;这这道我手里直接npm都安装不上&#xff0c;在网上也查询了多种方法&#xff0c;终于是找到问题所在了 问题1&#xff1a; 先是npm i 报错在下面图片&…

下拉菜单过渡

下拉过渡&#xff0c;利用Y轴的transform&#xff1a;scaleY(0) —》transform&#xff1a;scaleY(1) 代码&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8" /><meta name"viewport" cont…

实战:MyBatis适配多种数据库:MySQL、Oracle、PostGresql等

概叙 很多时候&#xff0c;一套代码要适配多种数据库&#xff0c;主流的三种库&#xff1a;MySQL、Oracle、PostGresql&#xff0c;刚好mybatis支持这种扩展&#xff0c;如下图所示&#xff0c;在一个“namespace”&#xff0c;判断唯一的标志是iddatabaseId&#xff0c;刚好写…

学习vue3的搭建

Vue3 Vite项目构建 环境准备 1. NodeJs安装 安装NodeJs&#xff0c;安装成功后&#xff0c;以管理员身份打开命令行&#xff0c;输入命令 node -v查看NodeJs版本&#xff1b;输入命令 npm -v查看npm版本。 2. 安装cnpm 因为npm是国外的&#xff0c;下载资源的时候会翻墙&…

mysql面试(一)

前言 从今天开始&#xff0c;更新一些mysql的基础知识&#xff0c;面试会遇到的知识点之类的内容。比如四个隔离级别&#xff0c;mvcc机制&#xff0c;三大日志&#xff0c;索引&#xff0c;B树的形成等等&#xff0c;从数据库的底层来剖析索引和树是怎么形成的&#xff0c;以…

LeetCode //C - 257. Binary Tree Paths

257. Binary Tree Paths Given the root of a binary tree, return all root-to-leaf paths in any order. A leaf is a node with no children. Example 1: Input: root [1,2,3,null,5] Output: [“1->2->5”,“1->3”] Example 2: Input: root [1] Output: […

服务器利用宝塔面板部署Django项目

目录 1. 使用命令启动Django项目1.1 使用 Xshell 连接服务器1.2 安装Anaconda1.3 启动Django项目1.4 使用tmux实现项目的后台运行 2. 使用Python项目管理器部署项目2.1 安装宝塔面板和软件2.2 添加站点2.3 上传项目文件2.3.1 收集静态文件2.3.2 生成依赖文件 2.4 安装安装Pytho…

如何查看Kafka的偏移量offset

本文介绍三种方法查看Kafka的偏移量offset。 1. API&#xff1a;ConsumerRecord的offset()方法查看offset。 2. API&#xff1a;KafkaConsumer的position(TopicPartition partition)方法查看offset。 3. 命令行&#xff1a;kafka-consumer-groups.sh命令查看offset。 前提条…

OpenHarmony 入门——ArkUI 自定义组件之间的状态装饰器小结(一)

文章大纲 引言一、状态管理概述二、基本术语三、状态装饰器总览 引言 前面说了ArkTS 是在TypeScript基础上结合ArkUI框架扩展定制的&#xff0c;状态管理中的各种装饰器就是扩展的功能之一&#xff0c;可以让开发者通过声明式UI快速高效实现组件之间的数据同步&#xff0c;至于…

从PyTorch官方的一篇教程说开去(4 - Q-table来源及解决问题实例)

偷个懒&#xff0c;代码来自比很久之前看的书&#xff0c;当时还在用gym&#xff0c;我做了微调以升级到gymnasium当前版本&#xff0c;确保可以正常演示。如果小伙伴或者原作者看到了麻烦提一下&#xff0c;我好备注一下出处。 您的进步和反馈是我最大的动力&#xff0c;小伙…

Dav_笔记10:Using SQL Plan Management之1

SQL计划基准概述 SQL计划管理是一种预防机制&#xff0c;可以记录和评估SQL语句的执行计划。此机制可以构建SQL计划基准&#xff0c;这是一组SQL语句的已接受计划。已接受的计划已被证明表现良好。 SQL计划基准的目的 SQL计划基准的目标是保持相应SQL语句的性能&#xff0c;…

1-如何挑选Android编译服务器

前几天&#xff0c;我在我的星球发了一条动态&#xff1a;入手洋垃圾、重操老本行。没错&#xff0c;利用业余时间&#xff0c;我又重新捣鼓捣鼓代码了。在接下来一段时间&#xff0c;我会分享我从服务器的搭建到完成Android产品开发的整个过程。这些东西之前都是折腾过的&…

【JAVA】堆、栈的理解

JAVA中的堆和栈 堆和栈的简单描述栈堆 示例1示例2如何判断操作的是原始对象本身还是引用地址的变量&#xff08;个人理解&#xff0c;仅作为记录&#xff09; 引言 在Java中&#xff0c;内存管理是一个重要的概念&#xff0c;它涉及到堆&#xff08;Heap&#xff09;和栈&#…

CTFSHOW game-gyctf web2

【2020年新春战“疫”】game-gyctf web2 参考https://www.cnblogs.com/aninock/p/15408090.html 说明&#xff1a;看见网上好像没多少人写&#xff0c;刚好玩到这道题了&#xff0c;就写一下吧。 一、利用入口 常规套路发现www.zip然后进行代码审计 index可以包含update&…

05 HTTP Tomcat Servlet

文章目录 HTTP1、简介2、请求数据格式3、响应数据格式 Tomcat1、简介2、基本使用3、Maven创建Web项目4、IDEA使用Tomcat Servlet1、简介2、方法介绍3、体系结构4、urlPattern配置5、XML配置 HTTP 1、简介 HTTP概念 HyperText Transfer Protocol&#xff0c;超文本传输协议&am…

浏览器打开抽奖系统html

<!DOCTYPE html> <html> <head> <meta charset"utf-8"> <title>在线抽奖 随机选取 自动挑选</title> <script src"https://libs.baidu.com/jquery/1.10.2/jquery.min.js"></script> <style> body {…