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    }