211 字
1 分钟
Canvas根据纯文本绘制图片,并生成file二进制流
接到个需求,要求根据给出的纯文本商标,智能生成商标图样(即纯文本图片),并自动上传服务器。不多说,开始动手
思路
- canvas绘制文字,并在合适的地方切断换行,获得base64字符串
- 将base64转换file二进制流
方案
根据最大宽度寻找canvas文字的切换断点方法
使用ctx2D.measureText()来获取canvas中的字串的宽度等信息
/** * 寻找canvas文字的切换断点 * @param {string} text 要寻找断点的文本 * @param {number} width 需要切断的最大宽度 * @param {any} context canvas画布 * @return {number} 断点位置 */function findTextBreakPoint(text, width, context) { let [min, max] = [0, text.length - 1]
while (min <= max) { // 取文本中值 const middle = Math.floor((min + max) / 2) // 通过 measureText(text).width 获取一半文本在画布中的像素宽度 const middleWidth = context.measureText(text.substr(0, middle)).width // 获取一半+1字符文本在画布中的像素宽度 const middleOneCharWidth = context.measureText(text.substr(0, middle + 1)).width // 如果加1字符后刚好超出最大宽度,说明切断点就在middle这里 if (middleWidth <= width && middleOneCharWidth > width) { return middle } // 如果一半宽度小于最大宽度,往前推进一个字符,反之后退 if (middleWidth < width) { min = middle + 1 } else { max = middle - 1 } } // 未找到断点,直接返回-1 return -1}获得根据最大宽度切割成的字串数组
/** * 将文字分割,存入数组返回 * @param {any} context canvas画布 * @param {string} text 要切断为数组的文本 * @param {number} width 需要切断的最大宽度 * @param {string} [font = ''] canvas文本样式 * @return {string[]} 切割后的字串数组 */function breakLinesForCanvas(context, text, width, font = '') { const result = [] let breakPoint = 0
if (font) { context.font = font } // 遍历寻找断点,直到找不到断点 while ((breakPoint = findTextBreakPoint(text, width, context)) !== -1) { // 切割断点前的字串,存入数组 result.push(text.substr(0, breakPoint)) // 将text设置为切割剩余的字串,继续遍历 text = text.substr(breakPoint) } // 如果还有剩余字串,丢入数组 if (text) { result.push(text) } return result}base64转换file二进制流(这方面不太熟,参考:图片URL转Base64,Base64转二进制文件流)
function base64ToFile(url) { // 截取并获取mine const arr = url.split(',') if (!arr || !arr[0]) throw new Error('获取文件mime失败')
const mimeMatch = arr[0].match(/:(.*);/) if (!mimeMatch) throw new Error('获取文件mime失败')
const mime = mimeMatch[1] // base64解码为Unicode编码 const bstr = window.atob(arr[1]) // 把每个unicode编码放入Unit8Array let n = bstr.length const u8arr = new Uint8Array(n) while (n--) { u8arr[n] = bstr.charCodeAt(n) } return new File([u8arr], '商标图样.jpg', {type: mime})}将给定文字绘制到canvas画布,并获得生成的File文件
function intelGenerate(text) { const canvas = document.createElement('canvas') // 设置生成的图片宽高 const [width, height] = [800, 800] canvas.width = width canvas.height = height const context = canvas.getContext('2d') context.fillStyle = '#fff' context.fillRect(0, 0, width, height)
// 设置文字样式 const lineHeight = 90 context.font = 'bold 80px SimSun' context.textAlign = 'center' context.textBaseline = 'middle' context.fillStyle = '#000'
// 获取切断目标文本后的数组 const result = this.breakLinesForCanvas(context, text, width) // 设置文字开始绘制的高度,保证生成文字垂直居中 const startTop = (height - result.length * lineHeight + lineHeight) / 2 // 遍历逐行填充文本 result.forEach((item, index) => { context.fillText(item, width / 2, lineHeight * index + startTop) })
// 将canvas画布内容转为base64 const imgBaseData = canvas.toDataURL('image/jpeg') // base64转换file二进制流 const file = this.base64ToFile(imgBaseData)
return file}补充
手动组装element-ui上传所需的file对象
function makeUploadFile(file) { return { file, uid: new Date().getTime(), size: file.size, name: file.name, raw: file, url: URL.createObjectURL(file) }} 分享
如果这篇文章对你有帮助,欢迎分享给更多人!
Canvas根据纯文本绘制图片,并生成file二进制流
https://marrydream.top/posts/web前端/canvas根据纯文本绘制图片并生成file二进制流/ 部分信息可能已经过时
相关文章 智能推荐