http://xml.apache.org/http://www.apache.org/http://www.w3.org/

Home

Overview
FAQ
License
Download
Install
Demo

In the news

Tools and Apps
Browser
Rasterizer
Font Converter
Pretty-printer

Architecture
Generator
DOM API
Scripting
JSVGCanvas
Transcoder API

Extensions

Testing

Contributors
Mail Lists

CVS Repository
Bug Database

Status

Glossary


イントロダクション

Batik SVG ジェネレータ

SVG (Scalable Vector Graphics) は、広範な領域、アプリケーションで約束されたグラフィック フォーマットとして登場しており、これとJavaを結びつけることが重要です。 このページでは、SVGジェネレータとして参照される、BatikのSVGGraphics2Dが、どのようにしてこれを可能にしているかを説明します。これは3部構成に分かれます:


SVGGraphics2Dとは何か

Javaプラットフォームでは、全てのレンダリングはjava.awt.Graphics2D抽象クラスを通じて行われます。これはdrawRect, fillRect, あるいはdrawStringといったメソッドを提供します。モニタやプリンタといった、それぞれの出力のタイプに応じて、この抽象クラスのスペシャライズされた実装があります。 SVGGraphics2D は、このインターフェースで、スクリーンやプリンタに描画するかわりに、SVGコンテンツを生成するための、新しい実装です。

SVGGraphics2D は以下のものを提供しています:

  • アプリケーションがグラフィックをSVGフォーマットで書き出すことが可能になります。
  • グラフィックコードをSVGにエクスポートするために、コードを修正する必要はありません。
  • ユーザーがDOM APIを使って生成されたドキュメントを操作することを可能にします。

高レベル アーキテクチャ

上記の図は、ジェネレータがどのようにDOM APIと連携するかを示しています。W3Cは、XMLコンテンツをJavaプログラミング言語オブジェクトで表現するAPIを定義しています。このAPIはプログラマーがメモリ上のXMLコンテンツを操作し、生成し、また変更することを可能にしています。DOM API には、Document, Element, Attrといった、Javaプログラミング言語でXMLドキュメント、要素、属性をモデル化するインターフェースが含まれています。

このジェネレータは、SVGGraphics2D インスタンスによってなされるレンダリング呼び出しに該当するSVGコンテンツを表す、DOMオブジェクトのツリーを管理します。言い換えれば、プログラムがSVGGraphics2DインスタンスでfillRectのようなレンダリングメソッドを呼び出すたびに、そのSVGに等しいものを表している新しいDOMのオブジェクトが、DOM ツリーに追加されます(たとえば、fillRect メソッドが呼び出されると、<rect> 要素が追加されます)。

このジェネレータを使用するプログラマーは、これでDOMツリーにアクセスして、以降のセクションで見るように、これを操作したり、出力ストリームにコンテンツを直接書き出すことができます。


どうやってSVGGraphics2Dを使うか

先のセクションの図から、SVGGraphics2D のインスタンスからSVGコンテンツ(DOMツリー)をビルドするためには、DOMのDocument クラスのインスタンスが必要であるということが分かりました。このDOMツリーは、SVGドキュメントのメモリ中の表現で、DOM APIを用いて操作したり、任意のjava.io.Writerを用いてストリーム出力したりといったことを可能にします。

以下の抜粋コードの例は、SVGコンテンツがどのようにJavaグラフィックスから生成されるかを示しています。


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
        Document document = domImpl.createDocument(null, "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
        // 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 コンテンツを TestSVGGen のインスタンスから生成するのは、3ステップのプロセスであることが分かります:

1. ジェネレータがXMLコンテンツをビルドするために用いられる org.w3c.dom.Document のインスタンスを生成する; Document のインスタンスを用いて、SVGジェネレータを生成します。


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

// Create an instance of org.w3c.dom.Document
Document document = domImpl.createDocument(null, "svg", null);

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

2. SVG ジェネレータからレンダリング コードを呼び出す. この例では、TestSVGGenpaint メソッドを呼び出しています:


// 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
// 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には、フィル カラーみたいな、プロパティを表現する、2つの方法があります: XMLの属性と、そしてCSSのインラインプロパティです。'useCss' パラメータによって、ユーザーはこのオプションを制御できます。


SVG ジェネレータのカスタマイズ

先のセクションでは、我々はただSVG生成プロセスが、SVG出力スタイルをXML属性にするか、それともCSSインラインプロパティにするかをカスタマイズできる、というのを見ただけでした。このセクションでは、より進んだカスタマイズの例をいくつかお話ししましょう。

SVGGraphics2D を生成する代わりに、単純にDocument を使用してSVG要素の生成を行うことによって、SVGGeneratorContext のインスタンスを使用するコンストラクタを用いることが出来ます。あなた自身のSVGGeneratorContext のインスタンスを用いることによって、あなたはより発展したカスタマイズを行うことができるでしょう。以下では、カスタマイズのできる、さまざまな例を見ることができます。

生成されるSVGファイル中に自分のコメントを作り出す

一番簡単で可能な例から始めます。もしBatik SVGジェネレータをあなたのJavaアプリケーションでインテグレートする場合、あなたはXMLコード中に生成されるコメントを特別化したくなるかもしれません。あなたは次のようにすることができます。


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

埋め込みSVGフォントを生成されるSVGファイル中で使用する

システム フォントを使用しない完全自己記述的なSVGファイルを作るために、あなたはSVGフォントの機能によって、SVGファイル中のドローイング文字列に用いられているフォントを埋め込むことができます。


SVGGeneratorContext ctx = SVGGeneratorContext.createDefault(myFactory);
ctx.setEmbeddedFontsOn(true);
SVGGraphics2D g2d = new SVGGraphics2D(ctx);
  

イメージを格納する方法をカスタマイズする

Graphics2D クラスで提供されているdrawImage メソッドのひとつを呼び出すたびに、あなたのイメージの標準的な表現が、生成されたSVGファイルから届く場所に生成されます。たとえば、base64エンコーディングが、デフォルトでは生成されてそのSVGファイル中に埋め込まれることになります。そうするかわりに、あなたはイメージを既定のディレクトリに、SVG仕様で要求されている2種類のラスタ フォーマットであるJPEGあるいはPNGとして、独立したファイルに書き出すこともできます。

あなたはSVGジェネレータで使用されているイメージハンドラを明示的に提供することで、デフォルトの振る舞いを変えることが出来ます。そうしたら、もう一度SVGGeneratorContext をこれに使ってみてください。以下の例では、全てのイメージがPNGフォーマットにコンバートされて"res/images"ディレクトリに書き出されます。


SVGGeneratorContext ctx = SVGGeneratorContext.createDefault(myFactory);
ImageHandler ihandler = new ImageHandlerPNGEncoder("res/images", null);
ctx.setImageHandler(ihandler);
SVGGraphics2D g2d = new SVGGraphics2D(ctx, false);
  

デフォルトイメージハンドラを使用すると、それぞれの1つ1つのdrawImage の呼び出しについて、イメージデータの新しいコピーとしてSVGファイルあるいは外部ファイルに出力されます。もしあなたが同じイメージを何度も使用していると、これは冗長なデータをたくさん含むSVGファイルになります。初期SVG DOMツリーの生成の間のわずかなパフォーマンスのペナルティを犠牲にすることで、あなたはイメージデータを再利用することもできます。このためには、以下に示すような、特別なイメージハンドラを使用します。


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ツリーを生成するSVGGraphics2D のインスタンスに渡します。以下の簡略化した例では、異なるSVGツリーが別々のSVGジェネレータの間で生成されうる例を示しています。共通のイメージは効率的に1回しか保存されていません。

  
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(null, "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のスタイルをカスタマイズする

あなたは提供されている2種類の選択肢(XML属性あるいはCSSインライン プロパティ)以外の方法によるスタイリングを必要とするかもしれません。たとえば、あなたはCSSプロパティをスタイルシートSVG要素のセクションに配置して、class属性を通じて参照したいかもしれません。この場合、あなたは新しいStyleHandler を、以下のように定義する必要があるでしょう。


public class StyleSheetStyleHandler {
    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 id in the style sheet
        String id = generatorContext.getIDGenerator().generateID("C");
        styleSheet.appendData("."+id+" {");
	// append each key/value pairs
        while (iter.hasNext()) {
            String key = (String)iter.next();
            String value = (String)styleMap.get(key);
            styleSheet.appendData(key+":"+value+";");
        }
        styleSheet.appendData("}\n");
	// reference the class id of the style sheet on the element to 
	// be styled
        element.setAttribute("class", id);
    }
}

こうしたら、あなたはSVGGraphics2D を、正しく設定されたSVGGeneratorContextで生成、利用することができます。


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

// use the g2d to dump drawings (component.paint(g2d))

// add a style sheet to the definition section
Element root = 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);

  

ペイント オブジェクトをSVG要素の変形に拡張する

SVGGraphics2D はSVG要素から一般的なJava 2Dオブジェクトを生成することが出来ます。しかし、あなたは時にはあなた自身のクラス、たとえばJava 2D java.awt.Paint インターフェースの実装などを持っていることがあります。このような場合、あなたはExtensionHandler を書いて、自分のSVGGeneratorContextを使用する必要があるかもしれません。

以下の例では、org.apache.batik.ext.awt.LinearGradientPaintという名前の、Batik のjava.awt.Paint インターフェースの実装を変形できるようなExtensionHandler の最初のドラフトを定義しています。

  class SubExtensionHandler extends DefaultExtensionHandler 
  {
    public SVGPaintDescriptor handlePaint(Paint paint,
                                          SVGGeneratorContext generatorCtx) 
    {
      if (paint instanceof LinearGradientPaint) {
          LinearGradientPaint gradient = (LinearGradientPaint)paint;
	  String id = generatorCtx.getIDGenerator().generateID("gradient");
          Element grad = generatorCtx.getDOMFactory().
               createElementNS(SVGSyntax.SVG_NAMESPACE_URI, 
                               SVGSyntax.SVG_LINEAR_GRADIENT_TAG);
          grad.setAttributeNS(null, SVGSyntax.SVG_ID_ATTRIBUTE, ref);
          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
        return null; // let the default mechanism do its job
    }
  }

  

そうしたら、これをSVGGeneratorContext 上に、 setExtensionHandler メソッドを用いてセットします。


SVGGeneratorContext ctx = SVGGeneratorContext.createDefault(myFactory);
ctx.setExtensionHandler(new SubExtensionHandler());
SVGGraphics2D g2d = new SVGGraphics2D(ctx);



Copyright © 2000-2001 The Apache Software Foundation. All Rights Reserved.