vue canvas应用——页面文字内容生成一张图片
根据页面文字内容生成一张图片
-
首先,安装 html2canvas 库: -
页面中引入: -
具体使用:
遇到了一需求,根据页面内容,生成一张图片,网上查找了相关资料,可以用html2canvas来实现。具体实现如下:
(1)首先,安装 html2canvas 库:
引入方式:
npm安装: npm install –save html2canvas
yarn安装: yarn add html2canvas
(2)页面中引入:
import html2canvas from 'html2canvas'
(3)具体使用:
先来放一下效果图,根据页面内容生成了一张包含相关信息的透明图片,如下图所示:
-
只有活动说明时:宽度为容器宽度,不需要根据文字来计算:

-
有价格和活动说明时,需要根据左边文字宽度来计算绘制矩形的宽度:

-
有标题、价格和活动说明时,同样需要根据左边文字宽度来计算绘制矩形的宽度:

完整代码如下:
<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 {
loading: false,
maxLen: 36,
priceBgColor: '',
activityBgColor: '',
formData: {
priceColor: [],
priceTitle: '',
priceTitleColor: '#EBD0B5',
price: '',
priceWordColor: '#EBD0B5',
activityColor: [],
activityDesc: '',
activityDescColor: '#EBD0B5',
imgUrl: ''
},
formRules: {
activityDesc: [
{ required: true, message: "请输入活动说明", 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(0, 0, 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(0, 350, leftDis + 24, 350, 0) // 确定好第一个点后, 第二个点是沿着y轴,向下,并且C点是严重水平轴,拐角大小为10个单位, 其他三个都是一样的道理
context.arcTo(leftDis + 24, 350, 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(0, 0, 24 + leftDis, 0)//这是一个从左到右的渐变
if (this.formData.priceColor[0]) {
grd.addColorStop(0, this.formData.priceColor[0])
}
if (this.formData.priceColor[1]) {
grd.addColorStop(1, this.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) / 2, 307)
context.fillStyle = this.formData.priceWordColor
context.fontWeight = 500
context.font = priceTitle ? '24px OPPOSans-H' : '30px OPPOSans-H'
context.fillText(price, 12, 332)
} else if (priceTitle) {
context.fillStyle = this.formData.priceTitleColor
context.fontWeight = 400
context.font = '18px OPPOSans-R'
context.fillText(priceTitle, 12 + (leftDis - priceTitleWidth) / 2, 308)
} else if (price) {
context.fillStyle = this.formData.priceWordColor
context.fontWeight = 500
context.font = priceTitle ? '24px OPPOSans-H' : '30px OPPOSans-H'
context.fillText(price, 12, 320)
}
}
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, 308, 350, 350)//这是一个从左到右的渐变
if (this.formData.activityColor[0]) {
grd.addColorStop(0, this.formData.activityColor[0])
}
if (this.formData.activityColor[1]) {
grd.addColorStop(1, this.formData.activityColor[1])
}
context.fillStyle = grd
}
context.fillRect(24 + leftDis, 308, 350 - 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(0, 308, 350, 350)//这是一个从左到右的渐变
if (this.formData.activityColor[0]) {
grd.addColorStop(0, this.formData.activityColor[0])
}
if (this.formData.activityColor[1]) {
grd.addColorStop(1, this.formData.activityColor[1])
}
context.fillStyle = grd
}
context.fillRect(0, 308, 350, 42)
}
}
}
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) / 2, 330)
}
}
// 生成图片信息
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(0, 350, leftDis + 24, 350, 0) // 确定好第一个点后, 第二个点是沿着y轴,向下,并且C点是严重水平轴,拐角大小为10个单位, 其他三个都是一样的道理
context.arcTo(leftDis + 24, 350, 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, 308, 350, 350)//这是一个从左到右的渐变
if (this.formData.activityColor[0]) {
grd.addColorStop(0, this.formData.activityColor[0])
}
if (this.formData.activityColor[1]) {
grd.addColorStop(1, this.formData.activityColor[1])
}
context.fillStyle = grd
}
context.fillRect(24 + leftDis, 308, 350 - leftDis, 42)
上面这里绘制从左到右的渐变色。
context.fillText(price, 12, 320)
上面这里是绘制文字内容。
// 创建隐藏的可下载链接,下载图片
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