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