以文本方式查看主题

-  中文XML论坛 - 专业的XML技术讨论区  (http://bbs.xml.org.cn/index.asp)
--  『 SVG/GML/VRML/X3D/XAML 』  (http://bbs.xml.org.cn/list.asp?boardid=21)
----  Batik 入门(四)[转帖]  (http://bbs.xml.org.cn/dispbbs.asp?boardid=21&rootid=&id=44730)


--  作者:supremeweb
--  发布时间:4/2/2007 1:48:00 PM

--  Batik 入门(四)[转帖]
SVG 生成器: SVGGraphics2D

在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);
    }
}


W 3 C h i n a ( since 2003 ) 旗 下 站 点
苏ICP备05006046号《全国人大常委会关于维护互联网安全的决定》《计算机信息网络国际联网安全保护管理办法》
5,609.375ms