001 /*----------------------------------------------------------------------------
002 This file is part of deegree, http://deegree.org/
003 Copyright (C) 2001-2009 by:
004 Department of Geography, University of Bonn
005 and
006 lat/lon GmbH
007
008 This library is free software; you can redistribute it and/or modify it under
009 the terms of the GNU Lesser General Public License as published by the Free
010 Software Foundation; either version 2.1 of the License, or (at your option)
011 any later version.
012 This library is distributed in the hope that it will be useful, but WITHOUT
013 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
014 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
015 details.
016 You should have received a copy of the GNU Lesser General Public License
017 along with this library; if not, write to the Free Software Foundation, Inc.,
018 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
019
020 Contact information:
021
022 lat/lon GmbH
023 Aennchenstr. 19, 53177 Bonn
024 Germany
025 http://lat-lon.de/
026
027 Department of Geography, University of Bonn
028 Prof. Dr. Klaus Greve
029 Postfach 1147, 53001 Bonn
030 Germany
031 http://www.geographie.uni-bonn.de/deegree/
032
033 e-mail: info@deegree.org
034 ----------------------------------------------------------------------------*/
035
036 package org.deegree.framework.util;
037
038 import java.awt.Graphics2D;
039 import java.awt.RenderingHints;
040 import java.awt.geom.AffineTransform;
041 import java.awt.geom.Rectangle2D;
042 import java.awt.image.BufferedImage;
043 import java.net.MalformedURLException;
044 import java.net.URL;
045
046 import org.apache.batik.bridge.BaseScriptingEnvironment;
047 import org.apache.batik.bridge.BridgeContext;
048 import org.apache.batik.bridge.BridgeException;
049 import org.apache.batik.bridge.GVTBuilder;
050 import org.apache.batik.bridge.ViewBox;
051 import org.apache.batik.dom.svg.SVGDOMImplementation;
052 import org.apache.batik.dom.svg.SVGOMDocument;
053 import org.apache.batik.dom.util.DOMUtilities;
054 import org.apache.batik.ext.awt.image.GraphicsUtil;
055 import org.apache.batik.gvt.CanvasGraphicsNode;
056 import org.apache.batik.gvt.GraphicsNode;
057 import org.apache.batik.transcoder.SVGAbstractTranscoder;
058 import org.apache.batik.transcoder.TranscoderException;
059 import org.apache.batik.transcoder.TranscoderOutput;
060 import org.apache.batik.transcoder.TranscodingHints;
061 import org.apache.batik.transcoder.keys.BooleanKey;
062 import org.apache.batik.util.ParsedURL;
063 import org.w3c.dom.DOMImplementation;
064 import org.w3c.dom.Document;
065 import org.w3c.dom.svg.SVGSVGElement;
066
067 /**
068 * <code>AliasingSVGTranscoder</code> to create a BufferedImage from an SVG with the possibility to
069 * set preferences of aliasing
070 *
071 * @author <a href="mailto:buesching@lat-lon.de">Lyn Buesching</a>
072 * @author last edited by: $Author:$
073 *
074 * @version $Revision:$, $Date:$
075 *
076 */
077 public class AliasingSVGTranscoder extends SVGAbstractTranscoder {
078
079 public static final TranscodingHints.Key KEY_ALIASING = new BooleanKey();
080
081 private BufferedImage bufferedImage = null;
082
083 @Override
084 protected void transcode( Document document, String uri, TranscoderOutput output )
085 throws TranscoderException {
086
087 if ( ( document != null ) && !( document.getImplementation() instanceof SVGDOMImplementation ) ) {
088 DOMImplementation impl;
089 impl = (DOMImplementation) hints.get( KEY_DOM_IMPLEMENTATION );
090 // impl = SVGDOMImplementation.getDOMImplementation();
091 document = DOMUtilities.deepCloneDocument( document, impl );
092 if ( uri != null ) {
093 try {
094 URL url = new URL( uri );
095 ( (SVGOMDocument) document ).setURLObject( url );
096 } catch ( MalformedURLException mue ) {
097 }
098 }
099 }
100
101 ctx = createBridgeContext();
102 SVGOMDocument svgDoc = (SVGOMDocument) document;
103 SVGSVGElement root = svgDoc.getRootElement();
104
105 // build the GVT tree
106 builder = new GVTBuilder();
107 // flag that indicates if the document is dynamic
108
109 boolean isDynamic = ( hints.containsKey( KEY_EXECUTE_ONLOAD )
110 && ( (Boolean) hints.get( KEY_EXECUTE_ONLOAD ) ).booleanValue() && ctx.isDynamicDocument( svgDoc ) );
111
112 GraphicsNode gvtRoot;
113 try {
114 if ( isDynamic )
115 ctx.setDynamicState( BridgeContext.DYNAMIC );
116
117 gvtRoot = builder.build( ctx, svgDoc );
118
119 // dispatch an 'onload' event if needed
120 if ( ctx.isDynamic() ) {
121 BaseScriptingEnvironment se;
122 se = new BaseScriptingEnvironment( ctx );
123 se.loadScripts();
124 se.dispatchSVGLoadEvent();
125 }
126 } catch ( BridgeException ex ) {
127 throw new TranscoderException( ex );
128 }
129
130 // get the 'width' and 'height' attributes of the SVG document
131 float docWidth = (float) ctx.getDocumentSize().getWidth();
132 float docHeight = (float) ctx.getDocumentSize().getHeight();
133
134 setImageSize( docWidth, docHeight );
135
136 // compute the preserveAspectRatio matrix
137 AffineTransform Px;
138
139 // take the AOI into account if any
140 if ( hints.containsKey( KEY_AOI ) ) {
141 Rectangle2D aoi = (Rectangle2D) hints.get( KEY_AOI );
142 // transform the AOI into the image's coordinate system
143 Px = new AffineTransform();
144 double sx = width / aoi.getWidth();
145 double sy = height / aoi.getHeight();
146 double scale = Math.min( sx, sy );
147 Px.scale( scale, scale );
148 double tx = -aoi.getX() + ( width / scale - aoi.getWidth() ) / 2;
149 double ty = -aoi.getY() + ( height / scale - aoi.getHeight() ) / 2;
150 ;
151 Px.translate( tx, ty );
152 // take the AOI transformation matrix into account
153 // we apply first the preserveAspectRatio matrix
154 curAOI = aoi;
155 } else {
156 String ref = new ParsedURL( uri ).getRef();
157
158 try {
159 Px = ViewBox.getViewTransform( ref, root, width, height );
160 } catch ( BridgeException ex ) {
161 throw new TranscoderException( ex );
162 }
163
164 if ( Px.isIdentity() && ( width != docWidth || height != docHeight ) ) {
165 // The document has no viewBox, we need to resize it by hand.
166 // we want to keep the document size ratio
167 float xscale, yscale;
168 xscale = width / docWidth;
169 yscale = height / docHeight;
170 float scale = Math.min( xscale, yscale );
171 Px = AffineTransform.getScaleInstance( scale, scale );
172 }
173
174 curAOI = new Rectangle2D.Float( 0, 0, width, height );
175 }
176
177 CanvasGraphicsNode cgn = getCanvasGraphicsNode( gvtRoot );
178 if ( cgn != null ) {
179 cgn.setViewingTransform( Px );
180 curTxf = new AffineTransform();
181 } else {
182 curTxf = Px;
183 }
184
185 gvtRoot = renderImage( output, gvtRoot, Px, (int) width, (int) height );
186
187 this.root = gvtRoot;
188
189 }
190
191 private GraphicsNode renderImage( TranscoderOutput output, GraphicsNode gvtRoot, AffineTransform Px, int w, int h )
192 throws TranscoderException {
193
194 Graphics2D g2d = createGraphics( w, h );
195 // Check anti-aliasing preference
196 if ( hints.containsKey( KEY_ALIASING ) ) {
197 boolean antialias = ( (Boolean) hints.get( KEY_ALIASING ) ).booleanValue();
198 g2d.setRenderingHint( RenderingHints.KEY_ANTIALIASING, antialias ? RenderingHints.VALUE_ANTIALIAS_ON
199 : RenderingHints.VALUE_ANTIALIAS_OFF );
200 } else {
201 g2d.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON );
202 }
203
204 g2d.clip( new java.awt.Rectangle( 0, 0, w, h ) );
205 g2d.transform( Px );
206 gvtRoot.paint( g2d );
207 g2d.dispose();
208 return null;
209 }
210
211 private Graphics2D createGraphics( int w, int h ) {
212 bufferedImage = new BufferedImage( w, h, BufferedImage.TYPE_INT_ARGB );
213 Graphics2D g2d = GraphicsUtil.createGraphics( bufferedImage );
214 return g2d;
215 }
216
217 /**
218 * @return BufferedImage the created BufferedImage
219 */
220 public BufferedImage getBufferedImage() {
221 return bufferedImage;
222 }
223
224 }