KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > batik > svggen > DefaultCachedImageHandler


1 /*
2
3    Copyright 2001,2003 The Apache Software Foundation
4
5    Licensed under the Apache License, Version 2.0 (the "License");
6    you may not use this file except in compliance with the License.
7    You may obtain a copy of the License at
8
9        http://www.apache.org/licenses/LICENSE-2.0
10
11    Unless required by applicable law or agreed to in writing, software
12    distributed under the License is distributed on an "AS IS" BASIS,
13    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14    See the License for the specific language governing permissions and
15    limitations under the License.
16
17  */

18 package org.apache.batik.svggen;
19
20 import java.awt.Dimension JavaDoc;
21 import java.awt.Graphics2D JavaDoc;
22 import java.awt.Image JavaDoc;
23 import java.awt.geom.AffineTransform JavaDoc;
24 import java.awt.image.BufferedImage JavaDoc;
25 import java.awt.image.RenderedImage JavaDoc;
26 import java.awt.image.renderable.RenderableImage JavaDoc;
27 import java.io.ByteArrayOutputStream JavaDoc;
28 import java.io.IOException JavaDoc;
29 import java.io.OutputStream JavaDoc;
30 import java.lang.reflect.Method JavaDoc;
31
32 import org.w3c.dom.Element JavaDoc;
33
34 /**
35  * This class is a default implementation of the GenericImageHandler
36  * for handlers implementing a caching strategy.
37  *
38  * @author <a HREF="mailto:vincent.hardy@eng.sun.com">Vincent Hardy</a>
39  * @version $Id: DefaultCachedImageHandler.java,v 1.8 2004/08/18 07:14:59 vhardy Exp $
40  * @see org.apache.batik.svggen.SVGGraphics2D
41  */

42 public abstract class DefaultCachedImageHandler
43     implements CachedImageHandler,
44                SVGSyntax,
45                ErrorConstants {
46
47     // duplicate the string here to remove dependencies on
48
// org.apache.batik.dom.util.XLinkSupport
49
static final String JavaDoc XLINK_NAMESPACE_URI =
50         "http://www.w3.org/1999/xlink";
51
52     static final AffineTransform JavaDoc IDENTITY = new AffineTransform JavaDoc();
53
54     // for createGraphics method.
55
private static Method JavaDoc createGraphics = null;
56     private static boolean initDone = false;
57     private final static Class JavaDoc[] paramc = new Class JavaDoc[] {BufferedImage JavaDoc.class};
58     private static Object JavaDoc[] paramo = null;
59
60     protected ImageCacher imageCacher;
61
62     /**
63      * The image cache can be used by subclasses for efficient image storage
64      */

65     public ImageCacher getImageCacher() {
66         return imageCacher;
67     }
68
69     void setImageCacher(ImageCacher imageCacher) {
70         if (imageCacher == null){
71             throw new IllegalArgumentException JavaDoc();
72         }
73
74         // Save current DOMTreeManager if any
75
DOMTreeManager dtm = null;
76         if (this.imageCacher != null){
77             dtm = this.imageCacher.getDOMTreeManager();
78         }
79
80         this.imageCacher = imageCacher;
81         if (dtm != null){
82             this.imageCacher.setDOMTreeManager(dtm);
83         }
84     }
85
86     /**
87      * This <tt>GenericImageHandler</tt> implementation does not
88      * need to interact with the DOMTreeManager.
89      */

90     public void setDOMTreeManager(DOMTreeManager domTreeManager){
91         imageCacher.setDOMTreeManager(domTreeManager);
92     }
93
94     /**
95      * This method creates a <code>Graphics2D</code> from a
96      * <code>BufferedImage</code>. If Batik extensions to AWT are
97      * in the CLASSPATH it uses them, otherwise, it uses the regular
98      * AWT method.
99      */

100     private static Graphics2D JavaDoc createGraphics(BufferedImage JavaDoc buf) {
101         if (!initDone) {
102             try {
103                 Class JavaDoc clazz = Class.forName("org.apache.batik.ext.awt.image.GraphicsUtil");
104                 createGraphics = clazz.getMethod("createGraphics", paramc);
105                 paramo = new Object JavaDoc[1];
106             } catch (Throwable JavaDoc t) {
107                 // happen only if Batik extensions are not their
108
} finally {
109                 initDone = true;
110             }
111         }
112         if (createGraphics == null)
113             return buf.createGraphics();
114         else {
115             paramo[0] = buf;
116             Graphics2D JavaDoc g2d = null;
117             try {
118                 g2d = (Graphics2D JavaDoc)createGraphics.invoke(null, paramo);
119             } catch (Exception JavaDoc e) {
120                 // should not happened
121
}
122             return g2d;
123         }
124     }
125
126     /**
127      * Creates an Element which can refer to an image.
128      * Note that no assumptions should be made by the caller about the
129      * corresponding SVG tag. By default, an &lt;image&gt; tag is
130      * used, but the {@link CachedImageHandlerBase64Encoder}, for
131      * example, overrides this method to use a different tag.
132      */

133     public Element JavaDoc createElement(SVGGeneratorContext generatorContext) {
134         // Create a DOM Element in SVG namespace to refer to an image
135
Element JavaDoc imageElement =
136             generatorContext.getDOMFactory().createElementNS
137             (SVG_NAMESPACE_URI, SVG_IMAGE_TAG);
138
139         return imageElement;
140     }
141
142     /**
143      * The handler sets the xlink:href tag and returns a transform
144      */

145     public AffineTransform JavaDoc handleImage(Image JavaDoc image,
146                                        Element JavaDoc imageElement,
147                                        int x, int y,
148                                        int width, int height,
149                                        SVGGeneratorContext generatorContext) {
150
151         int imageWidth = image.getWidth(null);
152         int imageHeight = image.getHeight(null);
153         AffineTransform JavaDoc af = null;
154
155         if(imageWidth == 0 || imageHeight == 0 ||
156            width == 0 || height == 0) {
157
158             // Forget about it
159
handleEmptyImage(imageElement);
160
161         } else {
162             // First set the href
163
try {
164                 handleHREF(image, imageElement, generatorContext);
165             } catch (SVGGraphics2DIOException e) {
166                 try {
167                     generatorContext.errorHandler.handleError(e);
168                 } catch (SVGGraphics2DIOException io) {
169                     // we need a runtime exception because
170
// java.awt.Graphics2D method doesn't throw exceptions..
171
throw new SVGGraphics2DRuntimeException(io);
172                 }
173             }
174
175             // Then create the transformation:
176
// Because we cache image data, the stored image may
177
// need to be scaled.
178
af = handleTransform(imageElement, x, y, imageWidth, imageHeight,
179                                  width, height, generatorContext);
180         }
181         return af;
182     }
183
184     /**
185      * The handler sets the xlink:href tag and returns a transform
186      */

187     public AffineTransform JavaDoc handleImage(RenderedImage JavaDoc image,
188                                        Element JavaDoc imageElement,
189                                        int x, int y,
190                                        int width, int height,
191                                        SVGGeneratorContext generatorContext) {
192
193         int imageWidth = image.getWidth();
194         int imageHeight = image.getHeight();
195         AffineTransform JavaDoc af = null;
196
197         if(imageWidth == 0 || imageHeight == 0 ||
198            width == 0 || height == 0) {
199
200             // Forget about it
201
handleEmptyImage(imageElement);
202
203         } else {
204             // First set the href
205
try {
206                 handleHREF(image, imageElement, generatorContext);
207             } catch (SVGGraphics2DIOException e) {
208                 try {
209                     generatorContext.errorHandler.handleError(e);
210                 } catch (SVGGraphics2DIOException io) {
211                     // we need a runtime exception because
212
// java.awt.Graphics2D method doesn't throw exceptions..
213
throw new SVGGraphics2DRuntimeException(io);
214                 }
215             }
216
217             // Then create the transformation:
218
// Because we cache image data, the stored image may
219
// need to be scaled.
220
af = handleTransform(imageElement, x, y, imageWidth, imageHeight,
221                                  width, height, generatorContext);
222         }
223         return af;
224     }
225
226     /**
227      * The handler sets the xlink:href tag and returns a transform
228      */

229     public AffineTransform JavaDoc handleImage(RenderableImage JavaDoc image,
230                                        Element JavaDoc imageElement,
231                                        double x, double y,
232                                        double width, double height,
233                                        SVGGeneratorContext generatorContext) {
234
235         double imageWidth = image.getWidth();
236         double imageHeight = image.getHeight();
237         AffineTransform JavaDoc af = null;
238
239         if(imageWidth == 0 || imageHeight == 0 ||
240            width == 0 || height == 0) {
241
242             // Forget about it
243
handleEmptyImage(imageElement);
244
245         } else {
246             // First set the href
247
try {
248                 handleHREF(image, imageElement, generatorContext);
249             } catch (SVGGraphics2DIOException e) {
250                 try {
251                     generatorContext.errorHandler.handleError(e);
252                 } catch (SVGGraphics2DIOException io) {
253                     // we need a runtime exception because
254
// java.awt.Graphics2D method doesn't throw exceptions..
255
throw new SVGGraphics2DRuntimeException(io);
256                 }
257             }
258
259             // Then create the transformation:
260
// Because we cache image data, the stored image may
261
// need to be scaled.
262
af = handleTransform(imageElement, x,y,
263                                  imageWidth, imageHeight,
264                                  width, height, generatorContext);
265         }
266         return af;
267     }
268
269     /**
270      * Determines the transformation needed to get the cached image to
271      * scale & position properly. Sets x and y attributes on the element
272      * accordingly.
273      */

274     protected AffineTransform JavaDoc handleTransform(Element JavaDoc imageElement,
275                                               double x, double y,
276                                               double srcWidth,
277                                               double srcHeight,
278                                               double dstWidth,
279                                               double dstHeight,
280                                               SVGGeneratorContext generatorContext) {
281         // In this the default case, <image> element, we just
282
// set x, y, width and height attributes.
283
// No additional transform is necessary.
284
imageElement.setAttributeNS(null,
285                                     SVG_X_ATTRIBUTE,
286                                     generatorContext.doubleString(x));
287         imageElement.setAttributeNS(null,
288                                     SVG_Y_ATTRIBUTE,
289                                     generatorContext.doubleString(y));
290         imageElement.setAttributeNS(null,
291                                     SVG_WIDTH_ATTRIBUTE,
292                                     generatorContext.doubleString(dstWidth));
293         imageElement.setAttributeNS(null,
294                                     SVG_HEIGHT_ATTRIBUTE,
295                                     generatorContext.doubleString(dstHeight));
296         return null;
297     }
298               
299     protected void handleEmptyImage(Element JavaDoc imageElement) {
300         imageElement.setAttributeNS(XLINK_NAMESPACE_URI,
301                                     ATTR_XLINK_HREF, "");
302         imageElement.setAttributeNS(null, SVG_WIDTH_ATTRIBUTE, "0");
303         imageElement.setAttributeNS(null, SVG_HEIGHT_ATTRIBUTE, "0");
304     }
305
306     /**
307      * The handler should set the xlink:href tag and the width and
308      * height attributes.
309      */

310     public void handleHREF(Image JavaDoc image, Element JavaDoc imageElement,
311                            SVGGeneratorContext generatorContext)
312         throws SVGGraphics2DIOException {
313         if (image == null)
314             throw new SVGGraphics2DRuntimeException(ERR_IMAGE_NULL);
315
316         int width = image.getWidth(null);
317         int height = image.getHeight(null);
318
319         if (width==0 || height==0) {
320             handleEmptyImage(imageElement);
321         } else {
322             if (image instanceof RenderedImage JavaDoc) {
323                 handleHREF((RenderedImage JavaDoc)image, imageElement,
324                            generatorContext);
325             } else {
326                 BufferedImage JavaDoc buf = buildBufferedImage(new Dimension JavaDoc(width, height));
327                 Graphics2D JavaDoc g = createGraphics(buf);
328                 g.drawImage(image, 0, 0, null);
329                 g.dispose();
330                 handleHREF((RenderedImage JavaDoc)buf, imageElement,
331                            generatorContext);
332             }
333         }
334     }
335
336     /**
337      * This method creates a BufferedImage of the right size and type
338      * for the derived class.
339      */

340     public BufferedImage JavaDoc buildBufferedImage(Dimension JavaDoc size){
341         return new BufferedImage JavaDoc(size.width, size.height, getBufferedImageType());
342     }
343
344     /**
345      * This template method should set the xlink:href attribute on the input
346      * Element parameter
347      */

348     protected void handleHREF(RenderedImage JavaDoc image, Element JavaDoc imageElement,
349                               SVGGeneratorContext generatorContext)
350         throws SVGGraphics2DIOException {
351         //
352
// Create an buffered image if necessary
353
//
354
BufferedImage JavaDoc buf = null;
355         if (image instanceof BufferedImage JavaDoc
356             &&
357             ((BufferedImage JavaDoc)image).getType() == getBufferedImageType()){
358             buf = (BufferedImage JavaDoc)image;
359         } else {
360             Dimension JavaDoc size = new Dimension JavaDoc(image.getWidth(), image.getHeight());
361             buf = buildBufferedImage(size);
362             
363             Graphics2D JavaDoc g = createGraphics(buf);
364             
365             g.drawRenderedImage(image, IDENTITY);
366             g.dispose();
367         }
368
369         //
370
// Cache image and set xlink:href
371
//
372
cacheBufferedImage(imageElement, buf, generatorContext);
373     }
374
375     /**
376      * This method will delegate to the <tt>handleHREF</tt> which
377      * uses a <tt>RenderedImage</tt>
378      */

379     protected void handleHREF(RenderableImage JavaDoc image, Element JavaDoc imageElement,
380                               SVGGeneratorContext generatorContext)
381         throws SVGGraphics2DIOException {
382         // Create an buffered image where the image will be drawn
383
Dimension JavaDoc size = new Dimension JavaDoc((int)Math.ceil(image.getWidth()),
384                                        (int)Math.ceil(image.getHeight()));
385         BufferedImage JavaDoc buf = buildBufferedImage(size);
386
387         Graphics2D JavaDoc g = createGraphics(buf);
388
389         g.drawRenderableImage(image, IDENTITY);
390         g.dispose();
391
392         handleHREF((RenderedImage JavaDoc)buf, imageElement, generatorContext);
393     }
394
395     protected void cacheBufferedImage(Element JavaDoc imageElement,
396                                       BufferedImage JavaDoc buf,
397                                       SVGGeneratorContext generatorContext)
398         throws SVGGraphics2DIOException {
399         
400         ByteArrayOutputStream JavaDoc os;
401         
402         if (generatorContext == null)
403             throw new SVGGraphics2DRuntimeException(ERR_CONTEXT_NULL);
404         
405         try {
406             os = new ByteArrayOutputStream JavaDoc();
407             // encode the image in memory
408
encodeImage(buf, os);
409             os.flush();
410             os.close();
411         } catch (IOException JavaDoc e) {
412             // should not happen since we do in-memory processing
413
throw new SVGGraphics2DIOException(ERR_UNEXPECTED, e);
414         }
415         
416         // ask the cacher for a reference
417
String JavaDoc ref = imageCacher.lookup(os,
418                                                   buf.getWidth(),
419                                                   buf.getHeight(),
420                                                   generatorContext);
421         
422         // set the URL
423
imageElement.setAttributeNS(XLINK_NAMESPACE_URI,
424                                     ATTR_XLINK_HREF,
425                                     getRefPrefix() + ref);
426     }
427  
428     /**
429      * Should return the prefix with wich the image reference
430      * should be pre-concatenated.
431      */

432     public abstract String JavaDoc getRefPrefix();
433
434     /**
435      * Derived classes should implement this method and encode the input
436      * BufferedImage as needed
437      */

438     public abstract void encodeImage(BufferedImage JavaDoc buf, OutputStream JavaDoc os)
439         throws IOException JavaDoc;
440  
441     /**
442      * This template method should be overridden by derived classes to
443      * declare the image type they need for saving to file.
444      */

445     public abstract int getBufferedImageType();
446   
447 }
448
Popular Tags