Save This Page
Home » iText-src-2.1.3 » com.lowagie » text » pdf » [javadoc | source]
    1   /*
    2    * $Id: PdfStream.java 3538 2008-07-08 13:08:04Z blowagie $
    3    *
    4    * Copyright 1999, 2000, 2001, 2002 Bruno Lowagie
    5    *
    6    * The contents of this file are subject to the Mozilla Public License Version 1.1
    7    * (the "License"); you may not use this file except in compliance with the License.
    8    * You may obtain a copy of the License at http://www.mozilla.org/MPL/
    9    *
   10    * Software distributed under the License is distributed on an "AS IS" basis,
   11    * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
   12    * for the specific language governing rights and limitations under the License.
   13    *
   14    * The Original Code is 'iText, a free JAVA-PDF library'.
   15    *
   16    * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by
   17    * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie.
   18    * All Rights Reserved.
   19    * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer
   20    * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved.
   21    *
   22    * Contributor(s): all the names of the contributors are added in the source code
   23    * where applicable.
   24    *
   25    * Alternatively, the contents of this file may be used under the terms of the
   26    * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the
   27    * provisions of LGPL are applicable instead of those above.  If you wish to
   28    * allow use of your version of this file only under the terms of the LGPL
   29    * License and not to allow others to use your version of this file under
   30    * the MPL, indicate your decision by deleting the provisions above and
   31    * replace them with the notice and other provisions required by the LGPL.
   32    * If you do not delete the provisions above, a recipient may use your version
   33    * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE.
   34    *
   35    * This library is free software; you can redistribute it and/or modify it
   36    * under the terms of the MPL as stated above or under the terms of the GNU
   37    * Library General Public License as published by the Free Software Foundation;
   38    * either version 2 of the License, or any later version.
   39    *
   40    * This library is distributed in the hope that it will be useful, but WITHOUT
   41    * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   42    * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more
   43    * details.
   44    *
   45    * If you didn't download this code from the following link, you should check if
   46    * you aren't using an obsolete version:
   47    * http://www.lowagie.com/iText/
   48    */
   49   
   50   package com.lowagie.text.pdf;
   51   
   52   import java.io.ByteArrayOutputStream;
   53   import java.io.IOException;
   54   import java.io.InputStream;
   55   import java.io.OutputStream;
   56   import java.util.zip.Deflater;
   57   import java.util.zip.DeflaterOutputStream;
   58   
   59   import com.lowagie.text.DocWriter;
   60   import com.lowagie.text.Document;
   61   import com.lowagie.text.ExceptionConverter;
   62   import java.util.ArrayList;
   63   
   64   /**
   65    * <CODE>PdfStream</CODE> is the Pdf stream object.
   66    * <P>
   67    * A stream, like a string, is a sequence of characters. However, an application can
   68    * read a small portion of a stream at a time, while a string must be read in its entirety.
   69    * For this reason, objects with potentially large amounts of data, such as images and
   70    * page descriptions, are represented as streams.<BR>
   71    * A stream consists of a dictionary that describes a sequence of characters, followed by
   72    * the keyword <B>stream</B>, followed by zero or more lines of characters, followed by
   73    * the keyword <B>endstream</B>.<BR>
   74    * All streams must be <CODE>PdfIndirectObject</CODE>s. The stream dictionary must be a direct
   75    * object. The keyword <B>stream</B> that follows the stream dictionary should be followed by
   76    * a carriage return and linefeed or just a linefeed.<BR>
   77    * Remark: In this version only the FLATEDECODE-filter is supported.<BR>
   78    * This object is described in the 'Portable Document Format Reference Manual version 1.7'
   79    * section 3.2.7 (page 60-63).<BR>
   80    *
   81    * @see		PdfObject
   82    * @see		PdfDictionary
   83    */
   84   
   85   public class PdfStream extends PdfDictionary {
   86       
   87       // membervariables
   88   
   89   	/**
   90   	 * A possible compression level.
   91   	 * @since	2.1.3
   92   	 */
   93   	public static final int DEFAULT_COMPRESSION = -1;
   94   	/**
   95   	 * A possible compression level.
   96   	 * @since	2.1.3
   97   	 */
   98   	public static final int NO_COMPRESSION = 0;
   99   	/**
  100   	 * A possible compression level.
  101   	 * @since	2.1.3
  102   	 */
  103   	public static final int BEST_SPEED = 1;
  104   	/**
  105   	 * A possible compression level.
  106   	 * @since	2.1.3
  107   	 */
  108   	public static final int BEST_COMPRESSION = 9;
  109   	
  110   	
  111   /** is the stream compressed? */
  112       protected boolean compressed = false;
  113       /**
  114        * The level of compression.
  115        * @since	2.1.3
  116        */
  117       protected int compressionLevel = NO_COMPRESSION;
  118       
  119       protected ByteArrayOutputStream streamBytes = null;
  120       protected InputStream inputStream;
  121       protected PdfIndirectReference ref;
  122       protected int inputStreamLength = -1;
  123       protected PdfWriter writer;
  124       protected int rawLength;
  125           
  126       static final byte STARTSTREAM[] = DocWriter.getISOBytes("stream\n");
  127       static final byte ENDSTREAM[] = DocWriter.getISOBytes("\nendstream");
  128       static final int SIZESTREAM = STARTSTREAM.length + ENDSTREAM.length;
  129   
  130       // constructors
  131       
  132   /**
  133    * Constructs a <CODE>PdfStream</CODE>-object.
  134    *
  135    * @param		bytes			content of the new <CODE>PdfObject</CODE> as an array of <CODE>byte</CODE>.
  136    */
  137    
  138       public PdfStream(byte[] bytes) {
  139           super();
  140           type = STREAM;
  141           this.bytes = bytes;
  142           rawLength = bytes.length;
  143           put(PdfName.LENGTH, new PdfNumber(bytes.length));
  144       }
  145     
  146       /**
  147        * Creates an efficient stream. No temporary array is ever created. The <CODE>InputStream</CODE>
  148        * is totally consumed but is not closed. The general usage is:
  149        * <p>
  150        * <pre>
  151        * InputStream in = ...;
  152        * PdfStream stream = new PdfStream(in, writer);
  153        * stream.flateCompress();
  154        * writer.addToBody(stream);
  155        * stream.writeLength();
  156        * in.close();
  157        * </pre>
  158        * @param inputStream the data to write to this stream
  159        * @param writer the <CODE>PdfWriter</CODE> for this stream
  160        */    
  161       public PdfStream(InputStream inputStream, PdfWriter writer) {
  162           super();
  163           type = STREAM;
  164           this.inputStream = inputStream;
  165           this.writer = writer;
  166           ref = writer.getPdfIndirectReference();
  167           put(PdfName.LENGTH, ref);
  168       }
  169     
  170   /**
  171    * Constructs a <CODE>PdfStream</CODE>-object.
  172    */
  173       
  174       protected PdfStream() {
  175           super();
  176           type = STREAM;
  177       }
  178       
  179       /**
  180        * Writes the stream length to the <CODE>PdfWriter</CODE>.
  181        * <p>
  182        * This method must be called and can only be called if the constructor {@link #PdfStream(InputStream,PdfWriter)}
  183        * is used to create the stream.
  184        * @throws IOException on error
  185        * @see #PdfStream(InputStream,PdfWriter)
  186        */
  187       public void writeLength() throws IOException {
  188           if (inputStream == null)
  189               throw new UnsupportedOperationException("writeLength() can only be called in a contructed PdfStream(InputStream,PdfWriter).");
  190           if (inputStreamLength == -1)
  191               throw new IOException("writeLength() can only be called after output of the stream body.");
  192           writer.addToBody(new PdfNumber(inputStreamLength), ref, false);
  193       }
  194       
  195       /**
  196        * Gets the raw length of the stream.
  197        * @return the raw length of the stream
  198        */
  199       public int getRawLength() {
  200           return rawLength;
  201       }
  202       
  203       /**
  204        * Compresses the stream.
  205        */
  206       public void flateCompress() {
  207       	flateCompress(DEFAULT_COMPRESSION);
  208       }
  209       
  210       /**
  211        * Compresses the stream.
  212   	 * @param compressionLevel the compression level (0 = best speed, 9 = best compression, -1 is default)
  213   	 * @since	2.1.3
  214        */
  215       public void flateCompress(int compressionLevel) {
  216           if (!Document.compress)
  217               return;
  218           // check if the flateCompress-method has already been
  219           if (compressed) {
  220               return;
  221           }
  222       	this.compressionLevel = compressionLevel;
  223           if (inputStream != null) {
  224               compressed = true;
  225               return;
  226           }
  227           // check if a filter already exists
  228           PdfObject filter = PdfReader.getPdfObject(get(PdfName.FILTER));
  229           if (filter != null) {
  230               if (filter.isName()) {
  231                   if (PdfName.FLATEDECODE.equals(filter))
  232                       return;
  233               }
  234               else if (filter.isArray()) {
  235                   if (((PdfArray) filter).contains(PdfName.FLATEDECODE))
  236                       return;
  237               }
  238               else {
  239                   throw new RuntimeException("Stream could not be compressed: filter is not a name or array.");
  240               }
  241           }
  242           try {
  243               // compress
  244               ByteArrayOutputStream stream = new ByteArrayOutputStream();
  245               DeflaterOutputStream zip = new DeflaterOutputStream(stream, new Deflater(compressionLevel));
  246               if (streamBytes != null)
  247                   streamBytes.writeTo(zip);
  248               else
  249                   zip.write(bytes);
  250               zip.close();
  251               // update the object
  252               streamBytes = stream;
  253               bytes = null;
  254               put(PdfName.LENGTH, new PdfNumber(streamBytes.size()));
  255               if (filter == null) {
  256                   put(PdfName.FILTER, PdfName.FLATEDECODE);
  257               }
  258               else {
  259                   PdfArray filters = new PdfArray(filter);
  260                   filters.add(PdfName.FLATEDECODE);
  261                   put(PdfName.FILTER, filters);
  262               }
  263               compressed = true;
  264           }
  265           catch(IOException ioe) {
  266               throw new ExceptionConverter(ioe);
  267           }
  268       }
  269   
  270   //    public int getStreamLength(PdfWriter writer) {
  271   //        if (dicBytes == null)
  272   //            toPdf(writer);
  273   //        if (streamBytes != null)
  274   //            return streamBytes.size() + dicBytes.length + SIZESTREAM;
  275   //        else
  276   //            return bytes.length + dicBytes.length + SIZESTREAM;
  277   //    }
  278       
  279       protected void superToPdf(PdfWriter writer, OutputStream os) throws IOException {
  280           super.toPdf(writer, os);
  281       }
  282       
  283       /**
  284        * @see com.lowagie.text.pdf.PdfDictionary#toPdf(com.lowagie.text.pdf.PdfWriter, java.io.OutputStream)
  285        */
  286       public void toPdf(PdfWriter writer, OutputStream os) throws IOException {
  287           if (inputStream != null && compressed)
  288               put(PdfName.FILTER, PdfName.FLATEDECODE);
  289           PdfEncryption crypto = null;
  290           if (writer != null)
  291               crypto = writer.getEncryption();
  292           if (crypto != null) {
  293               PdfObject filter = get(PdfName.FILTER);
  294               if (filter != null) {
  295                   if (PdfName.CRYPT.equals(filter))
  296                       crypto = null;
  297                   else if (filter.isArray()) {
  298                       ArrayList af = ((PdfArray)filter).getArrayList();
  299                       if (!af.isEmpty() && PdfName.CRYPT.equals(af.get(0)))
  300                           crypto = null;
  301                   }
  302               }
  303           }
  304           PdfObject nn = get(PdfName.LENGTH);
  305           if (crypto != null && nn != null && nn.isNumber()) {
  306               int sz = ((PdfNumber)nn).intValue();
  307               put(PdfName.LENGTH, new PdfNumber(crypto.calculateStreamSize(sz)));
  308               superToPdf(writer, os);
  309               put(PdfName.LENGTH, nn);
  310           }
  311           else
  312               superToPdf(writer, os);
  313           os.write(STARTSTREAM);
  314           if (inputStream != null) {
  315               rawLength = 0;
  316               DeflaterOutputStream def = null;
  317               OutputStreamCounter osc = new OutputStreamCounter(os);
  318               OutputStreamEncryption ose = null;
  319               OutputStream fout = osc;
  320               if (crypto != null && !crypto.isEmbeddedFilesOnly())
  321                   fout = ose = crypto.getEncryptionStream(fout);
  322               if (compressed)    
  323                   fout = def = new DeflaterOutputStream(fout, new Deflater(compressionLevel), 0x8000);
  324               
  325               byte buf[] = new byte[4192];
  326               while (true) {
  327                   int n = inputStream.read(buf);
  328                   if (n <= 0)
  329                       break;
  330                   fout.write(buf, 0, n);
  331                   rawLength += n;
  332               }
  333               if (def != null)
  334                   def.finish();
  335               if (ose != null)
  336                   ose.finish();
  337               inputStreamLength = osc.getCounter();
  338           }
  339           else {
  340               if (crypto != null && !crypto.isEmbeddedFilesOnly()) {
  341                   byte b[];
  342                   if (streamBytes != null) {
  343                       b = crypto.encryptByteArray(streamBytes.toByteArray());
  344                   }
  345                   else {
  346                       b = crypto.encryptByteArray(bytes);
  347                   }
  348                   os.write(b);
  349               }
  350               else {
  351                   if (streamBytes != null)
  352                       streamBytes.writeTo(os);
  353                   else
  354                       os.write(bytes);
  355               }
  356           }
  357           os.write(ENDSTREAM);
  358       }
  359       
  360       /**
  361        * Writes the data content to an <CODE>OutputStream</CODE>.
  362        * @param os the destination to write to
  363        * @throws IOException on error
  364        */    
  365       public void writeContent(OutputStream os) throws IOException {
  366           if (streamBytes != null)
  367               streamBytes.writeTo(os);
  368           else if (bytes != null)
  369               os.write(bytes);
  370       }
  371       
  372       /**
  373        * @see com.lowagie.text.pdf.PdfObject#toString()
  374        */
  375       public String toString() {
  376       	if (get(PdfName.TYPE) == null) return "Stream";
  377       	return "Stream of type: " + get(PdfName.TYPE);
  378       }
  379   }

Save This Page
Home » iText-src-2.1.3 » com.lowagie » text » pdf » [javadoc | source]