001    /*
002     * Font.java
003     *
004     *
005     *  The Salamander Project - 2D and 3D graphics libraries in Java
006     *  Copyright (C) 2004 Mark McKay
007     *
008     *  This library is free software; you can redistribute it and/or
009     *  modify it under the terms of the GNU Lesser General Public
010     *  License as published by the Free Software Foundation; either
011     *  version 2.1 of the License, or (at your option) any later version.
012     *
013     *  This library is distributed in the hope that it will be useful,
014     *  but WITHOUT ANY WARRANTY; without even the implied warranty of
015     *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
016     *  Lesser General Public License for more details.
017     *
018     *  You should have received a copy of the GNU Lesser General Public
019     *  License along with this library; if not, write to the Free Software
020     *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
021     *
022     *  Mark McKay can be contacted at mark@kitfox.com.  Salamander and other
023     *  projects can be found at http://www.kitfox.com
024     *
025     * Created on February 20, 2004, 10:00 PM
026     */
027    
028    package com.kitfox.svg;
029    
030    import com.kitfox.svg.app.data.Handler;
031    import com.kitfox.svg.xml.*;
032    
033    import java.awt.*;
034    import java.awt.geom.*;
035    import java.awt.image.*;
036    import java.net.*;
037    import java.util.List;
038    
039    /**
040     * Implements an embedded font.
041     *
042     * SVG specification: http://www.w3.org/TR/SVG/fonts.html
043     *
044     * @author Mark McKay
045     * @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
046     */
047    public class ImageSVG extends RenderableElement
048    {
049        float x = 0f;
050        float y = 0f;
051        float width = 0f;
052        float height = 0f;
053    
054    //    BufferedImage href = null;
055        URL imageSrc = null;
056    
057        AffineTransform xform;
058        Rectangle2D bounds;
059    
060        /** Creates a new instance of Font */
061        public ImageSVG()
062        {
063        }
064        
065        protected void build() throws SVGException
066        {
067            super.build();
068            
069            StyleAttribute sty = new StyleAttribute();
070            
071            if (getPres(sty.setName("x"))) x = sty.getFloatValueWithUnits();
072    
073            if (getPres(sty.setName("y"))) y = sty.getFloatValueWithUnits();
074    
075            if (getPres(sty.setName("width"))) width = sty.getFloatValueWithUnits();
076    
077            if (getPres(sty.setName("height"))) height = sty.getFloatValueWithUnits();
078    
079            try {
080                if (getPres(sty.setName("xlink:href")))
081                {
082                    URI src = sty.getURIValue(getXMLBase());
083                    if ("data".equals(src.getScheme()))
084                    {
085                        imageSrc = new URL(null, src.toASCIIString(), new Handler());
086                    }
087                    else
088                    {
089                        try {
090                            imageSrc = src.toURL();
091                        }
092                        catch (Exception e)
093                        {
094                            e.printStackTrace();
095                            imageSrc = null;
096                        }
097                    }
098                }
099            }
100            catch (Exception e)
101            {
102                throw new SVGException(e);
103            }
104    
105            diagram.getUniverse().registerImage(imageSrc);
106            
107            //Set widths if not set
108            BufferedImage img = diagram.getUniverse().getImage(imageSrc);
109            if (img == null)
110            {
111                xform = new AffineTransform();
112                bounds = new Rectangle2D.Float();
113                return;
114            }
115            
116            if (width == 0) width = img.getWidth();
117            if (height == 0) height = img.getHeight();
118            
119            //Determine image xform
120            xform = new AffineTransform();
121    //        xform.setToScale(this.width / img.getWidth(), this.height / img.getHeight());
122    //        xform.translate(this.x, this.y);
123            xform.translate(this.x, this.y);
124            xform.scale(this.width / img.getWidth(), this.height / img.getHeight());
125            
126            bounds = new Rectangle2D.Float(this.x, this.y, this.width, this.height);
127        }
128        
129        
130        
131        public float getX() { return x; }
132        public float getY() { return y; }
133        public float getWidth() { return width; }
134        public float getHeight() { return height; }
135    
136        void pick(Point2D point, boolean boundingBox, List retVec) throws SVGException
137        {
138            if (getBoundingBox().contains(point))
139            {
140                retVec.add(getPath(null));
141            }
142        }
143    
144        void pick(Rectangle2D pickArea, AffineTransform ltw, boolean boundingBox, List retVec) throws SVGException
145        {
146            if (ltw.createTransformedShape(getBoundingBox()).intersects(pickArea))
147            {
148                retVec.add(getPath(null));
149            }
150        }
151    
152        public void render(Graphics2D g) throws SVGException
153        {
154            StyleAttribute styleAttrib = new StyleAttribute();
155            if (getStyle(styleAttrib.setName("visibility")))
156            {
157                if (!styleAttrib.getStringValue().equals("visible")) return;
158            }
159            
160            beginLayer(g);
161            
162            float opacity = 1f;
163            if (getStyle(styleAttrib.setName("opacity")))
164            {
165                opacity = styleAttrib.getRatioValue();
166            }
167            
168            if (opacity <= 0) return;
169    
170            Composite oldComp = null;
171            
172            if (opacity < 1)
173            {
174                oldComp = g.getComposite();
175                Composite comp = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, opacity);
176                g.setComposite(comp);
177            }
178            
179            BufferedImage img = diagram.getUniverse().getImage(imageSrc);
180            if (img == null) return;
181            
182            AffineTransform curXform = g.getTransform();
183            g.transform(xform);
184            
185            g.drawImage(img, 0, 0, null);
186            
187            g.setTransform(curXform);
188            if (oldComp != null) g.setComposite(oldComp);
189            
190            finishLayer(g);
191        }
192        
193        public Rectangle2D getBoundingBox()
194        {
195            return boundsToParent(bounds);
196        }
197    
198        /**
199         * Updates all attributes in this diagram associated with a time event.
200         * Ie, all attributes with track information.
201         * @return - true if this node has changed state as a result of the time
202         * update
203         */
204        public boolean updateTime(double curTime) throws SVGException
205        {
206    //        if (trackManager.getNumTracks() == 0) return false;
207            boolean changeState = super.updateTime(curTime);
208    
209            //Get current values for parameters
210            StyleAttribute sty = new StyleAttribute();
211            boolean shapeChange = false;
212            
213            if (getPres(sty.setName("x")))
214            {
215                float newVal = sty.getFloatValueWithUnits();
216                if (newVal != x)
217                {
218                    x = newVal;
219                    shapeChange = true;
220                }
221            }
222            
223            if (getPres(sty.setName("y")))
224            {
225                float newVal = sty.getFloatValueWithUnits();
226                if (newVal != y)
227                {
228                    y = newVal;
229                    shapeChange = true;
230                }
231            }
232            
233            if (getPres(sty.setName("width")))
234            {
235                float newVal = sty.getFloatValueWithUnits();
236                if (newVal != width)
237                {
238                    width = newVal;
239                    shapeChange = true;
240                }
241            }
242            
243            if (getPres(sty.setName("height")))
244            {
245                float newVal = sty.getFloatValueWithUnits();
246                if (newVal != height)
247                {
248                    height = newVal;
249                    shapeChange = true;
250                }
251            }
252            
253            try {
254                if (getPres(sty.setName("xlink:href")))
255                {
256                    URI src = sty.getURIValue(getXMLBase());
257                    URL newVal = src.toURL();
258                    
259                    if (!newVal.equals(imageSrc))
260                    {
261                        imageSrc = newVal;
262                        shapeChange = true;
263                    }
264                }
265            }
266            catch (IllegalArgumentException ie)
267            {
268                new Exception("Image provided with illegal value for href: \"" + sty.getStringValue() + '"', ie).printStackTrace();
269            }
270            catch (Exception e)
271            {
272                e.printStackTrace();
273            }
274    
275            
276            if (shapeChange)
277            {
278                build();
279    //            diagram.getUniverse().registerImage(imageSrc);
280    //
281    //            //Set widths if not set
282    //            BufferedImage img = diagram.getUniverse().getImage(imageSrc);
283    //            if (img == null)
284    //            {
285    //                xform = new AffineTransform();
286    //                bounds = new Rectangle2D.Float();
287    //            }
288    //            else
289    //            {
290    //                if (width == 0) width = img.getWidth();
291    //                if (height == 0) height = img.getHeight();
292    //
293    //                //Determine image xform
294    //                xform = new AffineTransform();
295    ////                xform.setToScale(this.width / img.getWidth(), this.height / img.getHeight());
296    ////                xform.translate(this.x, this.y);
297    //                xform.translate(this.x, this.y);
298    //                xform.scale(this.width / img.getWidth(), this.height / img.getHeight());
299    //
300    //                bounds = new Rectangle2D.Float(this.x, this.y, this.width, this.height);
301    //            }
302    //
303    //            return true;
304            }
305            
306            return changeState || shapeChange;
307        }
308    }