深入理解数据URI和JavaScript图像生成

随着HTML5标准的不断发展,看到了众多令人兴奋的新特性。其中之一就是<canvas>元素,它为网页开发者提供了极大的自由度。本文将通过一个简单的实验,探讨如何在不使用<canvas>元素的情况下,在客户端生成图像动画。

建议读者访问以下资源,了解客户端生成的图像动画是如何使用数据URI实现的。这些资源主要关注基于旧式调色板的静态GIF图像动画,以及如何基于数据URI特性构建图像绘制工具。

为了更好地理解数据URI的用途,建议访问维基百科上的讨论。数据URI允许将图像数据嵌入到图像的src属性中。不需要从服务器获取它,也不需要使用<canvas>来绘制它。可以在客户端预先加载它,嵌入到网页中,或者可以使用JavaScript客户端代码来创建它。第一种方法会增加网页的大小,但对于小型动画图像很有用。第二种方法为提供了更多的自由度来从头开始创建图像。本文采用了第二种方法。

JavaScript生成的图像

一般的<img>元素如下所示:

<img id="myImage" src="http://image-url">

要加载来自Web服务器的图像,将图像URL作为图像src属性的值。要加载嵌入在网页中的图像,将以下内容作为图像src属性的值:

<img id="myImage" src="data:image/bmp;base64,image-data">

浏览器知道,在第二种情况下,图像数据不会通过向Web服务器发送HTTP请求获得,而是在图像标签的src属性中。浏览器解析这个并在页面上正确显示图像。

那么,在第二种情况下,src属性中包含的是什么?首先,通过指定data:image/bmp值告诉浏览器有图像数据。这包含了数据URI的定义和随后的图像数据的MIME类型。如果图像数据是base64编码的,也必须提供这个信息。所以,一般的数据URI头部是data:MIME-type[;base64],。MIME类型可以是任何支持的图像MIME类型,但必须以请求的格式提供图像数据,这在JavaScript世界中可能是一个真正的挑战,但并非不可能。

接下来是原始图像数据。它来自哪里?正如之前所说,它可以在其他地方获得并嵌入到网页中,或者直接嵌入到图像标签的src属性中。如果需要一个生成器,请访问这个网站。这个网页会生成需要放入网页中的代码,使用提供的图像。它还提供了生成的图像的预览。不错的工作,不是吗?

但是,如果想扩展到自己的需求呢?如果想每次页面加载时都从头生成一个新的图像呢?让现在深入JavaScript世界,因为这是在客户端唯一可以做到的,不使用任何可用的技术:Flash、ActiveX、HTML5、Java,或任何服务器端脚本语言。

在开始时,会保持简单,也就是说,只会使用BMP图像,当找到一些额外的时间时,可以扩展到现代浏览器支持的任何其他图像格式。

在维基百科上,可以找到关于BMP图像格式需要知道的一切。现在,看下面的每个位图图像的一般结构:

文件头 [正好14字节长] 位图头 [正好40字节长] 调色板 [0或n*3字节长,其中n是调色板中的颜色数量] 位图数据 [正好高度*宽度*位/像素字节长,四舍五入到4字节边界]

为了更清楚,从维基百科上借用了以下图片:

首先要做的就是填充这个头部信息,因为它不会改变(网页上的图像大小很少变化)。请参见以下JavaScript代码:

var imageHeader = ( 'BM'+ // "Magic Number" 或签名 num_file_bytes + // 文件大小(字节)* '\x00\x00'+ // 保留 '\x00\x00'+ // 保留 '\x36\x00\x00\x00'+ // BMP数据所在位置的偏移量(54字节) '\x28\x00\x00\x00'+ // 头部剩余字节数 // 从这里(40字节) width + // 位图的宽度(像素)* height + // 位图的高度(像素)* '\x01\x00'+ // 颜色平面的数量(1) '\x20\x00'+ // 32位/像素 '\x00\x00\x00\x00'+ // 无压缩(0) '\x00\x00\x00\x00'+ // BMP数据大小(字节)* '\x13\x0B\x00\x00'+ // 2835像素/米 - 水平分辨率 '\x13\x0B\x00\x00'+ // 2835像素/米 - 垂直分辨率 '\x00\x00\x00\x00'+ // 调色板中的颜色数量 // (保持0为32位) '\x00\x00\x00\x00'+ // 0重要颜色 // (意味着所有颜色都重要) );

这样,就为32bpp位图图像创建了头部,其大小为width*height。这种位图类型没有颜色表,所以它在头部中缺失。

由于有了正确的头部,现在可以分配图像数据。请参见以下:

var imageData = new Array();

它基本上是一个Array对象,将使用它来存储图像像素。说到像素,创建了以下类来存储颜色信息:

function Color(r, g, b) { this.red = parseInt(r) % 256; this.green = parseInt(g) % 256; this.blue = parseInt(b) % 256; return this; }

现在,要创建单个像素的值,考虑到32bpp颜色深度,使用了以下方法:

var color = new Color(red, green, blue); var newColor = String.fromCharCode(color.blue, color.green, color.red, 0);

当想为图像中的某个像素放置值(颜色)时,使用了以下方法:

imageData[y*width+x] = newColor;

这很难比这更简单了,对吧?

使用代码

基于之前的故事,创建了一个非常小的图形库,用JavaScript编写,将展示在客户端可以做什么。请参见以下示例:

var graphics = createGraphics(320, 240); graphics.clear(new Color(0, 0, 0)); graphics.updateImage("myImage");

注意:这将只在Firefox、Chrome、Opera和Safari中正确工作。

再次,为什么这样做?

在完整的HTML5标准实现的这个时代,这不是构建大型动画系统的可接受解决方案。但它仍然可以作为一种替代方案,尽管图形库提供的功能非常基本。这里缺少很多东西,如果有时间,会尝试实现它们。这是一个实验,是过去的技术,不是未来的。试图测试JavaScript语言在即时生成全彩色图像方面的速度,认为得到了有趣的结果。

看到了一些基于DOM的JavaScript图形库。在渲染过程中创建了大量的DIV元素,并且在客户端创建图像。这是另一种选择,也是可行的。

问题

要指出的第一个问题是渲染速度。尽管有些人会说它并不慢(它确实不是),但说它无法与HTML5<canvas>元素相匹配,也不应该。这个速度在很大程度上取决于图像的大小:图像越小,显示得越快。接下来,JavaScript渲染算法并不是世界上最快的,知道的。

第二件事是位图的类型(或颜色的数量)。使用的是32bpp位图,它们提供了质量,但它们是今天在市场上能找到的最大的。如果使用调色板化的位图,将处理更少的数据,它肯定会更快,但最多有256种不同的颜色可用,所以在质量上做出了妥协以获得更多的速度。

最后一件事是从头开始不断加载图像。每次设置图像src属性时,浏览器都会从头开始解析其信息,这是耗时的,考虑到前两个问题。压缩的图像数据是更好的解决方案(特别是对于调色板化的位图),但最好找到一个非常快的JavaScript GIF编码器。可以看这个作为例子,但要注意,因为它是实现生成单色GIF文件的。也可以寻找一个JavaScript LZW编码器。

沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485