This page describes the new proposed approach for handling images for the various output formats inside FOP.
Status 2008-08-04
- Most output formats have a longer if..elseif..elseif sections in their drawImage method.
- The PDF renderer has this extracted into various PDFImageHandler implementations (because of the PDF-in-PDF extension). This interface's flaw is that is has a dependency on the Renderer interface. This makes image support for PDF more extensible than those of the other renderers.
- XMLHandler (i.e. a different interface) implementations handle XML. There are renderer-dependent (SVG) and renderer-independent (JEuclid, Barcode4J) implementations.
- The RendererContext class is dependent on Renderer, too.
- Most output format specific helper and state classes are directly attached to the renderer.
The problems:
- With the introduction of the new intermediate format, the Renderer interface is sliding into the background. The existing image handling classes cannot be directly reused.
- XML handling is different from handling of other image types. With the Image Loader Framework this could be unified.
- Extending the RendererContext takes a lot of manually written code, packing and unpacking of values into and from a Map of name/value pairs.
Proposal
A new interface (ImageHandler) is introduced:
public interface ImageHandler { int getPriority(); ImageFlavor[] getSupportedImageFlavors(); boolean isCompatible(RenderingContext targetContext, Image image); Class getSupportedImageClass(); void handleImage(RenderingContext context, Image image, Rectangle pos) throws IOException; } public interface RenderingContext { String getMimeType(); FOUserAgent getUserAgent(); }
The RenderingContext interface is introduced as replacement for the RendererContext. Each output format implementation will provide an implementation of the RenderingContext. The RenderingContext (and therefore the ImageHandler) will remain a FOP-specific thing as decoupling the user agent is quite difficult and would not really help. But at any rate, independence of the Renderer interface is achieved.
The isCompatible()
method is used by the ImageHandlerRegistry to determine the right image handler for a combination of rendering context (representing the output format) and the image (as input data). Some minor extensions to the ImageFlavor class in XML Graphics Commons are necessary to properly support different sorts of XML flavors and make the XMLHandler superfluous. The clue is to provide "refinable" image flavors, i.e. the ability to define an XML DOM flavor and an SVG DOM flavor while the SVG DOM flavor is also an XML DOM flavor. Without this extension an image handler could not properly express that it supports SVG but not any other XML flavor. For external extensions like Barcode4J or JEuclid this means that they can simply provide a number of ImageConverter implementations (from the XML Graphics Commons Image Loader Framework). There wouldn't even be a dependency on any FOP classes except if some renderer-specific functionality is required (like handling BCOCA barcodes in AFP output). This also makes the image loader framework itself more attractive outside FOP.
Of course, this makes a number of classes and methods obsolete (like XMLHandler, RendererContext etc.). They have to be deprecated and removed at a later date. For the time being, this means some code duplication and re-routing of code flow. In the long term, we get a cleaner design and weaker coupling that works for both renderers and painters.