Home » pdfbox-1.1.0-src » org.apache.pdfbox.pdmodel.common » [javadoc | source]

    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   package org.apache.pdfbox.pdmodel.common;
   18   
   19   import java.io.ByteArrayInputStream;
   20   import java.io.ByteArrayOutputStream;
   21   import java.io.IOException;
   22   import java.io.InputStream;
   23   import java.io.OutputStream;
   24   
   25   import java.util.ArrayList;
   26   import java.util.List;
   27   import java.util.Map;
   28   
   29   import org.apache.pdfbox.cos.COSArray;
   30   import org.apache.pdfbox.cos.COSBase;
   31   import org.apache.pdfbox.cos.COSDictionary;
   32   import org.apache.pdfbox.cos.COSName;
   33   import org.apache.pdfbox.cos.COSStream;
   34   
   35   import org.apache.pdfbox.filter.Filter;
   36   import org.apache.pdfbox.filter.FilterManager;
   37   
   38   import org.apache.pdfbox.pdmodel.PDDocument;
   39   
   40   import org.apache.pdfbox.pdmodel.common.filespecification.PDFileSpecification;
   41   
   42   /**
   43    * A PDStream represents a stream in a PDF document.  Streams are tied to a single
   44    * PDF document.
   45    *
   46    * @author <a href="mailto:ben@benlitchfield.com">Ben Litchfield</a>
   47    * @version $Revision: 1.17 $
   48    */
   49   public class PDStream implements COSObjectable
   50   {
   51       private COSStream stream;
   52   
   53       /**
   54        * This will create a new PDStream object.
   55        */
   56       protected PDStream()
   57       {
   58           //should only be called by PDMemoryStream
   59       }
   60   
   61       /**
   62        * This will create a new PDStream object.
   63        *
   64        * @param document The document that the stream will be part of.
   65        */
   66       public PDStream( PDDocument document )
   67       {
   68           stream = new COSStream( document.getDocument().getScratchFile() );
   69       }
   70   
   71       /**
   72        * Constructor.
   73        *
   74        * @param str The stream parameter.
   75        */
   76       public PDStream( COSStream str )
   77       {
   78           stream = str;
   79       }
   80   
   81       /**
   82        * Constructor.  Reads all data from the input stream and embeds it into the
   83        * document, this will close the InputStream.
   84        *
   85        * @param doc The document that will hold the stream.
   86        * @param str The stream parameter.
   87        * @throws IOException If there is an error creating the stream in the document.
   88        */
   89       public PDStream( PDDocument doc, InputStream str ) throws IOException
   90       {
   91           this( doc, str, false );
   92       }
   93   
   94       /**
   95        * Constructor.  Reads all data from the input stream and embeds it into the
   96        * document, this will close the InputStream.
   97        *
   98        * @param doc The document that will hold the stream.
   99        * @param str The stream parameter.
  100        * @param filtered True if the stream already has a filter applied.
  101        * @throws IOException If there is an error creating the stream in the document.
  102        */
  103       public PDStream( PDDocument doc, InputStream str, boolean filtered ) throws IOException
  104       {
  105           OutputStream output = null;
  106           try
  107           {
  108               stream = new COSStream( doc.getDocument().getScratchFile() );
  109               if( filtered )
  110               {
  111                   output = stream.createFilteredStream();
  112               }
  113               else
  114               {
  115                   output = stream.createUnfilteredStream();
  116               }
  117               byte[] buffer = new byte[ 1024 ];
  118               int amountRead = -1;
  119               while( (amountRead = str.read(buffer)) != -1 )
  120               {
  121                   output.write( buffer, 0, amountRead );
  122               }
  123           }
  124           finally
  125           {
  126               if( output != null )
  127               {
  128                   output.close();
  129               }
  130               if( str != null )
  131               {
  132                   str.close();
  133               }
  134           }
  135       }
  136   
  137       /**
  138        * If there are not compression filters on the current stream then this
  139        * will add a compression filter, flate compression for example.
  140        */
  141       public void addCompression()
  142       {
  143           List filters = getFilters();
  144           if( filters == null )
  145           {
  146               filters = new ArrayList();
  147               filters.add( COSName.FLATE_DECODE );
  148               setFilters( filters );
  149           }
  150       }
  151   
  152       /**
  153        * Create a pd stream from either a regular COSStream on a COSArray of cos streams.
  154        * @param base Either a COSStream or COSArray.
  155        * @return A PDStream or null if base is null.
  156        * @throws IOException If there is an error creating the PDStream.
  157        */
  158       public static PDStream createFromCOS( COSBase base ) throws IOException
  159       {
  160           PDStream retval = null;
  161           if( base instanceof COSStream )
  162           {
  163               retval = new PDStream( (COSStream)base );
  164           }
  165           else if( base instanceof COSArray )
  166           {
  167               retval = new PDStream( new COSStreamArray( (COSArray)base ) );
  168           }
  169           else
  170           {
  171               if( base != null )
  172               {
  173                   throw new IOException( "Contents are unknown type:" + base.getClass().getName() );
  174               }
  175           }
  176           return retval;
  177       }
  178   
  179   
  180       /**
  181        * Convert this standard java object to a COS object.
  182        *
  183        * @return The cos object that matches this Java object.
  184        */
  185       public COSBase getCOSObject()
  186       {
  187           return stream;
  188       }
  189   
  190       /**
  191        * This will get a stream that can be written to.
  192        *
  193        * @return An output stream to write data to.
  194        *
  195        * @throws IOException If an IO error occurs during writing.
  196        */
  197       public OutputStream createOutputStream() throws IOException
  198       {
  199           return stream.createUnfilteredStream();
  200       }
  201   
  202       /**
  203        * This will get a stream that can be read from.
  204        *
  205        * @return An input stream that can be read from.
  206        *
  207        * @throws IOException If an IO error occurs during reading.
  208        */
  209       public InputStream createInputStream() throws IOException
  210       {
  211           return stream.getUnfilteredStream();
  212       }
  213   
  214       /**
  215        * This will get a stream with some filters applied but not others.  This is useful
  216        * when doing images, ie filters = [flate,dct], we want to remove flate but leave dct
  217        *
  218        * @param stopFilters A list of filters to stop decoding at.
  219        * @return A stream with decoded data.
  220        * @throws IOException If there is an error processing the stream.
  221        */
  222       public InputStream getPartiallyFilteredStream( List stopFilters ) throws IOException
  223       {
  224           FilterManager manager = stream.getFilterManager();
  225           InputStream is = stream.getFilteredStream();
  226           ByteArrayOutputStream os = new ByteArrayOutputStream();
  227           List filters = getFilters();
  228           String nextFilter = null;
  229           boolean done = false;
  230           for( int i=0; i<filters.size() && !done; i++ )
  231           {
  232               os.reset();
  233               nextFilter = (String)filters.get( i );
  234               if( stopFilters.contains( nextFilter ) )
  235               {
  236                   done = true;
  237               }
  238               else
  239               {
  240                   Filter filter = manager.getFilter( COSName.getPDFName(nextFilter) );
  241                   filter.decode( is, os, stream, i );
  242                   is = new ByteArrayInputStream( os.toByteArray() );
  243               }
  244           }
  245           return is;
  246       }
  247   
  248       /**
  249        * Get the cos stream associated with this object.
  250        *
  251        * @return The cos object that matches this Java object.
  252        */
  253       public COSStream getStream()
  254       {
  255           return stream;
  256       }
  257   
  258       /**
  259        * This will get the length of the filtered/compressed stream.  This is readonly in the
  260        * PD Model and will be managed by this class.
  261        *
  262        * @return The length of the filtered stream.
  263        */
  264       public int getLength()
  265       {
  266           return stream.getInt( "Length", 0 );
  267       }
  268   
  269       /**
  270        * This will get the list of filters that are associated with this stream.  Or
  271        * null if there are none.
  272        * @return A list of all encoding filters to apply to this stream.
  273        */
  274       public List getFilters()
  275       {
  276           List retval = null;
  277           COSBase filters = stream.getFilters();
  278           if( filters instanceof COSName )
  279           {
  280               COSName name = (COSName)filters;
  281               retval = new COSArrayList( name.getName(), name, stream, COSName.FILTER );
  282           }
  283           else if( filters instanceof COSArray )
  284           {
  285               retval = COSArrayList.convertCOSNameCOSArrayToList( (COSArray)filters );
  286           }
  287           return retval;
  288       }
  289   
  290       /**
  291        * This will set the filters that are part of this stream.
  292        *
  293        * @param filters The filters that are part of this stream.
  294        */
  295       public void setFilters( List filters )
  296       {
  297           COSBase obj = COSArrayList.convertStringListToCOSNameCOSArray( filters );
  298           stream.setItem( COSName.FILTER, obj );
  299       }
  300   
  301       /**
  302        * Get the list of decode parameters.  Each entry in the list will refer to
  303        * an entry in the filters list.
  304        *
  305        * @return The list of decode parameters.
  306        *
  307        * @throws IOException if there is an error retrieving the parameters.
  308        */
  309       public List getDecodeParms() throws IOException
  310       {
  311           List retval = null;
  312   
  313           COSBase dp = stream.getDictionaryObject( COSName.DECODE_PARMS );
  314           if( dp == null )
  315           {
  316               //See PDF Ref 1.5 implementation note 7, the DP is sometimes used instead.
  317               dp = stream.getDictionaryObject( COSName.DP );
  318           }
  319           if( dp instanceof COSDictionary )
  320           {
  321               Map map = COSDictionaryMap.convertBasicTypesToMap( (COSDictionary)dp );
  322               retval = new COSArrayList(map, dp, stream, COSName.DECODE_PARMS );
  323           }
  324           else if( dp instanceof COSArray )
  325           {
  326               COSArray array = (COSArray)dp;
  327               List actuals = new ArrayList();
  328               for( int i=0; i<array.size(); i++ )
  329               {
  330                   actuals.add(
  331                       COSDictionaryMap.convertBasicTypesToMap(
  332                           (COSDictionary)array.getObject( i ) ) );
  333               }
  334               retval = new COSArrayList(actuals, array);
  335           }
  336   
  337           return retval;
  338       }
  339   
  340       /**
  341        * This will set the list of decode parameterss.
  342        *
  343        * @param decodeParams The list of decode parameterss.
  344        */
  345       public void setDecodeParms( List decodeParams )
  346       {
  347           stream.setItem(
  348               COSName.DECODE_PARMS, COSArrayList.converterToCOSArray( decodeParams ) );
  349       }
  350   
  351       /**
  352        * This will get the file specification for this stream.  This is only
  353        * required for external files.
  354        *
  355        * @return The file specification.
  356        *
  357        * @throws IOException If there is an error creating the file spec.
  358        */
  359       public PDFileSpecification getFile() throws IOException
  360       {
  361           COSBase f = stream.getDictionaryObject( COSName.F );
  362           PDFileSpecification retval = PDFileSpecification.createFS( f );
  363           return retval;
  364       }
  365   
  366       /**
  367        * Set the file specification.
  368        * @param f The file specification.
  369        */
  370       public void setFile( PDFileSpecification f )
  371       {
  372           stream.setItem( COSName.F, f );
  373       }
  374   
  375       /**
  376        * This will get the list of filters that are associated with this stream.  Or
  377        * null if there are none.
  378        * @return A list of all encoding filters to apply to this stream.
  379        */
  380       public List getFileFilters()
  381       {
  382           List retval = null;
  383           COSBase filters = stream.getDictionaryObject( COSName.F_FILTER );
  384           if( filters instanceof COSName )
  385           {
  386               COSName name = (COSName)filters;
  387               retval = new COSArrayList( name.getName(), name, stream, COSName.F_FILTER );
  388           }
  389           else if( filters instanceof COSArray )
  390           {
  391               retval = COSArrayList.convertCOSNameCOSArrayToList( (COSArray)filters );
  392           }
  393           return retval;
  394       }
  395   
  396       /**
  397        * This will set the filters that are part of this stream.
  398        *
  399        * @param filters The filters that are part of this stream.
  400        */
  401       public void setFileFilters( List filters )
  402       {
  403           COSBase obj = COSArrayList.convertStringListToCOSNameCOSArray( filters );
  404           stream.setItem( COSName.F_FILTER, obj );
  405       }
  406   
  407       /**
  408        * Get the list of decode parameters.  Each entry in the list will refer to
  409        * an entry in the filters list.
  410        *
  411        * @return The list of decode parameters.
  412        *
  413        * @throws IOException if there is an error retrieving the parameters.
  414        */
  415       public List getFileDecodeParams() throws IOException
  416       {
  417           List retval = null;
  418   
  419           COSBase dp = stream.getDictionaryObject( COSName.F_DECODE_PARMS );
  420           if( dp instanceof COSDictionary )
  421           {
  422               Map map = COSDictionaryMap.convertBasicTypesToMap( (COSDictionary)dp );
  423               retval = new COSArrayList(map, dp, stream, COSName.F_DECODE_PARMS );
  424           }
  425           else if( dp instanceof COSArray )
  426           {
  427               COSArray array = (COSArray)dp;
  428               List actuals = new ArrayList();
  429               for( int i=0; i<array.size(); i++ )
  430               {
  431                   actuals.add(
  432                       COSDictionaryMap.convertBasicTypesToMap(
  433                           (COSDictionary)array.getObject( i ) ) );
  434               }
  435               retval = new COSArrayList(actuals, array);
  436           }
  437   
  438           return retval;
  439       }
  440   
  441       /**
  442        * This will set the list of decode params.
  443        *
  444        * @param decodeParams The list of decode params.
  445        */
  446       public void setFileDecodeParams( List decodeParams )
  447       {
  448           stream.setItem(
  449               "FDecodeParams", COSArrayList.converterToCOSArray( decodeParams ) );
  450       }
  451   
  452       /**
  453        * This will copy the stream into a byte array.
  454        *
  455        * @return The byte array of the filteredStream
  456        * @throws IOException When getFilteredStream did not work
  457        */
  458       public byte[] getByteArray() throws IOException
  459       {
  460           ByteArrayOutputStream output = new ByteArrayOutputStream();
  461           byte[] buf = new byte[1024];
  462           InputStream is = null;
  463           try
  464           {
  465               is = createInputStream();
  466               int amountRead = -1;
  467               while( (amountRead = is.read( buf )) != -1)
  468               {
  469                   output.write( buf, 0, amountRead );
  470               }
  471           }
  472           finally
  473           {
  474               if( is != null )
  475               {
  476                   is.close();
  477               }
  478           }
  479           return output.toByteArray();
  480       }
  481   
  482       /**
  483        * A convenience method to get this stream as a string.  Uses
  484        * the default system encoding.
  485        *
  486        * @return a String representation of this (input) stream, with the
  487        * platform default encoding.
  488        *
  489        * @throws IOException if there is an error while converting the stream
  490        *                     to a string.
  491        */
  492       public String getInputStreamAsString() throws IOException
  493       {
  494           byte[] bStream = getByteArray();
  495           return new String(bStream);
  496       }
  497   
  498       /**
  499        * Get the metadata that is part of the document catalog.  This will
  500        * return null if there is no meta data for this object.
  501        *
  502        * @return The metadata for this object.
  503        */
  504       public PDMetadata getMetadata()
  505       {
  506           PDMetadata retval = null;
  507           COSStream mdStream = (COSStream)stream.getDictionaryObject( COSName.METADATA );
  508           if( mdStream != null )
  509           {
  510               retval = new PDMetadata( mdStream );
  511           }
  512           return retval;
  513       }
  514   
  515       /**
  516        * Set the metadata for this object.  This can be null.
  517        *
  518        * @param meta The meta data for this object.
  519        */
  520       public void setMetadata( PDMetadata meta )
  521       {
  522           stream.setItem( COSName.METADATA, meta );
  523       }
  524   
  525       /**
  526        * Get the decoded stream length.
  527        *
  528        * @since Apache PDFBox 1.1.0
  529        * @see <a href="https://issues.apache.org/jira/browse/PDFBOX-636">PDFBOX-636</a>
  530        * @return the decoded stream length
  531        */
  532       public int getDecodedStreamLength()
  533       {
  534           return this.stream.getInt(COSName.DL);
  535       }
  536   
  537       /**
  538        * Set the decoded stream length.
  539        *
  540        * @since Apache PDFBox 1.1.0
  541        * @see <a href="https://issues.apache.org/jira/browse/PDFBOX-636">PDFBOX-636</a>
  542        * @param decodedStreamLength the decoded stream length
  543        */
  544       public void setDecodedStreamLength(int decodedStreamLength)
  545       {
  546           this.stream.setInt(COSName.DL, decodedStreamLength);
  547       }
  548   
  549   }

Home » pdfbox-1.1.0-src » org.apache.pdfbox.pdmodel.common » [javadoc | source]