001 //$HeadURL: svn+ssh://jwilden@svn.wald.intevation.org/deegree/base/branches/2.5_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 }