-----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 &lt;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]

Reply via email to