引自http://blog.csdn.net/firefight/archive/2007/02/06/1503099.aspx
使用 Batik 开发 SVG 应用程序
翻译时间 2007-2-6
修订记录 2007-2-23 语言修改
Thierry Kormann
ILOG
Les Taissounières HB2
1681 route des dolines
06560 Valbonne
France
e-mail: tkormann@ilog.fr
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] 图像的应用程序,其功能范围包括图像显示、生成和操作。工具集提供了一组核心模块,包括:
-
SVG 文档对象模型的实现( SVG DOM, W3C/SVG 工作组定义的标准应用程序接口),用于其生成和操作 SVG 内容;
-
transcoder 模块能够将 SVG 文档转换为光栅图像;
-
JSVGCanvas 模块,一个 swing 组件,可以用于渲染静态或动态的 SVG 内容。
本文的目的是介绍如何使用 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 树之间的关系。
图 1: SVG Generator 模块架构图
为了说明 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.w3c.dom.Document;
import org.w3c.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.w3c.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 文档对象模型
“文档对象模型是一个与平台和语言无关的接口,通过该接口,程序和脚本能够动态访问和更新文档内容、结构和风格。文档可以被进一步处理,处理结果能够与当前显示的页面合成。这就是对 W3C 和 WEB 中的 DOM 相关技术的概述。
-- DOM 工作组 (W3C)
在 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.w3c.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.w3c.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.w3c.dom.Document;
import org.w3c.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 "-//W3C//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 οnlοad="build(evt)" />
</svg>
图 2: 在 'onload' 事件派发后的结果图像
// Create an ImageTranscoder
ImageTranscoder transcoder = new ...;
transcoder.addTranscodingHint(ImageTranscoder.KEY_EXECUTE_ONLOAD, Boolean.TRUE);
// ...
总结一下, transcoder 模块中提供了从 SVG 文档转换为其它格式的 API 。 ImageTranscoder 是