vue canvas应用——页面文字内容生成一张图片

vue canvas应用——页面文字内容生成一张图片

根据页面文字内容生成一张图片

  1. 首先,安装 html2canvas 库:
  2. 页面中引入:
  3. 具体使用:

遇到了一需求,根据页面内容,生成一张图片,网上查找了相关资料,可以用html2canvas来实现。具体实现如下:

(1)首先,安装 html2canvas 库:

引入方式:

npm安装: npm install –save html2canvas

yarn安装: yarn add html2canvas

(2)页面中引入:

import html2canvas from 'html2canvas'

(3)具体使用:

先来放一下效果图,根据页面内容生成了一张包含相关信息的透明图片,如下图所示:

  1. 只有活动说明时:宽度为容器宽度,不需要根据文字来计算:
vue canvas应用——页面文字内容生成一张图片
  1. 有价格和活动说明时,需要根据左边文字宽度来计算绘制矩形的宽度:
vue canvas应用——页面文字内容生成一张图片
  1. 有标题、价格和活动说明时,同样需要根据左边文字宽度来计算绘制矩形的宽度:
vue canvas应用——页面文字内容生成一张图片

完整代码如下:

<template>
  <div class="add-pic-mark-container">
    <el-form :model="formData" label-width="120px" ref="form" :rules="formRules" v-loading="loading">
      <h3 class="title">素材配置信息:</h3>
      <div class="bottom-con">
        <div class="form-con left-con">
          <el-form-item label="区域颜色:">
            <bg-color :bgData="formData.priceColor" @updateC1="setPriceAreaColor" @updateC2="setPriceAreaColor" :title="''"></bg-color>
          </el-form-item>
          <el-form-item label="标题:">
            <div class="item-con">
              <el-input v-model="formData.priceTitle" clearable placeholder="请输入标题" :maxlength="maxLen"></el-input>
              <el-color-picker v-model="formData.priceTitleColor"></el-color-picker>
            </div>
          </el-form-item>
          <el-form-item label="价格:">
            <div class="item-con">
              <el-input v-model="formData.price" clearable placeholder="请输入价格" :maxlength="maxLen"></el-input>
              <el-color-picker v-model="formData.priceWordColor"></el-color-picker>
            </div>
          </el-form-item>
          <el-form-item label="活动颜色:">
            <bg-color :bgData="formData.activityColor" @updateC1="setActivityAreaColor" @updateC2="setActivityAreaColor" :title="''"></bg-color>
          </el-form-item>
          <el-form-item label="活动说明:" prop="activityDesc">
            <div class="item-con">
              <el-input v-model="formData.activityDesc" clearable placeholder="请输入活动说明" :maxlength="maxLen"></el-input>
              <el-color-picker v-model="formData.activityDescColor"></el-color-picker>
            </div>
          </el-form-item>
          <el-form-item label="透明图片:">
            <img :src="formData.imgUrl" alt srcset />
          </el-form-item>
        </div>
      </div>
      <el-form-item>
        <el-button @click="saveHandle" type="primary">保存</el-button>
        <el-button @click="cancleHandle">取消</el-button>
      </el-form-item>
    </el-form>
  </div>
</template>
<script>
import html2canvas from 'html2canvas'
import BgColor from '@/views/homepage/components/bgcolor.vue'

export default {
  name'AddMark',
  components: {
    BgColor
  },
  data () {
    return {
      loadingfalse,
      maxLen36,
      priceBgColor'',
      activityBgColor'',
      formData: {
        priceColor: [],
        priceTitle'',
        priceTitleColor'#EBD0B5',
        price'',
        priceWordColor'#EBD0B5',
        activityColor: [],
        activityDesc'',
        activityDescColor'#EBD0B5',
        imgUrl''
      },
      formRules: {
        activityDesc: [
          { requiredtruemessage"请输入活动说明"trigger"blur" }
        ]
      }
    }
  },
  created () {
  },
  mounted () {
  },
  methods: {
    drawPicture () {
      // 创建画布
      let canvas = document.createElement('canvas')
      // 绘制文字环境
      let context = canvas.getContext('2d')
      // 画布宽度
      canvas.width = 350
      // 画布高度
      canvas.height = 350
      // 填充背景颜色
      context.fillStyle = 'transparent'
      // 绘制文字之前填充白色
      context.fillRect(00, canvas.width, canvas.height)
      // 设置垂直对齐方式
      context.textBaseline = 'middle'
      // 设置字体颜色
      context.fillStyle = '#ebd0b5'

      let priceTitleWidth = 0
      let priceWidth = 0
      let leftDis = 0
      let priceTitle = this.formData.priceTitle
      let price = this.formData.price
      let activityDesc = this.formData.activityDesc
      if (priceTitle) {
        context.font = '18px OPPOSans-R'
        // 获取字体宽度
        priceTitleWidth = context.measureText(priceTitle).width
      }
      if (price) {
        context.font = priceTitle ? '24px OPPOSans-H' : '30px OPPOSans-H'
        // 获取字体宽度
        priceWidth = context.measureText(price).width
      }
      leftDis = priceTitleWidth > priceWidth ? priceTitleWidth : priceWidth
      // context.createLinearGradient(x0,y0,x1,y1) //创建线性的渐变对象
      // x0    渐变开始点的 x 坐标
      // y0    渐变开始点的 y 坐标
      // x1    渐变结束点的 x 坐标
      // y1    渐变结束点的 y 坐标

      // context.fillRect(x0,y0,w,h); // 绘制矩形
      // x0  // 矩形起点的x
      // y0 // 矩形起点的y
      // w // 矩形宽度
      // h // 矩形高度
      if (this.formData.priceColor) {
        if (this.formData.priceColor.length != 0) {
          if (priceTitle || price) {
            context.beginPath()
            const ySta = 290
            context.moveTo(0, ySta)  // 设置起点单位
            context.arcTo(0350, leftDis + 243500// 确定好第一个点后, 第二个点是沿着y轴,向下,并且C点是严重水平轴,拐角大小为10个单位, 其他三个都是一样的道理
            context.arcTo(leftDis + 24350, leftDis + 24, ySta, 0)
            context.arcTo(leftDis + 24, ySta, 0, ySta, 18)
            context.arcTo(0, ySta, leftDis + 24, ySta, 0)
            context.closePath()
          }
          if (this.formData.priceColor.length == 1) {
            if (this.formData.priceColor[0]) {
              context.fillStyle = this.formData.priceColor[0]
            } else if (this.formData.priceColor[1]) {
              context.fillStyle = this.formData.priceColor[1]
            }
          } else {
            let grd = null
            grd = context.createLinearGradient(0024 + leftDis, 0)//这是一个从左到右的渐变
            if (this.formData.priceColor[0]) {
              grd.addColorStop(0this.formData.priceColor[0])
            }
            if (this.formData.priceColor[1]) {
              grd.addColorStop(1this.formData.priceColor[1])
            }
            context.fillStyle = grd
          }
          context.fill()
          context.strokeStyle = 'transparent'
          context.stroke()
        }
      }
      if (priceTitle || price) {
        // 再次设置字体颜色,因为fillStyle时字体颜色被渐变色覆盖
        if (priceTitle && price) {
          context.fillStyle = this.formData.priceTitleColor
          context.fontWeight = 400
          context.font = '18px OPPOSans-R'
          context.fillText(priceTitle, 12 + (leftDis - priceTitleWidth) / 2307)
          context.fillStyle = this.formData.priceWordColor
          context.fontWeight = 500
          context.font = priceTitle ? '24px OPPOSans-H' : '30px OPPOSans-H'
          context.fillText(price, 12332)
        } else if (priceTitle) {
          context.fillStyle = this.formData.priceTitleColor
          context.fontWeight = 400
          context.font = '18px OPPOSans-R'
          context.fillText(priceTitle, 12 + (leftDis - priceTitleWidth) / 2308)
        } else if (price) {
          context.fillStyle = this.formData.priceWordColor
          context.fontWeight = 500
          context.font = priceTitle ? '24px OPPOSans-H' : '30px OPPOSans-H'
          context.fillText(price, 12320)
        }
      }
      if (price || priceTitle) {
        if (this.formData.activityColor) {
          if (this.formData.activityColor.length != 0) {
            if (this.formData.activityColor.length == 1) {
              if (this.formData.activityColor[0]) {
                context.fillStyle = this.formData.activityColor[0]
              } else if (this.formData.activityColor[1]) {
                context.fillStyle = this.formData.activityColor[1]
              }
            } else {
              let grd = context.createLinearGradient(24 + leftDis, 308350350)//这是一个从左到右的渐变
              if (this.formData.activityColor[0]) {
                grd.addColorStop(0this.formData.activityColor[0])
              }
              if (this.formData.activityColor[1]) {
                grd.addColorStop(1this.formData.activityColor[1])
              }
              context.fillStyle = grd
            }
            context.fillRect(24 + leftDis, 308350 - leftDis, 42)
          }
        }
      } else {
        if (this.formData.activityColor) {
          if (this.formData.activityColor.length != 0) {
            if (this.formData.activityColor.length == 1) {
              if (this.formData.activityColor[0]) {
                context.fillStyle = this.formData.activityColor[0]
              } else if (this.formData.activityColor[1]) {
                context.fillStyle = this.formData.activityColor[1]
              }
            } else {
              let grd = context.createLinearGradient(0308350350)//这是一个从左到右的渐变
              if (this.formData.activityColor[0]) {
                grd.addColorStop(0this.formData.activityColor[0])
              }
              if (this.formData.activityColor[1]) {
                grd.addColorStop(1this.formData.activityColor[1])
              }
              context.fillStyle = grd
            }
            context.fillRect(030835042)
          }
        }
      }
      if (activityDesc) {
        // 再次设置字体颜色,因为fillStyle时字体颜色被渐变色覆盖
        context.fillStyle = this.formData.activityDescColor
        context.fontWeight = 400
        if (price || priceTitle) {
          context.font = '18px OPPOSans-R'
          context.fillText(activityDesc, 34 + leftDis, 330)
        } else {
          context.font = '22px OPPOSans-R'
          const activityDescWidth = context.measureText(activityDesc).width
          context.fillText(activityDesc, (350 - activityDescWidth) / 2330)
        }
      }
      // 生成图片信息
      let dataUrl = canvas.toDataURL('image/png')
      this.formData.imgUrl = dataUrl
      // 创建隐藏的可下载链接,下载图片
      var eleLink = document.createElement("a");
      eleLink.href = this.formData.imgUrl; // 图片地址
      eleLink.download = "pictureName";
      // 触发点击
      document.body.appendChild(eleLink);
      eleLink.click();
      // 然后移除
      document.body.removeChild(eleLink);
      // console.log('this.formData.imgUrl', this.formData.imgUrl)
    },
    saveHandle (params) {
      this.$refs['form'].validate((valid) => {
        if (valid) {
          this.drawPicture()
        } else {
          console.log('error submit!!')
          return false
        }
      })
    },
    dataURLtoFile (data) {
      // 将base64 的图片转换成file对象上传 atob将ascii码解析成binary数据
      let binary = atob(data.split(',')[1]);
      let mime = data.split(',')[0].match(/:(.*?);/)[1];
      let array = [];
      for (let i = 0; i < binary.length; i++) {
        array.push(binary.charCodeAt(i));
      }
      let fileData = new Blob([new Uint8Array(array)], {
        type: mime,
      })
      let file = new File([fileData], `${new Date().getTime()}.png`, { type: mime })
      return file
    },
    cancleHandle () {
      this.$router.go(-1)
    },
    setPriceAreaColor () {
      if (this.formData.priceColor) {
        if (this.formData.priceColor.length != 0) {
          if (this.formData.priceColor[0] && this.formData.priceColor[1]) {
            const col1 = this.formData.priceColor[0]
            const col2 = this.formData.priceColor[1]
            this.priceBgColor = `linear-gradient(to right,${col1} 0%,${col2} 100%)`
          } else if (this.formData.priceColor[0]) {
            this.priceBgColor = this.formData.priceColor[0]
          } else if (this.formData.priceColor[1]) {
            this.priceBgColor = this.formData.priceColor[1]
          } else {
            this.priceBgColor = ''
          }
        }
      }
    },
    setActivityAreaColor () {
      if (this.formData.activityColor) {
        if (this.formData.activityColor.length != 0) {
          if (this.formData.activityColor[0] && this.formData.activityColor[1]) {
            const col1 = this.formData.activityColor[0]
            const col2 = this.formData.activityColor[1]
            this.activityBgColor = `linear-gradient(to right,${col1} 0%,${col2} 100%)`
          } else if (this.formData.activityColor[0]) {
            this.activityBgColor = this.formData.activityColor[0]
          } else if (this.formData.activityColor[1]) {
            this.activityBgColor = this.formData.activityColor[1]
          } else {
            this.activityBgColor = ''
          }
        }
      }
    },
  }
}
</script>
<style lang='less' scoped>
.add-pic-mark-container {
  .form-con {
    width: 600px;
    margin-top: 20px;
    .item-con {
      display: -webkit-flex; /* Safari */
      display: flex;
      align-items: center;
    }
  }
  .bottom-con {
    overflow: hidden;
    .left-con {
      float: left;
    }
  }
  .el-select {
    width: 100%;
  }
}
</style>

其中,drawPicture 方法就是绘制文字以及矩形框生成图片。

if (priceTitle || price) {
  context.beginPath()
  const ySta = 290
  context.moveTo(0, ySta)  // 设置起点单位
  context.arcTo(0350, leftDis + 243500// 确定好第一个点后, 第二个点是沿着y轴,向下,并且C点是严重水平轴,拐角大小为10个单位, 其他三个都是一样的道理
  context.arcTo(leftDis + 24350, leftDis + 24, ySta, 0)
  context.arcTo(leftDis + 24, ySta, 0, ySta, 18)
  context.arcTo(0, ySta, leftDis + 24, ySta, 0)
  context.closePath()
}

上面这块代码是当对应左边区域输入框有内容时,绘制左边的区域(右上角圆角的矩形)。

if (this.formData.activityColor.length == 1) {
  if (this.formData.activityColor[0]) {
    context.fillStyle = this.formData.activityColor[0]
  } else if (this.formData.activityColor[1]) {
    context.fillStyle = this.formData.activityColor[1]
  }
}

上面这里是设置背景颜色为纯色。

let grd = context.createLinearGradient(24 + leftDis, 308350350)//这是一个从左到右的渐变
  if (this.formData.activityColor[0]) {
    grd.addColorStop(0this.formData.activityColor[0])
  }
  if (this.formData.activityColor[1]) {
    grd.addColorStop(1this.formData.activityColor[1])
  }
  context.fillStyle = grd
}
context.fillRect(24 + leftDis, 308350 - leftDis, 42)

上面这里绘制从左到右的渐变色。

context.fillText(price, 12320)

上面这里是绘制文字内容。

// 创建隐藏的可下载链接,下载图片
var eleLink = document.createElement("a");
eleLink.href = this.formData.imgUrl; // 图片地址
eleLink.download = "pictureName";
// 触发点击
document.body.appendChild(eleLink);
eleLink.click();
// 然后移除
document.body.removeChild(eleLink);

上面这里是下载生成的图片。

————————————————

版权声明:本文为CSDN博主「*且听风吟」的原创文章

原文链接:https://blog.csdn.net/HH18700418030/article/details/109738973


原文始发于微信公众号(前端24):vue canvas应用——页面文字内容生成一张图片

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/216087.html

(0)
李, 若俞的头像李, 若俞

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!