使用Batik开发SVG应用程序
翻译时间 2007-2-6
修订记录 2007-2-23 语言修改
Thierry Kormann
ILOG
ILOG
Les Taissounières HB2
1681 route des dolines
06560 Valbonne
France
e-mail: [email protected]
fax: +33 4 92 96 61 62
主页: http://www.ilog.com
关键词: SVG, Batik, Toolkit, Developing, Applications
摘要
Batik是Apache软件基金会(Apache Software Foundation)开发的一个开源项目。该项目的目标是提供一组核心模块,通过使用这些模块可以实现特定的SVG解决方案。本文将介绍如何使用Batik组件开发具有SVG功能的JavaTM应用程序。
介绍
Batik是基于JavaTM技术的工具集,用于使用Scalable Vector Graphics (SVG) [1] 图像的应用程序,其功能范围包括图像显示、生成和操作。工具集提供了一组核心模块,包括:
本文的目的是介绍如何使用Batik组件开发具有SVG功能的JavaTM应用程序。文章包括三个部分。第一部分介绍在应用程序中如何创建和操作SVG内容。第二部分描述如何将SVG图像转换为其它图像格式,例如JPG或PNG。最后一部分介绍如何在JavaTM应用程序中增加SVG显示功能。
使用Batik创建SVG内容
Batik提供了两个模块创建或操作SVG内容,两个模块可以单独或组合使用。其中SVG Generator模块能够以SVG格式输出图像,而SVG DOM的实现提供了操作SVG内容的标准API。
SVG Generator模块
在JavaTM 平台中,所有的渲染操作通过java.awt.Graphics2D 抽象类完成,类中提供了drawRect,fillRect和 drawString等操作。不同类型的显示输出有其特定的具体实现,例如对显示器和打印机输出。JavaTM平台将根据渲染操作的上下文自动选择使用何种具体的实现。因此,开发人员仅仅需要关注Graphics2D 抽象类中的一般API。
Batik工具集中提供了一个新的Graphics2D实现类,名为SVGGraphics2D。在SVGGraphics2D中实现的Graphics2D一般API用于生成SVG内容,而不是输出到显示器或打印机。换一种说法,每当JavaTM 调用一个渲染方法,例如drawRect,SVGGraphics2D将生成对应的SVG内容(在此为一个<rect>元素)并追加到DOM [2] 树中。最终,一系列渲染操作生成的DOM树表达了开发人员创建的图形,图形内容与其它实现完全一致,唯一的不同是用SVG描述的。下图(图1)显示了SVGGraphics2D与DOM树之间的关系。
为了说明SVG Generator 是如何工作的,下面的例子演示如何创建SVGGraphics2D实例,并且象使用常规Graphics2D对象一样绘制图形。之后演示了如何输出生成的DOM树(DOM树不仅仅是SVG文档在内存中的表示,同时也是图形的内存表示)。
import java.awt.Rectangle;
import java.awt.Graphics2D;
import java.awt.Color;
import java.io.Writer;
import java.io.OutputStreamWriter;
import java.io.IOException;
import org.apache.batik.svggen.SVGGraphics2D;
import org.apache.batik.dom.GenericDOMImplementation;
import org.w 3c .dom.Document;
import org.w 3c .dom.DOMImplementation;
public class TestSVGGenerator {
public void paint(Graphics2D g2d) {
g2d.setPaint(Color.red);
g2d.fill(new Rectangle(10, 10, 100, 100));
}
public static void main(String [] args) throws IOException {
// Get a DOMImplementation
DOMImplementation domImpl =
GenericDOMImplementation.getDOMImplementation();
String svgNamespaceURI = "http://www.w3.org/2000/svg";
// Create an instance of org.w 3c .dom.Document
Document document =
domImpl.createDocument(svgNamespaceURI, "svg", null);
// Create an instance of the SVG Generator
SVGGraphics2D svgGenerator = new SVGGraphics2D(document);
// Render into the SVG Graphics2D implementation
TestSVGGenerator test = new TestSVGGenerator();
test.paint(svgGenerator);
// Finally, stream out SVG to the standard output using UTF-8
// character to byte encoding
boolean useCSS = true; // we want to use CSS style attribute
Writer out = new OutputStreamWriter(System.out, "UTF-8");
svgGenerator.stream(out, useCSS);
}
}
综上所述,SVG Generator能够以SVG格式输出图形。采用SVGGraphics2D类的应用程序不需要修改任何图形代码,简单的用SVGGraphics2D实例代替内建的Graphics2D实现就可以了。
使用SVG Generator,开发人员可以访问生成的DOM树以便进一步操作它,或者直接将其内容写入一个输出流。SVGGraphics2D类可以以很多方式进行定制。例如,用户可以选择自己需要的风格生成方式(使用style属性或XML表达属性),他们还可以改变SVG文档的大小,或者扩展生成器以支持定制的图形格式。更多关于SVG Generator的内容请参见Batik SVG Generator Tutorial [3] 。
SVG文档对象模型
“文档对象模型是一个与平台和语言无关的接口,通过该接口,程序和脚本能够动态访问和更新文档内容、结构和风格。文档可以被进一步处理,处理结果能够与当前显示的页面合成。这就是对W 3C 和WEB中的DOM相关技术的概述。
-- DOM工作组(W 3C )
在SVG中,DOM用于在内存中描述一个SVG文档。它是用于创建和操作<rect> 或 <cirle> 等元素的标准API。SVG工作组设计了DOM的扩展,称为SVG DOM。SVG DOM是SVG规范的一部分,提供了与SVG相关的额外的操作,帮助SVG开发人员完成诸如处理几何体或图形对象,得到字符串长度,或取得一个属性变化值等操作。
Batik提供了一个SVG DOM的实现,可以用于SVG内容的创建和操作。在Batik1.5beta2版本中实现了所有DOM特性,并支持一部分SVG DOM功能。下面的例子说明如何得到Batik SVG DOM实现。
import org.w 3c .dom.DOMImplementation;
import org.apache.batik.dom.svg.SVGDOMImplementation;
DOMImplementation impl = SVGDOMImplementation.getDOMImplementation();
通过DOMImplementation能够创建一个Document。下面的例子说明如何使用createDocument方法创建SVG文档,其输入参数中包括SVG名字空间URI和SVG根元素名称。
import org.apache.batik.dom.svg.SVGDOMImplementation;
import org.w 3c .dom.Document;
DOMImplementation impl = SVGDOMImplementation.getDOMImplementation();
String svgNS = "http://www.w3.org/2000/svg";
Document doc = impl.createDocument(svgNS, "svg", null);
最后,通过Document 对象,开发人员能够创建SVG内容。尽管Batik DOM实现是一个针对SVG DOM的实现,但是也能够支持一般的XML文档。下例中在(10, 20)处创建了一个大小为(100, 50)的红色矩形。
import org.apache.batik.dom.svg.SVGDOMImplementation;
import org.w 3c .dom.Document;
import org.w 3c .dom.Element;
DOMImplementation impl = SVGDOMImplementation.getDOMImplementation();
String svgNS = "http://www.w3.org/2000/svg";
Document doc = impl.createDocument(svgNS, "svg", null);
// get the root element (the svg element)
Element svgRoot = doc.getDocumentElement();
// set the width and height attribute on the svg root element
svgRoot.setAttributeNS(null, "width", "400");
svgRoot.setAttributeNS(null, "height", "450");
// create the rectangle
Element rect = doc.createElementNS(svgNS, "rect");
rect.setAttributeNS(null, "x", "10");
rect.setAttributeNS(null, "y", "20");
rect.setAttributeNS(null, "width", "100");
rect.setAttributeNS(null, "height", "50");
rect.setAttributeNS(null, "style", "fill:red");
// attach the rectangle to the svg root element
svgRoot.appendChild(rect);
生成的SVG内容如下:
<svg width="400" height="450">
<rect x="10" y="20" width="100" height="50" style="fill:red"/>
</svg>
最后,Batik提供了几个使用SVG DOM树的方法。下列两个模块可以用于渲染SVG文档,Transcoder 模块(见“使用Batik渲染SVG内容”一节)和 JSVGCanvas模块(见“使用Batik创建SVG应用程序”一节)。
使用Batik渲染SVG内容
Batik工具集提供了一个Transcoder 模块,其中ImageTranscoder类能够将SVG文档转换为PNG或JPG格式的光栅图像。TranscoderInput类和TranscoderOutput类分别对应转换的输入数据和输出数据。Transcoder支持几种不同的输入方式,例如InputStream,Document或Reader,以及不同的输出方式如OutputStream或 Writer。 下面使用PNGTranscoder演示如何将一个SVG文档转换为PNG图像。
import java.io.*;
import org.apache.batik.transcoder.image.PNGTranscoder;
import org.apache.batik.transcoder.TranscoderInput;
import org.apache.batik.transcoder.TranscoderOutput;
// Create a PNG transcoder
PNGTranscoder transcoder = new PNGTranscoder();
// Create the transcoder input
String svgInputURI = ...;
TranscoderInput input = new TranscoderInput(svgInputURI);
// Create the transcoder output
OutputStream ostream = ...;
TranscoderOutput output = new TranscoderOutput(ostream);
// Transform the svg document into a PNG image
transcoder.transcode(input, output);
// Flush and close the stream
ostream.flush();
ostream.close();
开发人员可以通过TranscodingHints类控制所转换SVG文档的渲染方式(例如使用的CSS媒体或CSS替代风格页),以及转换结果图像的不同选项(例如JPG的编码质量,图像格式的背景色是否支持透明,或图像大小)。为了设置或改变转换选项,用户应创建新的TranscodingHints对象并传给ImageTranscoder。如果只需要设置少量选项,可以通过ImageTranscoder类的addTranscodingHint方法完成。例如可以使用JPEGTranscoder设置JPG的编码质量:
// Create a JPG transcoder
JPEGTranscoder transcoder = new JPEGTranscoder();
transcoder.addTranscodingHint(JPEGTranscoder.KEY_QUALITY, new Float(.8));
// ...
下面的代码能够控制图像的大小,并可以在所有类型ImageTranscoder中使用:
// Create an ImageTranscoder
ImageTranscoder transcoder = new ...;
transcoder.addTranscodingHint(ImageTranscoder.KEY_WIDTH, new Integer(100));
此外,ImageTranscoder也可以用于处理动态SVG内容。用户可以选择转换选项KEY_EXECUTE_ONLOAD以保证SVG文件渲染处理完成。渲染可以在onload事件派发之前或之后进行,onload事件处理函数将在渲染前执行。因此,脚本可以在SVG内容渲染前对内容进行修改。下例中演示了一个简单的动态SVG文档,其结果图像见图2。
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W 3C //DTD SVG 1.0//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="300" height="300" viewBox="0 0 300 300">
<script type="text/ecmascript"><![CDATA[
function build(evt) {
var document = evt.target.ownerDocument;
var svgNamespaceURI = "http://www.w3.org/2000/svg";
var e = document.createElementNS(svgNamespaceURI, "rect");
e.setAttributeNS(null, "x", "50");
e.setAttributeNS(null, "y", "50");
e.setAttributeNS(null, "width", "200");
e.setAttributeNS(null, "height", "200");
e.setAttributeNS(null, "style", "fill:crimson");
evt.target.appendChild(e);
}
]]></script>
<g onload="build(evt)" />
</svg>
// Create an ImageTranscoder
ImageTranscoder transcoder = new ...;
transcoder.addTranscodingHint(ImageTranscoder.KEY_EXECUTE_ONLOAD, Boolean.TRUE);
// ...
总结一下,transcoder模块中提供了从SVG文档转换为其它格式的API。ImageTranscoder是transcoder中的一种,能够将静态或动态SVG内容转换为光栅图像例如PNG或JPG。通过设置名为TranscodingHints的某些选项可以控制或修改SVG文档的转换方式。该模块在SVG不能被内置处理的情况下特别有用,例如在IE浏览器中,当然也可以在服务器端的应用程序中使用。