vhardy 01/10/31 01:54:26
Modified: sources/org/apache/batik/apps/rasterizer Main.java
SVGConverter.java
sources/org/apache/batik/svggen
AbstractImageHandlerEncoder.java
DefaultImageHandler.java ErrorConstants.java
ImageHandlerBase64Encoder.java
ImageHandlerJPEGEncoder.java
ImageHandlerPNGEncoder.java SVGGraphics2D.java
SVGSyntax.java
resources/org/apache/batik/apps/rasterizer/resources
Messages.properties
test-sources/org/apache/batik/apps/rasterizer MainTest.java
SVGConverterTest.java
test-sources/org/apache/batik/test AbstractTest.java
Added: sources/org/apache/batik/svggen CachedImageHandler.java
CachedImageHandlerBase64Encoder.java
CachedImageHandlerJPEGEncoder.java
CachedImageHandlerPNGEncoder.java
CachedImageSVGGraphics2D.java ImageCacher.java
Log:
Added options to the rasterizer and related tests:
- user language
- user stylesheet
- resolution
- quality
Revision Changes Path
1.15 +96 -3 xml-batik/sources/org/apache/batik/apps/rasterizer/Main.java
Index: Main.java
===================================================================
RCS file: /home/cvs/xml-batik/sources/org/apache/batik/apps/rasterizer/Main.java,v
retrieving revision 1.14
retrieving revision 1.15
diff -u -r1.14 -r1.15
--- Main.java 2001/10/29 19:13:54 1.14
+++ Main.java 2001/10/31 09:54:25 1.15
@@ -46,7 +46,7 @@
* <tt>SVGConverter</tt> which is used to perform the conversion.
*
* @author <a href="mailto:[EMAIL PROTECTED]">Vincent Hardy</a>
- * @version $Id: Main.java,v 1.14 2001/10/29 19:13:54 vhardy Exp $
+ * @version $Id: Main.java,v 1.15 2001/10/31 09:54:25 vhardy Exp $
*/
public class Main implements SVGConverterController {
/**
@@ -363,6 +363,43 @@
= Messages.get("Main.cl.option.validate.description", "No description");
/**
+ * Option to specify the user language with which SVG
+ * documents should be processed
+ */
+ public static String CL_OPTION_LANGUAGE
+ = Messages.get("Main.cl.option.language", "-lang");
+
+ public static String CL_OPTION_LANGUAGE_DESCRIPTION
+ = Messages.get("Main.cl.option.language.description", "No description");
+
+ /**
+ * Option to specify an addition user stylesheet
+ */
+ public static String CL_OPTION_USER_STYLESHEET
+ = Messages.get("Main.cl.option.user.stylesheet", "-cssUser");
+
+ public static String CL_OPTION_USER_STYLESHEET_DESCRIPTION
+ = Messages.get("Main.cl.option.user.stylesheet.description", "No
description");
+
+ /**
+ * Option to specify the resolution for the output image
+ */
+ public static String CL_OPTION_DPI
+ = Messages.get("Main.cl.option.dpi", "-dpi");
+
+ public static String CL_OPTION_DPI_DESCRIPTION
+ = Messages.get("Main.cl.option.dpi.description", "No description");
+
+ /**
+ * Option to specify the output JPEG quality
+ */
+ public static String CL_OPTION_QUALITY
+ = Messages.get("Main.cl.option.quality", "-q");
+
+ public static String CL_OPTION_QUALITY_DESCRIPTION
+ = Messages.get("Main.cl.option.quality.description", "No description");
+
+ /**
* Static map containing all the option handlers able to analyze the
* various options.
*/
@@ -481,7 +518,7 @@
}
public String getOptionDescription(){
- return CL_OPTION_MEDIA_TYPE;
+ return CL_OPTION_MEDIA_TYPE_DESCRIPTION;
}
});
@@ -492,8 +529,64 @@
c.setAlternateStylesheet(optionValue);
}
+ public String getOptionDescription(){
+ return CL_OPTION_ALTERNATE_STYLESHEET_DESCRIPTION;
+ }
+ });
+
+ optionMap.put(CL_OPTION_USER_STYLESHEET,
+ new SingleValueOptionHandler(){
+ public void handleOption(String optionValue,
+ SVGConverter c){
+ c.setUserStylesheet(optionValue);
+ }
+
+ public String getOptionDescription(){
+ return CL_OPTION_USER_STYLESHEET_DESCRIPTION;
+ }
+ });
+
+ optionMap.put(CL_OPTION_LANGUAGE,
+ new SingleValueOptionHandler(){
+ public void handleOption(String optionValue,
+ SVGConverter c){
+ c.setLanguage(optionValue);
+ }
+
+ public String getOptionDescription(){
+ return CL_OPTION_LANGUAGE_DESCRIPTION;
+ }
+ });
+
+ optionMap.put(CL_OPTION_DPI,
+ new FloatOptionHandler(){
+ public void handleOption(float optionValue,
+ SVGConverter c){
+ if (optionValue <= 0){
+ throw new IllegalArgumentException();
+ }
+
+ c.setPixelToMillimeter(2.54f/optionValue);
+ }
+
+ public String getOptionDescription(){
+ return CL_OPTION_DPI_DESCRIPTION;
+ }
+ });
+
+ optionMap.put(CL_OPTION_QUALITY,
+ new FloatOptionHandler(){
+ public void handleOption(float optionValue,
+ SVGConverter c){
+ if (optionValue <= 0 || optionValue >= 1){
+ throw new IllegalArgumentException();
+ }
+
+ c.setQuality(optionValue);
+ }
+
public String getOptionDescription(){
- return CL_OPTION_ALTERNATE_STYLESHEET;
+ return CL_OPTION_QUALITY_DESCRIPTION;
}
});
1.5 +70 -1
xml-batik/sources/org/apache/batik/apps/rasterizer/SVGConverter.java
Index: SVGConverter.java
===================================================================
RCS file:
/home/cvs/xml-batik/sources/org/apache/batik/apps/rasterizer/SVGConverter.java,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -r1.4 -r1.5
--- SVGConverter.java 2001/10/30 13:59:34 1.4
+++ SVGConverter.java 2001/10/31 09:54:25 1.5
@@ -73,9 +73,14 @@
* <li>mediaType: controls the CSS media, or list of media, for which the
* image should be rendered.</li>
* <li>alternate: controls the alternate CSS stylesheet to activate, if any.</li>
+ * <li>language: controls the user language with which the SVG document should
+ * be converted.</li>
+ * <li>userStylesheet: defines the user stylesheet to apply to SVG documents
+ * in addition to other stylesheets referenced by or embedded in the SVG
documents.</li>
+ * <li>pixelToMillimeter: defines the size of a pixel when processing the SVG
documents.</li>
* </ul>
*
- * @version $Id: SVGConverter.java,v 1.4 2001/10/30 13:59:34 tkormann Exp $
+ * @version $Id: SVGConverter.java,v 1.5 2001/10/31 09:54:25 vhardy Exp $
* @author Henri Ruini
* @author <a href="mailto:[EMAIL PROTECTED]">Vincent Hardy</a>
*/
@@ -208,6 +213,15 @@
/** Output AOI area. */
protected Rectangle2D area = null;
+ /** Language */
+ protected String language = null;
+
+ /** User stylesheet */
+ protected String userStylesheet = null;
+
+ /** Pixel to Millimeter */
+ protected float pixelToMillimeter = -1f;
+
/** Validation flag */
protected boolean validate = false;
@@ -320,6 +334,44 @@
}
/**
+ * Sets the user language. If the value is null, then the default
+ * (see {@link org.apache.batik.transcoder.image.ImageTranscoder#getLanguage})
+ * is used.
+ */
+ public void setLanguage(String language){
+ this.language = language;
+ }
+
+ public String getLanguage(){
+ return language;
+ }
+
+ /**
+ * Sets the user stylesheet. May be null.
+ */
+ public void setUserStylesheet(String userStylesheet){
+ this.userStylesheet = userStylesheet;
+ }
+
+ public String getUserStylesheet(){
+ return userStylesheet;
+ }
+
+ /**
+ * Sets the pixel to millimeter conversion constant. A negative
+ * value will cause the default value
+ * (see {@link org.apache.batik.transcoder.image.ImageTranscoder#getPixelToMM})
+ * to be used.
+ */
+ public void setPixelToMillimeter(float pixelToMillimeter){
+ this.pixelToMillimeter = pixelToMillimeter;
+ }
+
+ public float getPixelToMillimeter(){
+ return pixelToMillimeter;
+ }
+
+ /**
* Sets the <tt>area</tt> as a Rectangle. This value can
* be null in which case the whole image will be rendered. If the
* area is not null, then only the portion of the image it
@@ -643,11 +695,28 @@
map.put(ImageTranscoder.KEY_ALTERNATE_STYLESHEET, alternateStylesheet);
}
+ // Set user stylesheet
+ if (userStylesheet != null){
+ map.put(ImageTranscoder.KEY_USER_STYLESHEET_URI, userStylesheet);
+ }
+
+ // Set the user language
+ if (language != null){
+ map.put(ImageTranscoder.KEY_LANGUAGE, language);
+ }
+
+ // Sets the pixel to millimeter ratio
+ if (pixelToMillimeter > 0){
+ map.put(ImageTranscoder.KEY_PIXEL_TO_MM, new Float(pixelToMillimeter));
+ }
+
// Set validation
if (validate){
map.put(ImageTranscoder.KEY_XML_PARSER_VALIDATING,
new Boolean(validate));
}
+
+
return map;
}
1.11 +64 -8
xml-batik/sources/org/apache/batik/svggen/AbstractImageHandlerEncoder.java
Index: AbstractImageHandlerEncoder.java
===================================================================
RCS file:
/home/cvs/xml-batik/sources/org/apache/batik/svggen/AbstractImageHandlerEncoder.java,v
retrieving revision 1.10
retrieving revision 1.11
diff -u -r1.10 -r1.11
--- AbstractImageHandlerEncoder.java 2001/09/19 12:52:32 1.10
+++ AbstractImageHandlerEncoder.java 2001/10/31 09:54:25 1.11
@@ -17,6 +17,10 @@
import java.awt.geom.AffineTransform;
import java.lang.reflect.Method;
import java.io.File;
+import java.io.OutputStream;
+import java.io.FileOutputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
import java.net.MalformedURLException;
import org.w3c.dom.Element;
@@ -29,7 +33,7 @@
* of the file created by this handler.
*
* @author <a href="mailto:[EMAIL PROTECTED]">Vincent Hardy</a>
- * @version $Id: AbstractImageHandlerEncoder.java,v 1.10 2001/09/19 12:52:32 cjolif
Exp $
+ * @version $Id: AbstractImageHandlerEncoder.java,v 1.11 2001/10/31 09:54:25 vhardy
Exp $
* @see org.apache.batik.svggen.SVGGraphics2D
* @see org.apache.batik.svggen.ImageHandlerJPEGEncoder
* @see org.apache.batik.svggen.ImageHandlerPNGEncoder
@@ -66,7 +70,7 @@
createGraphics = clazz.getMethod("createGraphics", paramc);
paramo = new Object[1];
} catch (Throwable t) {
- // happen only if Batik extensions are not their
+ // happen only if Batik extensions are not there
} finally {
initDone = true;
}
@@ -79,7 +83,7 @@
try {
g2d = (Graphics2D)createGraphics.invoke(null, paramo);
} catch (Exception e) {
- // should not happened
+ // should not happen
}
return g2d;
}
@@ -178,10 +182,43 @@
saveBufferedImageToFile(imageElement, buf, generatorContext);
}
- private void saveBufferedImageToFile(Element imageElement,
- BufferedImage buf,
- SVGGeneratorContext generatorContext)
+ void cacheBufferedImage(Element imageElement,
+ BufferedImage buf,
+ SVGGeneratorContext generatorContext)
throws SVGGraphics2DIOException {
+
+ ByteArrayOutputStream os;
+
+ if (generatorContext == null)
+ throw new SVGGraphics2DRuntimeException(ERR_CONTEXT_NULL);
+
+ try {
+ os = new ByteArrayOutputStream();
+ // encode the image in memory
+ encodeImage(buf, os);
+ os.close();
+ } catch (IOException e) {
+ // should not happen since we do in-memory processing
+ throw new SVGGraphics2DIOException(ERR_UNEXPECTED, e);
+ }
+
+ // ask the cacher for a reference
+ String imageFileName = imageCacher.lookup(os,
+ buf.getWidth(),
+ buf.getHeight(),
+ generatorContext);
+
+ // set the URL
+ imageElement.setAttributeNS(XLINK_NAMESPACE_URI,
+ ATTR_XLINK_HREF,
+ urlRoot + "/" + imageFileName);
+ }
+
+
+ protected void saveBufferedImageToFile(Element imageElement,
+ BufferedImage buf,
+ SVGGeneratorContext generatorContext)
+ throws SVGGraphics2DIOException {
if (generatorContext == null)
throw new SVGGraphics2DRuntimeException(ERR_CONTEXT_NULL);
@@ -221,9 +258,28 @@
/**
* Derived classes should implement this method and encode the input
* BufferedImage as needed
+ */
+ public abstract void encodeImage(BufferedImage buf, OutputStream os)
+ throws IOException;
+ // NOTE: This breaks super <- sub interface!
+ // The (BufferedImage, File) signature used to be abstract.
+ // Instead, it is now the (BufferedImage, OutputStream) signature.
+ // How serious is this?
+
+ /**
+ * This method encodes the BufferedImage to a file
*/
- public abstract void encodeImage(BufferedImage buf, File imageFile)
- throws SVGGraphics2DIOException;
+ public void encodeImage(BufferedImage buf, File imageFile)
+ throws SVGGraphics2DIOException {
+ try {
+ OutputStream os = new FileOutputStream(imageFile);
+ encodeImage(buf, os);
+ os.flush();
+ os.close();
+ } catch (IOException e) {
+ throw new SVGGraphics2DIOException(ERR_WRITE+imageFile.getName());
+ }
+ }
/**
* This method creates a BufferedImage of the right size and type
1.9 +209 -2
xml-batik/sources/org/apache/batik/svggen/DefaultImageHandler.java
Index: DefaultImageHandler.java
===================================================================
RCS file:
/home/cvs/xml-batik/sources/org/apache/batik/svggen/DefaultImageHandler.java,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -r1.8 -r1.9
--- DefaultImageHandler.java 2001/09/19 12:52:32 1.8
+++ DefaultImageHandler.java 2001/10/31 09:54:25 1.9
@@ -11,6 +11,7 @@
import java.awt.Image;
import java.awt.image.RenderedImage;
import java.awt.image.renderable.RenderableImage;
+import java.awt.geom.AffineTransform;
import org.w3c.dom.Element;
@@ -20,10 +21,13 @@
* attribute and sets the width and height of the element.
*
* @author <a href="mailto:[EMAIL PROTECTED]">Vincent Hardy</a>
- * @version $Id: DefaultImageHandler.java,v 1.8 2001/09/19 12:52:32 cjolif Exp $
+ * @author <a href="mailto:[EMAIL PROTECTED]">Paul Evenblij</a>
+ * @version $Id: DefaultImageHandler.java,v 1.9 2001/10/31 09:54:25 vhardy Exp $
* @see org.apache.batik.svggen.SVGGraphics2D
*/
-public class DefaultImageHandler implements ImageHandler, ErrorConstants {
+public class DefaultImageHandler implements ImageHandler,
+ CachedImageHandler,
+ ErrorConstants {
// duplicate the string here to remove dependencies on
// org.apache.batik.dom.util.XLinkSupport
static final String XLINK_NAMESPACE_URI =
@@ -34,6 +38,10 @@
*/
public DefaultImageHandler() {}
+ /*=================================================================*
+ * ImageHandler implementations
+ *=================================================================*/
+
/**
* The handler should set the xlink:href tag and the width and
* height attributes.
@@ -159,4 +167,203 @@
imageElement.setAttributeNS(XLINK_NAMESPACE_URI,
ATTR_XLINK_HREF, image.toString());
}
+
+
+ /*=================================================================*
+ * CachedImageHandler implementations
+ *=================================================================*/
+
+ protected ImageCacher imageCacher;
+
+ /**
+ * The image cache can be used by subclasses for efficient image storage
+ */
+ public ImageCacher getImageCacher() {
+ return imageCacher;
+ }
+
+ void setImageCacher(ImageCacher imageCacher) {
+ this.imageCacher = imageCacher;
+ }
+
+ /**
+ * Creates an Element which can refer to an image.
+ * Note that no assumptions should be made by the caller about the
+ * corresponding SVG tag.
+ */
+ public Element createElement(SVGGeneratorContext generatorContext) {
+ // Create a DOM Element in SVG namespace to refer to an image
+ Element imageElement =
+ generatorContext.getDOMFactory().createElementNS(
+ SVG_NAMESPACE_URI,
SVG_IMAGE_TAG);
+
+ return imageElement;
+ }
+
+ /**
+ * The handler sets the xlink:href tag and returns a transform
+ */
+ public AffineTransform handleImage(Image image,
+ Element imageElement,
+ int x, int y,
+ int width, int height,
+ SVGGeneratorContext generatorContext) {
+
+ int imageWidth = image.getWidth(null);
+ int imageHeight = image.getHeight(null);
+ AffineTransform af = null;
+
+ if(imageWidth == 0 || imageHeight == 0 ||
+ width == 0 || height == 0) {
+
+ // Forget about it
+ handleEmptyImage(imageElement);
+
+ } else {
+ // First set the href
+ try {
+ handleHREF(image, imageElement, generatorContext);
+ } catch (SVGGraphics2DIOException e) {
+ try {
+ generatorContext.errorHandler.handleError(e);
+ } catch (SVGGraphics2DIOException io) {
+ // we need a runtime exception because
+ // java.awt.Graphics2D method doesn't throw exceptions..
+ throw new SVGGraphics2DRuntimeException(io);
+ }
+ }
+
+ // Then create the transformation:
+ // Because we cache image data, the stored image may
+ // need to be scaled.
+ af = handleTransform(imageElement, (double) x, (double) y,
+ (double) imageWidth, (double) imageHeight,
+ (double) width, (double) height);
+ }
+ return af;
+ }
+
+ /**
+ * The handler sets the xlink:href tag and returns a transform
+ */
+ public AffineTransform handleImage(RenderedImage image,
+ Element imageElement,
+ int x, int y,
+ int width, int height,
+ SVGGeneratorContext generatorContext) {
+
+ int imageWidth = image.getWidth();
+ int imageHeight = image.getHeight();
+ AffineTransform af = null;
+
+ if(imageWidth == 0 || imageHeight == 0 ||
+ width == 0 || height == 0) {
+
+ // Forget about it
+ handleEmptyImage(imageElement);
+
+ } else {
+ // First set the href
+ try {
+ handleHREF(image, imageElement, generatorContext);
+ } catch (SVGGraphics2DIOException e) {
+ try {
+ generatorContext.errorHandler.handleError(e);
+ } catch (SVGGraphics2DIOException io) {
+ // we need a runtime exception because
+ // java.awt.Graphics2D method doesn't throw exceptions..
+ throw new SVGGraphics2DRuntimeException(io);
+ }
+ }
+
+ // Then create the transformation:
+ // Because we cache image data, the stored image may
+ // need to be scaled.
+ af = handleTransform(imageElement, (double) x, (double) y,
+ (double) imageWidth, (double) imageHeight,
+ (double) width, (double) height);
+ }
+ return af;
+ }
+
+ /**
+ * The handler sets the xlink:href tag and returns a transform
+ */
+ public AffineTransform handleImage(RenderableImage image,
+ Element imageElement,
+ double x, double y,
+ double width, double height,
+ SVGGeneratorContext generatorContext) {
+
+ double imageWidth = image.getWidth();
+ double imageHeight = image.getHeight();
+ AffineTransform af = null;
+
+ if(imageWidth == 0 || imageHeight == 0 ||
+ width == 0 || height == 0) {
+
+ // Forget about it
+ handleEmptyImage(imageElement);
+
+ } else {
+ // First set the href
+ try {
+ handleHREF(image, imageElement, generatorContext);
+ } catch (SVGGraphics2DIOException e) {
+ try {
+ generatorContext.errorHandler.handleError(e);
+ } catch (SVGGraphics2DIOException io) {
+ // we need a runtime exception because
+ // java.awt.Graphics2D method doesn't throw exceptions..
+ throw new SVGGraphics2DRuntimeException(io);
+ }
+ }
+
+ // Then create the transformation:
+ // Because we cache image data, the stored image may
+ // need to be scaled.
+ af = handleTransform(imageElement, x,y,
+ imageWidth, imageHeight,
+ width, height);
+ }
+ return af;
+ }
+
+ /**
+ * Determines the transformation needed to get the cached image to
+ * scale & position properly. Sets x and y attributes on the element
+ * accordingly.
+ */
+ protected AffineTransform handleTransform(Element imageElement,
+ double x, double y,
+ double srcWidth,
+ double srcHeight,
+ double dstWidth,
+ double dstHeight) {
+ // In this the default case, <image> element, we just
+ // set x, y, width and height attributes.
+ // No additional transform is necessary.
+
+ imageElement.setAttributeNS(null,
+ SVG_X_ATTRIBUTE,
+ AbstractSVGConverter.doubleString(x));
+ imageElement.setAttributeNS(null,
+ SVG_Y_ATTRIBUTE,
+ AbstractSVGConverter.doubleString(y));
+ imageElement.setAttributeNS(null,
+ SVG_WIDTH_ATTRIBUTE,
+ AbstractSVGConverter.doubleString(dstWidth));
+ imageElement.setAttributeNS(null,
+ SVG_HEIGHT_ATTRIBUTE,
+ AbstractSVGConverter.doubleString(dstHeight));
+ return null;
+ }
+
+ protected void handleEmptyImage(Element imageElement) {
+ imageElement.setAttributeNS(XLINK_NAMESPACE_URI,
+ ATTR_XLINK_HREF, "");
+ imageElement.setAttributeNS(null, SVG_WIDTH_ATTRIBUTE, "0");
+ imageElement.setAttributeNS(null, SVG_HEIGHT_ATTRIBUTE, "0");
+ }
+
}
1.3 +4 -0 xml-batik/sources/org/apache/batik/svggen/ErrorConstants.java
Index: ErrorConstants.java
===================================================================
RCS file: /home/cvs/xml-batik/sources/org/apache/batik/svggen/ErrorConstants.java,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- ErrorConstants.java 2001/04/26 14:17:03 1.2
+++ ErrorConstants.java 2001/10/31 09:54:25 1.3
@@ -28,6 +28,10 @@
"image should not be null";
public static final String ERR_WRITE =
"could not write image File ";
+ public static final String ERR_READ =
+ "could not read image File ";
+ public static final String ERR_IMAGE_HANDLER_NOT_SUPPORTED =
+ "imageHandler does not implement CachedImageHandler: ";
// SVGGraphics2D errors
1.14 +1 -4
xml-batik/sources/org/apache/batik/svggen/ImageHandlerBase64Encoder.java
Index: ImageHandlerBase64Encoder.java
===================================================================
RCS file:
/home/cvs/xml-batik/sources/org/apache/batik/svggen/ImageHandlerBase64Encoder.java,v
retrieving revision 1.13
retrieving revision 1.14
diff -u -r1.13 -r1.14
--- ImageHandlerBase64Encoder.java 2001/07/05 16:54:44 1.13
+++ ImageHandlerBase64Encoder.java 2001/10/31 09:54:25 1.14
@@ -28,14 +28,11 @@
* the data protocol.
*
* @author <a href="mailto:[EMAIL PROTECTED]">Vincent Hardy</a>
- * @version $Id: ImageHandlerBase64Encoder.java,v 1.13 2001/07/05 16:54:44 deweese
Exp $
+ * @version $Id: ImageHandlerBase64Encoder.java,v 1.14 2001/10/31 09:54:25 vhardy
Exp $
* @see org.apache.batik.svggen.SVGGraphics2D
* @see org.apache.batik.svggen.ImageHandler
*/
public class ImageHandlerBase64Encoder extends DefaultImageHandler {
- private static final String DATA_PROTOCOL_PNG_PREFIX =
- "data:image/png;base64,";
-
/**
* Build an <code>ImageHandlerBase64Encoder</code> instance.
*/
1.8 +8 -15
xml-batik/sources/org/apache/batik/svggen/ImageHandlerJPEGEncoder.java
Index: ImageHandlerJPEGEncoder.java
===================================================================
RCS file:
/home/cvs/xml-batik/sources/org/apache/batik/svggen/ImageHandlerJPEGEncoder.java,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -r1.7 -r1.8
--- ImageHandlerJPEGEncoder.java 2001/04/02 13:36:05 1.7
+++ ImageHandlerJPEGEncoder.java 2001/10/31 09:54:25 1.8
@@ -26,7 +26,7 @@
* image elements it handles.
*
* @author <a href="mailto:[EMAIL PROTECTED]">Vincent Hardy</a>
- * @version $Id: ImageHandlerJPEGEncoder.java,v 1.7 2001/04/02 13:36:05 cjolif Exp $
+ * @version $Id: ImageHandlerJPEGEncoder.java,v 1.8 2001/10/31 09:54:25 vhardy Exp $
* @see org.apache.batik.svggen.SVGGraphics2D
* @see org.apache.batik.svggen.ImageHandlerJPEGEncoder
* @see org.apache.batik.svggen.ImageHandlerPNGEncoder
@@ -64,20 +64,13 @@
* Derived classes should implement this method and encode the input
* BufferedImage as needed
*/
- public void encodeImage(BufferedImage buf, File imageFile)
- throws SVGGraphics2DIOException {
- try{
- OutputStream os = new FileOutputStream(imageFile);
- JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(os);
- JPEGEncodeParam param = encoder.getDefaultJPEGEncodeParam(buf);
- param.setQuality(1, false);
- encoder.encode(buf, param);
- os.flush();
- os.close();
- } catch(IOException e) {
- throw new SVGGraphics2DIOException(ERR_WRITE+imageFile.getName());
- }
- }
+ public void encodeImage(BufferedImage buf, OutputStream os)
+ throws IOException {
+ JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(os);
+ JPEGEncodeParam param = encoder.getDefaultJPEGEncodeParam(buf);
+ param.setQuality(1, false);
+ encoder.encode(buf, param);
+ }
/**
* This method creates a BufferedImage of the right size and type
1.9 +5 -11
xml-batik/sources/org/apache/batik/svggen/ImageHandlerPNGEncoder.java
Index: ImageHandlerPNGEncoder.java
===================================================================
RCS file:
/home/cvs/xml-batik/sources/org/apache/batik/svggen/ImageHandlerPNGEncoder.java,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -r1.8 -r1.9
--- ImageHandlerPNGEncoder.java 2001/07/04 16:50:02 1.8
+++ ImageHandlerPNGEncoder.java 2001/10/31 09:54:25 1.9
@@ -27,7 +27,7 @@
* image elements it handles.
*
* @author <a href="mailto:[EMAIL PROTECTED]">Vincent Hardy</a>
- * @version $Id: ImageHandlerPNGEncoder.java,v 1.8 2001/07/04 16:50:02 cjolif Exp $
+ * @version $Id: ImageHandlerPNGEncoder.java,v 1.9 2001/10/31 09:54:25 vhardy Exp $
* @see org.apache.batik.svggen.SVGGraphics2D
* @see org.apache.batik.svggen.ImageHandlerJPEGEncoder
* @see org.apache.batik.svggen.ImageHandlerPNGEncoder
@@ -65,16 +65,10 @@
* Derived classes should implement this method and encode the input
* BufferedImage as needed
*/
- public void encodeImage(BufferedImage buf, File imageFile)
- throws SVGGraphics2DIOException {
- try {
- OutputStream os = new FileOutputStream(imageFile);
- ImageEncoder encoder = new PNGImageEncoder(os, null);
- encoder.encode(buf);
- os.close();
- } catch (IOException e) {
- throw new SVGGraphics2DIOException(ERR_WRITE+imageFile.getName());
- }
+ public void encodeImage(BufferedImage buf, OutputStream os)
+ throws IOException {
+ ImageEncoder encoder = new PNGImageEncoder(os, null);
+ encoder.encode(buf);
}
/**
1.27 +8 -1 xml-batik/sources/org/apache/batik/svggen/SVGGraphics2D.java
Index: SVGGraphics2D.java
===================================================================
RCS file: /home/cvs/xml-batik/sources/org/apache/batik/svggen/SVGGraphics2D.java,v
retrieving revision 1.26
retrieving revision 1.27
diff -u -r1.26 -r1.27
--- SVGGraphics2D.java 2001/10/23 07:37:05 1.26
+++ SVGGraphics2D.java 2001/10/31 09:54:25 1.27
@@ -45,7 +45,7 @@
*
*
* @author <a href="mailto:[EMAIL PROTECTED]">Vincent Hardy</a>
- * @version $Id: SVGGraphics2D.java,v 1.26 2001/10/23 07:37:05 vhardy Exp $
+ * @version $Id: SVGGraphics2D.java,v 1.27 2001/10/31 09:54:25 vhardy Exp $
* @see org.apache.batik.ext.awt.g2d.GraphicContext
* @see org.apache.batik.svggen.DOMTreeManager
* @see org.apache.batik.svggen.DOMGroupManager
@@ -144,6 +144,13 @@
*/
public final DOMTreeManager getDOMTreeManager(){
return domTreeManager;
+ }
+
+ /**
+ * @return the DOMGroupManager used by this SVGGraphics2D instance
+ */
+ final DOMGroupManager getDOMGroupManager(){
+ return domGroupManager;
}
/**
1.6 +6 -1 xml-batik/sources/org/apache/batik/svggen/SVGSyntax.java
Index: SVGSyntax.java
===================================================================
RCS file: /home/cvs/xml-batik/sources/org/apache/batik/svggen/SVGSyntax.java,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -r1.5 -r1.6
--- SVGSyntax.java 2001/08/03 04:21:53 1.5
+++ SVGSyntax.java 2001/10/31 09:54:25 1.6
@@ -14,7 +14,7 @@
* Contains the definition of the SVG tags and attribute names.
*
* @author <a href="mailto:[EMAIL PROTECTED]">Vincent Hardy</a>
- * @version $Id: SVGSyntax.java,v 1.5 2001/08/03 04:21:53 bella Exp $
+ * @version $Id: SVGSyntax.java,v 1.6 2001/10/31 09:54:25 vhardy Exp $
*/
public interface SVGSyntax extends SVGConstants{
/**
@@ -49,6 +49,8 @@
public static final String ID_PREFIX_FE_SPECULAR_LIGHTING =
"feSpecularLighting";
public static final String ID_PREFIX_FONT = "font";
public static final String ID_PREFIX_GENERIC_DEFS = "genericDefs";
+ public static final String ID_PREFIX_IMAGE = "image";
+ public static final String ID_PREFIX_IMAGE_DEFS = "imageDefs";
public static final String ID_PREFIX_LINEAR_GRADIENT = "linearGradient";
public static final String ID_PREFIX_MASK = "mask";
public static final String ID_PREFIX_PATTERN = "pattern";
@@ -69,5 +71,8 @@
public static final String SPACE = " ";
public static final String URL_PREFIX = "url(";
public static final String URL_SUFFIX = ")";
+
+ public static final String DATA_PROTOCOL_PNG_PREFIX = "data:image/png;base64,";
+
}
1.1
xml-batik/sources/org/apache/batik/svggen/CachedImageHandler.java
Index: CachedImageHandler.java
===================================================================
/*****************************************************************************
* 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.svggen;
import java.awt.Image;
import java.awt.image.RenderedImage;
import java.awt.image.renderable.RenderableImage;
import java.awt.geom.AffineTransform;
import org.w3c.dom.Element;
/**
* Extends the default ImageHandler interface with calls to
* allow caching of raster images in generated SVG content.
*
* @author <a href="mailto:[EMAIL PROTECTED]">Paul Evenblij</a>
* @version $Id: CachedImageHandler.java,v 1.1 2001/10/31 09:54:25 vhardy Exp $
*/
public interface CachedImageHandler extends ImageHandler {
/**
* Creates an Element suitable for referring to images.
* Note that no assumptions can be made about the name of this Element.
*/
public Element createElement(SVGGeneratorContext generatorContext);
/**
* The handler should set the xlink:href tag and return a transform
*
* @param image the image under consideration
* @param imageElement the DOM Element for this image
* @param x x coordinate
* @param y y coordinate
* @param width width for rendering
* @param height height for rendering
* @param generatorContext the SVGGeneratorContext
*
* @return transform converting the image dimension to rendered dimension
*/
public AffineTransform handleImage(Image image, Element imageElement,
int x, int y,
int width, int height,
SVGGeneratorContext generatorContext);
/**
* The handler should set the xlink:href tag and return a transform
*
* @param image the image under consideration
* @param imageElement the DOM Element for this image
* @param x x coordinate
* @param y y coordinate
* @param width width for rendering
* @param height height for rendering
* @param generatorContext the SVGGeneratorContext
*
* @return transform converting the image dimension to rendered dimension
*/
public AffineTransform handleImage(RenderedImage image, Element imageElement,
int x, int y,
int width, int height,
SVGGeneratorContext generatorContext);
/**
* The handler should set the xlink:href tag and return a transform
*
* @param image the image under consideration
* @param imageElement the DOM Element for this image
* @param x x coordinate
* @param y y coordinate
* @param width width for rendering
* @param height height for rendering
* @param generatorContext the SVGGeneratorContext
*
* @return transform converting the image dimension to rendered dimension
*/
public AffineTransform handleImage(RenderableImage image, Element imageElement,
double x, double y,
double width, double height,
SVGGeneratorContext generatorContext);
/**
* Returns the image cache instance in use by this handler
*
* @return the image cache
*/
public ImageCacher getImageCacher();
}
1.1
xml-batik/sources/org/apache/batik/svggen/CachedImageHandlerBase64Encoder.java
Index: CachedImageHandlerBase64Encoder.java
===================================================================
/*****************************************************************************
* 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.svggen;
import java.awt.image.RenderedImage;
import java.awt.geom.AffineTransform;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import org.w3c.dom.*;
import org.apache.batik.util.Base64EncoderStream;
/**
* This subclass of {@link ImageHandlerBase64Encoder} implements
* functionality specific to the cached version of the image
* encoder.
*
* @author <a href="mailto:[EMAIL PROTECTED]">Paul Evenblij</a>
* @version $Id: CachedImageHandlerBase64Encoder.java,v 1.1 2001/10/31 09:54:25
vhardy Exp $
*/
public class CachedImageHandlerBase64Encoder extends ImageHandlerBase64Encoder {
/**
* Build a <code>CachedImageHandlerBase64Encoder</code> instance.
*/
public CachedImageHandlerBase64Encoder() {
super();
setImageCacher(new ImageCacher.Embedded());
}
/**
* Creates an Element which can refer to an image.
* Note that no assumptions should be made by the caller about the
* corresponding SVG tag.
*/
public Element createElement(SVGGeneratorContext generatorContext) {
// Create a DOM Element in SVG namespace to refer to an image
// For this cached version we return <use>
Element imageElement =
generatorContext.getDOMFactory().createElementNS(
SVG_NAMESPACE_URI, SVG_USE_TAG);
return imageElement;
}
/**
* This version of handleHREF encodes the input image into a
* PNG image whose bytes are then encoded with Base64. The
* resulting encoded data is used to set the url on the
* input imageElement.
*/
protected void handleHREF(RenderedImage image, Element imageElement,
SVGGeneratorContext generatorContext)
throws SVGGraphics2DIOException {
//
// Setup Base64Encoder stream to byte array.
//
ByteArrayOutputStream os = new ByteArrayOutputStream();
Base64EncoderStream b64Encoder = new Base64EncoderStream(os);
try {
//
// Now, encode the input image to the base 64 stream.
//
encodeImage(image, b64Encoder);
// Close the b64 encoder stream (terminates the b64 streams).
b64Encoder.close();
} catch (IOException e) {
// Should not happen because we are doing in-memory processing
throw new SVGGraphics2DIOException(ERR_UNEXPECTED, e);
}
//
// Ask for a href from the image cacher
//
String href = imageCacher.lookup(os,
image.getWidth(),
image.getHeight(),
generatorContext);
//
// Finally, write out url
//
imageElement.setAttributeNS(XLINK_NAMESPACE_URI,
ATTR_XLINK_HREF,
href);
}
/**
* Determines the transformation needed to get the cached image to
* scale & position properly. Sets x and y attributes on the element
* accordingly.
*/
protected AffineTransform handleTransform(Element imageElement,
double x, double y,
double srcWidth,
double srcHeight,
double dstWidth,
double dstHeight) {
// If scaling is necessary, create a transform, since "width" and "height"
// have no effect on a <use> element referring to an <image> element.
AffineTransform af = null;
double hRatio = dstWidth / srcWidth;
double vRatio = dstHeight / srcHeight;
double xScaled = x / hRatio;
double yScaled = y / vRatio;
if(hRatio != 1 || vRatio != 1) {
af = AffineTransform.getScaleInstance(hRatio, vRatio);
}
imageElement.setAttributeNS(null,
SVG_X_ATTRIBUTE,
AbstractSVGConverter.doubleString(xScaled));
imageElement.setAttributeNS(null,
SVG_Y_ATTRIBUTE,
AbstractSVGConverter.doubleString(yScaled));
return af;
}
}
1.1
xml-batik/sources/org/apache/batik/svggen/CachedImageHandlerJPEGEncoder.java
Index: CachedImageHandlerJPEGEncoder.java
===================================================================
/*****************************************************************************
* 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.svggen;
import java.awt.image.BufferedImage;
import org.w3c.dom.*;
/**
* Caching version of the JPEG image handler.
*
* @author <a href="mailto:[EMAIL PROTECTED]">Paul Evenblij</a>
* @version $Id: CachedImageHandlerJPEGEncoder.java,v 1.1 2001/10/31 09:54:25 vhardy
Exp $
*/
public class CachedImageHandlerJPEGEncoder extends ImageHandlerJPEGEncoder {
/**
* @param imageDir directory where this handler should generate images.
* If null, an IllegalArgumentException is thrown.
* @param urlRoot root for the urls that point to images created by this
* image handler. If null, then the url corresponding to imageDir
* is used.
*/
public CachedImageHandlerJPEGEncoder(String imageDir, String urlRoot)
throws SVGGraphics2DIOException {
super(imageDir, urlRoot);
setImageCacher(new ImageCacher.External(imageDir,
getPrefix(),
getSuffix()));
}
/**
* Save with caching.
*/
protected void saveBufferedImageToFile(Element imageElement,
BufferedImage buf,
SVGGeneratorContext generatorContext)
throws SVGGraphics2DIOException {
cacheBufferedImage(imageElement, buf, generatorContext);
}
}
1.1
xml-batik/sources/org/apache/batik/svggen/CachedImageHandlerPNGEncoder.java
Index: CachedImageHandlerPNGEncoder.java
===================================================================
/*****************************************************************************
* 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.svggen;
import java.awt.image.BufferedImage;
import org.w3c.dom.*;
/**
* Caching version of the PNG image handler.
*
* @author <a href="mailto:[EMAIL PROTECTED]">Paul Evenblij</a>
* @version $Id: CachedImageHandlerPNGEncoder.java,v 1.1 2001/10/31 09:54:25 vhardy
Exp $
*/
public class CachedImageHandlerPNGEncoder extends ImageHandlerPNGEncoder {
/**
* @param imageDir directory where this handler should generate images.
* If null, an IllegalArgumentException is thrown.
* @param urlRoot root for the urls that point to images created by this
* image handler. If null, then the url corresponding to imageDir
* is used.
*/
public CachedImageHandlerPNGEncoder(String imageDir, String urlRoot)
throws SVGGraphics2DIOException {
super(imageDir, urlRoot);
setImageCacher(new ImageCacher.External(imageDir,
getPrefix(),
getSuffix()));
}
/**
* Save with caching.
*/
protected void saveBufferedImageToFile(Element imageElement,
BufferedImage buf,
SVGGeneratorContext generatorContext)
throws SVGGraphics2DIOException {
cacheBufferedImage(imageElement, buf, generatorContext);
}
}
1.1
xml-batik/sources/org/apache/batik/svggen/CachedImageSVGGraphics2D.java
Index: CachedImageSVGGraphics2D.java
===================================================================
/*****************************************************************************
* 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.svggen;
import java.io.*;
import java.lang.*;
import java.util.*;
import java.awt.*;
import java.awt.image.*;
import java.awt.geom.*;
import java.awt.image.renderable.*;
import org.w3c.dom.*;
import org.apache.batik.ext.awt.g2d.AbstractGraphics2D;
import org.apache.batik.ext.awt.g2d.GraphicContext;
/**
* This specialization of the SVGGraphics2D class
* uses a caching mechanism for raster images.
*
* @author <a href="mailto:[EMAIL PROTECTED]">Paul Evenblij</a>
* @version $Id: CachedImageSVGGraphics2D.java,v 1.1 2001/10/31 09:54:25 vhardy Exp $
*/
public class CachedImageSVGGraphics2D extends SVGGraphics2D {
public CachedImageSVGGraphics2D(Document domFactory) {
super(domFactory);
CachedImageHandler imageHandler =
new CachedImageHandlerBase64Encoder();
imageHandler.getImageCacher().setDOMTreeManager(getDOMTreeManager());
getGeneratorContext().setImageHandler(imageHandler);
}
public CachedImageSVGGraphics2D(Document domFactory,
CachedImageHandler imageHandler,
ExtensionHandler extensionHandler,
boolean textAsShapes) {
super(domFactory, imageHandler, extensionHandler, textAsShapes);
getCachedImageHandler().getImageCacher().setDOMTreeManager(
getDOMTreeManager());
}
public CachedImageSVGGraphics2D(SVGGeneratorContext generatorCtx,
boolean textAsShapes) {
super(generatorCtx, textAsShapes);
getCachedImageHandler().getImageCacher().setDOMTreeManager(
getDOMTreeManager());
}
public CachedImageHandler getCachedImageHandler() {
ImageHandler imageHandler = getImageHandler();
if( ! (imageHandler instanceof CachedImageHandler)) {
throw new SVGGraphics2DRuntimeException(
ERR_IMAGE_HANDLER_NOT_SUPPORTED+
imageHandler.getClass().getName());
}
return (CachedImageHandler) imageHandler;
}
/**
* Draws as much of the specified image as is currently available.
* The image is drawn with its top-left corner at
* (<i>x</i>, <i>y</i>) in this graphics context's coordinate
* space. Transparent pixels in the image do not affect whatever
* pixels are already there.
* <p>
* This method returns immediately in all cases, even if the
* complete image has not yet been loaded, and it has not been dithered
* and converted for the current output device.
* <p>
* If the image has not yet been completely loaded, then
* <code>drawImage</code> returns <code>false</code>. As more of
* the image becomes available, the process that draws the image notifies
* the specified image observer.
* @param img the specified image to be drawn.
* @param x the <i>x</i> coordinate.
* @param y the <i>y</i> coordinate.
* @param observer object to be notified as more of
* the image is converted.
* @see java.awt.Image
* @see java.awt.image.ImageObserver
* @see java.awt.image.ImageObserver#imageUpdate(java.awt.Image, int, int,
int, int, int)
*/
public boolean drawImage(Image img, int x, int y,
ImageObserver observer) {
Element imageElement =
getCachedImageHandler().createElement(getGeneratorContext());
AffineTransform xform = getCachedImageHandler().handleImage(
img, imageElement,
x, y,
img.getWidth(null),
img.getHeight(null),
getGeneratorContext());
if (xform == null) {
getDOMGroupManager().addElement(imageElement);
} else {
AffineTransform inverseTransform = null;
try {
inverseTransform = xform.createInverse();
} catch(NoninvertibleTransformException e) {
// This should never happen since handleImage
// always returns invertible transform
throw new SVGGraphics2DRuntimeException(ERR_UNEXPECTED);
}
gc.transform(xform);
getDOMGroupManager().addElement(imageElement);
gc.transform(inverseTransform);
}
return true;
}
/**
* Draws as much of the specified image as has already been scaled
* to fit inside the specified rectangle.
* <p>
* The image is drawn inside the specified rectangle of this
* graphics context's coordinate space, and is scaled if
* necessary. Transparent pixels do not affect whatever pixels
* are already there.
* <p>
* This method returns immediately in all cases, even if the
* entire image has not yet been scaled, dithered, and converted
* for the current output device.
* If the current output representation is not yet complete, then
* <code>drawImage</code> returns <code>false</code>. As more of
* the image becomes available, the process that draws the image notifies
* the image observer by calling its <code>imageUpdate</code> method.
* <p>
* A scaled version of an image will not necessarily be
* available immediately just because an unscaled version of the
* image has been constructed for this output device. Each size of
* the image may be cached separately and generated from the original
* data in a separate image production sequence.
* @param img the specified image to be drawn.
* @param x the <i>x</i> coordinate.
* @param y the <i>y</i> coordinate.
* @param width the width of the rectangle.
* @param height the height of the rectangle.
* @param observer object to be notified as more of
* the image is converted.
* @see java.awt.Image
* @see java.awt.image.ImageObserver
* @see java.awt.image.ImageObserver#imageUpdate(java.awt.Image, int, int,
int, int, int)
*/
public boolean drawImage(Image img, int x, int y,
int width, int height,
ImageObserver observer){
Element imageElement =
getCachedImageHandler().createElement(getGeneratorContext());
AffineTransform xform = getCachedImageHandler().handleImage(
img, imageElement,
x, y,
width, height,
getGeneratorContext());
if (xform == null) {
getDOMGroupManager().addElement(imageElement);
} else {
AffineTransform inverseTransform = null;
try {
inverseTransform = xform.createInverse();
} catch(NoninvertibleTransformException e) {
// This should never happen since handleImage
// always returns invertible transform
throw new SVGGraphics2DRuntimeException(ERR_UNEXPECTED);
}
gc.transform(xform);
getDOMGroupManager().addElement(imageElement);
gc.transform(inverseTransform);
}
return true;
}
/**
* Renders a {@link RenderedImage},
* applying a transform from image
* space into user space before drawing.
* The transformation from user space into device space is done with
* the current <code>Transform</code> in the <code>Graphics2D</code>.
* The specified transformation is applied to the image before the
* transform attribute in the <code>Graphics2D</code> context is applied.
* The rendering attributes applied include the <code>Clip</code>,
* <code>Transform</code>, and <code>Composite</code> attributes. Note
* that no rendering is done if the specified transform is
* noninvertible.
* @param img the image to be rendered
* @param xform the transformation from image space into user space
* @see #transform
* @see #setTransform
* @see #setComposite
* @see #clip
* @see #setClip
*/
public void drawRenderedImage(RenderedImage img,
AffineTransform trans2) {
Element image =
getCachedImageHandler().createElement(getGeneratorContext());
AffineTransform trans1 = getCachedImageHandler().handleImage(
img, image,
img.getMinX(),
img.getMinY(),
img.getWidth(),
img.getHeight(),
getGeneratorContext());
AffineTransform xform;
// Concatenate the transformation we receive from the imageHandler
// to the user-supplied one. Be aware that both may be null.
if (trans2 == null) {
xform = trans1;
} else {
if(trans1 == null) {
xform = trans2;
} else {
xform = new AffineTransform(trans2);
xform.concatenate(trans1);
}
}
if(xform == null) {
getDOMGroupManager().addElement(image);
} else if(xform.getDeterminant() != 0){
AffineTransform inverseTransform = null;
try{
inverseTransform = xform.createInverse();
}catch(NoninvertibleTransformException e){
// This should never happen since we checked
// the matrix determinant
throw new SVGGraphics2DRuntimeException(ERR_UNEXPECTED);
}
gc.transform(xform);
getDOMGroupManager().addElement(image);
gc.transform(inverseTransform);
} else {
AffineTransform savTransform = new AffineTransform(gc.getTransform());
gc.transform(xform);
getDOMGroupManager().addElement(image);
gc.setTransform(savTransform);
}
}
/**
* Renders a
* {@link RenderableImage},
* applying a transform from image space into user space before drawing.
* The transformation from user space into device space is done with
* the current <code>Transform</code> in the <code>Graphics2D</code>.
* The specified transformation is applied to the image before the
* transform attribute in the <code>Graphics2D</code> context is applied.
* The rendering attributes applied include the <code>Clip</code>,
* <code>Transform</code>, and <code>Composite</code> attributes. Note
* that no rendering is done if the specified transform is
* noninvertible.
*<p>
* Rendering hints set on the <code>Graphics2D</code> object might
* be used in rendering the <code>RenderableImage</code>.
* If explicit control is required over specific hints recognized by a
* specific <code>RenderableImage</code>, or if knowledge of which hints
* are used is required, then a <code>RenderedImage</code> should be
* obtained directly from the <code>RenderableImage</code>
* and rendered using
*{@link #drawRenderedImage(RenderedImage, AffineTransform)}.
* @param img the image to be rendered
* @param xform the transformation from image space into user space
* @see #transform
* @see #setTransform
* @see #setComposite
* @see #clip
* @see #setClip
* @see #drawRenderedImage
*/
public void drawRenderableImage(RenderableImage img,
AffineTransform trans2){
Element image =
getCachedImageHandler().createElement(getGeneratorContext());
AffineTransform trans1 = getCachedImageHandler().handleImage(
img, image,
img.getMinX(),
img.getMinY(),
img.getWidth(),
img.getHeight(),
getGeneratorContext());
AffineTransform xform;
// Concatenate the transformation we receive from the imageHandler
// to the user-supplied one. Be aware that both may be null.
if (trans2 == null) {
xform = trans1;
} else {
if(trans1 == null) {
xform = trans2;
} else {
xform = new AffineTransform(trans2);
xform.concatenate(trans1);
}
}
if (xform == null) {
getDOMGroupManager().addElement(image);
} else if(xform.getDeterminant() != 0){
AffineTransform inverseTransform = null;
try{
inverseTransform = xform.createInverse();
}catch(NoninvertibleTransformException e){
// This should never happen because we checked the
// matrix determinant
throw new SVGGraphics2DRuntimeException(ERR_UNEXPECTED);
}
gc.transform(xform);
getDOMGroupManager().addElement(image);
gc.transform(inverseTransform);
} else {
AffineTransform savTransform = new AffineTransform(gc.getTransform());
gc.transform(xform);
getDOMGroupManager().addElement(image);
gc.setTransform(savTransform);
}
}
}
1.1 xml-batik/sources/org/apache/batik/svggen/ImageCacher.java
Index: ImageCacher.java
===================================================================
/*****************************************************************************
* 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.svggen;
import java.io.*;
import java.util.Hashtable;
import java.util.LinkedList;
import java.util.ListIterator;
import java.util.Arrays;
import java.util.zip.Checksum;
import java.util.zip.Adler32;
import java.awt.image.RenderedImage;
import org.w3c.dom.*;
/**
* This class implements caching functionality for raster images.
*
* @author <a href="mailto:[EMAIL PROTECTED]">Paul Evenblij</a>
* @version $Id: ImageCacher.java,v 1.1 2001/10/31 09:54:25 vhardy Exp $
*/
public abstract class ImageCacher implements SVGSyntax, ErrorConstants {
DOMTreeManager domTreeManager = null;
Hashtable imageCache;
Checksum checkSum;
/**
* Creates an ImageCacher.
*/
public ImageCacher() {
imageCache = new Hashtable();
checkSum = new Adler32();
}
/**
* Creates an ImageCacher.
*
* @param domTreeManager the DOMTreeManager for the tree this cacher works on
*/
public ImageCacher(DOMTreeManager domTreeManager) {
this();
setDOMTreeManager(domTreeManager);
}
/**
* Sets the DOMTreeManager this cacher should work on.
*
* @param domTreeManager the DOMTreeManager for the tree this cacher works on
*/
protected void setDOMTreeManager(DOMTreeManager domTreeManager) {
this.domTreeManager = domTreeManager;
}
/**
* Checks if the image is already in the cache, and
* adds it if not. Returns a unique id for the entry.
*
* @param os the image as a byte stream
* @param width the width of the image
* @param height the height of the image
* @param ctx the SVGGeneratorContext
*
* @return a URI for the image
* @throws SVGGraphics2DIOException if an error occurs during image file i/o
*/
public String lookup(ByteArrayOutputStream os,
int width, int height,
SVGGeneratorContext ctx)
throws SVGGraphics2DIOException {
// We determine a checksum value for the byte data, and use it
// as hash key for the image. This may not be unique, so we
// need to check on actual byte-for-byte equality as well.
// The checksum will be sufficient in most cases.
int checksum = getChecksum(os.toByteArray());
Integer key = new Integer(checksum);
String href = null;
Object data = getCacheableData(os);
LinkedList list = (LinkedList) imageCache.get(key);
if(list == null) {
// Key not found: make a new key/value pair
list = new LinkedList();
imageCache.put(key, list);
} else {
// Key found: check if the image is already in the list
for(ListIterator i = list.listIterator(0); i.hasNext(); ) {
ImageCacheEntry entry = (ImageCacheEntry) i.next();
if(entry.checksum == checksum && imagesMatch(entry.src, data)) {
href = entry.href;
break;
}
}
}
if(href == null) {
// Still no hit: add our own
ImageCacheEntry newEntry = createEntry(checksum, data,
width, height,
ctx);
list.add(newEntry);
href = newEntry.href;
}
return href;
}
/**
* Returns an object which can be cached.
* Implementation must determine which information
* should actually be stored.
*
* @param os the byte stream which is to be coerced
*/
abstract Object getCacheableData(ByteArrayOutputStream os);
/**
* Determines if two images are equal.
* Interpretation of the objects referred to by
* <code>o1</code> and <code>o2</code> is entirely
* implementation-dependent.
*
* @param o1 object referring to one image
* @param o2 object referring to the other image
*/
abstract boolean imagesMatch(Object o1, Object o2)
throws SVGGraphics2DIOException;
/**
* Creates a new entry for keeping in the cache.
*
* @param checksum the checksum from which the hash key is derived
* @param data the data to be cached
* @param width image width
* @param height image height
* @param ctx the SVGGeneratorContext
*/
abstract ImageCacheEntry createEntry(int checksum,
Object data,
int width, int height,
SVGGeneratorContext ctx)
throws SVGGraphics2DIOException;
/**
* Calculates a checksum value for the given data.
*/
int getChecksum(byte[] data) {
checkSum.reset();
checkSum.update(data, 0, data.length);
return (int) checkSum.getValue();
}
/**
* Instances of this class are created to keep track of the
* set of images processed by the ImageHandler. Each entry
* corresponds to one unique member of this set.
*/
private class ImageCacheEntry {
/** A checksum calculated for the data cached */
public int checksum;
/** An implementation-dependent object referring to the data */
public Object src;
/** A uri identifying the data */
public String href;
/**
* Creates a new entry
*/
public ImageCacheEntry(int checksum,
Object src,
String href) {
this.checksum = checksum;
this.src = src;
this.href = href;
}
}
/**
* Cache implementation for images embedded in the SVG file.
*/
public static class Embedded extends ImageCacher {
/**
* Sets the DOMTreeManager this cacher should work on.
*
* @param domTreeManager the DOMTreeManager for the tree this cacher works on
*/
protected void setDOMTreeManager(DOMTreeManager domTreeManager) {
// A new DOMTreeManager implies a new cache, because we cache
// images in the SVG tree itself
if(this.domTreeManager != domTreeManager) {
this.domTreeManager = domTreeManager;
this.imageCache = new Hashtable();
}
}
Object getCacheableData(ByteArrayOutputStream os) {
// In order to have only one instance of the image data
// in memory, we cache the entire xlink:href attribute value,
// so we can just pass a reference to the tree manager.
return DATA_PROTOCOL_PNG_PREFIX + os.toString();
}
boolean imagesMatch(Object o1, Object o2) {
return o1.equals(o2);
}
ImageCacheEntry createEntry(int checksum, Object data,
int width, int height,
SVGGeneratorContext ctx) {
// Get a new unique id
String id = ctx.idGenerator.generateID(ID_PREFIX_IMAGE);
// Add the image data reference to the <defs> section
addToTree(id, (String) data, width, height, ctx);
// Create new cache entry
return new ImageCacheEntry(checksum, data, SIGN_POUND + id);
}
/**
* Adds a new image element to the defs section for cached images.
*/
private void addToTree(String id,
String href,
int width, int height,
SVGGeneratorContext ctx) {
Document domFactory = domTreeManager.getDOMFactory();
Element imageDefs = getImageDefs(domFactory, ctx);
// Create and initialize the new image element
Element imageElement = domFactory.createElementNS(SVG_NAMESPACE_URI,
SVG_IMAGE_TAG);
imageElement.setAttributeNS(null, SVG_ID_ATTRIBUTE,
id);
imageElement.setAttributeNS(null, SVG_WIDTH_ATTRIBUTE,
Integer.toString(width));
imageElement.setAttributeNS(null, SVG_HEIGHT_ATTRIBUTE,
Integer.toString(height));
imageElement.setAttributeNS(DefaultImageHandler.XLINK_NAMESPACE_URI,
ATTR_XLINK_HREF,
href);
imageDefs.appendChild(imageElement);
}
/**
* Returns the top level defs section dedicated to cached
* embedded images, creating one if necessary.
* This one very simply creates a new defs section for each image,
* causing them to be spread throughout the entire SVG tree.
* A nicer implementation would group all imageDefs sections into
* one.
*/
private Element getImageDefs(Document domFactory,
SVGGeneratorContext ctx) {
Element imageDefs = domFactory.createElementNS(SVG_NAMESPACE_URI,
SVG_DEFS_TAG);
String id = ctx.idGenerator.generateID(ID_PREFIX_IMAGE_DEFS);
imageDefs.setAttributeNS(null, SVG_ID_ATTRIBUTE, id);
domTreeManager.appendGroup(imageDefs, null);
return imageDefs;
}
}
/**
* Cache implementation for file-based images.
*/
public static class External extends ImageCacher {
private String imageDir;
private String prefix;
private String suffix;
public External(String imageDir, String prefix, String suffix) {
super();
this.imageDir = imageDir;
this.prefix = prefix;
this.suffix = suffix;
}
Object getCacheableData(ByteArrayOutputStream os) {
return os;
}
boolean imagesMatch(Object o1, Object o2)
throws SVGGraphics2DIOException {
boolean match = false;
try {
FileInputStream imageStream =
new FileInputStream((File) o1);
int imageLen = imageStream.available();
byte[] imageBytes = new byte[imageLen];
byte[] candidateBytes =
((ByteArrayOutputStream) o2).toByteArray();
int bytesRead = imageStream.read(imageBytes);
match = Arrays.equals(imageBytes, candidateBytes);
} catch(IOException e) {
throw new SVGGraphics2DIOException(
ERR_READ+((File) o1).getName());
}
return match;
}
ImageCacheEntry createEntry(int checksum, Object data,
int width, int height,
SVGGeneratorContext ctx)
throws SVGGraphics2DIOException {
// Create a new file in image directory
File imageFile = null;
try {
// While the files we are generating exist, try to create
// another unique id.
while (imageFile == null) {
String fileId = ctx.idGenerator.generateID(prefix);
imageFile = new File(imageDir, fileId + suffix);
if (imageFile.exists())
imageFile = null;
}
// Write data to file
OutputStream outputStream = new FileOutputStream(imageFile);
((ByteArrayOutputStream) data).writeTo(outputStream);
((ByteArrayOutputStream) data).close();
} catch(IOException e) {
throw new SVGGraphics2DIOException(ERR_WRITE+imageFile.getName());
}
// Create new cache entry
return new ImageCacheEntry(checksum, imageFile, imageFile.getName());
}
}
}
1.3 +33 -0
xml-batik/resources/org/apache/batik/apps/rasterizer/resources/Messages.properties
Index: Messages.properties
===================================================================
RCS file:
/home/cvs/xml-batik/resources/org/apache/batik/apps/rasterizer/resources/Messages.properties,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- Messages.properties 2001/10/29 19:13:54 1.2
+++ Messages.properties 2001/10/31 09:54:25 1.3
@@ -86,6 +86,16 @@
-cssAlternate <alternate> \n \
\tCSS alternate stylesheet to use when converting the source \n \
\tSVG files. \n \
+ -cssUser <userStylesheet> \n \
+\tCSS user stylesheet URI to apply to converted SVG documents \n \
+\tin addition to any other referened or embeded stylesheets. \n \
+ -lang <userLanguage> \n \
+\tUser language to use when converting SVG documents.\n \
+ -q <quality> \n \
+\tQuality for the output image. This is only relevant for the \n \
+image/jpeg mime type. \n \
+ -dpi <resolution> \n \
+\tResolution for the ouptut image. \n \
-validate \n \
\tontrols whether the source SVG files should be validated. \n
@@ -143,6 +153,29 @@
SVG files. \n \
Example: -cssAlternate myFavoriteStylesheet \n \
Default: none
+
+Main.cl.option.cssUser.description = \
+-cssUser <userStylesheetURI> User CSS stylesheet to apply when converting SVG
files. \n \
+Example: -cssUser myStylesheet.css
+Default: none
+
+Main.cl.option.q.description = \
+-q <quality> Quality for the generated output image. This is only used for JPEG
conversion. \n \
+The value should be in the [0,1[ range. \n \
+Example: -q 0.5
+Default: 0.99
+
+Main.cl.option.dpi.description = \
+-dpi <resolution> Resolution for the output image. This is used to compute the \n \
+"pixel to millimeter" ratio used when processing SVG documents. \n \
+Example: -dpi 300
+Default: 96
+
+Main.cl.option.lang.description = \
+-lang <language> Language to use when processing SVG documents. This is important
for \n \
+SVG documents containing multiple languages. \n
+Example: -lang fr
+Default: en
Main.cl.option.validate.description = \
-validate controls whether the source SVG files should be validated.
1.2 +73 -1
xml-batik/test-sources/org/apache/batik/apps/rasterizer/MainTest.java
Index: MainTest.java
===================================================================
RCS file:
/home/cvs/xml-batik/test-sources/org/apache/batik/apps/rasterizer/MainTest.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- MainTest.java 2001/10/29 19:13:54 1.1
+++ MainTest.java 2001/10/31 09:54:26 1.2
@@ -24,7 +24,7 @@
* Validates the operation of the <tt>Main</tt> class.
*
* @author <a href="[EMAIL PROTECTED]">Vincent Hardy</a>
- * @version $Id: MainTest.java,v 1.1 2001/10/29 19:13:54 vhardy Exp $
+ * @version $Id: MainTest.java,v 1.2 2001/10/31 09:54:26 vhardy Exp $
*/
public class MainTest extends DefaultTestSuite {
@@ -275,6 +275,54 @@
addTest(t);
t.setId("MainConfigTest.validate");
+ t = new MainConfigTest("-lang fr"){
+ public TestReport validate(SVGConverter c){
+ if("fr".equals(c.getLanguage())){
+ return reportSuccess();
+ } else {
+ return reportError("-lang", "fr", c.getLanguage());
+ }
+ }
+ };
+ addTest(t);
+ t.setId("MainConfigTest.lang");
+
+ t = new MainConfigTest("-cssUser myStylesheet.css"){
+ public TestReport validate(SVGConverter c){
+ if("myStylesheet.css".equals(c.getUserStylesheet())){
+ return reportSuccess();
+ } else {
+ return reportError("-cssUser", "myStylesheet.css",
c.getUserStylesheet());
+ }
+ }
+ };
+ addTest(t);
+ t.setId("MainConfigTest.cssUser");
+
+ t = new MainConfigTest("-dpi 5.08"){
+ public TestReport validate(SVGConverter c){
+ if(c.getPixelToMillimeter() == .5f){
+ return reportSuccess();
+ } else {
+ return reportError("-dpi", ".5f", "" +
c.getPixelToMillimeter());
+ }
+ }
+ };
+ addTest(t);
+ t.setId("MainConfigTest.dpi");
+
+ t = new MainConfigTest("-q .5"){
+ public TestReport validate(SVGConverter c){
+ if(c.getQuality() == .5f){
+ return reportSuccess();
+ } else {
+ return reportError("-q", ".5f", "" + c.getQuality());
+ }
+ }
+ };
+ addTest(t);
+ t.setId("MainConfigTest.quality");
+
t = new MainConfigErrorTest("-d", "hello.svg -d");
addTest(t);
t.setId("MainConfigErrorTest.output");
@@ -307,6 +355,22 @@
addTest(t);
t.setId("MainConfigErrorTest.cssAlternate");
+ t = new MainConfigErrorTest("-lang", "hello.svg -lang");
+ addTest(t);
+ t.setId("MainConfigErrorTest.lang");
+
+ t = new MainConfigErrorTest("-cssUser", "hello.svg -cssUser");
+ addTest(t);
+ t.setId("MainConfigErrorTest.cssUser");
+
+ t = new MainConfigErrorTest("-dpi", "hello.svg -dpi");
+ addTest(t);
+ t.setId("MainConfigErrorTest.dpi");
+
+ t = new MainConfigErrorTest("-q", "hello.svg -q");
+ addTest(t);
+ t.setId("MainConfigErrorTest.quality");
+
t = new MainIllegalArgTest("-m", "-m images/jpeq");
addTest(t);
t.setId("MainIllegalArgTest.mediaType");
@@ -326,6 +390,14 @@
t = new MainIllegalArgTest("bg", "-bg a.b.c.d");
addTest(t);
t.setId("MainIllegalArgTest.bg");
+
+ t = new MainIllegalArgTest("dpi", "-dpi invalidDPI");
+ addTest(t);
+ t.setId("MainIllegalArgTest.dpi");
+
+ t = new MainIllegalArgTest("q", "-q illegalQuality");
+ addTest(t);
+ t.setId("MainIllegalArgTest.q");
}
1.9 +28 -1
xml-batik/test-sources/org/apache/batik/apps/rasterizer/SVGConverterTest.java
Index: SVGConverterTest.java
===================================================================
RCS file:
/home/cvs/xml-batik/test-sources/org/apache/batik/apps/rasterizer/SVGConverterTest.java,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -r1.8 -r1.9
--- SVGConverterTest.java 2001/10/31 08:33:00 1.8
+++ SVGConverterTest.java 2001/10/31 09:54:26 1.9
@@ -24,7 +24,7 @@
* of source and destination sources.
*
* @author <a href="mailto:[EMAIL PROTECTED]">Vincent Hardy</a>
- * @version $Id: SVGConverterTest.java,v 1.8 2001/10/31 08:33:00 tkormann Exp $
+ * @version $Id: SVGConverterTest.java,v 1.9 2001/10/31 09:54:26 vhardy Exp $
*/
public class SVGConverterTest extends DefaultTestSuite {
public SVGConverterTest(){
@@ -122,6 +122,33 @@
};
addTest(t);
t.setId("HintsConfigTest.KEY_ALTERNATE_STYLESHEET");
+
+ t = new HintsConfigTest(new Object[][]{
+ {ImageTranscoder.KEY_USER_STYLESHEET_URI, "userStylesheet.css"}}){
+ protected void deltaConfigure(SVGConverter c){
+ c.setUserStylesheet("userStylesheet.css");
+ }
+ };
+ addTest(t);
+ t.setId("HintsConfigTest.KEY_USER_STYLESHEET_URI");
+
+ t = new HintsConfigTest(new Object[][]{
+ {ImageTranscoder.KEY_LANGUAGE, "fr"}}){
+ protected void deltaConfigure(SVGConverter c){
+ c.setLanguage("fr");
+ }
+ };
+ addTest(t);
+ t.setId("HintsConfigTest.KEY_LANGUAGE");
+
+ t = new HintsConfigTest(new Object[][]{
+ {ImageTranscoder.KEY_PIXEL_TO_MM, new Float(.5f)}}){
+ protected void deltaConfigure(SVGConverter c){
+ c.setPixelToMillimeter(.5f);
+ }
+ };
+ addTest(t);
+ t.setId("HintsConfigTest.KEY_PIXEL_TO_MM");
t = new HintsConfigTest(new Object[][]{
{ImageTranscoder.KEY_XML_PARSER_VALIDATING, new Boolean(true)}}){
1.8 +6 -2 xml-batik/test-sources/org/apache/batik/test/AbstractTest.java
Index: AbstractTest.java
===================================================================
RCS file: /home/cvs/xml-batik/test-sources/org/apache/batik/test/AbstractTest.java,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -r1.7 -r1.8
--- AbstractTest.java 2001/10/19 09:22:17 1.7
+++ AbstractTest.java 2001/10/31 09:54:26 1.8
@@ -70,7 +70,7 @@
* </code>
*
* @author <a href="mailto:[EMAIL PROTECTED]">Vincent Hardy</a>
- * @version $Id: AbstractTest.java,v 1.7 2001/10/19 09:22:17 vhardy Exp $
+ * @version $Id: AbstractTest.java,v 1.8 2001/10/31 09:54:26 vhardy Exp $
*/
public abstract class AbstractTest implements Test {
/**
@@ -105,7 +105,11 @@
*/
public String getName(){
if(name == null){
- return getClass().getName();
+ if (id != null && !"".equals(id)){
+ return id;
+ } else {
+ return getClass().getName();
+ }
}
return name;
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]