001/** 002 * Copyright (c) 2011, The University of Southampton and the individual contributors. 003 * All rights reserved. 004 * 005 * Redistribution and use in source and binary forms, with or without modification, 006 * are permitted provided that the following conditions are met: 007 * 008 * * Redistributions of source code must retain the above copyright notice, 009 * this list of conditions and the following disclaimer. 010 * 011 * * Redistributions in binary form must reproduce the above copyright notice, 012 * this list of conditions and the following disclaimer in the documentation 013 * and/or other materials provided with the distribution. 014 * 015 * * Neither the name of the University of Southampton nor the names of its 016 * contributors may be used to endorse or promote products derived from this 017 * software without specific prior written permission. 018 * 019 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 020 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 021 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 022 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 023 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 024 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 025 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 026 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 027 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 028 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 029 */ 030package org.openimaj.image; 031 032import java.awt.geom.AffineTransform; 033import java.awt.image.BufferedImage; 034import java.io.ByteArrayInputStream; 035import java.io.ByteArrayOutputStream; 036import java.io.IOException; 037import java.io.OutputStreamWriter; 038import java.util.Comparator; 039 040import org.apache.batik.svggen.SVGGraphics2DIOException; 041import org.apache.batik.transcoder.TranscoderException; 042import org.apache.batik.transcoder.TranscoderInput; 043import org.apache.batik.transcoder.TranscoderOutput; 044import org.apache.batik.transcoder.image.ImageTranscoder; 045import org.apache.batik.transcoder.image.PNGTranscoder; 046import org.openimaj.image.colour.RGBColour; 047import org.openimaj.image.renderer.ImageRenderer; 048import org.openimaj.image.renderer.RenderHints; 049import org.openimaj.image.renderer.SVGRenderHints; 050import org.openimaj.image.renderer.SVGRenderer; 051import org.openimaj.math.geometry.point.Point2dImpl; 052import org.openimaj.math.geometry.shape.Rectangle; 053 054public class SVGImage extends Image<Float[], SVGImage> { 055 private SVGRenderer renderer; 056 057 /** 058 * @param hints 059 */ 060 public SVGImage(SVGRenderHints hints) { 061 this.renderer = new SVGRenderer(null, hints); 062 this.renderer.setImage(this); 063 } 064 065 private SVGImage() { 066 // TODO Auto-generated constructor stub 067 } 068 069 /** 070 * Construct an empty SVG-backed image of the given size 071 * 072 * @param w 073 * the width 074 * @param h 075 * the height 076 */ 077 public SVGImage(int w, int h) { 078 this(new SVGRenderHints(w, h)); 079 } 080 081 @Override 082 public SVGImage abs() { 083 return this; 084 } 085 086 @Override 087 public SVGImage addInplace(Image<?, ?> im) { 088 if (!(im instanceof SVGImage)) { 089 this.renderer.drawOIImage(im); 090 } else { 091 this.renderer.drawImage((SVGImage) im, 0, 0); 092 } 093 return null; 094 } 095 096 @Override 097 public SVGImage addInplace(Float[] num) { 098 return this; 099 } 100 101 @Override 102 public SVGImage clip(Float[] min, Float[] max) { 103 return this; 104 } 105 106 @Override 107 public SVGImage clipMax(Float[] thresh) { 108 return this; 109 } 110 111 @Override 112 public SVGImage clipMin(Float[] thresh) { 113 return this; 114 } 115 116 @Override 117 public SVGImage clone() { 118 final SVGImage svgImage = new SVGImage(); 119 svgImage.renderer = new SVGRenderer(svgImage, this.renderer.getGraphics2D().create()); 120 return svgImage; 121 } 122 123 @Override 124 public SVGRenderer createRenderer() { 125 return this.renderer; 126 } 127 128 @Override 129 public ImageRenderer<Float[], SVGImage> createRenderer(RenderHints options) { 130 return this.renderer; 131 } 132 133 @Override 134 public SVGImage divideInplace(Image<?, ?> im) { 135 throw new UnsupportedOperationException(); 136 } 137 138 @Override 139 public SVGImage divideInplace(Float[] val) { 140 throw new UnsupportedOperationException(); 141 } 142 143 @Override 144 public SVGImage extractROI(int x, int y, SVGImage img) { 145 img.renderer = new SVGRenderer(img, img.renderer.getRenderHints(), this.renderer.getGraphics2D().create(x, y, 146 img.getWidth(), img.getHeight())); 147 return img; 148 } 149 150 @Override 151 public SVGImage extractROI(int x, int y, int w, int h) { 152 final SVGImage ret = new SVGImage(w, h); 153 return extractROI(x, y, ret); 154 } 155 156 @Override 157 public SVGImage extractCentreSubPix(float cx, float cy, SVGImage out) { 158 return extractCenter((int) cx, (int) cy, out.getWidth(), out.getHeight()); 159 } 160 161 @Override 162 public SVGImage fill(Float[] colour) { 163 final SVGRenderHints hint = (SVGRenderHints) this.renderer.getRenderHints(); 164 this.renderer = new SVGRenderer(hint); 165 this.renderer.drawShapeFilled(this.getBounds(), colour); 166 return this; 167 } 168 169 @Override 170 public SVGImage flipX() { 171 final AffineTransform tx = AffineTransform.getScaleInstance(-1, 1); 172 tx.translate(this.getWidth(), 0); 173 this.renderer.getGraphics2D().transform(tx); 174 return this; 175 } 176 177 @Override 178 public SVGImage flipY() { 179 final AffineTransform tx = AffineTransform.getScaleInstance(1, -1); 180 tx.translate(0, -this.getHeight()); 181 this.renderer.getGraphics2D().transform(tx); 182 return this; 183 } 184 185 @Override 186 public Rectangle getContentArea() { 187 return new Rectangle(0, 0, getWidth(), getHeight()); 188 } 189 190 @Override 191 public SVGImage getField(org.openimaj.image.Image.Field f) { 192 throw new UnsupportedOperationException(); 193 } 194 195 @Override 196 public SVGImage getFieldCopy(org.openimaj.image.Image.Field f) { 197 throw new UnsupportedOperationException(); 198 } 199 200 @Override 201 public SVGImage getFieldInterpolate(org.openimaj.image.Image.Field f) { 202 throw new UnsupportedOperationException(); 203 } 204 205 @Override 206 public int getHeight() { 207 return this.renderer.getGraphics2D().getSVGCanvasSize().height; 208 } 209 210 @Override 211 public Float[] getPixel(int x, int y) { 212 throw new UnsupportedOperationException(); 213 } 214 215 @Override 216 public Comparator<? super Float[]> getPixelComparator() { 217 throw new UnsupportedOperationException(); 218 } 219 220 @Override 221 public Float[] getPixelInterp(double x, double y) { 222 throw new UnsupportedOperationException(); 223 } 224 225 @Override 226 public Float[] getPixelInterp(double x, double y, Float[] backgroundColour) { 227 throw new UnsupportedOperationException(); 228 } 229 230 @Override 231 public int getWidth() { 232 return this.renderer.getGraphics2D().getSVGCanvasSize().width; 233 } 234 235 @Override 236 public SVGImage internalCopy(SVGImage im) { 237 this.renderer = im.renderer.clone(); 238 this.renderer.setImage(this); 239 return this; 240 } 241 242 @Override 243 public SVGImage internalAssign(SVGImage im) { 244 this.renderer = im.renderer; 245 return this; 246 } 247 248 @Override 249 public SVGImage internalAssign(int[] pixelData, int width, int height) { 250 throw new UnsupportedOperationException(); 251 } 252 253 @Override 254 public SVGImage inverse() { 255 throw new UnsupportedOperationException(); 256 } 257 258 @Override 259 public Float[] max() { 260 throw new UnsupportedOperationException(); 261 } 262 263 @Override 264 public Float[] min() { 265 throw new UnsupportedOperationException(); 266 } 267 268 @Override 269 public SVGImage multiplyInplace(Image<?, ?> im) { 270 throw new UnsupportedOperationException(); 271 } 272 273 @Override 274 public SVGImage multiplyInplace(Float[] num) { 275 throw new UnsupportedOperationException(); 276 } 277 278 @Override 279 public SVGImage newInstance(int width, int height) { 280 return new SVGImage(width, height); 281 } 282 283 @Override 284 public SVGImage normalise() { 285 throw new UnsupportedOperationException(); 286 } 287 288 @Override 289 public void setPixel(int x, int y, Float[] val) { 290 this.renderer.drawPoint(new Point2dImpl(x, y), val, 1); 291 } 292 293 @Override 294 public SVGImage subtractInplace(Image<?, ?> im) { 295 throw new UnsupportedOperationException(); 296 } 297 298 @Override 299 public SVGImage subtractInplace(Float[] num) { 300 throw new UnsupportedOperationException(); 301 } 302 303 @Override 304 public SVGImage threshold(Float[] thresh) { 305 throw new UnsupportedOperationException(); 306 } 307 308 private static class BufferedImageTranscoder extends ImageTranscoder { 309 310 private BufferedImage img; 311 312 @Override 313 public BufferedImage createImage(int w, int h) { 314 final BufferedImage bi = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); 315 return bi; 316 } 317 318 @Override 319 public void writeImage(BufferedImage img, TranscoderOutput arg1) 320 throws TranscoderException 321 { 322 this.img = img; 323 } 324 325 public BufferedImage getBufferedImage() { 326 return this.img; 327 } 328 329 } 330 331 @Override 332 public byte[] toByteImage() { 333 final MBFImage mbf = createMBFImage(); 334 return mbf.toByteImage(); 335 } 336 337 public MBFImage createMBFImage() { 338 final BufferedImageTranscoder t = new BufferedImageTranscoder(); 339 t.addTranscodingHint(PNGTranscoder.KEY_WIDTH, (float) getWidth()); 340 t.addTranscodingHint(PNGTranscoder.KEY_HEIGHT, (float) getHeight()); 341 final ByteArrayOutputStream baos = new ByteArrayOutputStream(); 342 try { 343 this.renderer.write(new OutputStreamWriter(baos)); 344 baos.flush(); 345 baos.close(); 346 final byte[] barr = baos.toByteArray(); 347 final TranscoderInput input = new TranscoderInput(new ByteArrayInputStream(barr)); 348 t.transcode(input, null); 349 } catch (final SVGGraphics2DIOException e) { 350 } catch (final IOException e) { 351 } catch (final TranscoderException e) { 352 } 353 final MBFImage mbf = ImageUtilities.createMBFImage(t.getBufferedImage(), true); 354 return mbf; 355 } 356 357 @Override 358 public int[] toPackedARGBPixels() { 359 final MBFImage mbf = createMBFImage(); 360 return mbf.toPackedARGBPixels(); 361 } 362 363 @Override 364 public SVGImage zero() { 365 final SVGRenderHints hint = (SVGRenderHints) this.renderer.getRenderHints(); 366 this.renderer = new SVGRenderer(hint); 367 this.renderer.drawShapeFilled(this.getBounds(), RGBColour.BLACK); 368 return this; 369 } 370 371 @Override 372 public SVGImage overlayInplace(SVGImage image, int x, int y) { 373 throw new UnsupportedOperationException(); 374 } 375 376 @Override 377 public SVGImage replace(Float[] target, Float[] replacement) { 378 throw new UnsupportedOperationException(); 379 } 380}