-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Hello Vincent (and others), here is my actual version of my ImageMapTranscoder. It has been separated into serveral classes. It now consists of: - - A patch for the rasterizer to include itself (You can find this in one of my last mails. So I haven't added it to the mail. If you need it, simply ask me for it.) - - A FileXMLSerializerFactory, which creates a ContentHandler which writes to a TranscoderOutput (This one requires to include an implementation for javax.xml.transform) - - A PathGenerator, which generate "path events" to a PathListener - - An AbstractPathListener which is an abstract class hearing to them - - An AbstractFlattenedPathListener which is an abstract class hearing to flattened path events (only lines, no curves) - - An AbstractIntegerPathListener which converts the last to integer's - - An ImageMapTranscoder which uses SVGAbstractTranscoder, passs it's informations to the PathGenerator and writes a HTML ImageMap as SAX events to a ContentHandler provided by the FileXMLSerializerFactory.
First I had the idea to generate common xml code and use a xsl to generate the HTML Image Map. But then, this transcoder would have been a transformer in cocoon, not a serializer and it would be more work for me. Later this can be changed easily. Questions/ Problems: - - Getting descriptions for tags doesn't work. (why?) - - What is the standard way to get the svg title elements? For description I use getDescription(). - - What is missing, until it can go into cvs? With kind regards Torsten Knodt -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.0.7 (GNU/Linux) iD8DBQE9c80zvxZktkzSmiwRAu6+AJ4kqhPTKraMOzW4ZGqsaTpFbJI0CgCfR4oa Htdfrf1hbXWjQoOwoiXpII0= =XGMc -----END PGP SIGNATURE-----
/***************************************************************************** * Copyright (C) The Apache Software Foundation. All rights reserved. * * ------------------------------------------------------------------------- * * This software is published under the terms of the Apache Software License * * version 1.1, a copy of which has been included with this distribution in * * the LICENSE file. * *****************************************************************************/ package org.apache.batik.transcoder.imagemap; import org.apache.batik.transcoder.TranscoderException; /** * This class describes an abstract listener for flattened Path events. * * @author <a href="mailto:[EMAIL PROTECTED]">Torsten Knodt</a> */ public abstract class AbstractFlattenedPathListener implements PathListener { public final void cubicTo(float xa, float ya, float xb, float yb, float xc, float yc) throws TranscoderException { throw new TranscoderException ("A cubicTo shouldn't be called in a flattened PathListener"); } public final void quadTo(float xa, float ya, float xb, float yb) throws TranscoderException { throw new TranscoderException ("A quadTo shouldn't be called in a flattened PathListener"); } }
/***************************************************************************** * Copyright (C) The Apache Software Foundation. All rights reserved. * * ------------------------------------------------------------------------- * * This software is published under the terms of the Apache Software License * * version 1.1, a copy of which has been included with this distribution in * * the LICENSE file. * *****************************************************************************/ package org.apache.batik.transcoder.imagemap; /** * This class describes an abstract listener for Path events. * * @author <a href="mailto:[EMAIL PROTECTED]">Torsten Knodt</a> */ public abstract class AbstractPathListener implements PathListener { public float flattenValue() { return (float) 0.0; } }
/***************************************************************************** * Copyright (C) The Apache Software Foundation. All rights reserved. * * ------------------------------------------------------------------------- * * This software is published under the terms of the Apache Software License * * version 1.1, a copy of which has been included with this distribution in * * the LICENSE file. * *****************************************************************************/ package org.apache.batik.transcoder.imagemap; import org.apache.batik.transcoder.TranscoderException; /** * This interface describes a listener for Path events. * It is based on java.awt.geom.PathIterator, but doesn't require traversing. * Also it has support for link informations to the pathes. * * @author <a href="mailto:[EMAIL PROTECTED]">Torsten Knodt</a> */ interface PathListener { /** * Returns the flattening parameter to use. <tt>0</tt> means no flattening. * * @return flattening value */ public float flattenValue(); /** * This is called, when a new path starts. All parameters can be <tt>null</tt>, if * they are not provided by the source. * * @param href A hyperlink somewhere. * @param description A description for the link * @param title The title for the link. */ public void startPath(String href, String description, String title) throws TranscoderException; /** * This is called, when a path ends. */ public void endPath() throws TranscoderException; /** * This is called, when a new map starts. All parameters can be <tt>null</tt>, if * they are not provided by the source. * * @param description A description for the link * @param title The title for the link. */ public void startMap(String description, String title) throws TranscoderException; /** * This is called, when a map ends. */ public void endMap() throws TranscoderException; /** * This is called, when a path segment starts. * * @param x This is the horizontal position, where the segment starts. * @param y This is the vertical position, where the segment starts. */ public void startSegment(float x, float y) throws TranscoderException; /** * This is called, when a the next segment part is a bezier curve. * It is only called, when the flattening is not <tt>0</tt>. * * @param xa This is the horizontal position of the first control point of the curve. * @param ya This is the vertical position of the first control point of the curve. * @param xb This is the horizontal position of the second control point of the curve. * @param yb This is the vertical position of the second control point of the curve. * @param xc This is the horizontal position of the final control point of the curve. * @param yc This is the vertical position of the final control point of the curve. */ public void cubicTo(float xa, float ya, float xb, float yb, float xc, float yc) throws TranscoderException; /** * This is called, when a the next segment part is a quadratic curve. * It is only called, when the flattening is not <tt>0</tt>. * * @param xa This is the horizontal position of the control point of the curve. * @param ya This is the vertical position of the control point of the curve. * @param xb This is the horizontal position of the final control point of the curve. * @param yb This is the vertical position of the final control point of the curve. */ public void quadTo(float xa, float ya, float xb, float yb) throws TranscoderException; /** * This is called, when a the next segment part is a line. * * @param x This is the horizontal position, where the line ends. * @param y This is the vertical position, where the line ends. */ public void lineTo(float x, float y) throws TranscoderException; /** * This is called, when a path segment ends. */ public void endSegment() throws TranscoderException; }
/***************************************************************************** * Copyright (C) The Apache Software Foundation. All rights reserved. * * ------------------------------------------------------------------------- * * This software is published under the terms of the Apache Software License * * version 1.1, a copy of which has been included with this distribution in * * the LICENSE file. * *****************************************************************************/ package org.apache.batik.transcoder.imagemap; import org.apache.batik.transcoder.TranscoderException; import org.apache.batik.bridge.SVGUtilities; import org.apache.batik.bridge.BridgeContext; import org.apache.batik.bridge.GVTBuilder; import java.awt.geom.PathIterator; import java.awt.geom.AffineTransform; import org.w3c.dom.Document; import org.w3c.dom.Node; import org.w3c.dom.traversal.DocumentTraversal; import org.w3c.dom.traversal.NodeFilter; import org.w3c.dom.traversal.NodeIterator; import org.w3c.dom.svg.SVGAElement; import org.w3c.dom.svg.SVGElement; /** * Class for generating path events for <tt>PathListeners</tt> out of * <tt>Document</tt> objects. * @author <a href="mailto:[EMAIL PROTECTED]">Torsten Knodt</a> * */ public class PathGenerator { /** * Generates path events for <tt>PathListeners</tt> out of <tt>Document</tt> objects. * * @param document the document to transcode * @param builder the builder to use * @param ctx the bridge to use * @param listener the listener which should get the path events * @exception TranscoderException if an error occured while transcoding */ public static void transcode(Document document, GVTBuilder builder, BridgeContext ctx, AffineTransform curTxf, PathListener listener) throws TranscoderException { boolean flattened = listener.flattenValue() != 0; NodeIterator i = ((DocumentTraversal) document).createNodeIterator(document, NodeFilter.SHOW_ELEMENT, null, true); listener.startMap(SVGUtilities.getDescription ((SVGElement) document.getDocumentElement()), null); Node node; while ((node = i.nextNode()) != null) { SVGAElement e; try { e = (SVGAElement) node; } catch (ClassCastException ex) { e = null; } if (e != null) { listener.startPath(e.getHref().getBaseVal(), SVGUtilities.getDescription (e), null); int state = PathIterator.SEG_CLOSE; float[] lastpoints = null; for (PathIterator path = builder.build (ctx,e).getOutline().getPathIterator(curTxf, listener.flattenValue()); ! path.isDone(); path.next()) { float[] points = new float[6]; float[] newpoints; int seg = path.currentSegment (points); if (state == PathIterator.SEG_CLOSE && seg != PathIterator.SEG_MOVETO) throw new TranscoderException ("Only moveto Segments are allowed at begin of a path segment"); switch (seg) { case PathIterator.SEG_CLOSE: listener.endSegment(); newpoints = null; break; case PathIterator.SEG_CUBICTO: if (flattened) throw new TranscoderException ("Cubic segment not allowed in flattened path"); else listener.cubicTo(points[0], points[1], points[2], points[3], points[4], points[5]); newpoints = new float[] { points[4], points[5] }; break; case PathIterator.SEG_QUADTO: if (flattened) throw new TranscoderException ("Quad segment not allowed in flattened path"); else listener.quadTo(points[0], points[1], points[2], points[3]); newpoints = new float[] { points[2], points[3] }; break; case PathIterator.SEG_LINETO: newpoints = new float [] { points[0], points[1] }; if (! lastpoints.equals (newpoints)) listener.lineTo (points[0], points[1]); newpoints = new float[] { points[0], points[1] }; break; case PathIterator.SEG_MOVETO: listener.startSegment (points[0], points[1]); newpoints = new float[] { points[0], points[1] }; break; default: throw new TranscoderException ("Unknown segment with type number " + seg); } state = seg; lastpoints = newpoints; } listener.endPath(); } } listener.endMap(); } }
/***************************************************************************** * Copyright (C) The Apache Software Foundation. All rights reserved. * * ------------------------------------------------------------------------- * * This software is published under the terms of the Apache Software License * * version 1.1, a copy of which has been included with this distribution in * * the LICENSE file. * *****************************************************************************/ package org.apache.batik.transcoder.imagemap; import org.apache.batik.transcoder.TranscoderOutput; import org.apache.batik.transcoder.TranscoderException; import javax.xml.transform.sax.TransformerHandler; import javax.xml.transform.sax.SAXTransformerFactory; import javax.xml.transform.sax.SAXSource; import javax.xml.transform.stream.StreamResult; import javax.xml.transform.OutputKeys; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerConfigurationException; import org.xml.sax.SAXException; import org.xml.sax.ContentHandler; /** * This class is part of the image transcoder. * It creates a ContentHandler which is reponsible for the XML serilalization * * @author <a href="mailto:[EMAIL PROTECTED]">Torsten Knodt</a> */ class FileXMLSerializerFactory { /** * Get a ContentHandler for XML Serialization * * @param publicID Public DTD ID or <tt>null<tt> if not used * @param systemID System DTD ID or <tt>null<tt> if not used * @param MIME MIME TYPE or <tt>null<tt> if not used * @param output TranscoderOutput * @result ContentHandler * @exception TranscoderException if an error occured while transcoding */ protected static ContentHandler getContentHandler(String publicID, String systemID, String MIMEType, TranscoderOutput output) throws TranscoderException { TransformerHandler filter; try { SAXTransformerFactory tfactory = (SAXTransformerFactory) SAXTransformerFactory.newInstance(); if (tfactory.getFeature(SAXSource.FEATURE) && tfactory.getFeature(StreamResult.FEATURE)) { filter = tfactory.newTransformerHandler(); filter.setResult (new StreamResult (output.getOutputStream())); } else throw new TranscoderException ("Transformer doesn't support SAX Source or Stream Result"); } catch (TransformerConfigurationException ex) { throw new TranscoderException (ex); } Transformer trans = filter.getTransformer(); if (systemID != null) { filter.setSystemId (systemID); trans.setOutputProperty (OutputKeys.DOCTYPE_SYSTEM, systemID); } if (publicID != null) trans.setOutputProperty (OutputKeys.DOCTYPE_PUBLIC, publicID); trans.setOutputProperty (OutputKeys.INDENT, "yes"); trans.setOutputProperty (OutputKeys.MEDIA_TYPE, MIMEType); trans.setOutputProperty (OutputKeys.STANDALONE, "no"); trans.setOutputProperty (OutputKeys.OMIT_XML_DECLARATION, "no"); trans.setOutputProperty (OutputKeys.METHOD, "xml"); return filter; } }
/***************************************************************************** * Copyright (C) The Apache Software Foundation. All rights reserved. * * ------------------------------------------------------------------------- * * This software is published under the terms of the Apache Software License * * version 1.1, a copy of which has been included with this distribution in * * the LICENSE file. * *****************************************************************************/ package org.apache.batik.transcoder.imagemap; import org.apache.batik.transcoder.SVGAbstractTranscoder; import org.apache.batik.transcoder.TranscoderOutput; import org.apache.batik.transcoder.TranscoderException; import org.apache.batik.transcoder.TranscodingHints; import org.apache.batik.transcoder.keys.StringKey; import org.w3c.dom.Document; import org.xml.sax.helpers.AttributesImpl; import org.xml.sax.SAXException; import org.xml.sax.ContentHandler; /** * This class transcodes an input to a html imagemap. * <p>Two transcoding hints (<tt>KEY_WIDTH</tt> and * <tt>KEY_HEIGHT</tt>) can be used to respectively specify the image * width and the image height. If only one of these keys is specified, * the transcoder preserves the aspect ratio of the original image. * * <p>The <tt>KEY_MAP_NAME</tt> defines the name of the html map * to write in the <tt>id</tt> and <tt>name</tt> attribute of the * <tt>map</tt> tag. * * <p>Three additional transcoding hints that act on the SVG * processor can be specified: * * <p><tt>KEY_LANGUAGE</tt> to set the default language to use (may be * used by a <switch> SVG element for example), * <tt>KEY_USER_STYLESHEET_URI</tt> to fix the URI of a user * stylesheet, and <tt>KEY_MM_PER_PIXEL</tt> to specify the number of * millimeters in each pixel . * * @author <a href="mailto:[EMAIL PROTECTED]">Torsten Knodt</a> */ public class ImageMapTranscoder extends SVGAbstractTranscoder { private final String XHTML_URI = "http://www.w3.org/1999/xhtml"; private final String CDATA = "CDATA"; private final String AREA_TAG = "area"; private final String MAP_TAG = "map"; private final String MAP_TAG_NAME_ATTR = "name"; private final String MAP_TAG_ID_ATTR = "id"; private final String TITLE_ATTR = "title"; private final String ALT_ATTR = "alt"; private final String AREA_TAG_SHAPE_ATTR = "shape"; private final String AREA_TAG_SHAPE_ATTR_POLY = "poly"; private final String AREA_TAG_COORDS_ATTR = "coords"; private final String AREA_TAG_HREF_ATTR = "href"; private final String XHTML_SYSID = "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"; private final String XHTML_PUBID = "-//W3C//DTD XHTML 1.0 Strict//EN"; /** * Constructs a new <tt>ImageMapTranscoder</tt>. */ public ImageMapTranscoder() { super(); } /** * Transcodes the specified Document as an image in the specified output. * * @param document the document to transcode * @param uri the uri of the document or null if any * @param output the ouput where to transcode * @exception TranscoderException if an error occured while transcoding */ protected void transcode(Document document, String uri, TranscoderOutput output) throws TranscoderException { super.transcode(document, uri, output); final ContentHandler filter = FileXMLSerializerFactory.getContentHandler (XHTML_PUBID, XHTML_SYSID, "text/xml", output); try { filter.startDocument(); } catch (SAXException ex) { throw new TranscoderException (ex); } PathGenerator.transcode (document, builder, ctx, curTxf, new AbstractIntegerPathListener() { private String coords; private AttributesImpl att; public void startPath(String href, String description, String title) throws TranscoderException { att = new AttributesImpl(); if (description != null && ! description.equals("")) att.addAttribute("", TITLE_ATTR, TITLE_ATTR, CDATA, description); att.addAttribute("", ALT_ATTR, ALT_ATTR, CDATA, description == null ? "" : description); att.addAttribute("", AREA_TAG_SHAPE_ATTR, AREA_TAG_SHAPE_ATTR, CDATA, AREA_TAG_SHAPE_ATTR_POLY); att.addAttribute("", AREA_TAG_HREF_ATTR, AREA_TAG_HREF_ATTR, CDATA, href); } public void endPath() { att = null; } public void startMap(String description, String title) throws TranscoderException { att = new AttributesImpl(); if (description != null && ! description.equals("")) att.addAttribute("", TITLE_ATTR, TITLE_ATTR, CDATA, description); if (hints.containsKey (KEY_MAP_NAME)) { String s = (String) hints.get (KEY_MAP_NAME); att.addAttribute ("", MAP_TAG_ID_ATTR, MAP_TAG_ID_ATTR, CDATA, s); att.addAttribute ("", MAP_TAG_NAME_ATTR, MAP_TAG_NAME_ATTR, CDATA, s); } try { filter.startElement (XHTML_URI, MAP_TAG, MAP_TAG, att); } catch (SAXException ex) { throw new TranscoderException (ex); } } public void endMap() throws TranscoderException { try { filter.endElement (XHTML_URI, MAP_TAG, MAP_TAG); } catch (SAXException ex) { throw new TranscoderException (ex); } } public void startSegment(int x, int y) { coords = x + "," + y; } public void lineTo(int x, int y) { coords = coords + "," + x + "," + y; } public void endSegment() throws TranscoderException { AttributesImpl myatt = new AttributesImpl (att); myatt.addAttribute("", AREA_TAG_COORDS_ATTR, AREA_TAG_COORDS_ATTR, CDATA, coords); try { filter.startElement(XHTML_URI, AREA_TAG, AREA_TAG, myatt); filter.endElement(XHTML_URI, AREA_TAG, AREA_TAG); } catch (SAXException ex) { throw new TranscoderException (ex); } coords = null; } } ); try { filter.endDocument(); } catch (SAXException ex) { throw new TranscoderException (ex) ; } } public static final TranscodingHints.Key KEY_MAP_NAME = new StringKey(); }
/***************************************************************************** * Copyright (C) The Apache Software Foundation. All rights reserved. * * ------------------------------------------------------------------------- * * This software is published under the terms of the Apache Software License * * version 1.1, a copy of which has been included with this distribution in * * the LICENSE file. * *****************************************************************************/ package org.apache.batik.transcoder.imagemap; import org.apache.batik.transcoder.TranscoderException; /** * This class describes an abstract listener for path events using integer values. * * @author <a href="mailto:[EMAIL PROTECTED]">Torsten Knodt</a> */ public abstract class AbstractIntegerPathListener extends AbstractFlattenedPathListener { public final float flattenValue() { return (float) 1.0; } abstract public void startSegment (int x, int y) throws TranscoderException; abstract public void lineTo (int x, int y) throws TranscoderException; public final void startSegment(float x, float y) throws TranscoderException { startSegment (Math.round (x), Math.round (y)); } public final void lineTo(float x, float y) throws TranscoderException { lineTo (Math.round (x), Math.round (y)); } }
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]