-----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]