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                
115                
116                URI src = sty.getURIValue(getXMLBase());
117                if ("data".equals(src.getScheme()))
118                {
119                    imageSrc = new URL(null, src.toASCIIString(), new Handler());
120                }
121                else 
122                {
123                    
124                    if (!diagram.getUniverse().isImageDataInlineOnly())
125                    {
126                        try
127                        {
128                            imageSrc = src.toURL();
129                        } catch (Exception e)
130                        {
131                            Logger.getLogger(SVGConst.SVG_LOGGER).log(Level.WARNING,
132                                "Could not parse xlink:href " + src, e);
133    //                        e.printStackTrace();
134                            imageSrc = null;
135                        }
136                    }
137                }
138            }
139        } catch (Exception e)
140        {
141            throw new SVGException(e);
142        }
143
144        diagram.getUniverse().registerImage(imageSrc);
145
146        //Set widths if not set
147        BufferedImage img = diagram.getUniverse().getImage(imageSrc);
148        if (img == null)
149        {
150            xform = new AffineTransform();
151            bounds = new Rectangle2D.Float();
152            return;
153        }
154
155        if (width == 0)
156        {
157            width = img.getWidth();
158        }
159        if (height == 0)
160        {
161            height = img.getHeight();
162        }
163
164        //Determine image xform
165        xform = new AffineTransform();
166//        xform.setToScale(this.width / img.getWidth(), this.height / img.getHeight());
167//        xform.translate(this.x, this.y);
168        xform.translate(this.x, this.y);
169        xform.scale(this.width / img.getWidth(), this.height / img.getHeight());
170
171        bounds = new Rectangle2D.Float(this.x, this.y, this.width, this.height);
172    }
173
174    public float getX()
175    {
176        return x;
177    }
178
179    public float getY()
180    {
181        return y;
182    }
183
184    public float getWidth()
185    {
186        return width;
187    }
188
189    public float getHeight()
190    {
191        return height;
192    }
193
194    void pick(Point2D point, boolean boundingBox, List retVec) throws SVGException
195    {
196        if (getBoundingBox().contains(point))
197        {
198            retVec.add(getPath(null));
199        }
200    }
201
202    void pick(Rectangle2D pickArea, AffineTransform ltw, boolean boundingBox, List retVec) throws SVGException
203    {
204        if (ltw.createTransformedShape(getBoundingBox()).intersects(pickArea))
205        {
206            retVec.add(getPath(null));
207        }
208    }
209
210    public void render(Graphics2D g) throws SVGException
211    {
212        StyleAttribute styleAttrib = new StyleAttribute();
213        if (getStyle(styleAttrib.setName("visibility")))
214        {
215            if (!styleAttrib.getStringValue().equals("visible"))
216            {
217                return;
218            }
219        }
220
221        if (getStyle(styleAttrib.setName("display")))
222        {
223            if (styleAttrib.getStringValue().equals("none"))
224            {
225                return;
226            }
227        }
228
229        beginLayer(g);
230
231        float opacity = 1f;
232        if (getStyle(styleAttrib.setName("opacity")))
233        {
234            opacity = styleAttrib.getRatioValue();
235        }
236
237        if (opacity <= 0)
238        {
239            return;
240        }
241
242        Composite oldComp = null;
243
244        if (opacity < 1)
245        {
246            oldComp = g.getComposite();
247            Composite comp = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, opacity);
248            g.setComposite(comp);
249        }
250
251        BufferedImage img = diagram.getUniverse().getImage(imageSrc);
252        if (img == null)
253        {
254            return;
255        }
256
257        AffineTransform curXform = g.getTransform();
258        g.transform(xform);
259
260        g.drawImage(img, 0, 0, null);
261
262        g.setTransform(curXform);
263        if (oldComp != null)
264        {
265            g.setComposite(oldComp);
266        }
267
268        finishLayer(g);
269    }
270
271    public Rectangle2D getBoundingBox()
272    {
273        return boundsToParent(bounds);
274    }
275
276    /**
277     * Updates all attributes in this diagram associated with a time event. Ie,
278     * all attributes with track information.
279     *
280     * @return - true if this node has changed state as a result of the time
281     * update
282     */
283    public boolean updateTime(double curTime) throws SVGException
284    {
285//        if (trackManager.getNumTracks() == 0) return false;
286        boolean changeState = super.updateTime(curTime);
287
288        //Get current values for parameters
289        StyleAttribute sty = new StyleAttribute();
290        boolean shapeChange = false;
291
292        if (getPres(sty.setName("x")))
293        {
294            float newVal = sty.getFloatValueWithUnits();
295            if (newVal != x)
296            {
297                x = newVal;
298                shapeChange = true;
299            }
300        }
301
302        if (getPres(sty.setName("y")))
303        {
304            float newVal = sty.getFloatValueWithUnits();
305            if (newVal != y)
306            {
307                y = newVal;
308                shapeChange = true;
309            }
310        }
311
312        if (getPres(sty.setName("width")))
313        {
314            float newVal = sty.getFloatValueWithUnits();
315            if (newVal != width)
316            {
317                width = newVal;
318                shapeChange = true;
319            }
320        }
321
322        if (getPres(sty.setName("height")))
323        {
324            float newVal = sty.getFloatValueWithUnits();
325            if (newVal != height)
326            {
327                height = newVal;
328                shapeChange = true;
329            }
330        }
331
332        try
333        {
334            if (getPres(sty.setName("xlink:href")))
335            {
336                URI src = sty.getURIValue(getXMLBase());
337
338                URL newVal;
339                if ("data".equals(src.getScheme()))
340                {
341                    newVal = new URL(null, src.toASCIIString(), new Handler());
342                } else
343                {
344                    newVal = src.toURL();
345                }
346
347                if (!newVal.equals(imageSrc))
348                {
349                    imageSrc = newVal;
350                    shapeChange = true;
351                }
352            }
353        } catch (IllegalArgumentException ie)
354        {
355            Logger.getLogger(SVGConst.SVG_LOGGER).log(Level.WARNING,
356                "Image provided with illegal value for href: \""
357                + sty.getStringValue() + '"', ie);
358        } catch (Exception e)
359        {
360            Logger.getLogger(SVGConst.SVG_LOGGER).log(Level.WARNING,
361                "Could not parse xlink:href", e);
362        }
363
364
365        if (shapeChange)
366        {
367            build();
368//            diagram.getUniverse().registerImage(imageSrc);
369//
370//            //Set widths if not set
371//            BufferedImage img = diagram.getUniverse().getImage(imageSrc);
372//            if (img == null)
373//            {
374//                xform = new AffineTransform();
375//                bounds = new Rectangle2D.Float();
376//            }
377//            else
378//            {
379//                if (width == 0) width = img.getWidth();
380//                if (height == 0) height = img.getHeight();
381//
382//                //Determine image xform
383//                xform = new AffineTransform();
384////                xform.setToScale(this.width / img.getWidth(), this.height / img.getHeight());
385////                xform.translate(this.x, this.y);
386//                xform.translate(this.x, this.y);
387//                xform.scale(this.width / img.getWidth(), this.height / img.getHeight());
388//
389//                bounds = new Rectangle2D.Float(this.x, this.y, this.width, this.height);
390//            }
391//
392//            return true;
393        }
394
395        return changeState || shapeChange;
396    }
397}