batik详解

一、概述
Batik是为想使用svg格式图片来实现各种功能的应用程序和Applet提供的一个基于java的工具包。
工程创建的目的是为开发者提供一系列可以结合或单独使用来支持特殊的svg解决方案的核心模块。模块主要有SVGParser,SVGGernerator,SVGDOM。Batik工程的其他目的是使它具有高度的扩展性----举个例子,Batik允许开发者使用自定义的SVG元素。即使工程的目标是提供一系列核心模块,但是还是提供了一个完整的SVG浏览器,以便证实各个模块的有效性和交互性。
二、batik的用途
通过Batik,你可以在任何使用到java的地方操作SVG文档。你也可以使用各种Batik模块来在你的应用程序和Applet中来生成,操作和转换你的svg图像。
batik使通过java处理SVG内容变的简单。举个例子,通过使用batik的SVGGernerate模块,java应用程序和Applet可以非常简单的使输出图像的格式为SVG。使用batik的SVG viewing component, 应用程序或者Applet可以非常容易的整合SVG查看和交互功能。另外还可以使用Batik的模块将SVG转换为其他格式,比如说JPEG等图像格式和
PDF等其他向量格式.
Batik工具包包含如下各项:
模块 
  • SVG DOM implementation
  • 一系列SVG microsyntax parsers
  • scripting module
  • 一个 generator 用来从java2D中创建一个SVG document 
  • Swing SVG component
  • transcoder module

工具和应用程序

  • Squiggle, an SVG browser
  • An SVG rasterizer
  • A TTF to SVG converter
  • A pretty printer for SVG source files

三、SVG DOM API

DOM API定义了一个接口叫做DOMimplementation,这个接口用来表现任意DOM implementation之间的连接。这个类的作用是通过提供方法创建一个document来连接一个指定的DOM实例。然后具体的Document表现为一个XML Document 并且跟各种各样的DOM对象工厂比如Element,Attr,Text那样动作。

那么怎样才能获得一个依赖于你使用的DOM Implementation的DOMImplementation 实例呢?在Batik中DOM Implementation存在于包org.apache.batik.dom.svg中,类名为SVGDOMImplementation。以下例子表示怎样获取一个具体的DOMImplementation对象:

import org.w3c.dom.DOMImplementation;
import org.apache.batik.dom.svg.SVGDOMImplementation;

DOMImplementation impl = SVGDOMImplementation.getDOMImplementation();

一旦你已经拥有了一个DOMImplementation 实例,你将不能再依赖于batik的指定代码而要准备好使用DOM API了。
1.创建一个Doucument
使用DOMImplementation,你现在将可以创建一个Document。下面将举例说明怎么创建一个SVG Document。注意Batik的DOM implementation可以被用来表现一个SVG Document片断或者任意的XML Document。注意通过选择命名空间URI和SVG根元素本地名,我们将创建一个SVG Document。
import org.apache.batik.dom.svg.SVGDOMImplementation;
import org.w3c.dom.Document;

// 在SVGDOMImplementation中我们使用了一个不变的常量
// but we could have used "http://www.w3.org/2000/svg".
String svgNS = SVGDOMImplementation.SVG_NAMESPACE_URI;
DOMImplementation impl = SVGDOMImplementation.getDOMImplementation();
Document doc = impl.createDocument(svgNS, "svg", null);

 
当我们已经创建了一个SVG Document时,如果需要的话,我门可以映射这个document到一个SVGDocument。
 
2.创建一个SVG Document
最后使用Document对象,我们现在将构造SVG内容。注意上边创建的document,同时支持通用的XML和SVG。虽然Batik的DOM implementation是一个SVG DOM implementation,但是依赖于已经呈现的Document的指定的SVG方法,不能用于此点。
Document 可以使用DOM Leve2核心方法创建。以下的例子显示怎样在一个(400,450)范围的SVG屏幕中在(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 = SVGDOMImplementation.SVG_NAMESPACE_URI;
Document doc = impl.createDocument(svgNS, "svg", null);

// 获得根元素('svg' 元素).
Element svgRoot = doc.getDocumentElement();


// 设置'svg'根元素的宽,高属性.
svgRoot.setAttributeNS(null, "width", "400");

svgRoot.setAttributeNS(null, "height", "450");

// 创建矩形
Element rectangle = doc.createElementNS(svgNS, "rect");

rectangle.setAttributeNS(null, "x", "10");
rectangle.setAttributeNS(null, "y", "20");
rectangle.setAttributeNS(null, "width", "100");
rectangle.setAttributeNS(null, "height", "50");
rectangle.setAttributeNS(null, "fill", "red");

// 绑定 rectangle 到'svg'根元素.
svgRoot.appendChild(rectangle);

3.从一个SVG文件中创建一个Document
使用Batik,你也可以从一个URI,一个InputStream或者一个Reader中使用SAXSVGDocumentFactory创建一个SVG DOM树。下面的例子将举例说明怎么从一个URI中使用SAXSVGDocumentFactory类来创建一个SVG document。
 
import java.io.IOException;

import org.apache.batik.dom.svg.SAXSVGDocumentFactory;
import org.apache.batik.util.XMLResourceDescriptor;

import org.w3c.dom.Document;

try {
    String parser = XMLResourceDescriptor.getXMLParserClassName();
    SAXSVGDocumentFactory f = new SAXSVGDocumentFactory(parser);
    String uri = "http://www.example.org/diagram.svg";
    Document doc = f.createDocument(uri);

} catch (IOException ex) {
    // ...
}
 
  
四、解析器模块
SVG有很多没有属性值的微型语法使用,比如 SVGTransformable元素中的transform属性,path元素中的path data d属性等。以前这些属性不能很好的被解析,现在必要时可以通过SVG进程应用程序来使用。
1.解析器,操作者,生产者
在解析模块中,每个微语法通过一对类来支持---解析器和操作者。解析器是一个用来执行解析接口(用来从一个reader或者一个String中来解析值的接口)的类。操作者是微型语法的一个特殊接口,这个接口当相应元素的输入被解析后将调用接口中的相应的方法。在这些操作者接口中多种方法和适应类被提供。
解析器还包含一个错误操作,当输入解析错误时,错误操作的错误方法将被调用。如果错误处理没有跟解析器关联,那么当发生异常时将抛出ParseException。
解析模块支持的微语法如下:
Angles Clock values

Fragment identifiers

这个解析器被用来解析Fragment identifiers(片断定义)的svg允许的各种格式。

Lengths

解析SVG长度值

Length lists

用来解析逗号或者空格分隔的SVG长度列表。

Numbers

用于解析SVG数字值.

Number lists

用来解析逗号或者空格分隔的SVG数字值.

Path data

通过 PathParser执行, 通过 PathHandler处理. 用来解析 SVG path data, 就象path 元素中的d 属性一样.

Points

通过 PointsParser执行, 通过 PointsHandler处理. 用来解析 point 列表, 就象 polygon 元素中的points 属性那样.

Preserve aspect ratio values (保持屏幕比率值)

通过 PreserveAspectRatioParser执行, 通过 PreserveAspectRatioHandler处理. 用来解析在svg元素中的preserveAspectRatio 属性的值。

Transform lists

通过TransformListParser执行, 通过 TransformListHandler处理. 用来解析transform 列表, 就象在任意可以变换元素中的变换属性那样。

一些微型语法同样也有一个相应的生产者类,这个类是在解析的同时生成对象的一个处理接口的执行。

2.举例

下面例子用来举例怎么用一个解析器来解析一个点列表 

import java.awt.geom.Point2D;
import java.util.LinkedList;
import java.util.List;

import org.apache.batik.parser.DefaultPointsHandler;
import org.apache.batik.parser.ParseException;
import org.apache.batik.parser.PointsHandler;
import org.apache.batik.parser.PointsParser;

public class PointsParserExample {

    public List extractPoints(String s) throws ParseException {
        final LinkedList points = new LinkedList();
        PointsParser pp = new PointsParser();
        PointsHandler ph = new DefaultPointsHandler() {
            public void point(float x, float y) throws ParseException {
                Point2D p = new Point2D.Float(x, y);
                points.add(p);
            }
        };
        pp.setPointsHandler(ph);
        pp.parse(s);
        return points;
    }
}

这个例子使用 AWTTransformProducer 类来从一个SVG transform列表中生成一个 AffineTransform 对象:



 
   
 
   
 
   
import java.awt.geom.AffineTransform;

import org.apache.batik.parser.AWTTransformProducer;
import org.apache.batik.parser.ParseException;
import org.apache.batik.parser.TransformListParser;

public class TransformParserExample {

    public AffineTransform parseTransformList(String s) throws ParseException {
        TransformListParser p = new TransformListParser();
        AWTTransformProducer tp = new AWTTransformProducer();
        p.setTransformListHandler(tp);
        p.parse(s);
        return tp.getAffineTransform();
    }
}

使用 Rhino 特性 
Rhino有很多通过标准的ECMAScript解释器支持的特性,并且这个特性可以在batik中使用 。一个有用的特性是ECMAScript 代码可以使用java类和对象, 并且不仅仅是标准的ECMAScript 原始类型和通过Batik的主机对象扩展。
要从ECMAScript 中创建一个java类实例,你首先需要导入它存在的包。这个实现要使用Rhino 提供的importPackage 全局函数. 举个例子, 要导入javax.swing.JFrame 类, 你使用:
importPackage(Packages.javax.swing);
然后暴露在javax.swing保重每个类的一个全局属性,这个属性你可以用来创建一个新的这个类的对象, 类似于在java中的import javax.swing.*;声明。我们可以使用暴露的Jframe属性来创建一个新的这个类的实例 :
var frame = new JFrame("My test frame");
注意怎样将一个ECMAScript 字符串值,转换为 JFrame’s 构造器的一个参数. Rhino 将试图转换ECMAScript 值到适当的java原始类型或者对象用来在构造器或者方法调用下制造。在这个实例中 ECMAScript字符串值被转换为一个 java.lang.String 对象以便传给解释器。
注意,在这我们涉及到java对象,我们可以象我们在java源码中那样调用它的任何方法。下面这个完整的例子将论证这个,例子主要是点击一个绿色的圆,将弹出一个frame。 

  
  
    function showFrame() {
      var frame = new JFrame("My test frame");
      var label = new JLabel("Hello from Java objects created in ECMAScript!");
      label.setHorizontalAlignment(SwingConstants.CENTER);
      frame.getContentPane().add(label);
      frame.setSize(400, 100);
      frame.setVisible(true);
      frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
    }
  

自定义 Rhino 解释器 一个有用的Rhino解释器自定义的例子来自ECMAScript标准不提供任何预先确定的I/O设备来结合控制台的事实。无论如何,对于ECMAScript兼容语言来提供一个命名为打印输出信息到控制台的功能是非常通用的。在这我们将描述一个Batik Rhino 解释器自定义的例子来添加如下功能。你应该首先将默认的Batik ECMAScript 解释器子集化以便象下边所示的那样添加功能import org.apache.batik.script.rhino.RhinoInterpreter;import org.mozilla.javascript.Context;
import org.mozilla.javascript.Function;
import org.mozilla.javascript.Scriptable;
import org.mozilla.javascript.ScriptableObject;
import org.mozilla.javascript.PropertyException;public class ExtendedRhinoInterpreter extends RhinoIntepreter {    public ExtendedRhinoInterpreter() {        // Array of functions to put in the global object.
        final String[] names = { "print" }
        try {
            // Add the functions to the global object.
            getGlobalObject().defineFunctionProperties
                (names, ExtendedRhinoIntepreter.class,
                 ScriptableObject.DONTENUM);
        } catch (PropertyException e) {
            throw new Error(e);
        }
    }
   
    public static void print(Context cx, Scriptable thisObj,
                             Object[] args, Function funObj) {
        for (int i = 0; i < args.length; i++) {
            if (i > 0) {
                System.out.print(" ");
            }
   
            // Convert the ECMAScript value into a string form.
            String s = Context.toString(args[i]);
            System.out.print(s);
        }
        System.out.println();
    }
}
现在,你需要告诉Batik使用这个解释器代替默认的那个。为了实现这个目的,你必须首先定义一个工厂来创建一个
你的解释器实例。 
import org.apache.batik.script.Interpreter;
import org.apache.batik.script.InterpreterFactory;public class ExtendedRhinoInterpreterFactory
 implements InterpreterFactory {    public Interpreter createInterpreter() {
        return new ExtendedRhinoInterpreter();
    }
}
然后,你必须构建一个将使用这个工厂的IntepreterPool,并且在你的应用程序的 BridgeContext 上设定池
org.apache.batik.bridge.BridgeContext ctx = ...;
org.apache.batik.script.InterpreterPool pool =
    new org.apache.batik.script.InterpreterPool();
pool.putInterpreterFactory("text/ecmascript", 
                           new ExtendedRhinoInterpreterFactory());
ctx.setIntepreterPool(pool);
举个例子,如果你使用Batik SVG 浏览器程序,你应该可以使用在createBridgeContext()方法中
的JSVGCanvas类中先前的代码片段。 更深的是用Rhino工作参考Rhino主页 

在java平台中所有的绘图,都通过Graphics2D抽象类,这个类提供象drawRect,fillRect,drawString这样的方法。对于每个类型的输出这个抽象类都有指定的执行,比如屏幕或者打印机。SVGGraphics2D是这个接口的一个新的执行生成SVG内容,以用来替代画到屏幕或者打印机上。

SVGGraphics2D 拥有以下特性:
1.它允许应用程序输出图形到SVG格式
2.它输出图形到svg格式,不需要修改任何图形代码
3。它提供用户使用DOMApi操作生成文档的能力

以上图形显示生成器是怎样用DOMAPI工作的。W3C已经定义了一个API用来显示带有java对象的XML内容。这个API允许程序员在内存中操作,创建或者修改XML内容。DOMAPI包含象document,Element,Attr的接口,这些接口等价于java语言中的XML documents, elements 和attributes。

生成器管理一个DOM对象树用来显示相应于SVGGraphics2D实例的svg内容。换句话说,每次一个程序调用一个绘图方法,比如fillRect,在一个SVGGraphics2D实例中,一个新的DOM对象,描绘等价SVG,被添加到DOM树中。举个例子,一个矩形元素将在fillrect方法调用后被添加。

程序员使用这个生成器,可以存储DOM树到更深层的操作,或者可以直接写内容到一个输出流中,就象我们下面选项中看到的那样。

怎样使用SVGGraphics2D

从上面部分的描述我们可以看到为了使用一个SVGGraphics2D实例来构建SVG内容,一个文档类实例是必须的。DOM树是svg文档的内存内表现,它可以被用户使用DOMAPI深入操作,或者通过一个Write对象,流输出。下面的例子证明怎么从java图形中怎么生成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 TestSVGGen {

    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();

        // Create an instance of org.w3c.dom.Document.
        String svgNS = "http://www.w3.org/2000/svg";
        Document document = domImpl.createDocument(svgNS, "svg", null);

        // Create an instance of the SVG Generator.
        SVGGraphics2D svgGenerator = new SVGGraphics2D(document);

        // Ask the test to render into the SVG Graphics2D implementation.
        TestSVGGen test = new TestSVGGen();
        test.paint(svgGenerator);

        // Finally, stream out SVG to the standard output using
        // UTF-8 encoding.
        boolean useCSS = true; // we want to use CSS style attributes
        Writer out = new OutputStreamWriter(System.out, "UTF-8");
        svgGenerator.stream(out, useCSS);
    }
}

我们可以看到在我们的TestSVGGen实例中生成SVG内容包括三个步骤:

1.创建一个org.w3c.dom.Document实例,以便生成器用来构建它的XML内容,并且使用Document实例创建
一个SVG生成器


 // Get a DOMImplementation.
        DOMImplementation domImpl =
            GenericDOMImplementation.getDOMImplementation();

        // Create an instance of org.w3c.dom.Document.
        String svgNS = "http://www.w3.org/2000/svg";
        Document document = domImpl.createDocument(svgNS, "svg", null);

        // Create an instance of the SVG Generator.
        SVGGraphics2D svgGenerator = new SVGGraphics2D(document);


2.调用SVG生成器上的描绘代码。在我们的例子中,我们调用了TestSVGGen的paint方法



// Ask the test to render into the SVG Graphics2D implementation.
        TestSVGGen test = new TestSVGGen();
        test.paint(svgGenerator);



3.流输出svg内容。svg生成器可以流输出它的内容到任意的java.io.Writer中。在我们的例子中,我们流输出内容
到标准的输出流中




        // Finally, stream out SVG to the standard output using
        // UTF-8 encoding.
        boolean useCSS = true; // we want to use CSS style attributes
        Writer out = new OutputStreamWriter(System.out, "UTF-8");
        svgGenerator.stream(out, useCSS);




svg有两种方式来指定风格属性,比如填充颜色,显示属性或者CSS类型属性。useCss
 参数允许用户使用这个属性



svg生成器定制
在前面的段落中,我们已经看到SVG生成程序可以被定制来输出svg类型属性作为显示属性,或者css在线属性。在这个部分里我们将讨论一些高级定制的例子。
为了替代创建SVGGraphics2D只使用象创建SVG元素的工厂那样的document,我们可以
使用一个SVGGeneratorContext 实例的构造器。通过提供你拥有的
SVGGeneratorContext 实例,你将可以进行高级定制。你将发现如下的例子可以被定制。
1.在生成的SVG文件中存在你自己的注释
下面我们开始简单可行的例子。如果你在自己的java应用程序中结合Batik SVG生成器,
你将希望在XML代码中生成专门的注释。
DOMImplementation impl =
    GenericDOMImplementation.getDOMImplementation();
String svgNS = "http://www.w3.org/2000/svg";
Document myFactory = impl.createDocument(svgNS, "svg", null);

SVGGeneratorContext ctx = SVGGeneratorContext.createDefault(myFactory);
ctx.setComment("Generated by FooApplication with Batik SVG Generator");

SVGGraphics2D g2d = new SVGGraphics2D(ctx, false);
2.在生成的SVG文件中使用嵌入式svg字体


要有一个不使用系统字体来显示的独立的svg文件,你可以自己在svg文件中定义字体。
DOMImplementation impl =
    GenericDOMImplementation.getDOMImplementation();
String svgNS = "http://www.w3.org/2000/svg";
Document myFactory = impl.createDocument(svgNS, "svg", null);

SVGGeneratorContext ctx = SVGGeneratorContext.createDefault(myFactory);
ctx.setEmbeddedFontsOn(true);

SVGGraphics2D g2d = new SVGGraphics2D(ctx, true
);
3.定制图片存储路径


每次你调用一个通过SVGGraphics2D接口提供的drawImage方法时,默认图片绘制被创建并且放到一个默认文件
中。举个实例,一个base64编码被创建,并且通过默认嵌入到svg文件中去。作为选择,你可以选择将图片写到
事先定义好的文件夹中的一个单独的文件里。文件格式是svg规范要求的两种光栅格式图片:jpeg,png
你可以改变默认行为,通过在svg生成器中提供明确的提供图片句柄来使用。下面例子中所有图片将转换为png
格式,同时存放到res/images文件夹中
 
DOMImplementation impl =
    GenericDOMImplementation.getDOMImplementation();
String svgNS = "http://www.w3.org/2000/svg";
Document myFactory = impl.createDocument(svgNS, "svg", null);

SVGGeneratorContext ctx = SVGGeneratorContext.createDefault(myFactory);
GenericImageHandler ihandler = new ImageHandlerPNGEncoder("res/images", null);
ctx.setImageHandler(ihandler);

SVGGraphics2D g2d = new SVGGraphics2D(ctx, false);
为每个单独drawimage调用在一个新的被写到SVG文件或者一个扩展文件的图片数据拷贝中使用默认的图片处理结果。如果你一遍又一遍的使用相同的图片,这样做的结果就是在一个SVG文件中包含许多冗余信息。在初始化SVGDOm树的时候将会有微小的性能损失,你可以选择将图片重复使用。为了这个原因你要使用一个指定的图片处理器,如下:
DOMImplementation impl =
    GenericDOMImplementation.getDOMImplementation();
String svgNS = "http://www.w3.org/2000/svg";
Document myFactory = impl.createDocument(svgNS, "svg", null);

SVGGeneratorContext ctx = SVGGeneratorContext.createDefault(myFactory);

// Reuse our embedded base64-encoded image data.
GenericImageHandler ihandler = new CachedImageHandlerBase64Encoder();
ctx.setGenericImageHandler(ihandler);


SVGGraphics2D g2d = new SVGGraphics2D(ctx, false);
用隐藏的图片处理器,你甚至可以使用几个不同的SVG文档图片数据的相同拷贝的重用。只要保持图片处理的参考,并且传输它到为生成SVG DOM树使用的SVGGraphics实例中。下面简单的一个例子用来论证不同的SVG树通过单独的SVG生成器被创建,以便有效的存储任何通用图片。
class MySVGGenerator {

    // The image handler will write all images files to "res/images".
    private static ImageHandler ihandler =
        new CachedImageHandlerPNGEncoder("res/images", null);


    public void generateSVG(JPanel myCanvas, OutputStream outStream) {
        DOMImplementation domImpl =
            GenericDOMImplementation.getDOMImplementation();
        Document myFactory = domImpl.createDocument(svgNS, "svg", null);
        SVGGeneratorContext ctx =
            SVGGeneratorContext.createDefault(myFactory);
        ctx.setGenericImageHandler(ihandler);


        SVGGraphics2D svgGenerator = new SVGGraphics2D(ctx, false);

        // Create the SVG DOM tree.
        myCanvas.paintComponent(svgGenerator);

        Writer out = new OutputStreamWriter(outStream, "UTF-8");
        svgGenerator.stream(out, true);
    }
}
 
定制生成的SVG类型
 
你的需要相关风格可以不同于提供的两个选项(XML presentation attributes or CSS inline stylesheets)。举个例子,你可以希望将CSS属性方知道一个SVG风格的元素不分离,并且通过类属性提及到他们。那么你将需要定制一个如下所示的新的stylehandler
public class StyleSheetStyleHandler implements StyleHandler {

    // The CDATA section that holds the CSS stylesheet.
    private CDATASection styleSheet;

    // Build the handler with a reference to the stylesheet section.
    public StyleSheetStyleHandler(CDATASection styleSheet) {
        this.styleSheet = styleSheet;
    }

    public void setStyle(Element element, Map styleMap,
                         SVGGeneratorContext generatorContext) {
        Iterator iter = styleMap.keySet().iterator();

        // Create a new class in the style sheet.
        String id = generatorContext.getIDGenerator().generateID("C");
        styleSheet.appendData("."+ id +" {");

        // Append each key/value pair.
        while (iter.hasNext()) {
            String key = (String) iter.next();
            String value = (String) styleMap.get(key);
            styleSheet.appendData(key + ":" + value + ";");
        }

        styleSheet.appendData("}\n");

        // Reference the stylesheet class on the element to be styled.
        element.setAttributeNS(null, "class", id);
    }
}
然后你可以创建并且使用一个有正确配置的SVGGeneratorContext的一个SVGGraphics

2D

// Configure the SVGGraphics2D for a given Document myFactory.
SVGGeneratorContext ctx = SVGGeneratorContext.createDefault(myFactory);
CDATASection styleSheet = myFactory.createCDATASection("");
ctx.setStyleHandler(new StyleSheetStyleHandler(styleSheet));
SVGGraphics2D g2d = new SVGGraphics2D(ctx, false);

// Use the g2d to draw (e.g., component.paint(g2d)).

// Add a stylesheet to the definition section.
SVGSVGElement root = (SVGSVGElement) g2d.getRoot();
Element defs = root.getElementById(SVGSyntax.ID_PREFIX_GENERIC_DEFS);
Element style = myFactory.createElementNS
    (SVGSyntax.SVG_NAMESPACE_URI, SVGSyntax.SVG_STYLE_TAG);
style.setAttributeNS(null, SVGSyntax.SVG_TYPE_ATTRIBUTE, "text/css");
style.appendChild(styleSheet);
defs.appendChild(style);

// Dump the root content to a given Writer myWriter.
g2d.stream(root, myWriter);

扩展paint对象到SVG元素转换
 
SVGGraphics2D可以为通用的java 2d对象生成SVG元素,但是有时候你可以用你自己的类,比如java 2D Paint的执行接口。因为这个原因你需要写一个你将要设置在你的 SVGGeneratorContext中的ExtensionHandler。
在下边的例子中,我们定义 ExtensionHandler的一个草图,这个草图允许转换一个Paint接口的Batik执行,名称叫LinearGradientPaint。
class MyExtensionHandler extends DefaultExtensionHandler {

    public SVGPaintDescriptor handlePaint(Paint paint,
                                          SVGGeneratorContext generatorCtx) {
        if (paint instanceof LinearGradientPaint) {
            LinearGradientPaint gradient = (LinearGradientPaint) paint;

            // Create a new SVG 'linearGradient' element to represent the
            // LinearGradientPaint being used.
            String id = generatorCtx.getIDGenerator().generateID("gradient");
            Document doc = generatorCtx.getDOMFactory();
            Element grad = doc.createElementNS
                (SVGSyntax.SVG_NAMESPACE_URI,
                 SVGSyntax.SVG_LINEAR_GRADIENT_TAG);

            // Set the relevant attributes on the 'linearGradient' element.
            grad.setAttributeNS(null, SVGSyntax.SVG_ID_ATTRIBUTE, id);
            grad.setAttributeNS(null, SVGSyntax.SVG_GRADIENT_UNITS_ATTRIBUTE,
                                SVGSyntax.SVG_USER_SPACE_ON_USE_VALUE);
            Point2D pt = gradient.getStartPoint();
            grad.setAttributeNS(null, "x1", pt.getX());
            grad.setAttributeNS(null, "y1", pt.getY());
            pt = gradient.getEndPoint();
            grad.setAttributeNS(null, "x2", pt.getX());
            grad.setAttributeNS(null, "y2", pt.getY());

            switch (gradient.getCycleMethod()) {
            case MultipleGradientPaint.REFLECT:
                grad.setAttributeNS
                    (null, SVGSyntax.SVG_SPREAD_METHOD_ATTRIBUTE,
                     SVGSyntax.SVG_REFLECT_VALUE);
                break;
            case MultipleGradientPaint.REPEAT:
                grad.setAttributeNS
                    (null, SVGSyntax.SVG_SPREAD_METHOD_ATTRIBUTE,
                     SVGSyntax.SVG_REPEAT_VALUE);
                break;
            // 'pad' is the default...
            }

            // Here we should write the transform of the gradient
            // in the transform attribute...

            // Here we should write the stops of the gradients as 
            // children elements...

            return new SVGPaintDescriptor
                ("url(#" + ref + ")", SVGSyntax.SVG_OPAQUE_VALUE, grad);
        } else {
            // Let the default mechanism do its job.
            return null;
        }
    }
}
然后你需要在 SVGGeneratorContext上,通过使用setExtensionHandler方法设定它。
 
SVGGeneratorContext ctx = SVGGeneratorContext.createDefault(myFactory);
ctx.setExtensionHandler(new MyExtensionHandler());
SVGGraphics2D g2d = new SVGGraphics2D(ctx, false);
 
怎样查看生成的SVG文档
下面的代码详细描述怎么查看利用SVGGraphics2D对象生成的svg内容
import java.awt.*;
import java.awt.geom.*;

import javax.swing.*;

import org.apache.batik.swing.*;
import org.apache.batik.svggen.*;
import org.apache.batik.dom.svg.SVGDOMImplementation;

import org.w3c.dom.*;
import org.w3c.dom.svg.*;

public class ViewGeneratedSVGDemo {

    public static void main(String[] args) {
        // Create an SVG document.
        DOMImplementation impl = SVGDOMImplementation.getDOMImplementation();
        String svgNS = SVGDOMImplementation.SVG_NAMESPACE_URI;
        SVGDocument doc = (SVGDocument) impl.createDocument(svgNS, "svg", null);

        // Create a converter for this document.
        SVGGraphics2D g = new SVGGraphics2D(doc);

        // Do some drawing.
        Shape circle = new Ellipse2D.Double(0, 0, 50, 50);
        g.setPaint(Color.red);
        g.fill(circle);
        g.translate(60, 0);
        g.setPaint(Color.green);
        g.fill(circle);
        g.translate(60, 0);
        g.setPaint(Color.blue);
        g.fill(circle);
        g.setSVGCanvasSize(new Dimension(180, 50));

        // Populate the document root with the generated SVG content.
        Element root = doc.getDocumentElement();
        g.getRoot(root);

        // Display the document.
        JSVGCanvas canvas = new JSVGCanvas();
        JFrame f = new JFrame();
        f.getContentPane().add(canvas);
        canvas.setSVGDocument(doc);
        f.pack();
        f.setVisible(true);
    }
}

Batik Swing 组件

Batik Swing 组件模块的目标是提供一个可以用来显示SVG documentsSwing组件。使用JSVGCanvas类,你可以非常容易的显示一个SVGdocument(从一个URI或者一个DOM树中)并且允许用户来操作他,比如旋转,缩放,panning,选择文本或者激活链接。首先这个文档将解析如何去创建JSVGCanvas并且将它与一个Swing应用程序整合到一起。然后,描述一些先进的特性,比如用来跟踪所有在显示或者执行一个svg文档时发生的事件。

创建一个JSVGCanvas

下面的实例将解析如何创建一个符合Swing设计规则的Swing组件----JSVGCanvas。这意味着组件不具备线程安全并且在组件上的所有操作或者它显示的所有文档必须像在Swing指南中描述的那样执行。JSVGCanvas是一个javabeans,所以它可以在可视化应用程序构造器中使用。

注意

如果你要尝试这个例子,别忘了设置你的CLASSPATH以便它包含Batik类和资源,比如Xerceslib/xerces_2_5_0.jar)和XML APIs jarslib/xml-apis.jar lib/xml-apis-ext.jar.

import java.awt.*;
import java.awt.event.*;
import java.io.*;

import javax.swing.*;

import org.apache.batik.swing.JSVGCanvas;
import org.apache.batik.swing.gvt.GVTTreeRendererAdapter;
import org.apache.batik.swing.gvt.GVTTreeRendererEvent;
import org.apache.batik.swing.svg.SVGDocumentLoaderAdapter;
import org.apache.batik.swing.svg.SVGDocumentLoaderEvent;
import org.apache.batik.swing.svg.GVTTreeBuilderAdapter;
import org.apache.batik.swing.svg.GVTTreeBuilderEvent;

public class SVGApplication {

    public static void main(String[] args) {
        // Create a new JFrame.
        JFrame f = new JFrame("Batik");
        SVGApplication app = new SVGApplication(f);

        // Add components to the frame.
        f.getContentPane().add(app.createComponents());

        // Display the frame.
        f.addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
        });
        f.setSize(400, 400);
        f.setVisible(true);
    }
    
    // The frame.
    protected JFrame frame;

    // The "Load" button, which displays up a file chooser upon clicking.
    protected JButton button = new JButton("Load...");

    // The status label.
    protected JLabel label = new JLabel();

    // The SVG canvas.
    protected JSVGCanvas svgCanvas = new JSVGCanvas();

    public SVGApplication(JFrame f) {
        frame = f;
    }

    public JComponent createComponents() {
        // Create a panel and add the button, status label and the SVG canvas.
        final JPanel panel = new JPanel(new BorderLayout());

        JPanel p = new JPanel(new FlowLayout(FlowLayout.LEFT));
        p.add(button);
        p.add(label);

        panel.add("North", p);
        panel.add("Center", svgCanvas);

        // Set the button action.
        button.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent ae) {
                JFileChooser fc = new JFileChooser(".");
                int choice = fc.showOpenDialog(panel);
                if (choice == JFileChooser.APPROVE_OPTION) {
                    File f = fc.getSelectedFile();
                    try {
                        svgCanvas.setURI(f.toURL().toString());
                    } catch (IOException ex) {
                        ex.printStackTrace();
                    }
                }
            }
        });

        // Set the JSVGCanvas listeners.
        svgCanvas.addSVGDocumentLoaderListener(new SVGDocumentLoaderAdapter() {
            public void documentLoadingStarted(SVGDocumentLoaderEvent e) {
                label.setText("Document Loading...");
            }
            public void documentLoadingCompleted(SVGDocumentLoaderEvent e) {
                label.setText("Document Loaded.");
            }
        });

        svgCanvas.addGVTTreeBuilderListener(new GVTTreeBuilderAdapter() {
            public void gvtBuildStarted(GVTTreeBuilderEvent e) {
                label.setText("Build Started...");
            }
            public void gvtBuildCompleted(GVTTreeBuilderEvent e) {
                label.setText("Build Done.");
                frame.pack();
            }
        });

        svgCanvas.addGVTTreeRendererListener(new GVTTreeRendererAdapter() {
            public void gvtRenderingPrepare(GVTTreeRendererEvent e) {
                label.setText("Rendering Started...");
            }
            public void gvtRenderingCompleted(GVTTreeRendererEvent e) {
                label.setText("");
            }
        });

        return panel;
    }
}

这些监视器给与了这五个阶段(包括错误状态)的不同步骤的完整描述。 适配器类对于灵活创建新的舰艇器执行----- SVGDocumentLoaderAdapter, GVTTreeBuilderListenerAdapter, SVGLoadEventDispatcherAdapter, GVTTreeRendererAdapter UpdateManagerAdapter是可用的。

对于静态文档, 你可以假定JSVGCanvas gvtRenderingCompleted方法调用被调用时已经完成了它的工作 (解析, 构建和描绘)

在动态文档的情况下, 计算完成(parsing, building, SVGLoad dispatch, initial rendering and updates) 通过调用 updateManagerStopped 方法被标记.

添加交互

JSVGCanvas 提供一系列内部构造交互,这些交互允许用户操作显示文档,包括缩放,平移和旋转. 交互捕捉用户输入到 JSVGCanvas组件中并且 将它们转化为行为. 如果你要添加一个新的行为到JSVGCanvas, 你可以执行 Interactor 接口. 然后你可以通过添加新的元素到通过canvas的个体Interactors()方法返回的list中注册新的交互到组件中。


你可能感兴趣的:(SVG,Batik,batik,SVG)