KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > lowagie > text > pdf > PdfStream


1 /*
2  * $Id: PdfStream.java 2739 2007-05-04 11:24:51Z blowagie $
3  * $Name$
4  *
5  * Copyright 1999, 2000, 2001, 2002 Bruno Lowagie
6  *
7  * The contents of this file are subject to the Mozilla Public License Version 1.1
8  * (the "License"); you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at http://www.mozilla.org/MPL/
10  *
11  * Software distributed under the License is distributed on an "AS IS" basis,
12  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13  * for the specific language governing rights and limitations under the License.
14  *
15  * The Original Code is 'iText, a free JAVA-PDF library'.
16  *
17  * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by
18  * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie.
19  * All Rights Reserved.
20  * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer
21  * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved.
22  *
23  * Contributor(s): all the names of the contributors are added in the source code
24  * where applicable.
25  *
26  * Alternatively, the contents of this file may be used under the terms of the
27  * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the
28  * provisions of LGPL are applicable instead of those above. If you wish to
29  * allow use of your version of this file only under the terms of the LGPL
30  * License and not to allow others to use your version of this file under
31  * the MPL, indicate your decision by deleting the provisions above and
32  * replace them with the notice and other provisions required by the LGPL.
33  * If you do not delete the provisions above, a recipient may use your version
34  * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE.
35  *
36  * This library is free software; you can redistribute it and/or modify it
37  * under the terms of the MPL as stated above or under the terms of the GNU
38  * Library General Public License as published by the Free Software Foundation;
39  * either version 2 of the License, or any later version.
40  *
41  * This library is distributed in the hope that it will be useful, but WITHOUT
42  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
43  * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more
44  * details.
45  *
46  * If you didn't download this code from the following link, you should check if
47  * you aren't using an obsolete version:
48  * http://www.lowagie.com/iText/
49  */

50
51 package com.lowagie.text.pdf;
52
53 import java.io.ByteArrayOutputStream JavaDoc;
54 import java.io.IOException JavaDoc;
55 import java.io.InputStream JavaDoc;
56 import java.io.OutputStream JavaDoc;
57 import java.util.zip.Deflater JavaDoc;
58 import java.util.zip.DeflaterOutputStream JavaDoc;
59
60 import com.lowagie.text.DocWriter;
61 import com.lowagie.text.Document;
62 import com.lowagie.text.ExceptionConverter;
63 import java.util.ArrayList JavaDoc;
64
65 /**
66  * <CODE>PdfStream</CODE> is the Pdf stream object.
67  * <P>
68  * A stream, like a string, is a sequence of characters. However, an application can
69  * read a small portion of a stream at a time, while a string must be read in its entirety.
70  * For this reason, objects with potentially large amounts of data, such as images and
71  * page descriptions, are represented as streams.<BR>
72  * A stream consists of a dictionary that describes a sequence of characters, followed by
73  * the keyword <B>stream</B>, followed by zero or more lines of characters, followed by
74  * the keyword <B>endstream</B>.<BR>
75  * All streams must be <CODE>PdfIndirectObject</CODE>s. The stream dictionary must be a direct
76  * object. The keyword <B>stream</B> that follows the stream dictionary should be followed by
77  * a carriage return and linefeed or just a linefeed.<BR>
78  * Remark: In this version only the FLATEDECODE-filter is supported.<BR>
79  * This object is described in the 'Portable Document Format Reference Manual version 1.7'
80  * section 3.2.7 (page 60-63).<BR>
81  *
82  * @see PdfObject
83  * @see PdfDictionary
84  */

85
86 public class PdfStream extends PdfDictionary {
87     
88     // membervariables
89

90 /** is the stream compressed? */
91     protected boolean compressed = false;
92     
93     protected ByteArrayOutputStream JavaDoc streamBytes = null;
94     protected InputStream JavaDoc inputStream;
95     protected PdfIndirectReference ref;
96     protected int inputStreamLength = -1;
97     protected PdfWriter writer;
98     protected int rawLength;
99         
100     static final byte STARTSTREAM[] = DocWriter.getISOBytes("stream\n");
101     static final byte ENDSTREAM[] = DocWriter.getISOBytes("\nendstream");
102     static final int SIZESTREAM = STARTSTREAM.length + ENDSTREAM.length;
103
104     // constructors
105

106 /**
107  * Constructs a <CODE>PdfStream</CODE>-object.
108  *
109  * @param bytes content of the new <CODE>PdfObject</CODE> as an array of <CODE>byte</CODE>.
110  */

111  
112     public PdfStream(byte[] bytes) {
113         super();
114         type = STREAM;
115         this.bytes = bytes;
116         rawLength = bytes.length;
117         put(PdfName.LENGTH, new PdfNumber(bytes.length));
118     }
119   
120     /**
121      * Creates an efficient stream. No temporary array is ever created. The <CODE>InputStream</CODE>
122      * is totally consumed but is not closed. The general usage is:
123      * <p>
124      * <pre>
125      * InputStream in = ...;
126      * PdfStream stream = new PdfStream(in, writer);
127      * stream.flateCompress();
128      * writer.addToBody(stream);
129      * stream.writeLength();
130      * in.close();
131      * </pre>
132      * @param inputStream the data to write to this stream
133      * @param writer the <CODE>PdfWriter</CODE> for this stream
134      */

135     public PdfStream(InputStream JavaDoc inputStream, PdfWriter writer) {
136         super();
137         type = STREAM;
138         this.inputStream = inputStream;
139         this.writer = writer;
140         ref = writer.getPdfIndirectReference();
141         put(PdfName.LENGTH, ref);
142     }
143   
144 /**
145  * Constructs a <CODE>PdfStream</CODE>-object.
146  */

147     
148     protected PdfStream() {
149         super();
150         type = STREAM;
151     }
152     
153     /**
154      * Writes the stream length to the <CODE>PdfWriter</CODE>.
155      * <p>
156      * This method must be called and can only be called if the contructor {@link #PdfStream(InputStream,PdfWriter)}
157      * is used to create the stream.
158      * @throws IOException on error
159      * @see #PdfStream(InputStream,PdfWriter)
160      */

161     public void writeLength() throws IOException JavaDoc {
162         if (inputStream == null)
163             throw new UnsupportedOperationException JavaDoc("writeLength() can only be called in a contructed PdfStream(InputStream,PdfWriter).");
164         if (inputStreamLength == -1)
165             throw new IOException JavaDoc("writeLength() can only be called after output of the stream body.");
166         writer.addToBody(new PdfNumber(inputStreamLength), ref, false);
167     }
168     
169     /**
170      * Gets the raw length of the stream.
171      * @return the raw length of the stream
172      */

173     public int getRawLength() {
174         return rawLength;
175     }
176     
177     /**
178      * Compresses the stream.
179      */

180     
181     public void flateCompress() {
182         if (!Document.compress)
183             return;
184         // check if the flateCompress-method has already been
185
if (compressed) {
186             return;
187         }
188         if (inputStream != null) {
189             compressed = true;
190             return;
191         }
192         // check if a filter already exists
193
PdfObject filter = PdfReader.getPdfObject(get(PdfName.FILTER));
194         if (filter != null) {
195             if (filter.isName()) {
196                 if (PdfName.FLATEDECODE.equals(filter))
197                     return;
198             }
199             else if (filter.isArray()) {
200                 if (((PdfArray) filter).contains(PdfName.FLATEDECODE))
201                     return;
202             }
203             else {
204                 throw new RuntimeException JavaDoc("Stream could not be compressed: filter is not a name or array.");
205             }
206         }
207         try {
208             // compress
209
ByteArrayOutputStream JavaDoc stream = new ByteArrayOutputStream JavaDoc();
210             DeflaterOutputStream JavaDoc zip = new DeflaterOutputStream JavaDoc(stream);
211             if (streamBytes != null)
212                 streamBytes.writeTo(zip);
213             else
214                 zip.write(bytes);
215             zip.close();
216             // update the object
217
streamBytes = stream;
218             bytes = null;
219             put(PdfName.LENGTH, new PdfNumber(streamBytes.size()));
220             if (filter == null) {
221                 put(PdfName.FILTER, PdfName.FLATEDECODE);
222             }
223             else {
224                 PdfArray filters = new PdfArray(filter);
225                 filters.add(PdfName.FLATEDECODE);
226                 put(PdfName.FILTER, filters);
227             }
228             compressed = true;
229         }
230         catch(IOException JavaDoc ioe) {
231             throw new ExceptionConverter(ioe);
232         }
233     }
234
235 // public int getStreamLength(PdfWriter writer) {
236
// if (dicBytes == null)
237
// toPdf(writer);
238
// if (streamBytes != null)
239
// return streamBytes.size() + dicBytes.length + SIZESTREAM;
240
// else
241
// return bytes.length + dicBytes.length + SIZESTREAM;
242
// }
243

244     protected void superToPdf(PdfWriter writer, OutputStream JavaDoc os) throws IOException JavaDoc {
245         super.toPdf(writer, os);
246     }
247     
248     /**
249      * @see com.lowagie.text.pdf.PdfDictionary#toPdf(com.lowagie.text.pdf.PdfWriter, java.io.OutputStream)
250      */

251     public void toPdf(PdfWriter writer, OutputStream JavaDoc os) throws IOException JavaDoc {
252         if (inputStream != null && compressed)
253             put(PdfName.FILTER, PdfName.FLATEDECODE);
254         PdfEncryption crypto = null;
255         if (writer != null)
256             crypto = writer.getEncryption();
257         if (crypto != null) {
258             PdfObject filter = get(PdfName.FILTER);
259             if (filter != null) {
260                 if (PdfName.CRYPT.equals(filter))
261                     crypto = null;
262                 else if (filter.isArray()) {
263                     ArrayList JavaDoc af = ((PdfArray)filter).getArrayList();
264                     if (!af.isEmpty() && PdfName.CRYPT.equals(af.get(0)))
265                         crypto = null;
266                 }
267             }
268         }
269         PdfObject nn = get(PdfName.LENGTH);
270         if (crypto != null && nn != null && nn.isNumber()) {
271             int sz = ((PdfNumber)nn).intValue();
272             put(PdfName.LENGTH, new PdfNumber(crypto.calculateStreamSize(sz)));
273             superToPdf(writer, os);
274             put(PdfName.LENGTH, nn);
275         }
276         else
277             superToPdf(writer, os);
278         os.write(STARTSTREAM);
279         if (inputStream != null) {
280             rawLength = 0;
281             DeflaterOutputStream JavaDoc def = null;
282             OutputStreamCounter osc = new OutputStreamCounter(os);
283             OutputStreamEncryption ose = null;
284             OutputStream JavaDoc fout = osc;
285             if (crypto != null)
286                 fout = ose = crypto.getEncryptionStream(fout);
287             if (compressed)
288                 fout = def = new DeflaterOutputStream JavaDoc(fout, new Deflater JavaDoc(Deflater.BEST_COMPRESSION), 0x8000);
289             
290             byte buf[] = new byte[4192];
291             while (true) {
292                 int n = inputStream.read(buf);
293                 if (n <= 0)
294                     break;
295                 fout.write(buf, 0, n);
296                 rawLength += n;
297             }
298             if (def != null)
299                 def.finish();
300             if (ose != null)
301                 ose.finish();
302             inputStreamLength = osc.getCounter();
303         }
304         else {
305             if (crypto == null) {
306                 if (streamBytes != null)
307                     streamBytes.writeTo(os);
308                 else
309                     os.write(bytes);
310             }
311             else {
312                 byte b[];
313                 if (streamBytes != null) {
314                     b = crypto.encryptByteArray(streamBytes.toByteArray());
315                 }
316                 else {
317                     b = crypto.encryptByteArray(bytes);
318                 }
319                 os.write(b);
320             }
321         }
322         os.write(ENDSTREAM);
323     }
324     
325     /**
326      * Writes the data content to an <CODE>OutputStream</CODE>.
327      * @param os the destination to write to
328      * @throws IOException on error
329      */

330     public void writeContent(OutputStream JavaDoc os) throws IOException JavaDoc {
331         if (streamBytes != null)
332             streamBytes.writeTo(os);
333         else if (bytes != null)
334             os.write(bytes);
335     }
336 }
337
Popular Tags