    001    //$HeadURL: svn+ssh://developername@svn.wald.intevation.org/deegree/base/trunk/src/org/deegree/graphics/legend/LegendElement.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.legend;
    037
    038    import java.awt.BasicStroke;
    039    import java.awt.Color;
    040    import java.awt.FontMetrics;
    041    import java.awt.Graphics;
    042    import java.awt.Graphics2D;
    043    import java.awt.image.BufferedImage;
    044    import java.util.ArrayList;
    045
    046    import org.deegree.framework.log.ILogger;
    047    import org.deegree.framework.log.LoggerFactory;
    048    import org.deegree.graphics.displayelements.DisplayElementFactory;
    049    import org.deegree.graphics.displayelements.IncompatibleGeometryTypeException;
    050    import org.deegree.graphics.displayelements.PolygonDisplayElement;
    051    import org.deegree.graphics.sld.LineSymbolizer;
    052    import org.deegree.graphics.sld.PointSymbolizer;
    053    import org.deegree.graphics.sld.PolygonSymbolizer;
    054    import org.deegree.graphics.sld.RasterSymbolizer;
    055    import org.deegree.graphics.sld.Rule;
    056    import org.deegree.graphics.sld.Symbolizer;
    057    import org.deegree.graphics.sld.TextSymbolizer;
    058    import org.deegree.graphics.transformation.WorldToScreenTransform;
    059    import org.deegree.model.filterencoding.FilterEvaluationException;
    060    import org.deegree.model.spatialschema.Envelope;
    061    import org.deegree.model.spatialschema.GeometryFactory;
    062    import org.deegree.model.spatialschema.Position;
    063    import org.deegree.model.spatialschema.Surface;
    064    import org.deegree.ogcwebservices.wms.GraphicContextFactory;
    065
    066    /**
    067     * The implements the basic legend element. a legend element may has a label that can be set to eight positions relative
    068     * to the legend graphic. A <tt>LegendElement</tt> can be activated or deactivated. It depends on the using
    069     * application what effect this behavior will have.
    070     * <p>
    071     * <tt>LegendElement</tt>s can be collected in a <tt>LegendElementCollection</tt> which also is a
    072     * <tt>LegendElement</tt> to group elements or to create more complex elements.
    073     * <p>
    074     * Each <tt>LegendElement</tt> is able to paint itself as <tt>BufferedImage</tt>
    075     *
    076     * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a>
    077     * @version $Revision: 7363 $ $Date: 2007-05-29 20:47:55 +0200 (Di, 29 Mai 2007) $
    078     */
    079    public class LegendElement {
    080
    081        private static final ILogger LOG = LoggerFactory.getLogger( LegendElement.class );
    082
    083        /**
    084         * the list of rules
    085         */
    086        protected ArrayList<Rule> ruleslist = null;
    087
    088        /**
    089         * The initial empty label.
    090         */
    091        protected String label = "";
    092
    093        /**
    094         * The orientation initialized with 0.
    095         */
    096        protected double orientation = 0;
    097
    098        /**
    099         * The label position initialized with -1.
    100         */
    101        protected int labelPosition = -1;
    102
    103        /**
    104         * A flag signaling if the legend is active initialized with false.
    105         */
    106        protected boolean active = false;
    107
    108        /**
    109         * The width of the legend element initialized with 0;
    110         */
    111        protected int width = 0;
    112
    113        /**
    114         * The height of the legend element initialized with 0;
    115         */
    116        protected int height = 0;
    117
    118        /**
    119         * The width in pixels between the legend and it's label initialized with 10;
    120         */
    121        protected int bufferBetweenLegendAndLabel = 10;
    122
    123        /**
    124         * The icon of the legend
    125         */
    126        protected BufferedImage bi;
    127
    128        /**
    129         * empty constructor
    130         *
    131         */
    132        protected LegendElement() {
    133            this.ruleslist = new ArrayList<Rule>();
    134        }
    135
    136        /**
    137         * @param legendImage
    138         *            the icon of the legend.
    139         *
    140         *
    141         */
    142        LegendElement( BufferedImage legendImage ) {
    143            this();
    144            bi = legendImage;
    145        }
    146
    147        /**
    148         * constructor
    149         *
    150         * @param rules
    151         *            the different rules from the SLD
    152         * @param label
    153         *            the label beneath the legend symbol
    154         * @param orientation
    155         *            the rotation of the text in the legend
    156         * @param labelPosition
    157         *            the position of the text according to the symbol
    158         * @param active
    159         *            whether the legendsymbol is active or not
    160         * @param width
    161         *            the requested width of the legend symbol
    162         * @param height
    163         *            the requested height of the legend symbol
    164         */
    165        LegendElement( Rule[] rules, String label, double orientation, int labelPosition, boolean active, int width,
    166                       int height ) {
    167            this();
    168            setRules( rules );
    169            setLabel( label );
    170            setLabelOrientation( orientation );
    171            setLabelPlacement( labelPosition );
    172            setActive( active );
    173            setWidth( width );
    174            setHeight( height );
    175        }
    176
    177        /**
    178         * gets the Rules as an array
    179         *
    180         * @return array of sld rules
    181         */
    182        public Rule[] getRules() {
    183            if ( ruleslist != null && ruleslist.size() > 0 ) {
    184                return ruleslist.toArray( new Rule[ruleslist.size()] );
    185            }
    186            return null;
    187        }
    188
    189        /**
    190         * adds a rule to the ArrayList ruleslist
    191         *
    192         * @param rule
    193         *            a sld rule
    194         */
    195        public void addRule( Rule rule ) {
    196            this.ruleslist.add( rule );
    197        }
    198
    199        /**
    200         * sets the rules
    201         *
    202         * @param rules
    203         *            an array of sld rules
    204         */
    205        public void setRules( Rule[] rules ) {
    206            this.ruleslist.clear();
    207
    208            if ( rules != null ) {
    209                for ( int i = 0; i < rules.length; i++ ) {
    210                    this.ruleslist.add( rules[i] );
    211                }
    212            }
    213        }
    214
    215        /**
    216         * sets the label of the <tt>LegendElement</tt>
    217         *
    218         * @param label
    219         *            label of the <tt>LegendElement</tt>
    220         *
    221         */
    222        public void setLabel( String label ) {
    223            this.label = label;
    224        }
    225
    226        /**
    227         * returns the label set to <tt>LegendElement</tt>. If no label is set, the method returns <tt>null</tt>
    228         *
    229         * @return label of the <tt>LegendElement</tt> or <tt>null</tt>
    230         *
    231         */
    232        public String getLabel() {
    233            return this.label;
    234        }
    235
    236        /**
    237         * sets the orientation of the label of the <tt>LegendElement</tt>. A label can have an orientation from -90� to
    238         * 90� expressed in radians, where 0� is horizontal
    239         *
    240         * @param orientation
    241         */
    242        public void setLabelOrientation( double orientation ) {
    243            this.orientation = orientation;
    244        }
    245
    246        /**
    247         * returns the current orientation of the label of the <tt>LegendElement</tt> in radians. If the element hasn't a
    248         * label <tt>Double.NEGATIVE_INFINITY</tt> will be returned.
    249         *
    250         * @return orientation of the label of the <tt>LegendElement</tt> in radians
    251         */
    252        public double getLabelOrientation() {
    253            return this.orientation;
    254        }
    255
    256        /**
    257         * sets the placement of the label relative to the legend symbol. Possible values are:
    258         * <ul>
    259         * <li>LP_TOPCENTER
    260         * <li>LP_TOPLEFT
    261         * <li>LP_TOPRIGHT
    262         * <li>LP_RIGHT
    263         * <li>LP_LEFT
    264         * <li>LP_BOTTOMCENTER
    265         * <li>LP_BOTTOMRIGHT
    266         * <li>LP_BOTTOMLEFT
    267         * </ul>
    268         *
    269         * <pre>
    270         *   +---+---+---+
    271         *   | 1 | 0 | 2 |
    272         *   +---+---+---+
    273         *   | 4 |LEG| 3 |
    274         *   +---+---+---+
    275         *   | 7 | 5 | 6 |
    276         *   +---+---+---+
    277         * </pre>
    278         *
    279         * An implementation of the interface may not supoort all positions.
    280         *
    281         * @param labelPosition
    282         */
    283        public void setLabelPlacement( int labelPosition ) {
    284            this.labelPosition = labelPosition;
    285        }
    286
    287        /**
    288         * returns the placement of the label relative to the legend symbol. If the element hasn't a label
    289         * <tt>LegendElement.LP_NOLABEL</tt> will be returned. Otherwise possible values are:
    290         * <ul>
    291         * <li>LP_TOPCENTER
    292         * <li>LP_TOPLEFT
    293         * <li>LP_TOPRIGHT
    294         * <li>LP_RIGHT
    295         * <li>LP_LEFT
    296         * <li>LP_BOTTOMCENTER
    297         * <li>LP_BOTTOMRIGHT
    298         * <li>LP_BOTTOMLEFT
    299         * </ul>
    300         *
    301         * @return coded placement of the label relative to the legend symbol
    302         */
    303        public int getLabelPlacement() {
    304            return this.labelPosition;
    305        }
    306
    307        /**
    308         * activates or deactivates the label
    309         *
    310         * @param active
    311         */
    312        public void setActive( boolean active ) {
    313            this.active = active;
    314        }
    315
    316        /**
    317         * @return the activtion-status of the label
    318         */
    319        public boolean isActive() {
    320            return this.active;
    321        }
    322
    323        /**
    324         * sets the width of the LegendSymbol (in pixels)
    325         *
    326         * @param width
    327         */
    328        public void setWidth( int width ) {
    329            this.width = width;
    330        }
    331
    332        /**
    333         * @return the width of the LegendSymbol (in pixels)
    334         */
    335        public int getWidth() {
    336            return this.width;
    337        }
    338
    339        /**
    340         * sets the height of the LegendSymbol (in pixels)
    341         *
    342         * @param height
    343         */
    344        public void setHeight( int height ) {
    345            this.height = height;
    346        }
    347
    348        /**
    349         * @return the height of the LegendSymbol (in pixels)
    350         */
    351        public int getHeight() {
    352            return this.height;
    353        }
    354
    355        /**
    356         * returns the buffer place between the legend symbol and the legend label in pixels
    357         *
    358         * @return the buffer as integer in pixels
    359         */
    360        public int getBufferBetweenLegendAndLabel() {
    361            return this.bufferBetweenLegendAndLabel;
    362        }
    363
    364        /**
    365         * @see org.deegree.graphics.legend.LegendElement#getBufferBetweenLegendAndLabel()
    366         * @param i
    367         *            the buffer as integer in pixels
    368         */
    369        public void setBufferBetweenLegendAndLabel( int i ) {
    370            this.bufferBetweenLegendAndLabel = i;
    371        }
    372
    373        /**
    374         * draws a legendsymbol, if the SLD defines a point
    375         *
    376         * @param g
    377         *            the graphics context
    378         * @param c
    379         *            the PointSymbolizer representing the drawable point
    380         * @param width
    381         *            the requested width of the symbol
    382         * @param height
    383         *            the requested height of the symbol
    384         * @throws LegendException
    385         *             is thrown, if the parsing of the sld failes.
    386         */
    387        protected void drawPointLegend( Graphics g, PointSymbolizer c, int width, int height )
    388                                throws LegendException {
    389            org.deegree.graphics.sld.Graphic deegreegraphic = c.getGraphic();
    390            try {
    391                BufferedImage buffi = deegreegraphic.getAsImage( null );
    392                int w = buffi.getWidth();
    393                int h = buffi.getHeight();
    394                g.drawImage( buffi, width / 2 - w / 2, height / 2 - h / 2, null );
    395            } catch ( FilterEvaluationException feex ) {
    396                throw new LegendException( "FilterEvaluationException occured during " + "the creation of the legend:\n"
    397                                           + "The legend for the PointSymbol can't be processed.\n" + feex.getMessage() );
    398            }
    399
    400        }
    401
    402        /**
    403         * draws a legendsymbol, if the SLD defines a line
    404         *
    405         * @param g
    406         *            the graphics context
    407         * @param ls
    408         *            the LineSymbolizer representing the drawable line
    409         * @param width
    410         *            the requested width of the symbol
    411         * @param height
    412         *            the requested height of the symbol
    413         * @throws LegendException
    414         *             is thrown, if the parsing of the sld failes.
    415         */
    416        protected void drawLineStringLegend( Graphics2D g, LineSymbolizer ls, int width, int height )
    417                                throws LegendException {
    418
    419            org.deegree.graphics.sld.Stroke sldstroke = ls.getStroke();
    420            try {
    421                // color, opacity
    422                setColor( g, sldstroke.getStroke( null ), sldstroke.getOpacity( null ) );
    423                g.setStroke( getBasicStroke( sldstroke ) );
    424            } catch ( FilterEvaluationException feex ) {
    425                throw new LegendException( "FilterEvaluationException occured during the creation "
    426                                           + "of the legend:\n The legend for the LineSymbol can't be " + "processed.\n"
    427                                           + feex.getMessage() );
    428            }
    429
    430            // p1 = [0 | height]
    431            // p2 = [width / 3 | height / 3]
    432            // p3 = [width - width / 3 | height - height / 3]
    433            // p4 = [width | 0]
    434            int[] xPoints = { 0, width / 3, width - width / 3, width };
    435            int[] yPoints = { height, height / 3, height - height / 3, 0 };
    436            int nPoints = 4;
    437
    438            g.drawPolyline( xPoints, yPoints, nPoints );
    439
    440        }
    441
    442        /**
    443         * draws a legendsymbol, if the SLD defines a polygon
    444         *
    445         * @param g
    446         *            the graphics context
    447         * @param ps
    448         *            the PolygonSymbolizer representing the drawable polygon
    449         * @param width
    450         *            the requested width of the symbol
    451         * @param height
    452         *            the requested height of the symbol
    453         * @throws LegendException
    454         *             if the parsing of the sld failes.
    455         */
    456        protected void drawPolygonLegend( Graphics2D g, PolygonSymbolizer ps, int width, int height )
    457                                throws LegendException {
    458
    459            Position p1 = GeometryFactory.createPosition( 0, 0 );
    460            Position p2 = GeometryFactory.createPosition( 0, height - 1 );
    461            Position p3 = GeometryFactory.createPosition( width - 1, height - 1 );
    462            Position p4 = GeometryFactory.createPosition( width - 1, 0 );
    463
    464            Position[] pos = { p1, p2, p3, p4, p1 };
    465            Surface surface = null;
    466            try {
    467                surface = GeometryFactory.createSurface( pos, null, null, null );
    468            } catch ( Exception ex ) {
    469                throw new LegendException( "Exception occured during the creation of the legend:\n"
    470                                           + "The legendsymbol for the Polygon can't be processed.\n"
    471                                           + "Error in creating the Surface from the Positions.\n" + ex.getMessage() );
    472            }
    473
    474            PolygonDisplayElement pde = null;
    475            try {
    476                // Feature, Geometry, PolygonSymbolizer
    477                pde = DisplayElementFactory.buildPolygonDisplayElement( null, surface, ps );
    478            } catch ( IncompatibleGeometryTypeException igtex ) {
    479                throw new LegendException( "IncompatibleGeometryTypeException occured during "
    480                                           + "the creation of the legend:\n The legendsymbol for "
    481                                           + "the Polygon can't be processed.\nError in creating "
    482                                           + "the PolygonDisplayElement.\n" + igtex.getMessage() );
    483            } catch ( Exception e ) {
    484                throw new LegendException( "Could not create symbolizer:\n" + e.getMessage() );
    485            }
    486
    487            Envelope envelope = GeometryFactory.createEnvelope( p1, p3, null );
    488
    489            WorldToScreenTransform wtst = new WorldToScreenTransform( envelope, envelope );
    490            pde.paint( g, wtst, -1 );
    491
    492        }
    493
    494        /**
    495         * sets the color including an opacity
    496         *
    497         * @param g2
    498         *            the graphics contect as Graphics2D
    499         * @param color
    500         *            the requested color of the legend symbol
    501         * @param opacity
    502         *            the requested opacity of the legend symbol
    503         * @return the Graphics2D object containing color and opacity
    504         */
    505        private Graphics2D setColor( Graphics2D g2, Color color, double opacity ) {
    506            if ( opacity < 0.999 ) {
    507                final int alpha = (int) Math.round( opacity * 255 );
    508                final int red = color.getRed();
    509                final int green = color.getGreen();
    510                final int blue = color.getBlue();
    511                color = new Color( red, green, blue, alpha );
    512            }
    513            g2.setColor( color );
    514            return g2;
    515        }
    516
    517        /**
    518         * constructs a java.awt.BasicStroke for painting a LineString legend symbol.
    519         *
    520         * @param sldstroke
    521         *            the deegree sld stroke
    522         * @return a java.awt.BasicStroke
    523         * @throws LegendException
    524         *             if the sld cannot be processed
    525         */
    526        private BasicStroke getBasicStroke( org.deegree.graphics.sld.Stroke sldstroke )
    527                                throws LegendException {
    528            BasicStroke bs = null;
    529            try {
    530                float width = (float) sldstroke.getWidth( null );
    531                int cap = sldstroke.getLineCap( null );
    532                int join = sldstroke.getLineJoin( null );
    533                float miterlimit = 1f;
    534                float[] dash = sldstroke.getDashArray( null );
    535                float dash_phase = sldstroke.getDashOffset( null );
    536
    537                bs = new BasicStroke( width, cap, join, miterlimit, dash, dash_phase );
    538                // return new BasicStroke((float)sldstroke.getWidth(null), sldstroke.getLineCap(null),
    539                // sldstroke.getLineJoin(null), 1f, sldstroke.getDashArray(null),
    540                // sldstroke.getDashOffset(null));
    541
    542            } catch ( FilterEvaluationException ex ) {
    543                throw new LegendException( "FilterEvaluationException occured during the creation of the legend:\n"
    544                                           + "The Stroke of the element can't be processed.\n" + ex.getMessage() );
    545            }
    546            return bs;
    547        }
    548
    549        /**
    550         * calculates the FontMetrics of the LegendLabel in pixels. It returns an 3-dimensional array containing [0] the
    551         * width, [1] the ascent and [2] the descent.
    552         *
    553         * @param label
    554         *            the label of the LegendElement
    555         * @return the 3-dimensional INT-Array contains [0] the width of the string, [1] the ascent and [2] the descent.
    556         */
    557        protected int[] calculateFontMetrics( String label ) {
    558            int[] fontmetrics = new int[3];
    559
    560            BufferedImage bi = new BufferedImage( 1, 1, BufferedImage.TYPE_INT_ARGB );
    561            Graphics g = bi.getGraphics();
    562
    563            FontMetrics fm = g.getFontMetrics();
    564
    565            if ( label != null && label.length() > 0 ) {
    566                fontmetrics[0] = fm.stringWidth( label );
    567                fontmetrics[1] = fm.getAscent();
    568                fontmetrics[2] = fm.getDescent();
    569            } else {
    570                fontmetrics[0] = 0;
    571                fontmetrics[1] = 0;
    572                fontmetrics[2] = 0;
    573                // value = 1, because of a bug, which doesn't paint the right border of the
    574                // polygon-symbol.
    575                setBufferBetweenLegendAndLabel( 1 );
    576            }
    577            g.dispose();
    578
    579            return fontmetrics;
    580        }
    581
    582        /**
    583         * calculates the width and height of the resulting LegendSymbol depending on the LabelPlacement
    584         */
    585        private BufferedImage calculateImage( int labelposition, int labelwidth, int ascent, int descent, int legendwidth,
    586                                              int legendheight, int buffer, String mime ) {
    587            // eliminate buffer if label width is zero, so pixel counting works for the reference
    588            // implementation
    589            if ( labelwidth == 0 ) {
    590                buffer = 0;
    591            }
    592
    593            BufferedImage bi = (BufferedImage) GraphicContextFactory.createGraphicTarget(
    594                                                                                          mime,
    595                                                                                          ( legendwidth + buffer + labelwidth ),
    596                                                                                          legendheight );
    597
    598            Graphics g = bi.getGraphics();
    599            if ( !( mime.equalsIgnoreCase( "image/png" ) || mime.equalsIgnoreCase( "image/gif" ) ) ) {
    600                g.setColor( Color.WHITE );
    601                g.fillRect( 0, 0, bi.getWidth(), bi.getHeight() );
    602            }
    603            g.setColor( Color.BLACK );
    604            // TODO labelposition
    605
    606            switch ( labelposition ) {
    607            // LP_TOPCENTER
    608            case 0: {
    609                LOG.logInfo( "The text-position LP_TOPCENTER in the legend is not "
    610                             + "implemented yet.\n We put the text on the right side (EAST) of " + "the legendsymbol." );
    611                g.drawString( getLabel(), width + 10, height / 2 + ( ( ascent - descent ) / 2 ) );
    612                break;
    613            }
    614                // LP_TOPLEFT
    615            case 1: {
    616                LOG.logInfo( "The text-position LP_TOPLEFT in the legend is not implemented "
    617                             + "yet.\n We put the text on the right side (EAST) of the legendsymbol." );
    618                g.drawString( getLabel(), width + 10, height / 2 + ( ( ascent - descent ) / 2 ) );
    619                break;
    620            }
    621                // LP_TOPRIGHT
    622            case 2: {
    623                LOG.logInfo( "The text-position LP_TOPRIGHT in the legend is not implemented "
    624                             + "yet.\n We put the text on the right side (EAST) of the legendsymbol." );
    625                g.drawString( getLabel(), width + 10, height / 2 + ( ( ascent - descent ) / 2 ) );
    626                break;
    627            }
    628                // LP_RIGHT
    629            case 3: {
    630                LOG.logInfo( "The text-position LP_RIGHT in the legend is not implemented "
    631                             + "yet.\n We put the text on the right side (EAST) of the legendsymbol." );
    632                g.drawString( getLabel(), width + 10, height / 2 + ( ( ascent - descent ) / 2 ) );
    633                break;
    634
    635            }
    636                // LP_LEFT
    637            case 4: {
    638                g.drawString( getLabel(), width + 10, height / 2 + ( ( ascent - descent ) / 2 ) );
    639                break;
    640            }
    641                // LP_BOTTOMCENTER
    642            case 5: {
    643                LOG.logInfo( "The text-position LP_BOTTOMCENTER in the legend is not "
    644                             + "implemented yet.\n We put the text on the right side (EAST) of " + "the legendsymbol." );
    645                g.drawString( getLabel(), width + 10, height / 2 + ( ( ascent - descent ) / 2 ) );
    646                break;
    647            }
    648                // LP_BOTTOMRIGHT
    649            case 6: {
    650                LOG.logInfo( "The text-position LP_BOTTOMRIGHT in the legend is not "
    651                             + "implemented yet.\n We put the text on the right side (EAST) of " + "the legendsymbol." );
    652                g.drawString( getLabel(), width + 10, height / 2 + ( ( ascent - descent ) / 2 ) );
    653                break;
    654            }
    655                // LP_BOTTOMLEFT
    656            case 7: {
    657                LOG.logInfo( "The text-position LP_BOTTOMLEFT in the legend is not implemented "
    658                             + "yet.\n We put the text on the right side (EAST) of the legendsymbol." );
    659                g.drawString( getLabel(), width + 10, height / 2 + ( ( ascent - descent ) / 2 ) );
    660                break;
    661            }
    662            }
    663            g.dispose();
    664            return bi;
    665        }
    666
    667        /**
    668         * exports the <tt>LegendElement</tt> as </tt>BufferedImage</tt>
    669         *
    670         * @param mime
    671         *
    672         * @return the image
    673         * @throws LegendException
    674         */
    675        public BufferedImage exportAsImage( String mime )
    676                                throws LegendException {
    677
    678            if ( bi == null ) {
    679                // calculates the fontmetrics and creates the bufferedimage
    680                // if getLabel() is null is checked in calculateFontMetrics!
    681                int[] fontmetrics = calculateFontMetrics( getLabel() );
    682                bi = calculateImage( getLabelPlacement(), fontmetrics[0], fontmetrics[1], fontmetrics[2], getWidth(),
    683                                     getHeight(), getBufferBetweenLegendAndLabel(), mime );
    684                Graphics g = bi.getGraphics();
    685                ( (Graphics2D) g ).setClip( 0, 0, getWidth(), getHeight() );
    686                g.setColor( Color.WHITE );
    687                Rule[] myrules = getRules();
    688                Symbolizer[] symbolizer = null;
    689                // determines the legendsymbol and paints it
    690                for ( int a = 0; a < myrules.length; a++ ) {
    691                    symbolizer = myrules[a].getSymbolizers();
    692
    693                    for ( int b = 0; b < symbolizer.length; b++ ) {
    694                        if ( symbolizer[b] instanceof PointSymbolizer ) {
    695                            drawPointLegend( g, (PointSymbolizer) symbolizer[b], getWidth(), getHeight() );
    696                        }
    697                        if ( symbolizer[b] instanceof LineSymbolizer ) {
    698                            drawLineStringLegend( (Graphics2D) g, (LineSymbolizer) symbolizer[b], width, height );
    699                        }
    700                        if ( symbolizer[b] instanceof PolygonSymbolizer ) {
    701                            drawPolygonLegend( (Graphics2D) g, (PolygonSymbolizer) symbolizer[b], width, height );
    702                        }
    703                        if ( symbolizer[b] instanceof RasterSymbolizer ) {
    704                            // throw new LegendException("RasterSymbolizer is not implemented yet!");
    705                        }
    706                        if ( symbolizer[b] instanceof TextSymbolizer ) {
    707                            // throw new LegendException("TextSymbolizer is not implemented yet!");
    708                        }
    709                    }
    710
    711                    // g.setColor(Color.black);
    712                    // g.drawString(getLabel(), width + 10, height / 2 + ((fontmetrics[1] -
    713                    // fontmetrics[2]) / 2));
    714
    715                }
    716            } else {
    717                if ( mime.equalsIgnoreCase( "image/gif" ) || mime.equalsIgnoreCase( "image/png" ) ) {
    718                    BufferedImage bii = new BufferedImage( bi.getWidth(), bi.getHeight(), BufferedImage.TYPE_INT_ARGB );
    719                    Graphics g = bii.getGraphics();
    720                    g.drawImage( bi, 0, 0, null );
    721                    g.dispose();
    722                    bi = bii;
    723                } else if ( mime.equalsIgnoreCase( "image/jpg" ) || mime.equalsIgnoreCase( "image/jpeg" )
    724                            || mime.equalsIgnoreCase( "image/tif" ) || mime.equalsIgnoreCase( "image/tiff" )
    725                            || mime.equalsIgnoreCase( "image/bmp" ) ) {
    726                    BufferedImage bii = new BufferedImage( bi.getWidth(), bi.getHeight(), BufferedImage.TYPE_INT_RGB );
    727                    Graphics g = bii.getGraphics();
    728                    g.drawImage( bi, 0, 0, null );
    729                    g.dispose();
    730                    bi = bii;
    731                } else if ( mime.equalsIgnoreCase( "image/svg+xml" ) ) {
    732                    // not implemented yet
    733                }
    734            }
    735            return bi;
    736        }
    737    }