001: /*
002: * $Id: RtfImage.java 2825 2007-06-04 09:15:21Z blowagie $
003: * $Name$
004: *
005: * Copyright 2001, 2002, 2003, 2004 by Mark Hall
006: *
007: * The contents of this file are subject to the Mozilla Public License Version 1.1
008: * (the "License"); you may not use this file except in compliance with the License.
009: * You may obtain a copy of the License at http://www.mozilla.org/MPL/
010: *
011: * Software distributed under the License is distributed on an "AS IS" basis,
012: * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
013: * for the specific language governing rights and limitations under the License.
014: *
015: * The Original Code is 'iText, a free JAVA-PDF library'.
016: *
017: * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by
018: * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie.
019: * All Rights Reserved.
020: * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer
021: * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved.
022: *
023: * Contributor(s): all the names of the contributors are added in the source code
024: * where applicable.
025: *
026: * Alternatively, the contents of this file may be used under the terms of the
027: * LGPL license (the ?GNU LIBRARY GENERAL PUBLIC LICENSE?), in which case the
028: * provisions of LGPL are applicable instead of those above. If you wish to
029: * allow use of your version of this file only under the terms of the LGPL
030: * License and not to allow others to use your version of this file under
031: * the MPL, indicate your decision by deleting the provisions above and
032: * replace them with the notice and other provisions required by the LGPL.
033: * If you do not delete the provisions above, a recipient may use your version
034: * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE.
035: *
036: * This library is free software; you can redistribute it and/or modify it
037: * under the terms of the MPL as stated above or under the terms of the GNU
038: * Library General Public License as published by the Free Software Foundation;
039: * either version 2 of the License, or any later version.
040: *
041: * This library is distributed in the hope that it will be useful, but WITHOUT
042: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
043: * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more
044: * details.
045: *
046: * If you didn't download this code from the following link, you should check if
047: * you aren't using an obsolete version:
048: * http://www.lowagie.com/iText/
049: */
050:
051: package com.lowagie.text.rtf.graphic;
052:
053: import java.io.ByteArrayOutputStream;
054: import java.io.EOFException;
055: import java.io.IOException;
056: import java.io.InputStream;
057: import java.io.OutputStream;
058:
059: import com.lowagie.text.DocumentException;
060: import com.lowagie.text.Element;
061: import com.lowagie.text.Image;
062: import com.lowagie.text.pdf.codec.wmf.MetaDo;
063: import com.lowagie.text.rtf.RtfElement;
064: import com.lowagie.text.rtf.document.RtfDocument;
065: import com.lowagie.text.rtf.document.output.RtfByteArrayBuffer;
066: import com.lowagie.text.rtf.style.RtfParagraphStyle;
067: import com.lowagie.text.rtf.text.RtfParagraph;
068:
069: /**
070: * The RtfImage contains one image. Supported image types are jpeg, png, wmf, bmp.
071: *
072: * @version $Id: RtfImage.java 2825 2007-06-04 09:15:21Z blowagie $
073: * @author Mark Hall (mhall@edu.uni-klu.ac.at)
074: * @author Paulo Soares
075: * @author Thomas Bickel (tmb99@inode.at)
076: */
077: public class RtfImage extends RtfElement {
078:
079: /**
080: * Constant for the shape/picture group
081: */
082: private static final byte[] PICTURE_GROUP = "\\*\\shppict"
083: .getBytes();
084: /**
085: * Constant for a picture
086: */
087: private static final byte[] PICTURE = "\\pict".getBytes();
088: /**
089: * Constant for a jpeg image
090: */
091: private static final byte[] PICTURE_JPEG = "\\jpegblip".getBytes();
092: /**
093: * Constant for a png image
094: */
095: private static final byte[] PICTURE_PNG = "\\pngblip".getBytes();
096: /**
097: * Constant for a bmp image
098: */
099: private static final byte[] PICTURE_BMP = "\\dibitmap0".getBytes();
100: /**
101: * Constant for a wmf image
102: */
103: private static final byte[] PICTURE_WMF = "\\wmetafile8".getBytes();
104: /**
105: * Constant for the picture width
106: */
107: private static final byte[] PICTURE_WIDTH = "\\picw".getBytes();
108: /**
109: * Constant for the picture height
110: */
111: private static final byte[] PICTURE_HEIGHT = "\\pich".getBytes();
112: /**
113: * Constant for the picture width scale
114: */
115: private static final byte[] PICTURE_SCALED_WIDTH = "\\picwgoal"
116: .getBytes();
117: /**
118: * Constant for the picture height scale
119: */
120: private static final byte[] PICTURE_SCALED_HEIGHT = "\\pichgoal"
121: .getBytes();
122: /**
123: * Constant for horizontal picture scaling
124: */
125: private static final byte[] PICTURE_SCALE_X = "\\picscalex"
126: .getBytes();
127: /**
128: * Constant for vertical picture scaling
129: */
130: private static final byte[] PICTURE_SCALE_Y = "\\picscaley"
131: .getBytes();
132: /**
133: * "\bin" constant
134: */
135: private static final byte[] PICTURE_BINARY_DATA = "\\bin"
136: .getBytes();
137: /**
138: * Constant for converting pixels to twips
139: */
140: private static final int PIXEL_TWIPS_FACTOR = 15;
141:
142: /**
143: * The type of image this is.
144: */
145: private final int imageType;
146: /**
147: * Binary image data.
148: */
149: private final byte[][] imageData;
150: /**
151: * The alignment of this picture
152: */
153: private int alignment = Element.ALIGN_LEFT;
154: /**
155: * The width of this picture
156: */
157: private float width = 0;
158: /**
159: * The height of this picutre
160: */
161: private float height = 0;
162: /**
163: * The intended display width of this picture
164: */
165: private float plainWidth = 0;
166: /**
167: * The intended display height of this picture
168: */
169: private float plainHeight = 0;
170: /**
171: * Whether this RtfImage is a top level element and should
172: * be an extra paragraph.
173: */
174: private boolean topLevelElement = false;
175:
176: /**
177: * Constructs a RtfImage for an Image.
178: *
179: * @param doc The RtfDocument this RtfImage belongs to
180: * @param image The Image that this RtfImage wraps
181: * @throws DocumentException If an error occured accessing the image content
182: */
183: public RtfImage(RtfDocument doc, Image image)
184: throws DocumentException {
185: super (doc);
186: imageType = image.getOriginalType();
187: if (!(imageType == Image.ORIGINAL_JPEG
188: || imageType == Image.ORIGINAL_BMP
189: || imageType == Image.ORIGINAL_PNG
190: || imageType == Image.ORIGINAL_WMF || imageType == Image.ORIGINAL_GIF)) {
191: throw new DocumentException(
192: "Only BMP, PNG, WMF, GIF and JPEG images are supported by the RTF Writer");
193: }
194: alignment = image.getAlignment();
195: width = image.getWidth();
196: height = image.getHeight();
197: plainWidth = image.getPlainWidth();
198: plainHeight = image.getPlainHeight();
199: this .imageData = getImageData(image);
200: }
201:
202: /**
203: * Extracts the image data from the Image.
204: *
205: * @param image The image for which to extract the content
206: * @return The raw image data, not formated
207: * @throws DocumentException If an error occurs accessing the image content
208: */
209: private byte[][] getImageData(Image image) throws DocumentException {
210: final int WMF_PLACEABLE_HEADER_SIZE = 22;
211: final RtfByteArrayBuffer bab = new RtfByteArrayBuffer();
212:
213: try {
214: if (imageType == Image.ORIGINAL_BMP) {
215: bab.append(MetaDo.wrapBMP(image));
216: } else {
217: final byte[] iod = image.getOriginalData();
218: if (iod == null) {
219:
220: final InputStream imageIn = image.getUrl()
221: .openStream();
222: if (imageType == Image.ORIGINAL_WMF) { //remove the placeable header first
223: for (int k = 0; k < WMF_PLACEABLE_HEADER_SIZE; k++) {
224: if (imageIn.read() < 0)
225: throw (new EOFException(
226: "while removing wmf placeable header"));
227: }
228: }
229: bab.write(imageIn);
230: imageIn.close();
231:
232: } else {
233:
234: if (imageType == Image.ORIGINAL_WMF) {
235: //remove the placeable header
236: bab.write(iod, WMF_PLACEABLE_HEADER_SIZE,
237: iod.length - WMF_PLACEABLE_HEADER_SIZE);
238: } else {
239: bab.append(iod);
240: }
241:
242: }
243: }
244:
245: return (bab.toByteArrayArray());
246:
247: } catch (IOException ioe) {
248: throw new DocumentException(ioe.getMessage());
249: }
250: }
251:
252: /**
253: * lookup table used for converting bytes to hex chars.
254: * TODO Should probably be refactored into a helper class
255: */
256: public final static byte[] byte2charLUT = new byte[512]; //'0001020304050607 ... fafbfcfdfeff'
257: static {
258: char c = '0';
259: for (int k = 0; k < 16; k++) {
260: for (int x = 0; x < 16; x++) {
261: byte2charLUT[((k * 16) + x) * 2] = byte2charLUT[(((x * 16) + k) * 2) + 1] = (byte) c;
262: }
263: if (++c == ':')
264: c = 'a';
265: }
266: }
267:
268: /**
269: * Writes the image data to the given buffer as hex encoded text.
270: *
271: * @param bab
272: * @throws IOException
273: */
274: private void writeImageDataHexEncoded(final OutputStream bab)
275: throws IOException {
276: int cnt = 0;
277: for (int k = 0; k < imageData.length; k++) {
278: final byte[] chunk = imageData[k];
279: for (int x = 0; x < chunk.length; x++) {
280: bab.write(byte2charLUT, (chunk[x] & 0xff) * 2, 2);
281: if (++cnt == 64) {
282: bab.write('\n');
283: cnt = 0;
284: }
285: }
286: }
287: if (cnt > 0)
288: bab.write('\n');
289: }
290:
291: /**
292: * Returns the image raw data size in bytes.
293: *
294: * @return the size in bytes
295: */
296: private int imageDataSize() {
297: int size = 0;
298: for (int k = 0; k < imageData.length; k++) {
299: size += imageData[k].length;
300: }
301: return (size);
302: }
303:
304: /**
305: * Writes the RtfImage content
306: *
307: * @return the RtfImage content
308: * @deprecated replaced by {@link #writeContent(OutputStream)}
309: */
310: public byte[] write() {
311: final ByteArrayOutputStream result = new ByteArrayOutputStream();
312: try {
313: writeContent(result);
314: } catch (Exception ioe) {
315: ioe.printStackTrace();
316: }
317:
318: return (result.toByteArray());
319: }
320:
321: /**
322: * Writes the RtfImage content
323: */
324: public void writeContent(final OutputStream result)
325: throws IOException {
326: //new RuntimeException("info").printStackTrace();
327:
328: if (this .topLevelElement) {
329: result.write(RtfParagraph.PARAGRAPH_DEFAULTS);
330: switch (alignment) {
331: case Element.ALIGN_LEFT:
332: result.write(RtfParagraphStyle.ALIGN_LEFT);
333: break;
334: case Element.ALIGN_RIGHT:
335: result.write(RtfParagraphStyle.ALIGN_RIGHT);
336: break;
337: case Element.ALIGN_CENTER:
338: result.write(RtfParagraphStyle.ALIGN_CENTER);
339: break;
340: case Element.ALIGN_JUSTIFIED:
341: result.write(RtfParagraphStyle.ALIGN_JUSTIFY);
342: break;
343: }
344: }
345: result.write(OPEN_GROUP);
346: result.write(PICTURE_GROUP);
347: result.write(OPEN_GROUP);
348: result.write(PICTURE);
349: switch (imageType) {
350: case Image.ORIGINAL_JPEG:
351: result.write(PICTURE_JPEG);
352: break;
353: case Image.ORIGINAL_PNG:
354: case Image.ORIGINAL_GIF:
355: result.write(PICTURE_PNG);
356: break;
357: case Image.ORIGINAL_WMF:
358: case Image.ORIGINAL_BMP:
359: result.write(PICTURE_WMF);
360: break;
361: }
362: result.write(PICTURE_WIDTH);
363: result.write(intToByteArray((int) width));
364: result.write(PICTURE_HEIGHT);
365: result.write(intToByteArray((int) height));
366: if (this .document.getDocumentSettings()
367: .isWriteImageScalingInformation()) {
368: result.write(PICTURE_SCALE_X);
369: result
370: .write(intToByteArray((int) (100 * plainWidth / width)));
371: result.write(PICTURE_SCALE_Y);
372: result
373: .write(intToByteArray((int) (100 * plainHeight / height)));
374: }
375: if (this .document.getDocumentSettings().isImagePDFConformance()) {
376: result.write(PICTURE_SCALED_WIDTH);
377: result
378: .write(intToByteArray((int) (plainWidth * RtfElement.TWIPS_FACTOR)));
379: result.write(PICTURE_SCALED_HEIGHT);
380: result
381: .write(intToByteArray((int) (plainHeight * RtfElement.TWIPS_FACTOR)));
382: } else {
383: if (this .width != this .plainWidth
384: || this .imageType == Image.ORIGINAL_BMP) {
385: result.write(PICTURE_SCALED_WIDTH);
386: result
387: .write(intToByteArray((int) (plainWidth * PIXEL_TWIPS_FACTOR)));
388: }
389: if (this .height != this .plainHeight
390: || this .imageType == Image.ORIGINAL_BMP) {
391: result.write(PICTURE_SCALED_HEIGHT);
392: result
393: .write(intToByteArray((int) (plainHeight * PIXEL_TWIPS_FACTOR)));
394: }
395: }
396:
397: if (true) {
398: //binary
399: result.write('\n');
400: result.write(PICTURE_BINARY_DATA);
401: result.write(intToByteArray(imageDataSize()));
402: result.write(DELIMITER);
403: if (result instanceof RtfByteArrayBuffer) {
404: ((RtfByteArrayBuffer) result).append(imageData);
405: } else {
406: for (int k = 0; k < imageData.length; k++) {
407: result.write(imageData[k]);
408: }
409: }
410: } else {
411: //hex encoded
412: result.write(DELIMITER);
413: result.write('\n');
414: writeImageDataHexEncoded(result);
415: }
416:
417: result.write(CLOSE_GROUP);
418: result.write(CLOSE_GROUP);
419: if (this .topLevelElement) {
420: result.write(RtfParagraph.PARAGRAPH);
421: result.write(RtfParagraph.PARAGRAPH);
422: }
423: result.write('\n');
424: }
425:
426: /**
427: * Sets the alignment of this RtfImage. Uses the alignments from com.lowagie.text.Element.
428: *
429: * @param alignment The alignment to use.
430: */
431: public void setAlignment(int alignment) {
432: this .alignment = alignment;
433: }
434:
435: /**
436: * Set whether this RtfImage should behave like a top level element
437: * and enclose itself in a paragraph.
438: *
439: * @param topLevelElement Whether to behave like a top level element.
440: */
441: public void setTopLevelElement(boolean topLevelElement) {
442: this.topLevelElement = topLevelElement;
443: }
444:
445: }
|