KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > fop > render > rtf > rtflib > rtfdoc > RtfExternalGraphic


1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements. See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License. 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 /* $Id: RtfExternalGraphic.java 426576 2006-07-28 15:44:37Z jeremias $ */
19
20 package org.apache.fop.render.rtf.rtflib.rtfdoc;
21
22 /*
23  * This file is part of the RTF library of the FOP project, which was originally
24  * created by Bertrand Delacretaz <bdelacretaz@codeconsult.ch> and by other
25  * contributors to the jfor project (www.jfor.org), who agreed to donate jfor to
26  * the FOP project.
27  */

28
29 import org.apache.commons.io.IOUtils;
30 import org.apache.fop.render.rtf.rtflib.tools.ImageConstants;
31 import org.apache.fop.render.rtf.rtflib.tools.ImageUtil;
32 //import org.apache.fop.render.rtf.rtflib.tools.jpeg.Encoder;
33
//import org.apache.fop.render.rtf.rtflib.tools.jpeg.JPEGException;
34

35 import java.io.IOException JavaDoc;
36 import java.io.InputStream JavaDoc;
37 import java.io.Writer JavaDoc;
38
39 import java.io.File JavaDoc;
40 import java.net.URL JavaDoc;
41 import java.net.MalformedURLException JavaDoc;
42
43 /**
44  * Creates an RTF image from an external graphic file.
45  * This class belongs to the <fo:external-graphic> tag processing. <br>
46  *
47  * Supports relative path like "../test.gif", too (01-08-24) <br>
48  *
49  * Limitations:
50  * <li> Only the image types PNG, JPEG and EMF are supported
51  * <li> The GIF is supported, too, but will be converted to JPG
52  * <li> Only the attributes SRC (required), WIDTH, HEIGHT, SCALING are supported
53  * <li> The SCALING attribute supports (uniform | non-uniform)
54  *
55  * Known Bugs:
56  * <li> If the emf image has a desired size, the image will be clipped
57  * <li> The emf, jpg & png image will not be displayed in correct size
58  *
59  * @author <a HREF="mailto:a.putz@skynamics.com">Andreas Putz</a>
60  * @author Gianugo Rabellino gianugo@rabellino.it
61  */

62
63 public class RtfExternalGraphic extends RtfElement {
64     /** Exception thrown when an image file/URL cannot be read */
65     public static class ExternalGraphicException extends IOException JavaDoc {
66         ExternalGraphicException(String JavaDoc reason) {
67             super(reason);
68         }
69     }
70     
71     //////////////////////////////////////////////////
72
// Supported Formats
73
//////////////////////////////////////////////////
74
private static class FormatBase {
75
76         /**
77          * Determines whether the image is in the according format.
78          *
79          * @param data Image
80          *
81          * @return
82          * true If according type\n
83          * false Other type
84          */

85         public static boolean isFormat(byte[] data) {
86             return false;
87         }
88         
89         /**
90          * Convert image data if necessary - for example when format is not supported by rtf.
91          *
92          * @param data Image
93          * @param type Format type
94          */

95         public FormatBase convert(FormatBase format, byte[] data) {
96             return format;
97         }
98         
99         /**
100          * Determine image file format.
101          *
102          * @param data Image
103          *
104          * @return Image format class
105          */

106
107         public static FormatBase determineFormat(byte[] data) {
108
109             if (FormatPNG.isFormat(data)) {
110                 return new FormatPNG();
111             } else if (FormatJPG.isFormat(data)) {
112                 return new FormatJPG();
113             } else if (FormatEMF.isFormat(data)) {
114                 return new FormatEMF();
115             } else if (FormatGIF.isFormat(data)) {
116                 return new FormatGIF();
117             } else if (FormatBMP.isFormat(data)) {
118                 return new FormatBMP();
119             } else {
120                 return null;
121             }
122         }
123         
124         /**
125          * Get image type.
126          *
127          * @return Image format class
128          */

129         public int getType() {
130             return ImageConstants.I_NOT_SUPPORTED;
131         }
132         
133         /**
134          * Get rtf tag.
135          *
136          * @return Rtf tag for image format.
137          */

138         public String JavaDoc getRtfTag() {
139             return "";
140         }
141     }
142     
143     private static class FormatGIF extends FormatBase {
144         public static boolean isFormat(byte[] data) {
145             // Indentifier "GIF8" on position 0
146
byte [] pattern = new byte [] {(byte) 0x47, (byte) 0x49, (byte) 0x46, (byte) 0x38};
147
148             return ImageUtil.compareHexValues(pattern, data, 0, true);
149         }
150         
151         public int getType() {
152             return ImageConstants.I_GIF;
153         }
154     }
155     
156     private static class FormatEMF extends FormatBase {
157         public static boolean isFormat(byte[] data) {
158             // No offical Indentifier known
159
byte [] pattern = new byte [] {(byte) 0x01, (byte) 0x00, (byte) 0x00};
160
161             return ImageUtil.compareHexValues(pattern, data, 0, true);
162         }
163         
164         public int getType() {
165             return ImageConstants.I_EMF;
166         }
167         
168         public String JavaDoc getRtfTag() {
169             return "emfblip";
170         }
171     }
172     
173     private static class FormatBMP extends FormatBase {
174         public static boolean isFormat(byte[] data) {
175             byte [] pattern = new byte [] {(byte) 0x42, (byte) 0x4D};
176
177             return ImageUtil.compareHexValues(pattern, data, 0, true);
178         }
179         
180         public int getType() {
181             return ImageConstants.I_BMP;
182         }
183     }
184     
185     private static class FormatJPG extends FormatBase {
186         public static boolean isFormat(byte[] data) {
187             // Indentifier "0xFFD8" on position 0
188
byte [] pattern = new byte [] {(byte) 0xFF, (byte) 0xD8};
189
190             return ImageUtil.compareHexValues(pattern, data, 0, true);
191         }
192       
193         public int getType() {
194             return ImageConstants.I_JPG;
195         }
196         
197         public String JavaDoc getRtfTag() {
198             return "jpegblip";
199         }
200     }
201     
202     private static class FormatPNG extends FormatBase {
203         public static boolean isFormat(byte[] data) {
204             // Indentifier "PNG" on position 1
205
byte [] pattern = new byte [] {(byte) 0x50, (byte) 0x4E, (byte) 0x47};
206
207             return ImageUtil.compareHexValues(pattern, data, 1, true);
208         }
209         
210         public int getType() {
211             return ImageConstants.I_PNG;
212         }
213         
214         public String JavaDoc getRtfTag() {
215             return "pngblip";
216         }
217     }
218     
219     //////////////////////////////////////////////////
220
// @@ Members
221
//////////////////////////////////////////////////
222

223
224     /**
225      * The url of the image
226      */

227     protected URL JavaDoc url = null;
228
229     /**
230      * The height of the image (in pixels)
231      */

232     protected int height = -1;
233
234     /**
235      * The desired percent value of the height
236      */

237     protected int heightPercent = -1;
238
239     /**
240      * The desired height (in twips)
241      */

242     protected int heightDesired = -1;
243
244     /**
245      * Flag whether the desired height is a percentage
246      */

247     protected boolean perCentH = false;
248
249     /**
250      * The width of the image (in pixels)
251      */

252     protected int width = -1;
253
254     /**
255      * The desired percent value of the width
256      */

257     protected int widthPercent = -1;
258
259     /**
260      * The desired width (in twips)
261      */

262     protected int widthDesired = -1;
263
264     /**
265      * Flag whether the desired width is a percentage
266      */

267     protected boolean perCentW = false;
268
269     /**
270      * Flag whether the image size shall be adjusted
271      */

272     protected boolean scaleUniform = false;
273
274     /**
275      * Graphic compression rate
276      */

277      protected int graphicCompressionRate = 80;
278
279      /** The image data */
280      private byte[] imagedata = null;
281
282      /** The image format */
283      private FormatBase imageformat;
284
285     //////////////////////////////////////////////////
286
// @@ Construction
287
//////////////////////////////////////////////////
288

289
290     /**
291      * Default constructor.
292      * Create an RTF element as a child of given container.
293      *
294      * @param container a <code>RtfContainer</code> value
295      * @param writer a <code>Writer</code> value
296      * @throws IOException for I/O problems
297      */

298     public RtfExternalGraphic(RtfContainer container, Writer JavaDoc writer) throws IOException JavaDoc {
299         super (container, writer);
300     }
301
302     /**
303      * Default constructor.
304      *
305      * @param container a <code>RtfContainer</code> value
306      * @param writer a <code>Writer</code> value
307      * @param attributes a <code>RtfAttributes</code> value
308      * @throws IOException for I/O problems
309      */

310     public RtfExternalGraphic(RtfContainer container, Writer JavaDoc writer,
311     RtfAttributes attributes) throws IOException JavaDoc {
312         super (container, writer, attributes);
313     }
314
315
316     //////////////////////////////////////////////////
317
// @@ RtfElement implementation
318
//////////////////////////////////////////////////
319

320         /**
321          * RtfElement override - catches ExternalGraphicException and writes a warning
322          * message to the document if image cannot be read
323          * @throws IOException for I/O problems
324          */

325     protected void writeRtfContent() throws IOException JavaDoc {
326             try {
327                 writeRtfContentWithException();
328             } catch (ExternalGraphicException ie) {
329                 writeExceptionInRtf(ie);
330             }
331         }
332
333     /**
334      * Writes the RTF content to m_writer - this one throws ExternalGraphicExceptions
335      *
336      * @exception IOException On error
337      */

338     protected void writeRtfContentWithException() throws IOException JavaDoc {
339
340         if (writer == null) {
341             return;
342         }
343
344
345         if (url == null) {
346             throw new ExternalGraphicException("The attribute 'url' of "
347                     + "<fo:external-graphic> is null.");
348         }
349
350         String JavaDoc linkToRoot = System.getProperty("jfor_link_to_root");
351         if (linkToRoot != null) {
352             writer.write("{\\field {\\* \\fldinst { INCLUDEPICTURE \"");
353             writer.write(linkToRoot);
354             File JavaDoc urlFile = new File JavaDoc(url.getFile());
355             writer.write(urlFile.getName());
356             writer.write("\" \\\\* MERGEFORMAT \\\\d }}}");
357             return;
358         }
359
360 // getRtfFile ().getLog ().logInfo ("Writing image '" + url + "'.");
361

362
363         if (imagedata == null) {
364             try {
365                 final InputStream JavaDoc in = url.openStream();
366                 try {
367                     imagedata = IOUtils.toByteArray(url.openStream());
368                 } finally {
369                     IOUtils.closeQuietly(in);
370                 }
371             } catch (Exception JavaDoc e) {
372                 throw new ExternalGraphicException("The attribute 'src' of "
373                         + "<fo:external-graphic> has a invalid value: '"
374                         + url + "' (" + e + ")");
375             }
376         }
377
378         if (imagedata == null) {
379             return;
380         }
381
382         // Determine image file format
383
String JavaDoc file = url.getFile ();
384         imageformat = FormatBase.determineFormat(imagedata);
385         if (imageformat != null) {
386             imageformat = imageformat.convert(imageformat, imagedata);
387         }
388         
389         if (imageformat == null
390                 || imageformat.getType() == ImageConstants.I_NOT_SUPPORTED
391                 || "".equals(imageformat.getRtfTag())) {
392             throw new ExternalGraphicException("The tag <fo:external-graphic> "
393                     + "does not support "
394                     + file.substring(file.lastIndexOf(".") + 1)
395                     + " - image type.");
396         }
397
398         // Writes the beginning of the rtf image
399

400         writeGroupMark(true);
401         writeStarControlWord("shppict");
402         writeGroupMark(true);
403         writeControlWord("pict");
404
405         StringBuffer JavaDoc buf = new StringBuffer JavaDoc(imagedata.length * 3);
406
407         writeControlWord(imageformat.getRtfTag());
408
409         computeImageSize();
410         writeSizeInfo();
411
412         for (int i = 0; i < imagedata.length; i++) {
413             int iData = imagedata [i];
414
415             // Make positive byte
416
if (iData < 0) {
417                 iData += 256;
418             }
419
420             if (iData < 16) {
421                 // Set leading zero and append
422
buf.append('0');
423             }
424
425             buf.append(Integer.toHexString(iData));
426         }
427
428         int len = buf.length();
429         char[] chars = new char[len];
430
431         buf.getChars(0, len, chars, 0);
432         writer.write(chars);
433
434         // Writes the end of RTF image
435

436         writeGroupMark(false);
437         writeGroupMark(false);
438     }
439
440     private void computeImageSize () {
441         if (imageformat.getType() == ImageConstants.I_PNG) {
442             width = ImageUtil.getIntFromByteArray(imagedata, 16, 4, true);
443             height = ImageUtil.getIntFromByteArray(imagedata, 20, 4, true);
444         } else if (imageformat.getType() == ImageConstants.I_JPG) {
445             int basis = -1;
446             byte ff = (byte) 0xff;
447             byte c0 = (byte) 0xc0;
448             for (int i = 0; i < imagedata.length; i++) {
449                 byte b = imagedata[i];
450                 if (b != ff) {
451                     continue;
452                 }
453                 if (i == imagedata.length - 1) {
454                     continue;
455                 }
456                 b = imagedata[i + 1];
457                 if (b != c0) {
458                     continue;
459                 }
460                 basis = i + 5;
461                 break;
462             }
463
464             if (basis != -1) {
465                 width = ImageUtil.getIntFromByteArray(imagedata, basis + 2, 2, true);
466                 height = ImageUtil.getIntFromByteArray(imagedata, basis, 2, true);
467             }
468         } else if (imageformat.getType() == ImageConstants.I_EMF) {
469             int i = 0;
470             
471             i = ImageUtil.getIntFromByteArray(imagedata, 151, 4, false);
472             if (i != 0 ) {
473                 width = i;
474             }
475             
476             i = ImageUtil.getIntFromByteArray(imagedata, 155, 4, false);
477             if (i != 0 ) {
478                 height = i;
479             }
480             
481         }
482     }
483
484     private void writeSizeInfo () throws IOException JavaDoc {
485         // Set image size
486
if (width != -1) {
487             writeControlWord("picw" + width);
488         }
489         if (height != -1) {
490             writeControlWord("pich" + height);
491         }
492
493         if (widthDesired != -1) {
494             if (perCentW) {
495                 writeControlWord("picscalex" + widthDesired);
496             } else {
497                 //writeControlWord("picscalex" + widthDesired * 100 / width);
498
writeControlWord("picwgoal" + widthDesired);
499             }
500
501         } else if (scaleUniform && heightDesired != -1) {
502             if (perCentH) {
503                 writeControlWord("picscalex" + heightDesired);
504             } else {
505                 writeControlWord("picscalex" + heightDesired * 100 / height);
506             }
507         }
508
509         if (heightDesired != -1) {
510             if (perCentH) {
511                 writeControlWord("picscaley" + heightDesired);
512             } else {
513                 //writeControlWord("picscaley" + heightDesired * 100 / height);
514
writeControlWord("pichgoal" + heightDesired);
515             }
516
517         } else if (scaleUniform && widthDesired != -1) {
518             if (perCentW) {
519                 writeControlWord("picscaley" + widthDesired);
520             } else {
521                 writeControlWord("picscaley" + widthDesired * 100 / width);
522             }
523         }
524     }
525
526     //////////////////////////////////////////////////
527
// @@ Member access
528
//////////////////////////////////////////////////
529

530     /**
531      * Sets the desired height of the image.
532      *
533      * @param theHeight The desired image height (as a string in twips or as a percentage)
534      */

535     public void setHeight(String JavaDoc theHeight) {
536         this.heightDesired = ImageUtil.getInt(theHeight);
537         this.perCentH = ImageUtil.isPercent(theHeight);
538     }
539
540     /**
541      * Sets the desired width of the image.
542      *
543      * @param theWidth The desired image width (as a string in twips or as a percentage)
544      */

545     public void setWidth(String JavaDoc theWidth) {
546         this.widthDesired = ImageUtil.getInt(theWidth);
547         this.perCentW = ImageUtil.isPercent(theWidth);
548     }
549
550     /**
551      * Sets the flag whether the image size shall be adjusted.
552      *
553      * @param value
554      * true image width or height shall be adjusted automatically\n
555      * false no adjustment
556      */

557     public void setScaling(String JavaDoc value) {
558         if (value.equalsIgnoreCase("uniform")) {
559             this.scaleUniform = true;
560         }
561     }
562     
563     /**
564      * Sets the binary imagedata of the image.
565      *
566      * @param imagedata Binary imagedata as read from file.
567      * @throws IOException On error
568      */

569     public void setImageData(byte[] data) throws IOException JavaDoc {
570         this.imagedata = data;
571     }
572
573     /**
574      * Sets the url of the image.
575      *
576      * @param urlString Image url like "file://..."
577      * @throws IOException On error
578      */

579     public void setURL(String JavaDoc urlString) throws IOException JavaDoc {
580         URL JavaDoc tmpUrl = null;
581         try {
582             tmpUrl = new URL JavaDoc (urlString);
583         } catch (MalformedURLException JavaDoc e) {
584             try {
585                 tmpUrl = new File JavaDoc (urlString).toURL ();
586             } catch (MalformedURLException JavaDoc ee) {
587                 throw new ExternalGraphicException("The attribute 'src' of "
588                         + "<fo:external-graphic> has a invalid value: '"
589                         + urlString + "' (" + ee + ")");
590             }
591         }
592         this.url = tmpUrl;
593     }
594
595     /**
596      * Gets the compression rate for the image in percent.
597      * @return Compression rate
598      */

599     public int getCompressionRate () {
600         return graphicCompressionRate;
601     }
602
603     /**
604      * Sets the compression rate for the image in percent.
605      *
606      * @param percent Compression rate
607      * @return true if the compression rate is valid (0..100), false if invalid
608      */

609     public boolean setCompressionRate (int percent) {
610         if (percent < 1 || percent > 100) {
611             return false;
612         }
613
614         graphicCompressionRate = percent;
615         return true;
616     }
617
618
619     //////////////////////////////////////////////////
620
// @@ Helpers
621
//////////////////////////////////////////////////
622

623     /**
624      * @return true if this element would generate no "useful" RTF content
625      */

626     public boolean isEmpty() {
627         return url == null;
628     }
629 }
630
Popular Tags