引路蜂<a href="#0x1">0x1.术语概念</a><a href="#0x2">0x2.利用as3导出像素数据</a><a href="#0x3">0x3.html5读取导出的像素数据</a
引路蜂
- <a href="#0x1">0x1.术语概念</a>
- <a href="#0x2">0x2.利用as3导出像素数据</a>
- <a href="#0x3">0x3.html5读取导出的像素数据</a>
- <a href="#0x4">0x4.用画布显示像素数据</a>
- <a href="#0x5">0x5.引申出来的想法</a>
<a name="0x1"><strong><b><em>0x1.</em>术语概念</b></strong></a>
位图:位图图像用图像的宽度和高度来定义,以像素为量度单位,每个像素包含的位数表示像素包含的颜色数。在使用 RGB 颜色模型的位图图像中,像素由三个字节组成:红、绿和蓝。每个字节包含一个 0 至 255 之间的值。
Alpha : 颜色或图像中的透明度级别(更准确地说是指不透明度)。Alpha 量通常称为Alpha 通道值。
ARGB: 颜色一种配色方案,其中每个像素的颜色都是红、绿和蓝色值的混合颜色,并且其透明度被指定为一个 Alpha 值。
AS3 : 是ActionScript3 , flash开发所需要的脚本语言。 基于ECMA规范。
BitmapData: actionscript3的一个api ,专门用来处理位图数据的。
<a name="0x2"><strong><b><em>0x2.</em>利用as3导出像素数据</b></strong></a>
首先创建一个AS3的项目, 名字随便写啦。工程创建好去网上搜两张图片作为测试用。
嵌入图片数据
[Embed(source="assets/p2292415033.jpg")] public var bd1:Class; [Embed(source="assets/p2299425320.jpg")] public var bd2:Class;
读取数据到内存
var bitmapData1:BitmapData = (new bd1() as Bitmap).bitmapData; var bitmapData2:BitmapData = (new bd2() as Bitmap).bitmapData; var bytes:ByteArray = bitmapData1.getPixels(new Rectangle(0, 0, bitmapData1.width, bitmapData1.height)); trace(bytes.length);///1068000
图片宽度和高度是 445x600 那么对应的字节数是1068000, 为什么是1068000而不是267000呢,因为这个字节数组返回的是RGBA的数据,四个byte组成一个像素,所以在所有像素的基础上在x4 就是1068000这个值了。
接下来需要导出位图的原始像素了。
// setp2 导出位图var file:File = new File(File.applicationDirectory. resolvePath("data/test.bin").nativePath);try { var stream:FileStream = new FileStream(); stream.open(file, FileMode.WRITE); stream.writeBytes(bytes); stream.close(); trace("done");} catch (e:Error) { trace(e); stream.close();}
成功之后,我们可以看下工程下有没有这个data目录和文件。我们虽然成功导出了,但是现在还面临一个问题就是如何测试我们导出的数据是可以被html5所用呢? 继续吧。
<a name="0x3"><strong><b><em>0x3.</em>html5读取导出的像素数据</b></strong></a>
创建一个html5的工程,新建一个img的目录然后把我们生成的bin文件拷贝进去,继而开始撸代码吧。如果不知道怎么创建html5或者不知道什么是html5,请移步或者自行脑部去吧。创建一个空的画布,以备不时之需。
var canvas = document.createElement("canvas"); canvas.setAttribute("id", "mycanvas"); canvas.setAttribute("width", 800); canvas.setAttribute("height",600); var body = document.getElementsByTagName("body")[0]; body.appendChild(canvas);
我们通过使用2代XMLHttpRequest可以很方便的我们产生的2进制文件读取进来。var request = new XMLHttpRequest();request.open('GET', 'img/test.bin', true);request.responseType = 'arraybuffer';
request.onload = function(e) { if (this.status == 200) { console.log(this.response); } } request.send();
<a name="0x4"><strong><b><em>0x4.</em>用画布显示像素数据</b></strong></a>
通过之前的操作我们已经完成了从0到1的质变, 我们的测试才刚刚开始呢,所以诸位大神准备脑洞大开,进行杀戮吧。
ps:这里不得不吐槽一句,canvas和arraybuff的api设计太不站在人类的发展角度考虑了。
我们现在的是一个不需要图像解码的过程(一般异步加载的Image对象会执行解码),以往异步解码和同步解码都会拖性能(我做过一个测试500张小图片直接使用拷贝像素和默认解码的效率相差60多倍)。
现在我们看看我们所需要API的原型
没错我们需要的就是他,我们的好朋友。我们可以通过画布的这两个API对图形进行批量设置像素,重要的是没有解码的过程哦。。
这是ImageData的原型
我们发现他的get_data就是byte数组,这样我们可以不加处理的就把数据给设置进去。不过设置之前我们要设置他的宽度和高度哦。这个我们的数据里没有,不过我下一篇里会有更好的方案,目前先写死445x600吧。
因为一切都是理论, 所以实现的时候有个小问题就是数据不对,图像完全错误了。
所以需要动态的调整过来。html5的顺序是rgba而as3的顺序是argb,我也是醉了。
另外直接给imgData.data赋值也是不起作用。
var bytes = this.response; var arr=new Uint8Array(bytes,0,1068000); console.log(arr.length,arr[0],arr[1],arr[2],arr[3]); var ctx = canvas.getContext("2d"); var imgData=ctx.createImageData(445,600);// imgData.data=arr; for (var i=0;i<imgData.data.length;i+=4) { imgData.data[i+0]=arr[i+1];//r = a imgData.data[i+1]=arr[i+2];//g = r imgData.data[i+2]=arr[i+3];//b = g imgData.data[i+3]=arr[i+0];//a = b } console.log(imgData.data.length) ctx.putImageData(imgData,0,0); body.appendChild(canvas);
来张成功后的图。
<a name="0x5"><strong><b><em>0x5.</em>0x5.引申出来的想法</b></strong></a>
通过这次实验有几点不足。
1是生成的尺寸,比源文件大了10几倍, 因为没有用压缩算法,而以前用as3的时候直接可以使用ByteArray压缩体积会很小。html5还需要在研究一下,目前还不成熟。
2是读取图片的效率。如果是我当初理想化状态, imgData.data=arr;可以直接赋值,这无疑是效率的最优, 但是确是不能,也许我没有找对方法,有待优化。
3没有一种有效的组织形式,比如as3使用的类似技术的时候可以直接将n个byte数组和符号表等打包成一个2进制对象。直接系同级别的反序列化,不需要人工干预,目前无法大批量的生产。这点也需要优化。
好了。就写到这里吧。