来源:IBM developerWorks 中国
英文版:http://www.ibm.com/developerworks/library/x-tipjpeg/index.html?S_TACT=105AGX52&S_CMP=cn-a-x
在这篇技巧文章中,Benoit Marchal讨论了可升级矢量图形(Scalable Vector Graphics,SVG)的编程方法。除非SVG浏览器像Macromedia Flash播放器一样得到广泛应用,否则人们很难将SVG图像直接集成在Web站点上。在这段时间内,Web开发人员可以通过SVG生成JPEG以及其他的位图文件。SVG是纯粹的XML,因此特别有用。
可升级矢量图形是由W3C开发的一种图像格式。因为它是基于XML的,所以您可以通过样式表和其他XML脚本生成图形。SVG对于Web开发人员以及Web站点管理员来说是十分有价值的工具。在这篇技巧文章中,我将向您展示如何用SVG自动生成图像,例如,根据统计数据生成统计图。
1 SVG是什么?
SVG是一种XML词汇表,用于描述矢量图像。图像分为两类:位图和矢量图。位图(如JPEG、GIF或者PNG文件)通过像素网格表示一幅图像。矢量图(SVG或Macromedia Flash)通过基本的形状来描述图像,例如圆形、矩形、直线、曲线等等。Adobe Photoshop是位图编辑器,而Adobe Illustrator则是矢量图像编辑器。
位图的文件更大,缩放时也更难做到不损失图像质量。假设有一幅图像,上面是一个直径为50个像素的圆形。那么对应于位图的尺寸必须至少有50×50个像素,也就是2,500个像素。如果这个圆形的直径是100像素,那么这个位图的尺寸就达到了100×100像素,足足增大了四倍(即10,000个像素)。JPEG、GIF和PNG文件都通过压缩的方式减少文件大小。然而压缩带来的帮助是有限度的,位图依然比矢量图形大很多。
事实上,与这幅图对应的矢量图形只有一条指令:"绘制一个直径为50像素的圆形。"更进一步说,如果圆形变大,存储它的文件并不会更大(只是变成了"绘制一个直径为100像素的圆形。")不过并不是每一幅图像都能够分解成基本的形状,比如说对于照片,这种方法就无能为力了。因此位图的地位依然很重要,但是对于那些可以分解成基本形状的图像,比如图表、标志、和化学公式等等,矢量文件格式天生就具有较高的效率。
放大或者缩小一幅位图,将会损失掉图像的质量。事实上当您将像素网格的直径扩大两倍,您获得的像素数量就是原来的四倍,因此您需要将图像外推四分之三!反过来讲,要将矢量图像放大两倍,您只需要绘制更大的形状就可以了。
现在,Web上最流行的矢量格式是Macromedia Flash。这是一种很了不起的格式,许多厂商都支持它,但是这种工具也存在所有权的问题。SVG是一种新的标准,它由W3C开发,意在提供Flash之外的另一种选择。
Web设计社区关于用SVG取代Flash的讨论已经进行了很多次了。大家主要关心的问题是,现在是97%的PC用户都可以使用Flash,但是SVG却还没有那么流行。不过事情总是可以变化的,既然SVG是一项标准,那么最终浏览器还是会支持它的,不过要想让它和Flash一样流行,可能还需要若干年。
2 无头部图形
Batik要用Graphics2D才能生成图像。这是处理2D图形的标准Java API,这一点对于UNIX或是Linux Web服务器来说可能会有问题。因为Graphics2D需要有X11服务器才能运行,而Web服务器上很少会有X11。从JDK 1.4开始,您可以通过将java.awt.headless属性设置为true,运行所谓的无头部应用程序。请注意,JDK依然还会链接到X11库,但是已经没有必要启动服务器了。您可以在命令行中直接设置这一属性:
java -Djava.awt.headless=true
-jar batik-rasterizer.jar chart.svg
3 用程序检验效果
即使SVG的可用性目前还不如Flash,但是应用SVG还是会带来一些好处。SVG吸引人的特点之一就是,它是一种XML词汇表,因此可以很方便的用我们熟悉的工具,如XML解析器、脚本、XSL样式表等,来处理SVG。为了解决缺乏浏览器的支持这一问题,我们可以将SVG图像转换成广泛支持的格式,比如GIF或是JPEG。
Apache为我们提供了一种开放源代码的SVG渲染工具,名叫Batik(参阅参考资料)。Batik具有很多不同的功能,如图像浏览器、创建图像的工具、以及光栅化程序(rasterizer)。我最感兴趣的是光栅化程序,因为它可以将SVG文件转换成位图。
话说得已经够多了,现在要开始编写代码了。代码1是一段Python脚本,可以根据一组数据创建条形图。请注意,您不一定非得用Python才能实现本篇技巧文章中的任务,Perl、Javascript、Java语言以及最重要的XSL样式表都能够等效完成工作。关键问题在于,既然SVG文件是XML,那么任何XML工具都应该适用。
代码1 printsvg.py
from sys import stdin
def read_data():
data = []
line = stdin.readline()
while line != '\n' and line != '':
data.append(line.split())
line = stdin.readline()
return data
def print_bars(data):
position = 0
for i in data:
height = int(i[1]) * 2
if height > 200:
height = 200
print ' <rect x="%(x)i" y="%(y)i" width="30" \
height="%(height)i"/>' % { 'x': position * 40 + 10,
'y': 200 - height, 'height': height }
print ' <text x="%(x)i" y="215">%(text)s\
</text>' % { 'text': i[0], 'x' : position * 40 + 20 }
position += 1
return
def print_svg(data):
print u'<?xml version="1.0"?> \
\n<svg xmlns="http://www.w3.org/2000/svg" \
\n id="body" \
\n width="%(width)i" \
\n height="220" \
\n viewBox="0 0 %(width)i 220"> \
\n <polyline style="stroke:black; fill:none" id="axis" \
points="0,0 0,200 %(width)i,200"/> \
\n <g id="boxes" style="stroke:black; fill:green; \
text-anchor: middle">' % { 'width': len(data) * 40 + 10 }
print_bars(data)
print ' </g> \
\n</svg>'
return
if __name__ == "__main__":
print_svg(read_data())
这段脚本是一个过滤器,因此它要从标准输入设备上获得输入数据,然后将处理结果写到标准输出设备上。它希望数据分行表示,每一行有两部分数据 -- -- 行标签和百分比。您可以用重定向操作符来处理文件,如下所示:
python printsvg.py < data.txt > chart.svg
代码2是一个数据集的例子。显然,您可以在瞬间生成大量图形,只要给脚本指定不同的数据集就可以了。这对于统计应用来说是很有用的。
代码2 data.txt
Jan. 43
Feb. 34
Mar. 98
Apr. 29
May 52
Jun. 33
Jul. 15
Aug. 11
Sep. 65
Oct. 78
Nov. 98
Dec. 87
如果要将SVG图像转换成更加常用的格式,您可以安装Batik的光栅化程序(参阅参考资料),然后发出下面的命令:
java -jar batik-rasterizer.jar chart.svg
用代码2中的数据运行代码1中的脚本,您最终将得到如图1所示的图像:

java -jar batik-rasterizer.jar -m image/jpeg -q 0.8 chart.svg
-m 代表图像的MIME类型,-q表示JPEG的质量因子(介于0和1之间的数字)。
4 话题的引伸
使用SVG和Batik工具箱带来的主要好处是,您可以通过XML生成图像,每一种XML工具,包括脚本与样式表,现在都可以用来产生Web图像了。
我解释了如何生成条形图,相同的技术也适用于其他的图形,如导航按钮、技术图纸、UML模型等。请注意,您的脚本是没必要生成全部图像的。假使要导入用Adobe Illustrator之类的图像编辑器创建的标志或者其他图像,您可以采用下面的步骤:
在图像编辑器中,将图像保存为SVG。
在脚本中,插入下面的指令:<use xlink:href="/logo.svg"/>
有了Batik光栅化程序和颇具灵活性的XML,您将发现SVG真的是所向披靡。
5 参考资料
您可以参阅本文英文原文http://www.ibm.com/developerworks/library/x-tipjpeg/index.html?S_TACT=105AGX52&S_CMP=cn-a-x.
请下载本文用到的Batik toolkit。这里面包括了光栅化程序,可以将SVG文件转换成位图。
请访问Adobe SVG Zone,这里是开始学习SVG的好地方。里面可以下载SVG浏览器(让您的浏览器可以显示SVG)、演示和教程。
请到SVG中国 XML专区上查找更多的XML资料。
关于作者

Benoit Marchal,顾问,Pineapplesoft
Benoit Marchal是一名来自比利时的顾问。他是《XML by Example,Second Edition》一书以及其他几本XML书籍的作者。Benoit能够为您的XML项目提供帮助。可以通过
这个 E-mail 地址已经被防止灌水恶意程序保护,您需要激活 Java Script 才能观看
或者他的个人主页marchal.com与Benoit取得联系。
(THE END)