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        if (getStyle(styleAttrib.setName("display")))
215        {
216            if (styleAttrib.getStringValue().equals("none"))
217            {
218                return;
219            }
220        }
221
222        beginLayer(g);
223
224        float opacity = 1f;
225        if (getStyle(styleAttrib.setName("opacity")))
226        {
227            opacity = styleAttrib.getRatioValue();
228        }
229
230        if (opacity <= 0)
231        {
232            return;
233        }
234
235        Composite oldComp = null;
236
237        if (opacity < 1)
238        {
239            oldComp = g.getComposite();
240            Composite comp = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, opacity);
241            g.setComposite(comp);
242        }
243
244        BufferedImage img = diagram.getUniverse().getImage(imageSrc);
245        if (img == null)
246        {
247            return;
248        }
249
250        AffineTransform curXform = g.getTransform();
251        g.transform(xform);
252
253        g.drawImage(img, 0, 0, null);
254
255        g.setTransform(curXform);
256        if (oldComp != null)
257        {
258            g.setComposite(oldComp);
259        }
260
261        finishLayer(g);
262    }
263
264    public Rectangle2D getBoundingBox()
265    {
266        return boundsToParent(bounds);
267    }
268
269    /**
270     * Updates all attributes in this diagram associated with a time event. Ie,
271     * all attributes with track information.
272     *
273     * @return - true if this node has changed state as a result of the time
274     * update
275     */
276    public boolean updateTime(double curTime) throws SVGException
277    {
278//        if (trackManager.getNumTracks() == 0) return false;
279        boolean changeState = super.updateTime(curTime);
280
281        //Get current values for parameters
282        StyleAttribute sty = new StyleAttribute();
283        boolean shapeChange = false;
284
285        if (getPres(sty.setName("x")))
286        {
287            float newVal = sty.getFloatValueWithUnits();
288            if (newVal != x)
289            {
290                x = newVal;
291                shapeChange = true;
292            }
293        }
294
295        if (getPres(sty.setName("y")))
296        {
297            float newVal = sty.getFloatValueWithUnits();
298            if (newVal != y)
299            {
300                y = newVal;
301                shapeChange = true;
302            }
303        }
304
305        if (getPres(sty.setName("width")))
306        {
307            float newVal = sty.getFloatValueWithUnits();
308            if (newVal != width)
309            {
310                width = newVal;
311                shapeChange = true;
312            }
313        }
314
315        if (getPres(sty.setName("height")))
316        {
317            float newVal = sty.getFloatValueWithUnits();
318            if (newVal != height)
319            {
320                height = newVal;
321                shapeChange = true;
322            }
323        }
324
325        try
326        {
327            if (getPres(sty.setName("xlink:href")))
328            {
329                URI src = sty.getURIValue(getXMLBase());
330
331                URL newVal;
332                if ("data".equals(src.getScheme()))
333                {
334                    newVal = new URL(null, src.toASCIIString(), new Handler());
335                } else
336                {
337                    newVal = src.toURL();
338                }
339
340                if (!newVal.equals(imageSrc))
341                {
342                    imageSrc = newVal;
343                    shapeChange = true;
344                }
345            }
346        } catch (IllegalArgumentException ie)
347        {
348            Logger.getLogger(SVGConst.SVG_LOGGER).log(Level.WARNING,
349                "Image provided with illegal value for href: \""
350                + sty.getStringValue() + '"', ie);
351        } catch (Exception e)
352        {
353            Logger.getLogger(SVGConst.SVG_LOGGER).log(Level.WARNING,
354                "Could not parse xlink:href", e);
355        }
356
357
358        if (shapeChange)
359        {
360            build();
361//            diagram.getUniverse().registerImage(imageSrc);
362//
363//            //Set widths if not set
364//            BufferedImage img = diagram.getUniverse().getImage(imageSrc);
365//            if (img == null)
366//            {
367//                xform = new AffineTransform();
368//                bounds = new Rectangle2D.Float();
369//            }
370//            else
371//            {
372//                if (width == 0) width = img.getWidth();
373//                if (height == 0) height = img.getHeight();
374//
375//                //Determine image xform
376//                xform = new AffineTransform();
377////                xform.setToScale(this.width / img.getWidth(), this.height / img.getHeight());
378////                xform.translate(this.x, this.y);
379//                xform.translate(this.x, this.y);
380//                xform.scale(this.width / img.getWidth(), this.height / img.getHeight());
381//
382//                bounds = new Rectangle2D.Float(this.x, this.y, this.width, this.height);
383//            }
384//
385//            return true;
386        }
387
388        return changeState || shapeChange;
389    }
390}