| /* |
| |
| Licensed to the Apache Software Foundation (ASF) under one or more |
| contributor license agreements. See the NOTICE file distributed with |
| this work for additional information regarding copyright ownership. |
| The ASF licenses this file to You under the Apache License, Version 2.0 |
| (the "License"); you may not use this file except in compliance with |
| the License. You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| |
| */ |
| package org.apache.batik.transcoder.image; |
| |
| import java.awt.AlphaComposite; |
| import java.awt.Graphics2D; |
| import java.awt.Paint; |
| import java.awt.Shape; |
| import java.awt.geom.AffineTransform; |
| import java.awt.geom.Rectangle2D; |
| import java.awt.image.BufferedImage; |
| import java.awt.image.DataBufferInt; |
| import java.awt.image.SinglePixelPackedSampleModel; |
| |
| import org.apache.batik.ext.awt.image.GraphicsUtil; |
| import org.apache.batik.gvt.renderer.ConcreteImageRendererFactory; |
| import org.apache.batik.gvt.renderer.ImageRenderer; |
| import org.apache.batik.gvt.renderer.ImageRendererFactory; |
| import org.apache.batik.transcoder.SVGAbstractTranscoder; |
| import org.apache.batik.transcoder.TranscoderException; |
| import org.apache.batik.transcoder.TranscoderOutput; |
| import org.apache.batik.transcoder.TranscodingHints; |
| import org.apache.batik.transcoder.keys.BooleanKey; |
| import org.apache.batik.transcoder.keys.PaintKey; |
| import org.w3c.dom.Document; |
| |
| /** |
| * This class enables to transcode an input to an image of any format. |
| * |
| * <p>Two transcoding hints (<code>KEY_WIDTH</code> and |
| * <code>KEY_HEIGHT</code>) 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 <code>KEY_BACKGROUND_COLOR</code> defines the background color |
| * to use for opaque image formats, or the background color that may |
| * be used for image formats that support alpha channel. |
| * |
| * <p>The <code>KEY_AOI</code> represents the area of interest to paint |
| * in device space. |
| * |
| * <p>Three additional transcoding hints that act on the SVG |
| * processor can be specified: |
| * |
| * <p><code>KEY_LANGUAGE</code> to set the default language to use (may be |
| * used by a <switch> SVG element for example), |
| * <code>KEY_USER_STYLESHEET_URI</code> to fix the URI of a user |
| * stylesheet, and <code>KEY_MM_PER_PIXEL</code> to specify the number of |
| * millimeters in each pixel . |
| * |
| * @author <a href="mailto:Thierry.Kormann@sophia.inria.fr">Thierry Kormann</a> |
| * @version $Id$ |
| */ |
| public abstract class ImageTranscoder extends SVGAbstractTranscoder { |
| |
| /** |
| * Constructs a new <code>ImageTranscoder</code>. |
| */ |
| protected ImageTranscoder() { |
| } |
| |
| /** |
| * 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 { |
| |
| // Sets up root, curTxf & curAoi |
| super.transcode(document, uri, output); |
| |
| // prepare the image to be painted |
| int w = (int)(width+0.5); |
| int h = (int)(height+0.5); |
| |
| // paint the SVG document using the bridge package |
| // create the appropriate renderer |
| ImageRenderer renderer = createRenderer(); |
| renderer.updateOffScreen(w, h); |
| // curTxf.translate(0.5, 0.5); |
| renderer.setTransform(curTxf); |
| renderer.setTree(this.root); |
| this.root = null; // We're done with it... |
| |
| try { |
| // now we are sure that the aoi is the image size |
| Shape raoi = new Rectangle2D.Float(0, 0, width, height); |
| // Warning: the renderer's AOI must be in user space |
| renderer.repaint(curTxf.createInverse(). |
| createTransformedShape(raoi)); |
| BufferedImage rend = renderer.getOffScreen(); |
| renderer = null; // We're done with it... |
| |
| BufferedImage dest = createImage(w, h); |
| |
| Graphics2D g2d = GraphicsUtil.createGraphics(dest); |
| if (hints.containsKey(KEY_BACKGROUND_COLOR)) { |
| Paint bgcolor = (Paint)hints.get(KEY_BACKGROUND_COLOR); |
| g2d.setComposite(AlphaComposite.SrcOver); |
| g2d.setPaint(bgcolor); |
| g2d.fillRect(0, 0, w, h); |
| } |
| if (rend != null) { // might be null if the svg document is empty |
| g2d.drawRenderedImage(rend, new AffineTransform()); |
| } |
| g2d.dispose(); |
| rend = null; // We're done with it... |
| writeImage(dest, output); |
| } catch (Exception ex) { |
| throw new TranscoderException(ex); |
| } |
| } |
| |
| /** |
| * Method so subclasses can modify the Renderer used to render document. |
| */ |
| protected ImageRenderer createRenderer() { |
| ImageRendererFactory rendFactory = new ConcreteImageRendererFactory(); |
| // ImageRenderer renderer = rendFactory.createDynamicImageRenderer(); |
| return rendFactory.createStaticImageRenderer(); |
| } |
| |
| /** |
| * Converts an image so that viewers which do not support the |
| * alpha channel will see a white background (and not a black |
| * one). |
| * @param img the image to convert |
| * @param sppsm |
| */ |
| protected void forceTransparentWhite(BufferedImage img, SinglePixelPackedSampleModel sppsm) { |
| // |
| // This is a trick so that viewers which do not support |
| // the alpha channel will see a white background (and not |
| // a black one). |
| // |
| int w = img.getWidth(); |
| int h = img.getHeight(); |
| DataBufferInt biDB=(DataBufferInt)img.getRaster().getDataBuffer(); |
| int scanStride = sppsm.getScanlineStride(); |
| int dbOffset = biDB.getOffset(); |
| int[] pixels = biDB.getBankData()[0]; |
| int p = dbOffset; |
| int adjust = scanStride - w; |
| int a=0, r=0, g=0, b=0, pel=0; |
| for(int i=0; i<h; i++){ |
| for(int j=0; j<w; j++){ |
| pel = pixels[p]; |
| a = (pel >> 24) & 0xff; |
| r = (pel >> 16) & 0xff; |
| g = (pel >> 8 ) & 0xff; |
| b = pel & 0xff; |
| r = (255*(255 -a) + a*r)/255; |
| g = (255*(255 -a) + a*g)/255; |
| b = (255*(255 -a) + a*b)/255; |
| pixels[p++] = |
| (a<<24 & 0xff000000) | |
| (r<<16 & 0xff0000) | |
| (g<<8 & 0xff00) | |
| (b & 0xff); |
| } |
| p += adjust; |
| } |
| } |
| |
| /** |
| * Creates a new image with the specified dimension. |
| * @param width the image width in pixels |
| * @param height the image height in pixels |
| */ |
| public abstract BufferedImage createImage(int width, int height); |
| |
| /** |
| * Writes the specified image to the specified output. |
| * @param img the image to write |
| * @param output the output where to store the image |
| * @throws TranscoderException if an error occured while storing the image |
| */ |
| public abstract void writeImage(BufferedImage img, TranscoderOutput output) |
| throws TranscoderException; |
| |
| // -------------------------------------------------------------------- |
| // Keys definition |
| // -------------------------------------------------------------------- |
| |
| /** |
| * The image background paint key. |
| * <table summary="" border="0" cellspacing="0" cellpadding="1"> |
| * <tr> |
| * <th valign="top" align="right">Key:</th> |
| * <td valign="top">KEY_BACKGROUND_COLOR</td> |
| * </tr> |
| * <tr> |
| * <th valign="top" align="right">Value:</th> |
| * <td valign="top">Paint</td> |
| * </tr> |
| * <tr> |
| * <th valign="top" align="right">Default:</th> |
| * <td valign="top">null</td> |
| * </tr> |
| * <tr> |
| * <th valign="top" align="right">Required:</th> |
| * <td valign="top">No</td> |
| * </tr> |
| * <tr> |
| * <th valign="top" align="right">Description:</th> |
| * <td valign="top">Specify the background color to use. |
| * The color is required by opaque image formats and is used by |
| * image formats that support alpha channel.</td> |
| * </tr> |
| * </table> |
| */ |
| public static final TranscodingHints.Key KEY_BACKGROUND_COLOR |
| = new PaintKey(); |
| |
| /** |
| * The forceTransparentWhite key. |
| * |
| * <table summary="" border="0" cellspacing="0" cellpadding="1"> |
| * <tr> |
| * <th valign="top" align="right">Key:</th> |
| * <td valign="top">KEY_FORCE_TRANSPARENT_WHITE</td> |
| * </tr> |
| * <tr> |
| * <th valign="top" align="right">Value:</th> |
| * <td valign="top">Boolean</td> |
| * </tr> |
| * <tr> |
| * <th valign="top" align="right">Default:</th> |
| * <td valign="top">false</td> |
| * </tr> |
| * <tr> |
| * <th valign="top" align="right">Required:</th> |
| * <td valign="top">No</td> |
| * </tr> |
| * <tr> |
| * <th valign="top" align="right">Description:</th> |
| * <td valign="top">It controls whether the encoder should force |
| * the image's fully transparent pixels to be fully transparent |
| * white instead of fully transparent black. This is useful when |
| * the encoded file is displayed in a browser which does not |
| * support transparency correctly and lets the image display with |
| * a white background instead of a black background. |
| * <br> |
| * However, note that the modified image will display differently |
| * over a white background in a viewer that supports |
| * transparency. |
| * <br> |
| * Not all Transcoders use this key (in particular some formats |
| * can't preserve the alpha channel at all in which case this |
| * is not used).</td> |
| * </tr> |
| * </table> |
| */ |
| public static final TranscodingHints.Key KEY_FORCE_TRANSPARENT_WHITE |
| = new BooleanKey(); |
| } |