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(hints);
062        }
063
064        private SVGImage() {
065                // TODO Auto-generated constructor stub
066        }
067
068        /**
069         * Construct an empty SVG-backed image of the given size
070         * 
071         * @param w
072         *            the width
073         * @param h
074         *            the height
075         */
076        public SVGImage(int w, int h) {
077                this(new SVGRenderHints(w, h));
078        }
079
080        @Override
081        public SVGImage abs() {
082                return this;
083        }
084
085        @Override
086        public SVGImage addInplace(Image<?, ?> im) {
087                if (!(im instanceof SVGImage)) {
088                        this.renderer.drawOIImage(im);
089                } else {
090                        this.renderer.drawImage((SVGImage) im, 0, 0);
091                }
092                return null;
093        }
094
095        @Override
096        public SVGImage addInplace(Float[] num) {
097                return this;
098        }
099
100        @Override
101        public SVGImage clip(Float[] min, Float[] max) {
102                return this;
103        }
104
105        @Override
106        public SVGImage clipMax(Float[] thresh) {
107                return this;
108        }
109
110        @Override
111        public SVGImage clipMin(Float[] thresh) {
112                return this;
113        }
114
115        @Override
116        public SVGImage clone() {
117                final SVGImage svgImage = new SVGImage();
118                svgImage.renderer = new SVGRenderer(svgImage, this.renderer.getGraphics2D().create());
119                return svgImage;
120        }
121
122        @Override
123        public SVGRenderer createRenderer() {
124                return this.renderer;
125        }
126
127        @Override
128        public ImageRenderer<Float[], SVGImage> createRenderer(RenderHints options) {
129                return this.renderer;
130        }
131
132        @Override
133        public SVGImage divideInplace(Image<?, ?> im) {
134                throw new UnsupportedOperationException();
135        }
136
137        @Override
138        public SVGImage divideInplace(Float[] val) {
139                throw new UnsupportedOperationException();
140        }
141
142        @Override
143        public SVGImage extractROI(int x, int y, SVGImage img) {
144                img.renderer = new SVGRenderer(img, img.renderer.getRenderHints(), this.renderer.getGraphics2D().create(x, y,
145                                img.getWidth(), img.getHeight()));
146                return img;
147        }
148
149        @Override
150        public SVGImage extractROI(int x, int y, int w, int h) {
151                final SVGImage ret = new SVGImage(w, h);
152                return extractROI(x, y, ret);
153        }
154
155        @Override
156        public SVGImage extractCentreSubPix(float cx, float cy, SVGImage out) {
157                return extractCenter((int) cx, (int) cy, out.getWidth(), out.getHeight());
158        }
159
160        @Override
161        public SVGImage fill(Float[] colour) {
162                final SVGRenderHints hint = (SVGRenderHints) this.renderer.getRenderHints();
163                this.renderer = new SVGRenderer(hint);
164                this.renderer.drawShapeFilled(this.getBounds(), colour);
165                return this;
166        }
167
168        @Override
169        public SVGImage flipX() {
170                final AffineTransform tx = AffineTransform.getScaleInstance(-1, 1);
171                tx.translate(this.getWidth(), 0);
172                this.renderer.getGraphics2D().transform(tx);
173                return this;
174        }
175
176        @Override
177        public SVGImage flipY() {
178                final AffineTransform tx = AffineTransform.getScaleInstance(1, -1);
179                tx.translate(0, -this.getHeight());
180                this.renderer.getGraphics2D().transform(tx);
181                return this;
182        }
183
184        @Override
185        public Rectangle getContentArea() {
186                return new Rectangle(0, 0, getWidth(), getHeight());
187        }
188
189        @Override
190        public SVGImage getField(org.openimaj.image.Image.Field f) {
191                throw new UnsupportedOperationException();
192        }
193
194        @Override
195        public SVGImage getFieldCopy(org.openimaj.image.Image.Field f) {
196                throw new UnsupportedOperationException();
197        }
198
199        @Override
200        public SVGImage getFieldInterpolate(org.openimaj.image.Image.Field f) {
201                throw new UnsupportedOperationException();
202        }
203
204        @Override
205        public int getHeight() {
206                return this.renderer.getGraphics2D().getSVGCanvasSize().height;
207        }
208
209        @Override
210        public Float[] getPixel(int x, int y) {
211                throw new UnsupportedOperationException();
212        }
213
214        @Override
215        public Comparator<? super Float[]> getPixelComparator() {
216                throw new UnsupportedOperationException();
217        }
218
219        @Override
220        public Float[] getPixelInterp(double x, double y) {
221                throw new UnsupportedOperationException();
222        }
223
224        @Override
225        public Float[] getPixelInterp(double x, double y, Float[] backgroundColour) {
226                throw new UnsupportedOperationException();
227        }
228
229        @Override
230        public int getWidth() {
231                return this.renderer.getGraphics2D().getSVGCanvasSize().width;
232        }
233
234        @Override
235        public SVGImage internalCopy(SVGImage im) {
236                this.renderer = im.renderer.clone();
237                this.renderer.setImage(this);
238                return this;
239        }
240
241        @Override
242        public SVGImage internalAssign(SVGImage im) {
243                this.renderer = im.renderer;
244                return this;
245        }
246
247        @Override
248        public SVGImage internalAssign(int[] pixelData, int width, int height) {
249                throw new UnsupportedOperationException();
250        }
251
252        @Override
253        public SVGImage inverse() {
254                throw new UnsupportedOperationException();
255        }
256
257        @Override
258        public Float[] max() {
259                throw new UnsupportedOperationException();
260        }
261
262        @Override
263        public Float[] min() {
264                throw new UnsupportedOperationException();
265        }
266
267        @Override
268        public SVGImage multiplyInplace(Image<?, ?> im) {
269                throw new UnsupportedOperationException();
270        }
271
272        @Override
273        public SVGImage multiplyInplace(Float[] num) {
274                throw new UnsupportedOperationException();
275        }
276
277        @Override
278        public SVGImage newInstance(int width, int height) {
279                return new SVGImage(width, height);
280        }
281
282        @Override
283        public SVGImage normalise() {
284                throw new UnsupportedOperationException();
285        }
286
287        @Override
288        public void setPixel(int x, int y, Float[] val) {
289                this.renderer.drawPoint(new Point2dImpl(x, y), val, 1);
290        }
291
292        @Override
293        public SVGImage subtractInplace(Image<?, ?> im) {
294                throw new UnsupportedOperationException();
295        }
296
297        @Override
298        public SVGImage subtractInplace(Float[] num) {
299                throw new UnsupportedOperationException();
300        }
301
302        @Override
303        public SVGImage threshold(Float[] thresh) {
304                throw new UnsupportedOperationException();
305        }
306
307        private static class BufferedImageTranscoder extends ImageTranscoder {
308
309                private BufferedImage img;
310
311                @Override
312                public BufferedImage createImage(int w, int h) {
313                        final BufferedImage bi = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
314                        return bi;
315                }
316
317                @Override
318                public void writeImage(BufferedImage img, TranscoderOutput arg1)
319                                throws TranscoderException
320                {
321                        this.img = img;
322                }
323
324                public BufferedImage getBufferedImage() {
325                        return this.img;
326                }
327
328        }
329
330        @Override
331        public byte[] toByteImage() {
332                final MBFImage mbf = createMBFImage();
333                return mbf.toByteImage();
334        }
335
336        public MBFImage createMBFImage() {
337                final BufferedImageTranscoder t = new BufferedImageTranscoder();
338                t.addTranscodingHint(PNGTranscoder.KEY_WIDTH, (float) getWidth());
339                t.addTranscodingHint(PNGTranscoder.KEY_HEIGHT, (float) getHeight());
340                final ByteArrayOutputStream baos = new ByteArrayOutputStream();
341                try {
342                        this.renderer.write(new OutputStreamWriter(baos));
343                        baos.flush();
344                        baos.close();
345                        final byte[] barr = baos.toByteArray();
346                        final TranscoderInput input = new TranscoderInput(new ByteArrayInputStream(barr));
347                        t.transcode(input, null);
348                } catch (final SVGGraphics2DIOException e) {
349                } catch (final IOException e) {
350                } catch (final TranscoderException e) {
351                }
352                final MBFImage mbf = ImageUtilities.createMBFImage(t.getBufferedImage(), true);
353                return mbf;
354        }
355
356        @Override
357        public int[] toPackedARGBPixels() {
358                final MBFImage mbf = createMBFImage();
359                return mbf.toPackedARGBPixels();
360        }
361
362        @Override
363        public SVGImage zero() {
364                final SVGRenderHints hint = (SVGRenderHints) this.renderer.getRenderHints();
365                this.renderer = new SVGRenderer(hint);
366                this.renderer.drawShapeFilled(this.getBounds(), RGBColour.BLACK);
367                return this;
368        }
369
370        @Override
371        public SVGImage overlayInplace(SVGImage image, int x, int y) {
372                throw new UnsupportedOperationException();
373        }
374
375        @Override
376        public SVGImage replace(Float[] target, Float[] replacement) {
377                throw new UnsupportedOperationException();
378        }
379}