001 //$HeadURL: https://svn.wald.intevation.org/svn/deegree/base/branches/2.4_testing/src/org/deegree/graphics/sld/ExternalGraphic.java $
002 /*----------------------------------------------------------------------------
003 This file is part of deegree, http://deegree.org/
004 Copyright (C) 2001-2009 by:
005 Department of Geography, University of Bonn
006 and
007 lat/lon GmbH
008
009 This library is free software; you can redistribute it and/or modify it under
010 the terms of the GNU Lesser General Public License as published by the Free
011 Software Foundation; either version 2.1 of the License, or (at your option)
012 any later version.
013 This library is distributed in the hope that it will be useful, but WITHOUT
014 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
015 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
016 details.
017 You should have received a copy of the GNU Lesser General Public License
018 along with this library; if not, write to the Free Software Foundation, Inc.,
019 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
020
021 Contact information:
022
023 lat/lon GmbH
024 Aennchenstr. 19, 53177 Bonn
025 Germany
026 http://lat-lon.de/
027
028 Department of Geography, University of Bonn
029 Prof. Dr. Klaus Greve
030 Postfach 1147, 53001 Bonn
031 Germany
032 http://www.geographie.uni-bonn.de/deegree/
033
034 e-mail: info@deegree.org
035 ----------------------------------------------------------------------------*/
036 package org.deegree.graphics.sld;
037
038 import static org.deegree.framework.xml.XMLTools.escape;
039
040 import java.awt.image.BufferedImage;
041 import java.io.ByteArrayInputStream;
042 import java.io.ByteArrayOutputStream;
043 import java.io.IOException;
044 import java.io.InputStream;
045 import java.net.MalformedURLException;
046 import java.net.URISyntaxException;
047 import java.net.URL;
048 import java.util.HashMap;
049 import java.util.Map;
050
051 import javax.media.jai.JAI;
052 import javax.media.jai.RenderedOp;
053
054 import org.apache.batik.transcoder.SVGAbstractTranscoder;
055 import org.apache.batik.transcoder.Transcoder;
056 import org.apache.batik.transcoder.TranscoderException;
057 import org.apache.batik.transcoder.TranscoderInput;
058 import org.apache.batik.transcoder.TranscoderOutput;
059 import org.apache.batik.transcoder.image.PNGTranscoder;
060 import org.deegree.framework.log.ILogger;
061 import org.deegree.framework.log.LoggerFactory;
062 import org.deegree.framework.util.StringTools;
063 import org.deegree.framework.xml.Marshallable;
064 import org.deegree.model.feature.Feature;
065 import org.deegree.model.feature.FeatureProperty;
066
067 import com.sun.media.jai.codec.MemoryCacheSeekableStream;
068
069 /**
070 * The ExternalGraphic element allows a reference to be made to an external graphic file with a Web URL. The
071 * OnlineResource sub-element gives the URL and the Format sub-element identifies the expected document MIME type of a
072 * successful fetch. Knowing the MIME type in advance allows the styler to select the best- supported format from the
073 * list of URLs with equivalent content.
074 *
075 *
076 * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a>
077 * @author last edited by: $Author: apoth $
078 *
079 * @version $Revision: 25372 $, $Date: 2010-07-15 14:11:34 +0200 (Do, 15. Jul 2010) $
080 */
081 public class ExternalGraphic implements Marshallable {
082
083 private static final ILogger LOG = LoggerFactory.getLogger( ExternalGraphic.class );
084
085 private BufferedImage image = null;
086
087 private String format = null;
088
089 private URL onlineResource = null;
090
091 private TranscoderInput input = null;
092
093 private ByteArrayOutputStream bos = null;
094
095 private TranscoderOutput output = null;
096
097 private Transcoder trc = null;
098
099 private static Map<String, BufferedImage> cache = null;
100 static {
101 if ( cache == null ) {
102 cache = new HashMap<String, BufferedImage>( 500 );
103 }
104 }
105
106 /**
107 * Creates a new ExternalGraphic_Impl object.
108 *
109 * @param format
110 * @param onlineResource
111 */
112 ExternalGraphic( String format, URL onlineResource ) {
113 setFormat( format );
114 setOnlineResource( onlineResource );
115 }
116
117 /**
118 * the Format sub-element identifies the expected document MIME type of a successful fetch.
119 *
120 * @return Format of the external graphic
121 *
122 */
123 public String getFormat() {
124 return format;
125 }
126
127 /**
128 * sets the format (MIME type)
129 *
130 * @param format
131 * Format of the external graphic
132 *
133 */
134 public void setFormat( String format ) {
135 this.format = format;
136 }
137
138 /**
139 * The OnlineResource gives the URL of the external graphic
140 *
141 * @return URL of the external graphic
142 *
143 */
144 public URL getOnlineResource() {
145 return onlineResource;
146 }
147
148 /**
149 * sets the online resource / URL of the external graphic
150 *
151 * @param onlineResource
152 * URL of the external graphic
153 *
154 */
155 public void setOnlineResource( URL onlineResource ) {
156 this.onlineResource = onlineResource;
157 // TODO
158 // removing this is just experimental; possibly initializeOnlineResource( Feature feature )
159 // must be adapted
160 // String file = onlineResource.getFile();
161 // int idx = file.indexOf( "$" );
162 // if ( idx == -1 ) {
163 // retrieveImage( onlineResource );
164 // }
165 }
166
167 /**
168 * @param onlineResource
169 */
170 private void retrieveImage( URL onlineResource ) {
171
172 try {
173 String t = onlineResource.toURI().toASCIIString();
174 if ( t.trim().toLowerCase().endsWith( ".svg" ) ) {
175 // initialize the the classes required for svg handling
176 bos = new ByteArrayOutputStream( 2000 );
177 output = new TranscoderOutput( bos );
178 // PNGTranscoder is needed to handle transparent parts
179 // of a SVG
180 trc = new PNGTranscoder();
181 try {
182 input = new TranscoderInput( t );
183 } catch ( Exception e ) {
184 e.printStackTrace();
185 }
186 } else {
187 InputStream is = onlineResource.openStream();
188 MemoryCacheSeekableStream mcss = new MemoryCacheSeekableStream( is );
189 RenderedOp rop = JAI.create( "stream", mcss );
190 image = rop.getAsBufferedImage();
191 mcss.close();
192 is.close();
193 }
194 } catch ( Exception e ) {
195 LOG.logError( e.getMessage(), e );
196 }
197 }
198
199 /**
200 * returns the external graphic as an image. this method is not part of the sld specifications but it is added for
201 * speed up applications
202 *
203 * @param targetSizeX
204 * @param targetSizeY
205 * @param feature
206 *
207 * @return the external graphic as BufferedImage
208 */
209 public BufferedImage getAsImage( int targetSizeX, int targetSizeY, Feature feature ) {
210
211 if ( ( ( this.input == null ) && ( this.image == null ) ) || feature != null ) {
212 URL onlineResource = initializeOnlineResource( feature );
213 retrieveImage( onlineResource );
214 }
215
216 if ( input != null ) {
217 image = cache.get( targetSizeX + '_' + targetSizeY + '_' + onlineResource.getFile() );
218 if ( image == null ) {
219 if ( targetSizeX <= 0 ) {
220 targetSizeX = 1;
221 }
222 if ( targetSizeY <= 0 ) {
223 targetSizeY = 1;
224 }
225
226 trc.addTranscodingHint( SVGAbstractTranscoder.KEY_HEIGHT, new Float( targetSizeX ) );
227 trc.addTranscodingHint( SVGAbstractTranscoder.KEY_WIDTH, new Float( targetSizeY ) );
228 try {
229 trc.transcode( input, output );
230 try {
231 bos.flush();
232 bos.close();
233 } catch ( IOException e3 ) {
234 e3.printStackTrace();
235 }
236 } catch ( TranscoderException e ) {
237 LOG.logError( e.getMessage(), e );
238 }
239 try {
240 ByteArrayInputStream is = new ByteArrayInputStream( bos.toByteArray() );
241 MemoryCacheSeekableStream mcss = new MemoryCacheSeekableStream( is );
242 RenderedOp rop = JAI.create( "stream", mcss );
243 image = rop.getAsBufferedImage();
244 cache.put( targetSizeX + '_' + targetSizeY + '_' + onlineResource.getFile(), image );
245 mcss.close();
246 } catch ( IOException e1 ) {
247 LOG.logError( e1.getMessage(), e1 );
248 }
249 }
250 }
251
252 return image;
253 }
254
255 /**
256 * @param feature
257 * @return online resource URL
258 */
259 private URL initializeOnlineResource( Feature feature ) {
260
261 String file = null;
262 try {
263 file = this.onlineResource.toURI().toASCIIString();
264 LOG.logDebug( "external graphic pattern: ", file );
265 } catch ( URISyntaxException e1 ) {
266 e1.printStackTrace();
267 }
268 String[] tags = StringTools.extractStrings( file, "$", "$" );
269
270 if ( tags != null ) {
271 FeatureProperty[] properties = feature.getProperties();
272 for ( int i = 0; i < tags.length; i++ ) {
273 String tag = tags[i].substring( 1, tags[i].length() - 1 );
274 for ( int j = 0; j < properties.length; j++ ) {
275 if ( properties[j].getName().getLocalName().equals( tag ) ) {
276 String to = properties[j].getValue().toString();
277 file = StringTools.replace( file, tags[i], to, true );
278 }
279 }
280 }
281 }
282 URL onlineResource = null;
283 try {
284 onlineResource = new URL( file );
285 LOG.logDebug( "external graphic URL: ", file );
286 } catch ( MalformedURLException e ) {
287 LOG.logError( e.getMessage(), e );
288 }
289 return onlineResource;
290 }
291
292 /**
293 * sets the external graphic as an image.
294 *
295 * @param image
296 * the external graphic as BufferedImage
297 */
298 public void setAsImage( BufferedImage image ) {
299 this.image = image;
300 }
301
302 /**
303 * exports the content of the ExternalGraphic as XML formated String
304 *
305 * @return xml representation of the ExternalGraphic
306 */
307 public String exportAsXML() {
308
309 StringBuffer sb = new StringBuffer( 200 );
310 sb.append( "<ExternalGraphic>" );
311 sb.append( "<OnlineResource xmlns:xlink='http://www.w3.org/1999/xlink' " );
312 sb.append( "xlink:type='simple' xlink:href='" );
313 try {
314 sb.append( onlineResource.toURI().toASCIIString() + "'/>" );
315 } catch ( URISyntaxException e ) {
316 e.printStackTrace();
317 }
318 sb.append( "<Format>" ).append( escape( format ) ).append( "</Format>" );
319 sb.append( "</ExternalGraphic>" );
320 return sb.toString();
321 }
322
323 }