canvas转图片中的文字自动换行
概述
最近项目用到了canvas转图片,但是由于canvas对文字排版的支持非常弱,一般我们在canvas上画不同排版的文字(比如竖排文字)都是利用js计算横纵坐标,然后一个字一个字地画出来,今天无意中看到一个使用svg的方法,记录下来,供以后开发时参考,相信对其他人也有用。
参考资料:
svg和canvas介绍
svg和canvas都支持图形渲染,它们各有侧重:
- svg:更适用于高保真文档,静态图像,可交互图表图形,2D游戏等。
- canvas:更适用于屏幕截图,视频操作,很多对象的复杂场景,web广告等。
foreignObject元素
foreignObject元素是个非常强大的元素,它可以在其中使用具有其它XML命名空间的XML元素,简单来说,就是我们可以利用foreignObject元素把html“画在”svg里面!
示例如下。其中xmlns表示XML命名空间,标记它是一个svg或者一个xhtml。注意:svg和xhtml都属于XML。
<svg xmlns="http://www.w3.org/2000/svg">
<foreignObject width="120" height="50">
<body xmlns="http://www.w3.org/1999/xhtml">
<p>文字。</p>
</body>
</foreignObject>
</svg>
另外,所有的svg都必须加上这个svg的命名空间标识,否则它就会以XML文档树的形式渲染。示例如下:
//渲染出来的是数字
<svg width="12" height="12" viewBox="0 0 12 12"><path d="M10.263 10.874L6 6.61l-4.264 4.264a.431.431 0 0 1-.61-.61L5.39 6.001 1.128 1.736a.431.431 0 0 1 .61-.61L6 5.391l4.264-4.263a.431.431 0 0 1 .61.61L6.61 6l4.262 4.264a.43.43 0 1 1-.61.609z" stroke="#979797" fill="#999"/></svg>
//渲染出来的是图形
<svg width="12" height="12" viewBox="0 0 12 12" xmlns="http://www.w3.org/2000/svg"><path d="M10.263 10.874L6 6.61l-4.264 4.264a.431.431 0 0 1-.61-.61L5.39 6.001 1.128 1.736a.431.431 0 0 1 .61-.61L6 5.391l4.264-4.263a.431.431 0 0 1 .61.61L6.61 6l4.262 4.264a.43.43 0 1 1-.61.609z" stroke="#979797" fill="#999"/></svg>
canvas中文本换行
由于我们可以利用foreignObject把html转化为SVG,然后我们可以把svg画在canvas里面,最后用canvas把它转化为图形。
示例如下:
//首先初始化canvas
var canvas = document.querySelector('#canvas');
var context = canvas.getContext('2d');
//获取文字的长度
context.font = "20px 微软雅黑";
var textLength = context.measureText(text).width;
//画一个svg图片
var img = new Image();
//对文字长度做判断,一行的文字字要大些,二行的文字字要小些
if(textLength <= 135) {
img.src = 'data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg"><foreignObject width="270" height="45"><body xmlns="http://www.w3.org/1999/xhtml" style="margin:0;color:#e7793f;text-align:center;font-size:40px;line-height:45px;font:微软雅黑;">'+ text +'</body></foreignObject></svg>';
} else {
img.src = 'data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg"><foreignObject width="270" height="60"><body xmlns="http://www.w3.org/1999/xhtml" style="margin:0;color:#e7793f;text-align:left;font-size:25px;line-height:30px;font:微软雅黑;overflow: hidden;display: -webkit-box;text-overflow: ellipsis;--webkit-box-orient: vertical;--webkit-line-clamp: 2;word-break: break-all;">'+ text +'</body></foreignObject></svg>';
}
//把图片绘制上去,并利用canvas生成图片
img.onload = function() {
context.drawImage(img, 72, 1080);
document.querySelector('#ticket').src = canvas.toDataURL('image/png');
}
canvas文字竖排
理论上有三种方法来解决:
1.利用js逐个字符逐行绘制,但是这样对英文要做特殊处理,不能单个字符绘制,而应该旋转90度。相关参考代码如下:
fillTextVertical: function(context, text, x, y) {
var canvas = context.canvas;
var arrText = text.split('');
var arrWidth = arrText.map(function (letter) {
return context.measureText(letter).width;
});
var align = context.textAlign;
var baseline = context.textBaseline;
//emoji的位置
var emoji_arr = fn.findEmoji(text);
//emoji第一位的缓存
var emoji_first = '';
if (align == 'left') {
x = x + Math.max.apply(null, arrWidth) / 2;
} else if (align == 'right') {
x = x - Math.max.apply(null, arrWidth) / 2;
}
if (baseline == 'bottom' || baseline == 'alphabetic' || baseline == 'ideographic') {
y = y - arrWidth[0] / 2;
} else if (baseline == 'top' || baseline == 'hanging') {
y = y + arrWidth[0] / 2;
}
context.textAlign = 'center';
context.textBaseline = 'middle';
// 开始逐字绘制
arrText.forEach(function (letter, index) {
// 确定下一个字符的纵坐标位置
var letterWidth = arrWidth[index];
// 是否需要旋转判断
var code = letter.charCodeAt(0);
//是否是emoji的第二位
if(emoji_arr.indexOf(index) != -1) {
emoji_first = letter;
return;
}
//是否是emoji
if(emoji_arr.indexOf(index - 1) != -1) {
letter = emoji_first + letter;
emoji_first = '';
} else {
if (code <= 256) {
context.translate(x, y);
// 英文字符,旋转90°
context.rotate(90 * Math.PI / 180);
context.translate(-x, -y);
} else if (index > 0 && text.charCodeAt(index - 1) < 256) {
// y修正
y = y + arrWidth[index - 1] / 2;
}
}
context.fillText(letter, x, y);
// 旋转坐标系还原成初始态
context.setTransform(1, 0, 0, 1, 0, 0);
// 确定下一个字符的纵坐标位置
var letterWidth = arrWidth[index];
y = y + letterWidth;
});
// 水平垂直对齐方式还原
context.textAlign = align;
context.textBaseline = baseline;
},
上面方法的缺点是,对emoji符号使用正则匹配的,但仍然会有部分emoji符号匹配不到导致乱码。
2.使用foreignObject绘制。但是有一些bug,就是在安卓机上emoji表情会错位,而且在ios上会被莫名截断。
3.使用html2canvas库。还是有一个bug,就是对英文的竖排支持不是很理想,英文会横排显示。
总之上面的方法各有各的优缺点,完美的竖排兼容emoji的实现是不可能的,这辈子都不可能的!0.0
canvas转图片中的文字自动换行的更多相关文章
- canvas文字自动换行、圆角矩形画法、生成图片手机长按保存、方形图片变圆形
canvas的文字自动换行函数封装 // str:要绘制的字符串 // canvas:canvas对象 // initX:绘制字符串起始x坐标 // initY:绘制字符串起始y坐标 // lineH ...
- Azure 认知服务 (5) 计算机视觉API - 使用C#代码实现读取图片中的文字(OCR)功能
<Windows Azure Platform 系列文章目录> 在笔者之前的文章:Azure 认知服务 (4) 计算机视觉API - 读取图片中的文字 (OCR) 介绍了使用用户界面,在海 ...
- Azure 认知服务 (4) 计算机视觉API - 读取图片中的文字 (OCR)
<Windows Azure Platform 系列文章目录> 微软Azure认知服务的计算机视觉API,还提供读取图片中的文字功能 在海外的Windows Azure认知服务的读取图片功 ...
- 使用Python进行OCR -- 识别图片中的文字
工具 Tesseract pytesseract tesserocr 朋友需要一个工具,将图片中的文字提取出来.我帮他在网上找了一些OCR的应用,都不好用.所以准备自己研究,写一个Web APP供他使 ...
- Mac上如何把图片中的文字转换成word/pdf文字
如何把图片文字转换成word文字? - 知乎 https://www.zhihu.com/question/25488536 在 OneNote for Mac 中插入的圖片複製文字 - OneNot ...
- 使用echart的雷达图的时候,如果文字越界的解决办法记录,标签文字自动换行
使用echart的雷达图的时候,如果文字越界的解决办法记录,标签文字自动换行 前几天项目中有一个图表的是用echart生成的,遇到一个问题,就是在手机端显示的售时候,如果文字太长就会超出div,之前的 ...
- 电脑端的全能扫描王:图片转文字识别、识别pdf、图片中的文字,图片提取txt
手机中有全能扫描王,但PC端没有.所以需要另外找. 发现微软的oneNode有提供类似的功能. 第一步.下载Microsoft OneNode http://www.onenote.com/downl ...
- java从图片中识别文字
package com.dream.common; import java.awt.image.BufferedImage; import java.io.File; import java.io.I ...
- HTML DIV中文字自动换行 , 顶部对齐
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <meta ht ...
随机推荐
- pytest 一.安装和使用入门
pytest --fixtures Python版本: Python 2.7.3.4.3.5.3.6.Jython.PyPy-2.3 平台:Unix / Posix和windows PyPI包名称:p ...
- Maven中阿里云私服配置
在国内maven仓库连接速度太慢 ,虽然对于很多互联网企业和大中型软件公司,建个镜像是分分钟的事.但对于个人开发者确实是个问题.解决办法可以用阿里云的MAVEN私服.有两种方法: 1.在$MAVEN_ ...
- 最小化webpack项目
先把代码贴出来,以后慢慢加说明 参考资料:入门 Webpack,看这篇就够了 / webpack 搭建自动打开,刷新浏览器 一.功能代码1.index.html <!DOCTYPE html&g ...
- vue的一些注意点
每个 Vue 实例都会代理其 data 对象里所有的属性. 注意只有这些被代理的属性是响应的.如果在实例创建之后添加新的属性到实例上,它不会触发视图更新. 除了 data 属性,Vue实例暴露了一些有 ...
- css关于浮动的高度塌陷
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- OO第9-11作业总结
一. 规格化设计 规格化抽象,即将执行的细节抽象为用户所需求的行为(模块做什么). 主要作用在于提高工程设计中的可维护性,可读性,明确功能,使整个编程任务变得清晰有序以减少程序BUG. 说其发展历 ...
- makefile与动态链接库案例分析——动态库链接动态库
http://blog.csdn.net/huqinwei987/article/details/50517780 背景:效率考虑,要重用把服务器主备机方案,以库Libmdpha(高可用)的形式加进主 ...
- P3398 仓鼠找sugar (一道LCA的裸题)
https://www.luogu.org/problemnew/show/P3398 题意简单概括一下就是求树上两条路径是否相交; 有这样一个性质: if相交,则必有lca(a,b) 在路径c &l ...
- web安全系列3:http拦截
这是web安全系列第三篇,我们讲讲HTTP请求的拦截.关于http的内容请翻看我的上一篇文章. 首先,我们开始需要一个安装好的java环境,64位的.请自行安装和配置环境变量,如果遇到问题可以留言评论 ...
- java -version显示版本和JAvA_HOME配置不一样
当你需要安装多个版本的jdk时,可能会遇到更改了JAVA_HOME后java -version不变的情况. 一般情况下,将你的JAVA_HOME改为你要用的jdk的安装路径,然后你使用的就是这个版本的 ...