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のビルトイン拡張メカニズムの概要を示すことにあります。オープンソース プロジェクトとして、当然のように誰でも任意の拡張を自分のしたいように行うことができますが、Batikは一定の方針で、さまざまな拡張の形態とともに設計されてきました。

拡張が期待される主な分野としては:

一般に、拡張は Jar ファイル のドキュメントで説明されているように、サービス プロバイダ インターフェースを通じて行われます。

このことは、Batikの拡張は単純に新しいjarファイルをクラスパスに含めるだけで良く、Batikのソースに手を加えることが必要ではない!ということを意味します

Note もしBatikのチームが拡張の重要なエリアを見落としていると感じられたら、あなたの考えをメーリングリストに伝えてください。


カスタムXMLタグ

まず「カスタムXMLタグをサポートするっていうのはどういう意味?」ということが問われなければならないでしょうね。

Batikが考案している基本的な選択肢が3つあります:

  • DOMツリーの中に出現するタグ -

  • あなたのカスタムタグがウェルフォームドな(そして適格かもしれない)XMLであるかぎり、それらはSVG DOMツリー中に出現しうるものです。レンダリングの際には、Batikはそのツリーの、未知のタグを使用しているブランチはスキップするでしょう(もしそれが標準SVGタグを子ノードに含むものであっても、それらは描画されることがないでしょう)。
    あなたの個人的なタグには、もしそのXMLを検証するつもりがなくても、XMLネームスペースを利用することを強く推奨します。
    これは、もしあなたが特別なデータの一部を標準のSVGドローイングに追加しようと思った時に便利になるでしょう。それは注釈かもしれないし、あるいはアプリケーション固有のデータであるかもしれません。一般にこれはsvgブラウザやラスタライザに固有に便利なのではありませんが、もしあなたがカスタムのブラウザを、ラスタライザを、あるいは前後処理のツールを書いている時には、非常に便利なものになるでしょう。
  • DOMツリー中のカスタム エレメントを使用するタグ -

  • もし(ふるまいやパフォーマンスの理由などから)あなたのタグをDOMツリー中でカスタム エレメントのサブクラスとして使用する必要がある場合は、あなたは Batik DOMへの拡張を提供する必要があります。
    そうすることによって、あなたはDOMエレメントの標準メソッドをオーバーライドしたり、あなたのDOMエレメントに追加メソッドを提供したりする、という機会を得られます。たとえば、Batikの全てのSVG要素はgetAttributeメソッドを実装しており、これでCSSのスタイリング プロパティを参照することができます。また、SVG DOMを実装するための追加メソッドも提供されています。
  • レンダリングされるタグ -

  • おそらく、カスタムタグを開発するもっとも一般的な理由は、SVG言語に新しいレンダリング プリミティヴを追加することでしょう。この場合、あなたはBatikブリッジの拡張を提供しなければなりません。このブリッジ拡張は、Batikの新しいプリミティヴのレンダリングを扱うためのクラスを構築する責務を負っています。
    ほとんどの場合、DOM拡張を書いて、タグが他のSVGタグと同じように振る舞うようにする必要もあるでしょう(特にスタイリングをサポートする場合は)。
    Batik DOM 拡張を書く

    SVG DOMツリーで使用される要素を拡張する機能は、Batikのノードのデフォルト実装の代わりに利用できるノードの実装を、ユーザーに提供することをさせてくれます。これがなされる理由はさまざまですが、もっとも一般的なのは、標準のノードの呼び出し(たとえば属性のルックアップにスタイリングを含めるなど)の振る舞いを拡張したり、そのタグのDOMインターフェースを実装するために行われることです。

    DOMツリーをビルドする、カギとなるクラスはExtensibleSVGDOMImplementation クラスです。このクラスのインスタンスがコンストラクトされると、これはorg.apache.batik.dom.svg.DomExtensionのサービス プロバイダ インターフェースのインスタンスを検索します。その後、そのそれぞれについて、自身の'registerTags' メソッドを呼び出します。このメソッドは通常、操作したいそれぞれのタグについてregisterCustomElementFactory を呼び出します。

    Batikで、ノードを拡張するもっともありがちな理由は、個々のノードの属性にあるCSSスタイリングを提供するというものです。この目的のために、Batikではあなたがextendすることができるクラスを提供しています: org.apache.batik.extension.PrefixableStylableExtensionElement 。 もしこのクラスを派生させた場合、あなたは3つのメソッドを実装する必要があるだけです: getLocalName, getNamespaceURI, newNode (そしてコンストラクタですね)。もしあなたがほしいのが特別なスタイル サポートだけであれば、(多くの場合)あなたはこの段階でもうエレメントの実装を終えています。

    このディストリビューションには多くの例が含まれています

    • org.apache.batik.extension.svg.BatikStarElement
    • org.apache.batik.extension.svg.BatikRegularPolygonElement
    • org.apache.batik.extension.svg.BatikHistogramNormalizationElement
    • org.apache.batik.extension.svg.SolidColorElement
    • org.apache.batik.extension.svg.ColorSwitchElement

    Included with these examples is org.apache.batik.extension.svg.BatikDomExtension which is the required instance of DomExtension used to register the elements with the ExtensibleSVGDOMImplementation.

    When your new element requires new 'presentation attributes' (XML attributes that can be modified through CSS or depending on your view point the other way round, CSS properties that can be specified using XML attributes), you may also need to extend the CSS engine. This can be done by registering a custom CSS value factory. Both of the color examples do this (see BatikDomExtension).


    Writing a Batik Bridge Extension

    Before you write a bridge extension it may be useful to understand what the role the bridge package plays in Batik. The bridge package is responsible for creating and maintaining elements in the Graphics Vector Toolkit (GVT) tree based on the corresponding element in the SVG DOM. This is done because for a variety of reasons the SVG DOM is not well suited for rendering, thus GVT tree is used for all rendering and transcoding operations.

    The key class for managing this link is the BridgeContext. This class maintains an association between a tag name with namespace and a particular bridge instance that will handle it. The work of constructing the proper entity or entities in the GVT tree is then deferred to the Bridge registered for a particular tag. If no bridge is regiestered nothing is done.

    New associations can be added by implementors of the BridgeExtension Service Provider Interface. This interface has a number of methods that provide information about the particular extension being registered (including contact information, and the list of implemented extensions). It also has a 'registerTags' method which is responsible for registering the bridge instances with a BridgeContext. All the built in bridges are bundled with a BridgeExtension (in org.apache.batik.bridge), as are the example extensions (in org.apache.batik.extension.svg), so these are both good places to start.

    The Bridge interface itself is very simple. It only includes methods to get the namespace and local name of the tag the bridge is responsible for. This interface is then extended for each of the major concepts present in SVG:

  • GraphicsNodeBridge -
  • These are probably the most common SVG elements they represent graphic elements in what I'll call the "visible" SVG tree. These are the elements most other bridges modify in some way (by clipping, masking, filtering, etc).
    Example tags: svg, g, path, rect.
    Example Extensions: BatikRegularPolygonElementBridge, BatikStarElementBridge.
  • FilterBridge -
  • Handles the SVG 'filter' element. If you wanted to implement a new tag that could be referenced from the 'filter' attribute on an SVG graphics node then you would need to subclass this bridge. However adding new types of filters to the existing SVG 'filter' element is accomplished via the FilterPrimitiveBridge.
    Example tag: filter
  • FilterPrimitiveBridge -
  • Constructs an element in the filter chain applied to a SVG graphics node.
    Example tags: feBlend, feCompose, ...
    Example Extensions: BatikHistogramNormalizationElementBridge
  • PaintBridge -
  • Constructs a java Paint object to be used in filling or stroking graphic elements.
    Example tags: gradient, pattern.
    Example Extensions: SolidColorBridge, ColorSwitchBridge
  • ClipBridge -
  • Constructs a ClipRable to apply to a Graphics Node. This provides a path that data is clipped to.
    Example tag: clip-path.
  • MarkerBridge -
  • Constructs a Marker for annotating the path of a GraphicsNode.
    Example tag: marker
  • MaskBridge -
  • Constructs a Mask Filter to apply to a Graphics Node. Mask Filters typically modify the alpha channel of the Graphics Node output to make portions fully or partially transparent that wouldn't be otherwise.
    Example tag: mask.

    Extension writers are free to work with any of the above bridges, however the three most common are likely to be the GraphicsNodeBridge, the FilterPrimitiveBridge, and the PaintBridge (each of which have example extensions available for inspection). Each of these interfaces has several extremely useful subclasses that handle much of the common behavior among elements.

    In some simple cases it is possible to only provide an extension to the Bridge and get your desired effect, however in most cases you will find that for your element to behave like a normal SVG element (for example supporting styling) you will need to provide a DOM extension as well.

    GraphicsNodeBridge

    The graphics node bridge is oriented around constructing a new GraphicsNode in the GVT tree. The GraphicsNode is the basic element that makes up the GVT tree. Each GraphicsNode has a paint method that is responsible for painting the object (including considering clipping, masking, filtering, and opacity for the node).

    If you want to you can implement bridge.GraphicsNodeBridge interface directly or subclass bridge.AbstractGraphicsNodeBridge. This gives you the most flexibility since you can construct your new subclass of gvt.GraphicsNode where you can implement the paint method to do essentially anything you want, this is also a lot of work (and I'm not going to try and explain everything needed to pull this off).

    However, if you just want to generate a custom filled or stroked shape the easiest way is to subclass either of the following classes. In this case you are essentially only responsible for constructing a standard java Shape object to describe the desired area to operate on:

  • SVGShapeElementBridge -
  • Subclasses of this class only need to implement buildShape, getNamespaceURI, and getLocalName. buildShape generally constructs a java.awt.Shape object and sets it on the provided shapeNode object, however it may adjust other features of the given shape node.
  • SVGDecoratedShapeElementBridge -
  • This is very similar to SVGShapeElementBridge, except it also handles the standard marker properties. Markers will be place at each the end of each segment of the path.

    If you decide that you need to implement a new subclass of GraphicsNode I strongly suggest that you derive off of AbstractGraphicsNode as this class does much of the work to behave like a drawn element in SVG (like clipping, filtering, masking). In this case you implement the primitivePaint method instead of the paint method.


    FilterPrimitiveBridge

    The Filter primitive bridge is concerned with the construction of individual elements of the filter chain. Unlike graphics nodes which generally just draw new objects on top of the destination, filters take existing image data and modify it to apply effects.

    This part of GVT rendering is based on the Java2D java.awt.image.renderable.RenderableImage and java.awt.image.RenderedImage interfaces. This provides a convenient framework to handle image processing (an inherently resolution dependent operation) in the resolution independent system defined by SVG.

    The majority of classes for part of Batik are present in the batik.ext.awt.image.* package hierarchy which contains a large set of generally useful extensions to the core JDK classes and methods.

    Note that the FilterPrimitiveBridge is invoked once for each reference to the <filter> tag that the filter primitive is part of. So if a filter effect is used a half dozen times the createFilter method will be called a half dozen times, even though the tag may only appear once in the file. This means that it is safe for the Filters returned to be 'fixed' for a particular GraphicsNode being filtered.

    You will notice that Batik uses extended versions of the standard Renderable and Rendered image classes to provide additional information about surround requirements for operations as well as a few convenience methods. These interfaces are called: java.ext.awt.image.renderable.Filter and java.ext.awt.image.rendered.CacheableRed. Batik contains simple wrapper classes that can take the default JDK Renderable and Rendered Image interfaces. Within the code base the convention 'Red' for classes implementing RenderedImage, and 'Rable' for classes implementing RenderableImage is commonly used ('Red' is to be pronounced like the color, and 'Rable' is to be pronounced like 'horrible' with a silent 'h').

    The FilterPrimitiveBridge really has only one method right now: createFilter that must construct an instance of Filter to perform the required operation. This is still a fairly complex task given the general need to support accessing the various standard sources of image data. To this end there is a provided subclass, AbstractSVGFilterPrimitiveElementBridge This provides convenience methods to handle many common tasks.

    Generally the bulk of the work in writing a filter extension is the writing of the Filter instance not tying it into the GVT tree. Batik does contain several base classes that make this processes a bit easier. ext.awt.image.renderable.AbstractRable, ext.awt.image.rendered.AbstractRed, and ext.awt.image.rendered.AbstractTiledRed. TiledRed ties into the Batik tile cache (use this with caution as it is a complex area of the Batik code).

    The ext.awt.image.rendered and renderable packages contain quite a number of fairly general examples covering most common cases, please refer to them for more detail.


    PaintBridge

    The PaintBridge constructs an instance of the java.awt.Paint to be used to fill or stroke shapes/text (part of the paint server architecture of SVG).

    Like the filter primitive bridge the PaintBridge is invoked for each reference to the paint. This makes it possible to customize the Paint returned for the particular element to be painted.

    This is how the gradients and patterns are implemented in Batik, so it is possible to construct rather complex paint effects through this mechanism.

    For paints you are mostly on your own, because unlike the other cases there aren't any really generally useful base classes to derive off, the closest is the AbstractSVGGradientElementBridge which is used to handle most of the radial and linear gradient attributes.

    The existing gradient paint implementations are in ext.awt, the pattern implementation is in gvt since it requires access to gvt internals.




    New File Formats

    When Batik encounters an 'image' element and it determines the element does not reference an SVG file. It defers the loading of the referenced image to org.apache.batik.ext.awt.image.spi.ImageTagRegistry. This class maintains a list of RegistryEntries, generally one for each format.

    Since the formats supported natively by Batik are also implemented through this mechanism. The JPEGRegistryEntry and PNGRegistryEntry should be used as good references for extensions.

    RegistryEntry

    There are currently two flavors of RegistryEntry:

  • URLRegistryEntry -
  • These take a ParsedURL and try to decide if the URL is intended for them. This group of entries is mostly intended to handle alternate network protocols. It can also be useful for interfacing with libraries that want a URL instead of a stream.
  • StreamRegistryEntry -
  • These work with a markable InputStream. This is the preferred form of registry entry as it generally avoids opening a potentially expensive connection multiple times, instead it opens the stream once and relies on mark and reset to allow entries to check the stream.

    Helper classes

    There exists quite a number of classes to assist in implementing a RegistryEntry. It is strongly recommended that you review these classes and make use of them where appropriate. They will likely save you time and improve the integration with Batik.

  • MagicNumberRegistryEntry -
  • An abstract class that can handle the isCompatibleStream method for formats that make use of "magic numbers". Magic numbers are a well known sequence of bytes at a well known offset in the file, that are commonly used to identify image file formats.
  • RedRable -
  • This takes any java.awt.image.RenderedImage and wraps it into a Filter (Batik's subclass of RenderableImage). This is extremely useful for single resolution file formats.
  • DeferRable -
  • This allows one to load the image in a background thread, rather than hold up the construction of the GVT tree while reading the image (useful since reading the image is generally I/O bound, so it makes a good background task). This is used by most of the current Image readers.
  • AbstractRable -
  • An abstract base class that makes it relatively easy to implement the Filter interface.
  • AbstractRed -
  • An abstract base class that makes it relatively easy to implement the CacheableRed interface (Batik's subclass of RenderedImage).


    New URL Protocols

    For a variety of reasons (not the least of which is the heavy use of the 'data:' protocol in SVG). Several parts of Batik use a util.ParsedURL instead of the JDK's java.net.URL class.

    ParsedURL offers a few advantages over the JDK's URL class. First, it is designed to make minimal use of exceptions, so it is possible to use it to parse a malformed URL and get "the good parts". Second, it is extensible, so support for new protocols can be added, even protocols that change the normal parsing rules for URLs (such as our friend the 'data' protocol). Third it can automatically check a stream when opened for common compression types and decode them for you (this behavior can also be bypassed if needed).

    The service class is org.apache.batik.util.ParsedURLProtocolHandler. This interface consists of three methods, one returns the protocol to be handled, one is for parsing an absolute URL string and one is for parsing relative URL strings. Both the parsing methods return an object of type ParsedURLData (the instance may of course be a subclass of ParsedURLData).

    The ParsedURLData class holds all the data and implements the all the stream handling commands for the ParsedURL class. This allows ProtocolHandlers to return custom subclasses for particular protocols.



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