001    //$HeadURL: https://sushibar/svn/deegree/base/trunk/resources/eclipse/svn_classfile_header_template.xml $
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    
037    package org.deegree.io.mapinfoapi;
038    
039    import static java.awt.Color.black;
040    import static java.awt.Color.decode;
041    import static java.awt.Color.white;
042    import static java.awt.Font.TRUETYPE_FONT;
043    import static java.awt.Font.createFont;
044    import static java.awt.image.BufferedImage.TYPE_INT_ARGB;
045    import static java.io.File.createTempFile;
046    import static java.lang.Integer.parseInt;
047    import static java.lang.Integer.toHexString;
048    import static java.lang.Math.sqrt;
049    import static javax.imageio.ImageIO.write;
050    import static javax.media.jai.JAI.create;
051    import static org.apache.batik.transcoder.SVGAbstractTranscoder.KEY_HEIGHT;
052    import static org.apache.batik.transcoder.SVGAbstractTranscoder.KEY_WIDTH;
053    import static org.deegree.framework.log.LoggerFactory.getLogger;
054    import static org.deegree.framework.xml.XMLTools.appendElement;
055    import static org.deegree.framework.xml.XMLTools.getNodes;
056    import static org.deegree.framework.xml.XMLTools.getRequiredElement;
057    import static org.deegree.ogcbase.CommonNamespaces.GMLNS;
058    import static org.deegree.ogcbase.CommonNamespaces.GML_PREFIX;
059    import static org.deegree.ogcbase.CommonNamespaces.OGCNS;
060    import static org.deegree.ogcbase.CommonNamespaces.OGC_PREFIX;
061    import static org.deegree.ogcbase.CommonNamespaces.SLDNS;
062    import static org.deegree.ogcbase.CommonNamespaces.SLD_PREFIX;
063    import static org.deegree.ogcbase.CommonNamespaces.XLINK_PREFIX;
064    import static org.deegree.ogcbase.CommonNamespaces.XLNNS;
065    import static org.deegree.ogcbase.CommonNamespaces.XSINS;
066    import static org.deegree.ogcbase.CommonNamespaces.XSI_PREFIX;
067    import static org.deegree.ogcbase.CommonNamespaces.getNamespaceContext;
068    
069    import java.awt.Color;
070    import java.awt.Font;
071    import java.awt.FontFormatException;
072    import java.awt.Graphics2D;
073    import java.awt.image.BufferedImage;
074    import java.io.ByteArrayInputStream;
075    import java.io.ByteArrayOutputStream;
076    import java.io.File;
077    import java.io.FileOutputStream;
078    import java.io.IOException;
079    import java.io.InputStream;
080    import java.io.InputStreamReader;
081    import java.io.StringReader;
082    import java.net.MalformedURLException;
083    import java.net.URL;
084    import java.text.DecimalFormat;
085    import java.util.HashMap;
086    import java.util.HashSet;
087    import java.util.List;
088    import java.util.Map;
089    import java.util.zip.ZipEntry;
090    import java.util.zip.ZipFile;
091    
092    import javax.media.jai.RenderedOp;
093    
094    import org.apache.batik.transcoder.TranscoderException;
095    import org.apache.batik.transcoder.TranscoderInput;
096    import org.apache.batik.transcoder.TranscoderOutput;
097    import org.apache.batik.transcoder.image.PNGTranscoder;
098    import org.deegree.datatypes.QualifiedName;
099    import org.deegree.framework.log.ILogger;
100    import org.deegree.framework.xml.NamespaceContext;
101    import org.deegree.framework.xml.XMLFragment;
102    import org.deegree.framework.xml.XMLParsingException;
103    import org.deegree.graphics.Theme;
104    import org.w3c.dom.DOMException;
105    import org.w3c.dom.Element;
106    import org.w3c.dom.Node;
107    import org.xml.sax.SAXException;
108    
109    import com.sun.media.jai.codec.MemoryCacheSeekableStream;
110    
111    /**
112     * <code>MIFStyle2SLD</code>
113     *
114     * @author <a href="mailto:schmitz@lat-lon.de">Andreas Schmitz</a>
115     * @author last edited by: $Author:$
116     *
117     * @version $Revision:$, $Date:$
118     */
119    public class MIFStyle2SLD {
120    
121        private static final NamespaceContext nsContext = getNamespaceContext();
122    
123        private static final ILogger LOG = getLogger( MIFStyle2SLD.class );
124    
125        private Font symbolFont;
126    
127        private static File BRUSHES, POINTS;
128    
129        private static final double SQRT2 = sqrt( 2 );
130    
131        static {
132            // copy the brushes.zip to temp dir
133            // necessary, because we cannot directly extract a singe entry from jar-enclosed zip
134            try {
135                BRUSHES = File.createTempFile( "brushes", ".zip" );
136                BRUSHES.deleteOnExit();
137    
138                InputStream in = MIFStyle2SLD.class.getResourceAsStream( "brushes.zip" );
139                if ( in == null ) {
140                    in = Theme.class.getResourceAsStream( "fillpatterns.zip" );
141                }
142                FileOutputStream out = new FileOutputStream( BRUSHES );
143    
144                byte[] buf = new byte[16384];
145    
146                int read;
147                if ( in != null ) {
148                    while ( ( read = in.read( buf ) ) != -1 ) {
149                        out.write( buf, 0, read );
150                    }
151                    in.close();
152                }
153                out.close();
154    
155            } catch ( IOException e ) {
156                LOG.logError( "Could not find the brushes zip file", e );
157            }
158            // same for more complicated points
159            try {
160                POINTS = File.createTempFile( "points", ".zip" );
161                POINTS.deleteOnExit();
162    
163                InputStream in = MIFStyle2SLD.class.getResourceAsStream( "points.zip" );
164                if ( in == null ) {
165                    in = Theme.class.getResourceAsStream( "points.zip" );
166                }
167                FileOutputStream out = new FileOutputStream( POINTS );
168    
169                byte[] buf = new byte[16384];
170    
171                int read;
172                if ( in != null ) {
173                    while ( ( read = in.read( buf ) ) != -1 ) {
174                        out.write( buf, 0, read );
175                    }
176                    in.close();
177                }
178                out.close();
179            } catch ( IOException e ) {
180                LOG.logError( "Could not find the points zip file", e );
181            }
182        }
183    
184        /**
185         * @param symbolFont
186         * @throws FontFormatException
187         * @throws IOException
188         */
189        public MIFStyle2SLD( String symbolFont ) throws FontFormatException, IOException {
190            this.symbolFont = createFont( TRUETYPE_FONT, new File( symbolFont ) );
191        }
192    
193        /**
194         * @param symbolFont
195         * @throws FontFormatException
196         * @throws IOException
197         */
198        public MIFStyle2SLD( URL symbolFont ) throws FontFormatException, IOException {
199            this.symbolFont = createFont( TRUETYPE_FONT, symbolFont.openStream() );
200        }
201    
202        /**
203         * @param name
204         *            the layer name
205         * @return an empty SLD document
206         */
207        public static XMLFragment getSLDTemplate( String name ) {
208            XMLFragment doc = new XMLFragment( new QualifiedName( SLD_PREFIX, "StyledLayerDescriptor", SLDNS ) );
209            Element root = doc.getRootElement();
210            root.setAttribute( "version", "1.0.0" );
211            root.setAttribute( "xmlns:app", "http://www.deegree.org/app" );
212            root.setAttribute( "xmlns:" + XLINK_PREFIX, XLNNS.toASCIIString() );
213            root.setAttribute( "xmlns:" + OGC_PREFIX, OGCNS.toASCIIString() );
214            root.setAttribute( "xmlns:" + GML_PREFIX, GMLNS.toASCIIString() );
215            root.setAttribute( "xmlns:" + XSI_PREFIX, XSINS.toASCIIString() );
216            root.setAttribute( XSI_PREFIX + ":schemaLocation",
217                               SLDNS.toASCIIString() + " http://schemas.opengis.net/sld/1.0.0/StyledLayerDescriptor.xsd" );
218    
219            Element e = appendElement( root, SLDNS, SLD_PREFIX + ":NamedLayer" );
220            appendElement( e, SLDNS, SLD_PREFIX + ":Name", "default:" + name );
221            e = appendElement( e, SLDNS, SLD_PREFIX + ":UserStyle" );
222            appendElement( e, SLDNS, SLD_PREFIX + ":Name", "default:" + name );
223            appendElement( e, SLDNS, SLD_PREFIX + ":Title", "default:" + name );
224            appendElement( e, SLDNS, SLD_PREFIX + ":IsDefault", "1" );
225            e = appendElement( e, SLDNS, SLD_PREFIX + ":FeatureTypeStyle" );
226            appendElement( e, SLDNS, SLD_PREFIX + ":Name", "default:" + name );
227    
228            String str = doc.getAsString();
229    
230            // wrap it, so the namespace bindings are correct (is there a better way to add them to the
231            // root element?)
232            try {
233                return new XMLFragment( new StringReader( str ), "http://www.systemid.org" );
234            } catch ( SAXException ex ) {
235                // eat it, it must be parseable
236            } catch ( IOException ex ) {
237                // eat it, it must be parseable
238            }
239    
240            return null;
241        }
242    
243        /**
244         * @param id
245         * @param rule
246         */
247        public static void appendIDFilter( String id, Element rule ) {
248            appendElement( rule, SLDNS, SLD_PREFIX + ":Name", id );
249            Element e = appendElement( rule, OGCNS, OGC_PREFIX + ":Filter" );
250            Element or = appendElement( e, OGCNS, OGC_PREFIX + ":Or" );
251            e = appendElement( or, OGCNS, OGC_PREFIX + ":PropertyIsLike" );
252            e.setAttribute( "wildCard", "*" );
253            e.setAttribute( "escape", "\\" );
254            e.setAttribute( "singleChar", "?" );
255            appendElement( e, OGCNS, OGC_PREFIX + ":PropertyName", "app:styleid" );
256            appendElement( e, OGCNS, OGC_PREFIX + ":Literal", id );
257    
258            // it could be part of a combined (polygon) style
259            e = appendElement( or, OGCNS, OGC_PREFIX + ":PropertyIsLike" );
260            e.setAttribute( "wildCard", "*" );
261            e.setAttribute( "escape", "\\" );
262            e.setAttribute( "singleChar", "?" );
263            appendElement( e, OGCNS, OGC_PREFIX + ":PropertyName", "app:styleid" );
264            appendElement( e, OGCNS, OGC_PREFIX + ":Literal", "*_" + id );
265    
266            e = appendElement( or, OGCNS, OGC_PREFIX + ":PropertyIsLike" );
267            e.setAttribute( "wildCard", "*" );
268            e.setAttribute( "escape", "\\" );
269            e.setAttribute( "singleChar", "?" );
270            appendElement( e, OGCNS, OGC_PREFIX + ":PropertyName", "app:styleid" );
271            appendElement( e, OGCNS, OGC_PREFIX + ":Literal", id + "_*" );
272        }
273    
274        /**
275         * @param map
276         * @param doc
277         * @throws DOMException
278         * @throws IOException
279         * @throws XMLParsingException
280         * @throws SAXException
281         */
282        public void insertSymbolStyle( Map<String, String> map, XMLFragment doc )
283                                throws DOMException, IOException, XMLParsingException, SAXException {
284    
285            if ( map.size() != 4 && map.size() != 5 ) {
286                LOG.logWarning( "Symbol style not supported yet: " + map );
287                return;
288            }
289    
290            // custom bitmap symbol style
291            if ( map.size() == 5 ) {
292                int size = parseInt( map.get( "size" ) );
293    
294                if ( map.get( "filename" ) == null ) {
295                    LOG.logWarning( "Symbol style not supported yet: " + map );
296                    return;
297                }
298    
299                File file = new File( map.get( "filename" ) );
300                if ( !file.exists() ) {
301                    LOG.logWarning( "The specified symbol does not exist: " + file.toString() );
302                    return;
303                }
304    
305                Element e = getRequiredElement( doc.getRootElement(), ".//" + SLD_PREFIX + ":FeatureTypeStyle", nsContext );
306                e = appendElement( e, SLDNS, SLD_PREFIX + ":Rule" );
307                appendIDFilter( map.get( "styleid" ), e );
308                e = appendElement( e, SLDNS, SLD_PREFIX + ":PointSymbolizer" );
309                e = appendElement( e, SLDNS, SLD_PREFIX + ":Graphic" );
310                appendElement( e, SLDNS, SLD_PREFIX + ":Size", "" + size );
311                e = appendElement( e, SLDNS, SLD_PREFIX + ":ExternalGraphic" );
312                Element o = appendElement( e, SLDNS, SLD_PREFIX + ":OnlineResource" );
313                o.setAttributeNS( XLNNS.toASCIIString(), XLINK_PREFIX + ":href", file.toURI().toURL().toExternalForm() );
314                o.setAttributeNS( XLNNS.toASCIIString(), XLINK_PREFIX + ":type", "simple" );
315                appendElement( e, SLDNS, SLD_PREFIX + ":Format", "image/bmp" );
316    
317                return;
318            }
319    
320            Color c = decode( map.get( "color" ) );
321    
322            int size = parseInt( map.get( "size" ) );
323            int symbol = parseInt( map.get( "shape" ) );
324    
325            BufferedImage img = null;
326    
327            switch ( symbol ) {
328            case 31:
329                // don't do anything
330                return;
331            case 32:
332                img = symbolFromTwoChars( symbolFont, (char) 61473, (char) 61479, size, c, black );
333                break;
334            case 33:
335                img = symbolFromTwoChars( symbolFont, (char) 61474, (char) 61480, size, c, black );
336                break;
337            case 34:
338                img = symbolFromTwoChars( symbolFont, (char) 61475, (char) 61481, size, c, black );
339                break;
340            case 35:
341                img = symbolFromTwoChars( symbolFont, (char) 61476, (char) 61482, size, c, black );
342                break;
343            case 36:
344                img = symbolFromTwoChars( symbolFont, (char) 61477, (char) 61483, size, c, black );
345                break;
346            case 37:
347                img = symbolFromTwoChars( symbolFont, (char) 61478, (char) 61484, size, c, black );
348                break;
349            case 38:
350            case 39:
351            case 40:
352            case 41:
353            case 42:
354            case 43:
355            case 49:
356            case 50:
357            case 51:
358            case 52:
359            case 53:
360            case 54:
361            case 55:
362            case 56:
363            case 57:
364            case 58:
365            case 60:
366            case 61:
367            case 62:
368            case 63:
369            case 64:
370                img = symbolFromFont( symbolFont, (char) ( 61473 + symbol - 32 ), size, c );
371                break;
372            case 44:
373            case 45:
374            case 46:
375            case 47:
376            case 48:
377            case 65:
378            case 66:
379            case 67: {
380                ZipFile zip = new ZipFile( POINTS );
381                ZipEntry entry = zip.getEntry( symbol + ".svg" );
382                XMLFragment svg = new XMLFragment( new InputStreamReader( zip.getInputStream( entry ) ),
383                                                   "http://www.systemid.org" );
384                zip.close();
385                updateSVGColors( svg, toHexColor( c ), toHexColor( c ) );
386                img = renderSVGImage( svg, size );
387                break;
388            }
389            case 59: {
390                ZipFile zip = new ZipFile( POINTS );
391                ZipEntry entry = zip.getEntry( symbol + ".svg" );
392                XMLFragment svg = new XMLFragment( new InputStreamReader( zip.getInputStream( entry ) ),
393                                                   "http://www.systemid.org" );
394                zip.close();
395                updateSVGColors( svg, toHexColor( c ), toHexColor( c ) );
396                img = renderSVGImage( svg, size );
397                break;
398            }
399            }
400    
401            if ( img == null ) {
402                img = new BufferedImage( 1, 1, TYPE_INT_ARGB );
403            }
404    
405            File symbolFile = createTempFile( "mmsvg", ".png" );
406            write( img, "png", symbolFile );
407            symbolFile.deleteOnExit();
408    
409            Element e = getRequiredElement( doc.getRootElement(), ".//" + SLD_PREFIX + ":FeatureTypeStyle", nsContext );
410            e = appendElement( e, SLDNS, SLD_PREFIX + ":Rule" );
411            appendIDFilter( map.get( "styleid" ), e );
412            e = appendElement( e, SLDNS, SLD_PREFIX + ":PointSymbolizer" );
413            e = appendElement( e, SLDNS, SLD_PREFIX + ":Graphic" );
414            e = appendElement( e, SLDNS, SLD_PREFIX + ":ExternalGraphic" );
415            Element o = appendElement( e, SLDNS, SLD_PREFIX + ":OnlineResource" );
416            o.setAttributeNS( XLNNS.toASCIIString(), XLINK_PREFIX + ":href", symbolFile.toURI().toURL().toExternalForm() );
417            o.setAttributeNS( XLNNS.toASCIIString(), XLINK_PREFIX + ":type", "simple" );
418            appendElement( e, SLDNS, SLD_PREFIX + ":Format", "image/png" );
419        }
420    
421        private static void appendSimpleLine( Element rule, String cssPattern, int width, Color c ) {
422            Element e = appendElement( rule, SLDNS, SLD_PREFIX + ":LineSymbolizer" );
423            e = appendElement( e, SLDNS, SLD_PREFIX + ":Stroke" );
424            appendElement( e, SLDNS, SLD_PREFIX + ":CssParameter", toHexColor( c ) ).setAttribute( "name", "stroke" );
425            appendElement( e, SLDNS, SLD_PREFIX + ":CssParameter", "" + width ).setAttribute( "name", "stroke-width" );
426            if ( cssPattern != null ) {
427                appendElement( e, SLDNS, SLD_PREFIX + ":CssParameter", cssPattern ).setAttribute( "name",
428                                                                                                  "stroke-dasharray" );
429            }
430        }
431    
432        private static void appendImageLine( Element rule, String image, int width, Color c )
433                                throws MalformedURLException, IOException, SAXException, XMLParsingException {
434            XMLFragment svg = new XMLFragment( MIFStyle2SLD.class.getResource( "lines/" + image ) );
435            updateSVGColors( svg, toHexColor( c ), toHexColor( c ) );
436            BufferedImage img = renderSVGImage( svg, 0 );
437            File svgFile = createTempFile( "mmsvg", ".png" );
438            write( img, "png", svgFile );
439            svgFile.deleteOnExit();
440    
441            Element e = appendElement( rule, SLDNS, SLD_PREFIX + ":LineSymbolizer" );
442            e = appendElement( e, SLDNS, SLD_PREFIX + ":Stroke" );
443            appendElement( e, SLDNS, SLD_PREFIX + ":CssParameter", "0" ).setAttribute( "name", "stroke-width" );
444            appendElement( e, SLDNS, SLD_PREFIX + ":CssParameter", "0" ).setAttribute( "name", "stroke-opacity" );
445            e = appendElement( e, SLDNS, SLD_PREFIX + ":GraphicStroke" );
446            e = appendElement( e, SLDNS, SLD_PREFIX + ":Graphic" );
447            appendElement( e, SLDNS, SLD_PREFIX + ":Size", "" + width );
448            e = appendElement( e, SLDNS, SLD_PREFIX + ":ExternalGraphic" );
449            Element o = appendElement( e, SLDNS, SLD_PREFIX + ":OnlineResource" );
450            o.setAttributeNS( XLNNS.toASCIIString(), XLINK_PREFIX + ":href", svgFile.toURI().toURL().toExternalForm() );
451            o.setAttributeNS( XLNNS.toASCIIString(), XLINK_PREFIX + ":type", "simple" );
452            appendElement( e, SLDNS, SLD_PREFIX + ":Format", "image/png" );
453        }
454    
455        /**
456         * @param pattern
457         *            a pattern like "1 2 1 2"
458         * @param mult
459         * @return the new pattern with each value multiplied by mult
460         */
461        public static String multiplyPattern( String pattern, int mult ) {
462            String[] elems = pattern.split( "[ ]" );
463            StringBuffer sb = new StringBuffer( pattern.length() );
464    
465            for ( int i = 0; i < elems.length; ++i ) {
466                int k = mult * parseInt( elems[i] );
467                sb.append( k );
468                if ( i < elems.length - 1 ) {
469                    sb.append( " " );
470                }
471            }
472    
473            return sb.toString();
474        }
475    
476        /**
477         * @param map
478         * @param doc
479         * @throws XMLParsingException
480         * @throws SAXException
481         * @throws IOException
482         * @throws MalformedURLException
483         */
484        public static void insertPenStyle( Map<String, String> map, XMLFragment doc )
485                                throws MalformedURLException, IOException, SAXException, XMLParsingException {
486            int pattern = parseInt( map.get( "pattern" ) );
487            Color c = decode( map.get( "color" ) );
488            int width = parseInt( map.get( "width" ) );
489            if ( width > 10 ) {
490                width = width * 10 + 10;
491                width = (int) ( width / 72d / SQRT2 );
492                LOG.logDebug( "Calculated pixel width from points", width );
493            }
494    
495            Element e = getRequiredElement( doc.getRootElement(), ".//" + SLD_PREFIX + ":FeatureTypeStyle", nsContext );
496            Element rule = appendElement( e, SLDNS, SLD_PREFIX + ":Rule" );
497            appendIDFilter( map.get( "styleid" ), rule );
498    
499            switch ( pattern ) {
500            case 1:
501                break;
502            case 2:
503                appendSimpleLine( rule, null, width, c );
504                break;
505            case 3:
506                appendSimpleLine( rule, multiplyPattern( "1 1", width ), width, c );
507                break;
508            case 4:
509                appendSimpleLine( rule, multiplyPattern( "2 2", width ), width, c );
510                break;
511            case 5:
512                appendSimpleLine( rule, multiplyPattern( "3 1", width ), width, c );
513                break;
514            case 6:
515                appendSimpleLine( rule, multiplyPattern( "5 1", width ), width, c );
516                break;
517            case 7:
518                appendSimpleLine( rule, multiplyPattern( "10 3", width ), width, c );
519                break;
520            case 8:
521                appendSimpleLine( rule, multiplyPattern( "20 5", width ), width, c );
522                break;
523            case 9:
524                appendSimpleLine( rule, multiplyPattern( "5 5", width ), width, c );
525                break;
526            case 10:
527                appendSimpleLine( rule, multiplyPattern( "1 5", width ), width, c );
528                break;
529            case 11:
530                appendSimpleLine( rule, multiplyPattern( "3 5", width ), width, c );
531                break;
532            case 12:
533                appendSimpleLine( rule, multiplyPattern( "7 7", width ), width, c );
534                break;
535            case 13:
536                appendSimpleLine( rule, multiplyPattern( "10 10", width ), width, c );
537                break;
538            case 14:
539                appendSimpleLine( rule, multiplyPattern( "9 3 1 3", width ), width, c );
540                break;
541            case 15:
542                appendSimpleLine( rule, multiplyPattern( "12 2 1 2", width ), width, c );
543                break;
544            case 16:
545                appendSimpleLine( rule, multiplyPattern( "12 2 2 2", width ), width, c );
546                break;
547            case 17:
548                appendSimpleLine( rule, multiplyPattern( "20 10 5 10", width ), width, c );
549                break;
550            case 18:
551                appendSimpleLine( rule, multiplyPattern( "20 4 4 4 4 4", width ), width, c );
552                break;
553            case 19:
554                appendSimpleLine( rule, multiplyPattern( "20 4 4 4 4 4 4 4", width ), width, c );
555                break;
556            case 20:
557                appendSimpleLine( rule, multiplyPattern( "9 3 1 3 1 3", width ), width, c );
558                break;
559            case 21:
560                appendSimpleLine( rule, multiplyPattern( "12 3 1 3 1 3", width ), width, c );
561                break;
562            case 22:
563                appendSimpleLine( rule, multiplyPattern( "12 3 1 3 1 3 1 3", width ), width, c );
564                break;
565            case 23:
566                appendSimpleLine( rule, multiplyPattern( "5 1 1 1", width ), width, c );
567                break;
568            case 24:
569                appendSimpleLine( rule, multiplyPattern( "5 1 1 1 1 1", width ), width, c );
570                break;
571            case 25:
572                appendSimpleLine( rule, multiplyPattern( "9 1 1 1 3 1 1 1", width ), width, c );
573                break;
574            case 26: {
575                appendSimpleLine( rule, null, width, c );
576                appendSimpleLine( rule, multiplyPattern( "1 8", width ), width * 5, c );
577                break;
578            }
579            case 27: {
580                appendSimpleLine( rule, null, width, c );
581                appendSimpleLine( rule, multiplyPattern( "1 10", width ), width * 5, c );
582                break;
583            }
584            case 28: {
585                appendSimpleLine( rule, null, width, c );
586                appendSimpleLine( rule, multiplyPattern( "1 15", width ), width * 5, c );
587                break;
588            }
589            case 29: {
590                appendSimpleLine( rule, null, width, c );
591                appendImageLine( rule, "29.svg", width * 16, c );
592                break;
593            }
594            case 30: {
595                appendSimpleLine( rule, null, width, c );
596                appendImageLine( rule, "30.svg", width * 16, c );
597                break;
598            }
599            case 31: {
600                appendSimpleLine( rule, null, width, c );
601                appendSimpleLine( rule, multiplyPattern( "1 1 12", width ), width * 5, c );
602                break;
603            }
604            case 32: {
605                appendSimpleLine( rule, multiplyPattern( "6 3 5 0", width ), width, c );
606                appendSimpleLine( rule, multiplyPattern( "1 13", width ), width * 5, c );
607                break;
608            }
609            case 33: {
610                appendSimpleLine( rule, multiplyPattern( "7 3 4 0", width ), width, c );
611                appendSimpleLine( rule, multiplyPattern( "1 1 1 11", width ), width * 5, c );
612                break;
613            }
614            case 34: {
615                appendSimpleLine( rule, multiplyPattern( "0 1 10 2", width ), width, c );
616                appendImageLine( rule, "34.svg", width * 26, c );
617                break;
618            }
619            case 35: {
620                appendSimpleLine( rule, multiplyPattern( "0 1 10 2", width ), width, c );
621                appendImageLine( rule, "35.svg", width * 26, c );
622                break;
623            }
624            case 36: {
625                appendImageLine( rule, "36.svg", width * 11, c );
626                break;
627            }
628            case 37: {
629                appendSimpleLine( rule, multiplyPattern( "10 3", width ), width, c );
630                appendSimpleLine( rule, multiplyPattern( "1 8 1 3", width ), width * 5, c );
631                break;
632            }
633            case 38: {
634                appendSimpleLine( rule, null, width, c );
635                appendImageLine( rule, "38-39.svg", width * 20, c );
636                break;
637            }
638            case 39: {
639                appendSimpleLine( rule, multiplyPattern( "0 3 10 7", width ), width, c );
640                appendImageLine( rule, "38-39.svg", width * 20, c );
641                break;
642            }
643            case 40: {
644                appendSimpleLine( rule, multiplyPattern( "10 3 3 3", width ), width, c );
645                appendSimpleLine( rule, multiplyPattern( "0 14 1 4", width ), width * 5, c );
646                break;
647            }
648            case 41: {
649                appendSimpleLine( rule, multiplyPattern( "0 5 4 1", width ), width, c );
650                appendSimpleLine( rule, multiplyPattern( "4 1 0 5", width ), width * 3, c );
651                break;
652            }
653            case 42: {
654                appendSimpleLine( rule, multiplyPattern( "0 5 4 1 4 1", width ), width, c );
655                appendSimpleLine( rule, multiplyPattern( "5 10", width ), width * 3, c );
656                break;
657            }
658            case 43: {
659                appendSimpleLine( rule, multiplyPattern( "0 5 4 1 4 1 4 1", width ), width, c );
660                appendSimpleLine( rule, multiplyPattern( "5 15", width ), width * 3, c );
661                break;
662            }
663            case 44: {
664                appendSimpleLine( rule, multiplyPattern( "0 5 4 1 4 1 4 1 4 1", width ), width, c );
665                appendSimpleLine( rule, multiplyPattern( "5 20", width ), width * 3, c );
666                break;
667            }
668            case 45: {
669                appendSimpleLine( rule, null, width, c );
670                appendSimpleLine( rule, multiplyPattern( "4 15", width ), width * 3, c );
671                break;
672            }
673            case 46: {
674                appendSimpleLine( rule, multiplyPattern( "1 3", width ), width * 4, c );
675                break;
676            }
677            case 47: {
678                appendImageLine( rule, "47.svg", width * 7, c );
679                break;
680            }
681            case 48: {
682                appendSimpleLine( rule, null, width, c );
683                appendImageLine( rule, "48.svg", width * 5, c );
684                break;
685            }
686            case 49: {
687                appendSimpleLine( rule, null, width, c );
688                appendImageLine( rule, "49.svg", width * 5, c );
689                break;
690            }
691            case 50: {
692                appendSimpleLine( rule, null, width, c );
693                appendImageLine( rule, "50.svg", width * 6, c );
694                break;
695            }
696            case 51: {
697                appendSimpleLine( rule, null, width, c );
698                appendImageLine( rule, "51.svg", width * 6, c );
699                break;
700            }
701            case 52: {
702                appendSimpleLine( rule, multiplyPattern( "0 3 10 1", width ), width, c );
703                appendImageLine( rule, "52.svg", width * 14, c );
704                break;
705            }
706            case 53: {
707                appendSimpleLine( rule, multiplyPattern( "0 3 10 1", width ), width, c );
708                appendImageLine( rule, "53.svg", width * 14, c );
709                break;
710            }
711            case 54: {
712                appendSimpleLine( rule, null, width, c );
713                appendImageLine( rule, "54.svg", width * 11, c );
714                break;
715            }
716            case 55: {
717                appendSimpleLine( rule, null, width, c );
718                appendImageLine( rule, "55.svg", width * 11, c );
719                break;
720            }
721            case 56: {
722                appendSimpleLine( rule, null, width, c );
723                appendImageLine( rule, "56.svg", width * 16, c );
724                break;
725            }
726            case 57:
727            case 58: {
728                appendImageLine( rule, pattern + ".svg", width * 11, c );
729                break;
730            }
731            case 63: {
732                appendSimpleLine( rule, null, width + 1, c );
733                appendSimpleLine( rule, null, width, white );
734                break;
735            }
736            case 65: {
737                appendSimpleLine( rule, null, width + 1, black );
738                appendSimpleLine( rule, null, width, c );
739                break;
740            }
741            case 67: {
742                appendSimpleLine( rule, null, width + 1, c );
743                appendSimpleLine( rule, null, width, black );
744                break;
745            }
746            case 68: {
747                appendSimpleLine( rule, multiplyPattern( "12 3", width ), width + 1, c );
748                appendSimpleLine( rule, null, width, white );
749                break;
750            }
751            case 69: {
752                appendSimpleLine( rule, null, width + 1, c );
753                appendSimpleLine( rule, null, width, white );
754                appendSimpleLine( rule, "1 " + 20 * width, width * 5, c );
755                break;
756            }
757            case 70: {
758                appendSimpleLine( rule, multiplyPattern( "15 15", width ), width, c );
759                appendSimpleLine( rule, multiplyPattern( "0 15 15 0", width ), width, black );
760                break;
761            }
762            case 71: {
763                appendSimpleLine( rule, multiplyPattern( "17 23", width ), width, c );
764                appendSimpleLine( rule, multiplyPattern( "0 20 17 3", width ), width, black );
765                break;
766            }
767            case 72: {
768                appendSimpleLine( rule, multiplyPattern( "25 5", width ), width + 1, black );
769                appendSimpleLine( rule, null, width, c );
770                break;
771            }
772            case 73: {
773                appendSimpleLine( rule, null, width + 1, c );
774                appendSimpleLine( rule, multiplyPattern( "12 12", width ), width, white );
775                break;
776            }
777            case 74: {
778                appendSimpleLine( rule, null, width + 1, black );
779                appendSimpleLine( rule, multiplyPattern( "12 12", width ), width, c );
780                break;
781            }
782            case 75: {
783                appendSimpleLine( rule, null, width + 1, black );
784                appendSimpleLine( rule, multiplyPattern( "12 12", width ), width, c );
785                appendSimpleLine( rule, multiplyPattern( "0 12 12 0", width ), width, white );
786                break;
787            }
788            case 76: {
789                appendSimpleLine( rule, null, width + 1, black );
790                appendSimpleLine( rule, multiplyPattern( "25 25", width ), width, c );
791                appendSimpleLine( rule, multiplyPattern( "0 25 25 0", width ), width, white );
792                break;
793            }
794            case 77: {
795                appendSimpleLine( rule, null, width + 1, c );
796                appendSimpleLine( rule, multiplyPattern( "12 12", width ), width, black );
797                appendSimpleLine( rule, multiplyPattern( "0 12 12 0", width ), width, white );
798                break;
799            }
800            case 81: {
801                appendSimpleLine( rule, null, width, black );
802                appendImageLine( rule, "81-85.svg", width * 10, c );
803                break;
804            }
805            case 82: {
806                appendImageLine( rule, "81-85.svg", width * 10, c );
807                break;
808            }
809            case 83: {
810                appendSimpleLine( rule, multiplyPattern( "0 2 1 7", width ), width, black );
811                appendImageLine( rule, "81-85.svg", width * 10, c );
812                break;
813            }
814            case 84: {
815                appendSimpleLine( rule, null, width * 5, black );
816                appendSimpleLine( rule, null, width * 5 - 1, white );
817                appendImageLine( rule, "81-85.svg", width * 10, c );
818                break;
819            }
820            case 85: {
821                appendSimpleLine( rule, null, width * 6 + 1, black );
822                appendSimpleLine( rule, null, width * 6, white );
823                appendImageLine( rule, "81-85.svg", width * 10, c );
824                break;
825            }
826            case 89: {
827                appendSimpleLine( rule, null, width, black );
828                appendSimpleLine( rule, multiplyPattern( "5 5", width ), width * 5, c );
829                break;
830            }
831            case 90: {
832                appendSimpleLine( rule, multiplyPattern( "5 5", width ), width * 5, c );
833                break;
834            }
835            case 91: {
836                appendSimpleLine( rule, multiplyPattern( "0 7 1 2", width ), width, black );
837                appendSimpleLine( rule, multiplyPattern( "5 5", width ), width * 5, c );
838                break;
839            }
840            case 92: {
841                appendSimpleLine( rule, null, width * 5, black );
842                appendSimpleLine( rule, null, width * 5 - 1, white );
843                appendSimpleLine( rule, multiplyPattern( "5 5", width ), width * 5, c );
844                break;
845            }
846            case 93: {
847                appendSimpleLine( rule, null, width * 6 + 1, black );
848                appendSimpleLine( rule, null, width * 6, white );
849                appendSimpleLine( rule, multiplyPattern( "5 5", width ), width * 5, c );
850                break;
851            }
852            case 97: {
853                appendSimpleLine( rule, null, width, black );
854                appendImageLine( rule, "97-101.svg", width * 10, c );
855                break;
856            }
857            case 98: {
858                appendImageLine( rule, "97-101.svg", width * 10, c );
859                break;
860            }
861            case 99: {
862                appendSimpleLine( rule, multiplyPattern( "0 2 1 7", width ), width, black );
863                appendImageLine( rule, "97-101.svg", width * 10, c );
864                break;
865            }
866            case 100: {
867                appendSimpleLine( rule, null, width * 5, black );
868                appendSimpleLine( rule, null, width * 5 - 1, white );
869                appendImageLine( rule, "97-101.svg", width * 10, c );
870                break;
871            }
872            case 101: {
873                appendSimpleLine( rule, null, width * 6 + 1, black );
874                appendSimpleLine( rule, null, width * 6, white );
875                appendImageLine( rule, "97-101.svg", width * 10, c );
876                break;
877            }
878            case 105: {
879                appendSimpleLine( rule, null, width, black );
880                appendImageLine( rule, "105-109.svg", width * 10, c );
881                break;
882            }
883            case 106: {
884                appendImageLine( rule, "105-109.svg", width * 10, c );
885                break;
886            }
887            case 107: {
888                appendSimpleLine( rule, multiplyPattern( "0 2 1 7", width ), width, black );
889                appendImageLine( rule, "105-109.svg", width * 10, c );
890                break;
891            }
892            case 108: {
893                appendSimpleLine( rule, null, width * 5, black );
894                appendSimpleLine( rule, null, width * 5 - 1, white );
895                appendImageLine( rule, "105-109.svg", width * 10, c );
896                break;
897            }
898            case 109: {
899                appendSimpleLine( rule, null, width * 6 + 1, black );
900                appendSimpleLine( rule, null, width * 6, white );
901                appendImageLine( rule, "105-109.svg", width * 10, c );
902                break;
903            }
904            case 114: {
905                appendSimpleLine( rule, null, width * 3, c );
906                appendImageLine( rule, "114.svg", width * 20, c );
907                break;
908            }
909            case 115: {
910                appendSimpleLine( rule, null, width * 3, c );
911                appendImageLine( rule, "115.svg", width * 20, c );
912                break;
913            }
914            case 116: {
915                appendSimpleLine( rule, null, width * 3, c );
916                appendImageLine( rule, "116.svg", width * 20, c );
917                break;
918            }
919            case 117: {
920                appendSimpleLine( rule, null, width * 2, c );
921                appendImageLine( rule, "117.svg", width * 10, c );
922                break;
923            }
924            case 118: {
925                appendSimpleLine( rule, null, width * 5 + 1, black );
926                appendSimpleLine( rule, null, width * 5, white );
927                appendSimpleLine( rule, multiplyPattern( "1 5", width ), width * 10, c );
928                break;
929            }
930            default:
931                LOG.logWarning( "Ignoring fancy pen style, as it cannot be mapped to SLD." );
932                break;
933            }
934    
935        }
936    
937        private static final DecimalFormat formatter = new DecimalFormat( "000" );
938    
939        /**
940         * @param map
941         * @param doc
942         * @param name
943         * @throws SAXException
944         * @throws IOException
945         * @throws MalformedURLException
946         * @throws XMLParsingException
947         */
948        public static void insertBrushStyle( Map<String, String> map, XMLFragment doc, String name )
949                                throws MalformedURLException, IOException, SAXException, XMLParsingException {
950            int pattern = parseInt( map.get( "pattern" ) );
951            Color fore = decode( map.get( "forecolor" ) );
952            Color back = null;
953            if ( map.get( "backcolor" ) != null ) {
954                back = decode( map.get( "backcolor" ) );
955            }
956    
957            if ( pattern == 1 ) {
958                return;
959            }
960    
961            if ( pattern == 2 ) {
962                Element e = getRequiredElement( doc.getRootElement(), ".//" + SLD_PREFIX + ":FeatureTypeStyle", nsContext );
963                e = appendElement( e, SLDNS, SLD_PREFIX + ":Rule" );
964                appendIDFilter( map.get( "styleid" ), e );
965                appendElement( e, SLDNS, SLD_PREFIX + ":Name", "default:" + name );
966                e = appendElement( e, SLDNS, SLD_PREFIX + ":PolygonSymbolizer" );
967                e = appendElement( e, SLDNS, SLD_PREFIX + ":Fill" );
968                appendElement( e, SLDNS, SLD_PREFIX + ":CssParameter", toHexColor( fore ) ).setAttribute( "name", "fill" );
969                return;
970            }
971    
972            ZipFile zip = new ZipFile( MIFStyle2SLD.BRUSHES );
973            ZipEntry entry = zip.getEntry( formatter.format( pattern ) + ".svg" );
974    
975            XMLFragment svg = null;
976            try {
977                svg = new XMLFragment( new InputStreamReader( zip.getInputStream( entry ), "UTF-8" ),
978                                       "http://www.systemid.org" );
979                zip.close();
980            } catch ( NullPointerException npe ) {
981                LOG.logWarning( "Could not find brush symbol for brush number " + pattern );
982                return;
983            }
984    
985            updateFillPatternSVG( svg, toHexColor( fore ), back == null ? null : toHexColor( back ) );
986    
987            BufferedImage img = renderSVGImage( svg, 0 );
988            File svgFile = createTempFile( "mmsvg", ".png" );
989            write( img, "png", svgFile );
990            svgFile.deleteOnExit();
991    
992            Element e = getRequiredElement( doc.getRootElement(), ".//" + SLD_PREFIX + ":FeatureTypeStyle", nsContext );
993            e = appendElement( e, SLDNS, SLD_PREFIX + ":Rule" );
994            appendIDFilter( map.get( "styleid" ), e );
995            e = appendElement( e, SLDNS, SLD_PREFIX + ":PolygonSymbolizer" );
996            e = appendElement( e, SLDNS, SLD_PREFIX + ":Fill" );
997            e = appendElement( e, SLDNS, SLD_PREFIX + ":GraphicFill" );
998            e = appendElement( e, SLDNS, SLD_PREFIX + ":Graphic" );
999            e = appendElement( e, SLDNS, SLD_PREFIX + ":ExternalGraphic" );
1000            Element o = appendElement( e, SLDNS, SLD_PREFIX + ":OnlineResource" );
1001            o.setAttributeNS( XLNNS.toASCIIString(), XLINK_PREFIX + ":href", svgFile.toURI().toURL().toExternalForm() );
1002            o.setAttributeNS( XLNNS.toASCIIString(), XLINK_PREFIX + ":type", "simple" );
1003            appendElement( e, SLDNS, SLD_PREFIX + ":Format", "image/png" );
1004        }
1005    
1006        /**
1007         * @param map
1008         * @param doc
1009         * @throws XMLParsingException
1010         */
1011        public static void insertTextStyle( Map<String, String> map, XMLFragment doc )
1012                                throws XMLParsingException {
1013            String fontName = map.get( "fontname" );
1014            int styles = parseInt( map.get( "style" ) );
1015            String style = ( styles & 2 ) == 2 ? "italic" : "normal";
1016            String weight = ( styles & 1 ) == 1 ? "bold" : "normal";
1017            boolean halo = ( styles & 256 ) == 256;
1018            Color fore = decode( map.get( "forecolor" ) );
1019            Color back = null;
1020            if ( map.get( "backcolor" ) != null ) {
1021                back = decode( map.get( "backcolor" ) );
1022            }
1023    
1024            Element e = getRequiredElement( doc.getRootElement(), ".//" + SLD_PREFIX + ":FeatureTypeStyle", nsContext );
1025            e = appendElement( e, SLDNS, SLD_PREFIX + ":Rule" );
1026            appendIDFilter( map.get( "styleid" ), e );
1027            Element symbolizer = appendElement( e, SLDNS, SLD_PREFIX + ":TextSymbolizer" );
1028            e = appendElement( symbolizer, SLDNS, SLD_PREFIX + ":Label" );
1029            appendElement( e, OGCNS, OGC_PREFIX + ":PropertyName", "app:text_geometry" );
1030            e = appendElement( symbolizer, SLDNS, SLD_PREFIX + ":Font" );
1031            appendElement( e, SLDNS, SLD_PREFIX + ":CssParameter", fontName ).setAttribute( "name", "font-family" );
1032            appendElement( e, SLDNS, SLD_PREFIX + ":CssParameter", style ).setAttribute( "name", "font-style" );
1033            appendElement( e, SLDNS, SLD_PREFIX + ":CssParameter", weight ).setAttribute( "name", "font-weight" );
1034            appendElement( e, SLDNS, SLD_PREFIX + ":CssParameter", toHexColor( fore ) ).setAttribute( "name", "font-color" );
1035            e = appendElement( e, SLDNS, SLD_PREFIX + ":CssParameter", "92" ); // TODO max font size?
1036            e.setAttribute( "name", "font-size" );
1037            // Element div = appendElement( e, OGCNS, OGC_PREFIX + ":Div" );
1038            // appendElement( div, OGCNS, OGC_PREFIX + ":Literal", map.get( "ratio" ) );
1039            // appendElement( div, OGCNS, OGC_PREFIX + ":PropertyName", "app:$SCALE" );
1040            if ( halo ) {
1041                e = appendElement( symbolizer, SLDNS, SLD_PREFIX + ":Halo" );
1042                appendElement( e, SLDNS, SLD_PREFIX + ":Radius", "2" );
1043                e = appendElement( e, SLDNS, SLD_PREFIX + ":Fill" );
1044                e = appendElement( e, SLDNS, SLD_PREFIX + ":CssParameter", back == null ? "#ffffff" : toHexColor( back ) );
1045                e.setAttribute( "name", "fill" );
1046            }
1047            e = appendElement( symbolizer, SLDNS, SLD_PREFIX + ":Fill" );
1048            appendElement( e, SLDNS, SLD_PREFIX + ":CssParameter", toHexColor( fore ) ).setAttribute( "name", "fill" );
1049    
1050            e = appendElement( symbolizer, SLDNS, SLD_PREFIX + ":BoundingBox" );
1051            Element m = appendElement( e, SLDNS, SLD_PREFIX + ":Minx" );
1052            appendElement( m, OGCNS, OGC_PREFIX + ":PropertyName", "app:text_minx" );
1053            m = appendElement( e, SLDNS, SLD_PREFIX + ":Miny" );
1054            appendElement( m, OGCNS, OGC_PREFIX + ":PropertyName", "app:text_miny" );
1055            m = appendElement( e, SLDNS, SLD_PREFIX + ":Maxx" );
1056            appendElement( m, OGCNS, OGC_PREFIX + ":PropertyName", "app:text_maxx" );
1057            m = appendElement( e, SLDNS, SLD_PREFIX + ":Maxy" );
1058            appendElement( m, OGCNS, OGC_PREFIX + ":PropertyName", "app:text_maxy" );
1059        }
1060    
1061        /**
1062         * @param styles
1063         * @param name
1064         *            the layer name
1065         * @return a SLD document with temporary file references for point symbols
1066         */
1067        public XMLFragment getStyle( Map<String, HashSet<HashMap<String, String>>> styles, String name ) {
1068            XMLFragment doc = getSLDTemplate( name );
1069    
1070            HashSet<HashMap<String, String>> symbols = styles.get( "symbol" );
1071            if ( LOG.isDebug() ) {
1072                LOG.logDebug( "Found " + ( symbols == null ? "no" : symbols.size() ) + " symbol styles." );
1073            }
1074            if ( symbols != null ) {
1075                for ( Map<String, String> map : symbols ) {
1076                    try {
1077                        insertSymbolStyle( map, doc );
1078                    } catch ( DOMException e ) {
1079                        LOG.logError( "Unknown error", e );
1080                    } catch ( IOException e ) {
1081                        LOG.logError( "Unknown error", e );
1082                    } catch ( XMLParsingException e ) {
1083                        LOG.logError( "Unknown error", e );
1084                    } catch ( SAXException e ) {
1085                        LOG.logError( "Unknown error", e );
1086                    }
1087                }
1088            }
1089    
1090            HashSet<HashMap<String, String>> pens = styles.get( "pen" );
1091            if ( LOG.isDebug() ) {
1092                LOG.logDebug( "Found " + ( pens == null ? "no" : pens.size() ) + " pen styles." );
1093            }
1094            if ( pens != null ) {
1095                for ( Map<String, String> map : pens ) {
1096                    try {
1097                        insertPenStyle( map, doc );
1098                    } catch ( MalformedURLException e ) {
1099                        LOG.logError( "Unknown error", e );
1100                    } catch ( IOException e ) {
1101                        LOG.logError( "Unknown error", e );
1102                    } catch ( SAXException e ) {
1103                        LOG.logError( "Unknown error", e );
1104                    } catch ( XMLParsingException e ) {
1105                        LOG.logError( "Unknown error", e );
1106                    }
1107                }
1108            }
1109    
1110            HashSet<HashMap<String, String>> brushes = styles.get( "brush" );
1111            if ( LOG.isDebug() ) {
1112                LOG.logDebug( "Found " + ( brushes == null ? "no" : brushes.size() ) + " brushes." );
1113            }
1114            if ( brushes != null ) {
1115                for ( Map<String, String> map : brushes ) {
1116                    try {
1117                        insertBrushStyle( map, doc, name );
1118                    } catch ( MalformedURLException e ) {
1119                        LOG.logError( "Unknown error", e );
1120                    } catch ( IOException e ) {
1121                        LOG.logError( "Unknown error", e );
1122                    } catch ( SAXException e ) {
1123                        LOG.logError( "Unknown error", e );
1124                    } catch ( XMLParsingException e ) {
1125                        LOG.logError( "Unknown error", e );
1126                    }
1127                }
1128            }
1129    
1130            HashSet<HashMap<String, String>> texts = styles.get( "text" );
1131            if ( LOG.isDebug() ) {
1132                LOG.logDebug( "Found " + ( texts == null ? "no" : texts.size() ) + " texts." );
1133            }
1134            if ( texts != null ) {
1135                for ( Map<String, String> map : texts ) {
1136                    try {
1137                        insertTextStyle( map, doc );
1138                    } catch ( XMLParsingException e ) {
1139                        LOG.logError( "Unknown error", e );
1140                    }
1141                }
1142            }
1143    
1144            if ( LOG.isDebug() ) {
1145                LOG.logDebug( "Generated SLD document", doc.getAsPrettyString() );
1146            }
1147    
1148            return doc;
1149        }
1150    
1151        /**
1152         * @param doc
1153         * @param size
1154         * @return an SVG image with black colors overwritten with the given colors
1155         */
1156        public static BufferedImage renderSVGImage( XMLFragment doc, int size ) {
1157            ByteArrayOutputStream bos = new ByteArrayOutputStream( size * size * 4 );
1158            TranscoderOutput output = new TranscoderOutput( bos );
1159    
1160            PNGTranscoder trc = new PNGTranscoder();
1161            try {
1162                Element root = doc.getRootElement();
1163                TranscoderInput input = new TranscoderInput( root.getOwnerDocument() );
1164                if ( size > 0 ) {
1165                    trc.addTranscodingHint( KEY_HEIGHT, new Float( size ) );
1166                    trc.addTranscodingHint( KEY_WIDTH, new Float( size ) );
1167                }
1168                trc.transcode( input, output );
1169                bos.close();
1170                ByteArrayInputStream is = new ByteArrayInputStream( bos.toByteArray() );
1171                MemoryCacheSeekableStream mcss = new MemoryCacheSeekableStream( is );
1172                RenderedOp rop = create( "stream", mcss );
1173                return rop.getAsBufferedImage();
1174            } catch ( TranscoderException e ) {
1175                LOG.logError( "Unknown error", e );
1176            } catch ( MalformedURLException e ) {
1177                LOG.logError( "Unknown error", e );
1178            } catch ( IOException e ) {
1179                LOG.logError( "Unknown error", e );
1180            }
1181    
1182            return null;
1183        }
1184    
1185        /**
1186         * @param col
1187         * @return a #rrggbb string
1188         */
1189        public static String toHexColor( Color col ) {
1190            if ( col == null ) {
1191                col = black;
1192            }
1193            String scol = toHexString( col.getRGB() & 0xffffff );
1194            while ( scol.length() < 6 ) {
1195                scol = "0" + scol;
1196            }
1197    
1198            return "#" + scol;
1199        }
1200    
1201        /**
1202         * @param doc
1203         * @param stroke
1204         * @param fill
1205         * @throws XMLParsingException
1206         */
1207        public static void updateSVGColors( XMLFragment doc, String fill, String stroke )
1208                                throws XMLParsingException {
1209            List<Node> ns = getNodes( doc.getRootElement(), ".//@style", nsContext );
1210            for ( Node n : ns ) {
1211                String v = n.getTextContent();
1212                v = v.replace( "fill:#000000", "fill:" + fill );
1213                v = v.replace( "fill:black", "fill:" + fill );
1214                v = v.replace( "stroke:#000000", "stroke:" + stroke );
1215                v = v.replace( "stroke:black", "stroke:" + stroke );
1216                n.setTextContent( v );
1217            }
1218        }
1219    
1220        /**
1221         * @param doc
1222         * @param foreground
1223         * @param background
1224         * @throws XMLParsingException
1225         */
1226        public static void updateFillPatternSVG( XMLFragment doc, String foreground, String background )
1227                                throws XMLParsingException {
1228            List<Node> ns = getNodes( doc.getRootElement(), ".//@style", nsContext );
1229            for ( Node n : ns ) {
1230                String v = n.getTextContent();
1231                v = v.replace( "fill:#000000", "fill:" + foreground );
1232                v = v.replace( "fill:black", "fill:" + foreground );
1233                v = v.replace( "stroke:#000000", "stroke:" + foreground );
1234                v = v.replace( "stroke:black", "stroke:" + foreground );
1235                if ( background != null ) {
1236                    v = v.replace( "fill:none", "fill:" + background );
1237                }
1238                n.setTextContent( v );
1239            }
1240        }
1241    
1242        /**
1243         * @param font
1244         * @param theChar
1245         * @param size
1246         * @param color
1247         * @return an image the char has been written onto
1248         */
1249        public static BufferedImage symbolFromFont( Font font, char theChar, int size, Color color ) {
1250            if ( font.canDisplay( theChar ) ) {
1251                BufferedImage img = new BufferedImage( size, size, TYPE_INT_ARGB );
1252                Graphics2D g = img.createGraphics();
1253                g.setFont( font.deriveFont( (float) size ) );
1254                g.setColor( color );
1255                g.drawString( theChar + "", 0, size );
1256                g.dispose();
1257                return img;
1258            }
1259    
1260            return null;
1261        }
1262    
1263        /**
1264         * @param font
1265         * @param theChar1
1266         * @param theChar2
1267         * @param size
1268         * @param color1
1269         * @param color2
1270         * @return an image with the second char written over the first one
1271         */
1272        public static BufferedImage symbolFromTwoChars( Font font, char theChar1, char theChar2, int size, Color color1,
1273                                                        Color color2 ) {
1274            if ( font.canDisplay( theChar1 ) && font.canDisplay( theChar2 ) ) {
1275                BufferedImage img = new BufferedImage( size, size, TYPE_INT_ARGB );
1276                Graphics2D g = img.createGraphics();
1277                g.setFont( font.deriveFont( (float) size ) );
1278                g.setColor( color1 );
1279                g.drawString( theChar1 + "", 0, size );
1280                g.setColor( color2 );
1281                g.drawString( theChar2 + "", 0, size );
1282                g.dispose();
1283                return img;
1284            }
1285    
1286            return null;
1287        }
1288    
1289    }