001/*
002 * SVG Salamander
003 * Copyright (c) 2004, Mark McKay
004 * All rights reserved.
005 *
006 * Redistribution and use in source and binary forms, with or 
007 * without modification, are permitted provided that the following
008 * conditions are met:
009 *
010 *   - Redistributions of source code must retain the above 
011 *     copyright notice, this list of conditions and the following
012 *     disclaimer.
013 *   - Redistributions in binary form must reproduce the above
014 *     copyright notice, this list of conditions and the following
015 *     disclaimer in the documentation and/or other materials 
016 *     provided with the distribution.
017 *
018 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
019 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
020 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
021 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
022 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
023 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
024 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
025 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
026 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
027 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
028 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
029 * OF THE POSSIBILITY OF SUCH DAMAGE. 
030 * 
031 * Mark McKay can be contacted at mark@kitfox.com.  Salamander and other
032 * projects can be found at http://www.kitfox.com
033 *
034 * Created on February 20, 2004, 10:00 PM
035 */
036package com.kitfox.svg;
037
038import com.kitfox.svg.app.data.Handler;
039import com.kitfox.svg.xml.StyleAttribute;
040import java.awt.AlphaComposite;
041import java.awt.Composite;
042import java.awt.Graphics2D;
043import java.awt.geom.AffineTransform;
044import java.awt.geom.Point2D;
045import java.awt.geom.Rectangle2D;
046import java.awt.image.BufferedImage;
047import java.net.URI;
048import java.net.URL;
049import java.util.List;
050import java.util.logging.Level;
051import java.util.logging.Logger;
052
053/**
054 * Implements an image.
055 *
056 * @author Mark McKay
057 * @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
058 */
059public class ImageSVG extends RenderableElement
060{
061    public static final String TAG_NAME = "image";
062    
063    float x = 0f;
064    float y = 0f;
065    float width = 0f;
066    float height = 0f;
067//    BufferedImage href = null;
068    URL imageSrc = null;
069    AffineTransform xform;
070    Rectangle2D bounds;
071
072    /**
073     * Creates a new instance of Font
074     */
075    public ImageSVG()
076    {
077    }
078
079    public String getTagName()
080    {
081        return TAG_NAME;
082    }
083
084    protected void build() throws SVGException
085    {
086        super.build();
087
088        StyleAttribute sty = new StyleAttribute();
089
090        if (getPres(sty.setName("x")))
091        {
092            x = sty.getFloatValueWithUnits();
093        }
094
095        if (getPres(sty.setName("y")))
096        {
097            y = sty.getFloatValueWithUnits();
098        }
099
100        if (getPres(sty.setName("width")))
101        {
102            width = sty.getFloatValueWithUnits();
103        }
104
105        if (getPres(sty.setName("height")))
106        {
107            height = sty.getFloatValueWithUnits();
108        }
109
110        try
111        {
112            if (getPres(sty.setName("xlink:href")))
113            {
114                URI src = sty.getURIValue(getXMLBase());
115                if ("data".equals(src.getScheme()))
116                {
117                    imageSrc = new URL(null, src.toASCIIString(), new Handler());
118                } else
119                {
120                    try
121                    {
122                        imageSrc = src.toURL();
123                    } catch (Exception e)
124                    {
125                        Logger.getLogger(SVGConst.SVG_LOGGER).log(Level.WARNING,
126                            "Could not parse xlink:href " + src, e);
127//                        e.printStackTrace();
128                        imageSrc = null;
129                    }
130                }
131            }
132        } catch (Exception e)
133        {
134            throw new SVGException(e);
135        }
136
137        diagram.getUniverse().registerImage(imageSrc);
138
139        //Set widths if not set
140        BufferedImage img = diagram.getUniverse().getImage(imageSrc);
141        if (img == null)
142        {
143            xform = new AffineTransform();
144            bounds = new Rectangle2D.Float();
145            return;
146        }
147
148        if (width == 0)
149        {
150            width = img.getWidth();
151        }
152        if (height == 0)
153        {
154            height = img.getHeight();
155        }
156
157        //Determine image xform
158        xform = new AffineTransform();
159//        xform.setToScale(this.width / img.getWidth(), this.height / img.getHeight());
160//        xform.translate(this.x, this.y);
161        xform.translate(this.x, this.y);
162        xform.scale(this.width / img.getWidth(), this.height / img.getHeight());
163
164        bounds = new Rectangle2D.Float(this.x, this.y, this.width, this.height);
165    }
166
167    public float getX()
168    {
169        return x;
170    }
171
172    public float getY()
173    {
174        return y;
175    }
176
177    public float getWidth()
178    {
179        return width;
180    }
181
182    public float getHeight()
183    {
184        return height;
185    }
186
187    void pick(Point2D point, boolean boundingBox, List retVec) throws SVGException
188    {
189        if (getBoundingBox().contains(point))
190        {
191            retVec.add(getPath(null));
192        }
193    }
194
195    void pick(Rectangle2D pickArea, AffineTransform ltw, boolean boundingBox, List retVec) throws SVGException
196    {
197        if (ltw.createTransformedShape(getBoundingBox()).intersects(pickArea))
198        {
199            retVec.add(getPath(null));
200        }
201    }
202
203    public void render(Graphics2D g) throws SVGException
204    {
205        StyleAttribute styleAttrib = new StyleAttribute();
206        if (getStyle(styleAttrib.setName("visibility")))
207        {
208            if (!styleAttrib.getStringValue().equals("visible"))
209            {
210                return;
211            }
212        }
213
214        beginLayer(g);
215
216        float opacity = 1f;
217        if (getStyle(styleAttrib.setName("opacity")))
218        {
219            opacity = styleAttrib.getRatioValue();
220        }
221
222        if (opacity <= 0)
223        {
224            return;
225        }
226
227        Composite oldComp = null;
228
229        if (opacity < 1)
230        {
231            oldComp = g.getComposite();
232            Composite comp = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, opacity);
233            g.setComposite(comp);
234        }
235
236        BufferedImage img = diagram.getUniverse().getImage(imageSrc);
237        if (img == null)
238        {
239            return;
240        }
241
242        AffineTransform curXform = g.getTransform();
243        g.transform(xform);
244
245        g.drawImage(img, 0, 0, null);
246
247        g.setTransform(curXform);
248        if (oldComp != null)
249        {
250            g.setComposite(oldComp);
251        }
252
253        finishLayer(g);
254    }
255
256    public Rectangle2D getBoundingBox()
257    {
258        return boundsToParent(bounds);
259    }
260
261    /**
262     * Updates all attributes in this diagram associated with a time event. Ie,
263     * all attributes with track information.
264     *
265     * @return - true if this node has changed state as a result of the time
266     * update
267     */
268    public boolean updateTime(double curTime) throws SVGException
269    {
270//        if (trackManager.getNumTracks() == 0) return false;
271        boolean changeState = super.updateTime(curTime);
272
273        //Get current values for parameters
274        StyleAttribute sty = new StyleAttribute();
275        boolean shapeChange = false;
276
277        if (getPres(sty.setName("x")))
278        {
279            float newVal = sty.getFloatValueWithUnits();
280            if (newVal != x)
281            {
282                x = newVal;
283                shapeChange = true;
284            }
285        }
286
287        if (getPres(sty.setName("y")))
288        {
289            float newVal = sty.getFloatValueWithUnits();
290            if (newVal != y)
291            {
292                y = newVal;
293                shapeChange = true;
294            }
295        }
296
297        if (getPres(sty.setName("width")))
298        {
299            float newVal = sty.getFloatValueWithUnits();
300            if (newVal != width)
301            {
302                width = newVal;
303                shapeChange = true;
304            }
305        }
306
307        if (getPres(sty.setName("height")))
308        {
309            float newVal = sty.getFloatValueWithUnits();
310            if (newVal != height)
311            {
312                height = newVal;
313                shapeChange = true;
314            }
315        }
316
317        try
318        {
319            if (getPres(sty.setName("xlink:href")))
320            {
321                URI src = sty.getURIValue(getXMLBase());
322
323                URL newVal;
324                if ("data".equals(src.getScheme()))
325                {
326                    newVal = new URL(null, src.toASCIIString(), new Handler());
327                } else
328                {
329                    newVal = src.toURL();
330                }
331
332                if (!newVal.equals(imageSrc))
333                {
334                    imageSrc = newVal;
335                    shapeChange = true;
336                }
337            }
338        } catch (IllegalArgumentException ie)
339        {
340            Logger.getLogger(SVGConst.SVG_LOGGER).log(Level.WARNING,
341                "Image provided with illegal value for href: \""
342                + sty.getStringValue() + '"', ie);
343        } catch (Exception e)
344        {
345            Logger.getLogger(SVGConst.SVG_LOGGER).log(Level.WARNING,
346                "Could not parse xlink:href", e);
347        }
348
349
350        if (shapeChange)
351        {
352            build();
353//            diagram.getUniverse().registerImage(imageSrc);
354//
355//            //Set widths if not set
356//            BufferedImage img = diagram.getUniverse().getImage(imageSrc);
357//            if (img == null)
358//            {
359//                xform = new AffineTransform();
360//                bounds = new Rectangle2D.Float();
361//            }
362//            else
363//            {
364//                if (width == 0) width = img.getWidth();
365//                if (height == 0) height = img.getHeight();
366//
367//                //Determine image xform
368//                xform = new AffineTransform();
369////                xform.setToScale(this.width / img.getWidth(), this.height / img.getHeight());
370////                xform.translate(this.x, this.y);
371//                xform.translate(this.x, this.y);
372//                xform.scale(this.width / img.getWidth(), this.height / img.getHeight());
373//
374//                bounds = new Rectangle2D.Float(this.x, this.y, this.width, this.height);
375//            }
376//
377//            return true;
378        }
379
380        return changeState || shapeChange;
381    }
382}