接到个需求,要求根据给出的纯文本商标,智能生成商标图样(即纯文本图片),并自动上传服务器。不多说,开始动手
思路
- canvas绘制文字,并在合适的地方切断换行,获得base64字符串
- 将base64转换file二进制流
方案
根据最大宽度寻找canvas文字的切换断点方法
使用ctx2D.measureText()来获取canvas中的字串的宽度等信息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
|
function findTextBreakPoint(text, width, context) { let [min, max] = [0, text.length - 1]
while (min <= max) { const middle = Math.floor((min + max) / 2) const middleWidth = context.measureText(text.substr(0, middle)).width const middleOneCharWidth = context.measureText(text.substr(0, middle + 1)).width if (middleWidth <= width && middleOneCharWidth > width) { return middle } if (middleWidth < width) { min = middle + 1 } else { max = middle - 1 } } return -1 }
|
获得根据最大宽度切割成的字串数组
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
|
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.substr(breakPoint) } if (text) { result.push(text) } return result }
|
base64转换file二进制流(这方面不太熟,参考:图片URL转Base64,Base64转二进制文件流)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| function base64ToFile(url) { 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] const bstr = window.atob(arr[1]) 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文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| 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) })
const imgBaseData = canvas.toDataURL('image/jpeg') const file = this.base64ToFile(imgBaseData)
return file }
|
补充
手动组装element-ui上传所需的file对象
1 2 3 4 5 6 7 8 9 10
| function makeUploadFile(file) { return { file, uid: new Date().getTime(), size: file.size, name: file.name, raw: file, url: URL.createObjectURL(file) } }
|