谈谈文字图片像素化
先来看个简单的demo-> 像素粒子化
demo是基于3d旋转算法+像素粒子化实现的,尚有一些bug和性能问题,我们不做深究。本篇主要谈谈如何将文字和图片的像素粒子化。针对这个demo,也就是如何实现如下两个图片的转换。
无论文字还是图片,本篇所讲都是针对画布,这点要清楚。如果是文字,用fillText方法将文字写到画布上,如果是图片,则用drawImage方法将图片画到画布上。然后通过getImageData方法获取像素,进行判断,从而取得想要的坐标。不了解getImageData的具体可参考:getImageData
如何获取想要的像素点坐标?一般情况下我们可以根据像素点rgba中的a值(透明度)进行判断。
法1:
var canvas = document.getElementById('canvas'); var ctx = canvas.getContext('2d'); var img = document.getElementById('img1'); ctx.drawImage(img, 0, 0); var data = ctx.getImageData(0, 0, canvas.width, canvas.height).data; var length = data.length; var textPoint = []; for (var i = 0, wl = canvas.width * 4; i < length; i += 4) { if (data[i + 3]) { // 根据透明度判断 var x = (i % wl) / 4; var y = parseInt(i / wl) textPoint.push([x, y]); } }
法2:
var canvas = document.getElementById('canvas'); var ctx = canvas.getContext('2d'); var img = document.getElementById('img1'); ctx.drawImage(img, 0, 0); var textPoint = []; var imgData = ctx.getImageData(0, 0, canvas.width, canvas.height); for(var i = 0; i < imgData.width; i++) for(var j = 0; j < imgData.height; j++) { var index = (i + j * imgData.width) * 4 + 3; if(imgData.data[index]) { textPoint.push([i, j]); } }
fillText:
ctx.font = "bold 12px serif" ctx.textAlign = "left"; ctx.textBaseline = "top"; ctx.fillStyle = 'red'; ctx.fillText('慧', 0, 0);
1、文字像素粒子化
- 小文字 * textSize 法
这是一种比较常用的方法。首先在画布上用fillText写文字,但是写的文字像素要小,一般选择笔画宽2~3个像素,甚至一个像素点。然后通过getImageData获取的data值再进行判断计算获得坐标,其实就是获得文字所组成像素的相对位置。然后将获得的坐标乘以一个常数,就是粒子的大小(实际粒子大小可能会小于textSize以产生粒子间的间隙),这里把它称为textSize,乘以常数后得到一个新的坐标即为粒子化后粒子的坐标。这样在每帧渲染时只需操作新的坐标即可,得到的是相对来说扩大textSize倍的字。
demo:06wj demo
优点:可任意文字代码扩展性强
缺点:字体选择少;效果不直观,需调整文字大小和textSize值调整效果
总结:适用于粒子大的demo,一般文字宽度1~3个像素
- 大文字 + 舍弃部分像素点法
这种方法也比较常见。首先在画布上用fillText写好文字,但是文字一定要大,跟最终出现的效果文字差不多大小,然后也是通过getImageData操作像素点,但是这里要舍弃部分像素点,因为并发的粒子太多进程会卡掉。舍弃多少因情况而异,一般舍弃的数量和粒子的大小成正比,因为舍弃的粒子需要留下的粒子通过扩大来占位。
怎么舍弃?方法参数根据需要的效果随意,例举一二:
demo:W·Axes 粒子化Demo2 岑安 demo
优点:可任意文字代码扩展性强;最终大小效果直观
缺点:字体选择少;需要靠舍弃像素的多少调整粒子大小
总结:适用于粒子小的demo
- 其他
直接用大文字,因为像素点太多太密,而且如果不舍弃的话粒子只能以0.5为半径,体验十分差,在粒子化中基本不考虑。倒是在别的方面可能有用处,花丛效果文字就用到了,因为每帧不用重绘,所以渲染也不会卡。
直接用小文字那就根本不用考虑了。
2、图片像素粒子化
demo采用的就是图片像素粒子化。先把图片draw到画布上,接下去的操作就和文字一样了。这里提一点,在本地操作时,getImageData方法报错:
提示跨域操作data,实际上就是跨域操作图片了。解决方法就是把代码和图片都放到服务器环境下(相同域名)。因为本地测试用的图片是文件夹内的,js跨域限制是不能获取非同一域名下的数据的, 而本地的位置是没有域名的,所以浏览器都认为你是跨域,导致报错。或者check Javascript - getImageData after fillRect and drawImage
图片操作的结果其实就和小文字*textSize类似(有人可能会说可以用大图片,剔除部分像素点,但是大图片体积大加载不易,并且剔除麻烦,我这里就不考虑了),不同的是图片能操作各种炫酷的文字,除了文字之外图片还能操作别的需要的形状。图片的像素点也有要求,像素点太多后续渲染压力会很大浏览器会崩溃,最好像素删减后控制在1000以内,一般图片20*20可取图上所有像素点;不考虑直接用大图片,浏览器会崩溃,所以只能小图片 * size。
demo:岑安 JX官网首页3D粒子效果
优点:不仅限于文字,适用范围广; 文字字体选择多样,效果好看
缺点:获取图片不方便;可扩展性不强每个demo要重新获取图片
3、其他
粒子化除了文字和图片外,还有很多,比如数组模拟,这里就不加介绍了,具体请check:事情没有想象中那么难--JX官网首页3D粒子效果