Home » pdfbox-1.1.0-src » org.apache.pdfbox.filter » [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.filter;
   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   import java.io.EOFException;
   25   import java.util.zip.DeflaterOutputStream;
   26   import java.util.zip.InflaterInputStream;
   27   import java.util.zip.ZipException;
   28   
   29   import org.apache.commons.logging.Log;
   30   import org.apache.commons.logging.LogFactory;
   31   import org.apache.pdfbox.cos.COSArray;
   32   import org.apache.pdfbox.cos.COSBase;
   33   import org.apache.pdfbox.cos.COSDictionary;
   34   
   35   /**
   36    * This is the used for the FlateDecode filter.
   37    *
   38    * @author <a href="mailto:ben@benlitchfield.com">Ben Litchfield</a>
   39    * @author Marcel Kammer
   40    * @version $Revision: 1.12 $
   41    */
   42   public class FlateFilter implements Filter 
   43   {
   44   
   45       /**
   46        * Log instance.
   47        */
   48       private static final Log log = LogFactory.getLog(FlateFilter.class);
   49   
   50       private static final int    BUFFER_SIZE    = 2048;
   51   
   52       /**
   53        * {@inheritDoc}
   54        */
   55       public void decode(InputStream compressedData, OutputStream result, COSDictionary options, int filterIndex ) 
   56       throws IOException
   57       {
   58           COSBase baseObj = options.getDictionaryObject(new String[] {"DecodeParms","DP"});
   59           COSDictionary dict = null;
   60           if( baseObj instanceof COSDictionary )
   61           {
   62               dict = (COSDictionary)baseObj;
   63           }
   64           else if( baseObj instanceof COSArray )
   65           {
   66               COSArray paramArray = (COSArray)baseObj;
   67               if( filterIndex < paramArray.size() )
   68               {
   69                   dict = (COSDictionary)paramArray.getObject( filterIndex );
   70               }
   71           }
   72           else if( baseObj == null )
   73           {
   74               //do nothing
   75           }
   76           else
   77           {
   78               throw new IOException( "Error: Expected COSArray or COSDictionary and not " 
   79                       + baseObj.getClass().getName() );
   80           }
   81   
   82   
   83           int predictor = -1;
   84           int colors = -1;
   85           int bitsPerPixel = -1;
   86           int columns = -1;
   87           InflaterInputStream decompressor = null;
   88           ByteArrayInputStream bais = null;
   89           ByteArrayOutputStream baos = null;
   90           if (dict!=null)
   91           {
   92               predictor = dict.getInt("Predictor");
   93               if(predictor > 1)
   94               {
   95                   colors = dict.getInt("Colors");
   96                   bitsPerPixel = options.getInt("BitsPerComponent");
   97                   columns = dict.getInt("Columns");
   98               }
   99           }
  100   
  101           try
  102           {
  103               // Decompress data to temporary ByteArrayOutputStream
  104               decompressor = new InflaterInputStream(compressedData);
  105               int amountRead;
  106               int mayRead = compressedData.available();
  107   
  108               if (mayRead > 0) 
  109               {
  110                   byte[] buffer = new byte[Math.min(mayRead,BUFFER_SIZE)];
  111   
  112                   // Decode data using given predictor
  113                   if (predictor==-1 || predictor == 1 || predictor == 10)
  114                   {
  115                       try 
  116                       {
  117                           // decoding not needed
  118                           while ((amountRead = decompressor.read(buffer, 0, Math.min(mayRead,BUFFER_SIZE))) != -1)
  119                           {
  120                               result.write(buffer, 0, amountRead);
  121                           }
  122                       }
  123                       catch (OutOfMemoryError exception) 
  124                       {
  125                           // if the stream is corrupt an OutOfMemoryError may occur
  126                           log.error("Stop reading corrupt stream");
  127                       }
  128                       catch (ZipException exception) 
  129                       {
  130                           // if the stream is corrupt an OutOfMemoryError may occur
  131                           log.error("Stop reading corrupt stream");
  132                       }
  133                       catch (EOFException exception) 
  134                       {
  135                           // if the stream is corrupt an OutOfMemoryError may occur
  136                           log.error("Stop reading corrupt stream");
  137                       }
  138                   }
  139                   else
  140                   {
  141                       /*
  142                        * Reverting back to default values
  143                        */
  144                       if( colors == -1 )
  145                       {
  146                           colors = 1;
  147                       }
  148                       if( bitsPerPixel == -1 )
  149                       {
  150                           bitsPerPixel = 8;
  151                       }
  152                       if( columns == -1 )
  153                       {
  154                           columns = 1;
  155                       }
  156   
  157                       baos = new ByteArrayOutputStream();
  158                       while ((amountRead = decompressor.read(buffer, 0, Math.min(mayRead,BUFFER_SIZE))) != -1)
  159                       {
  160                           baos.write(buffer, 0, amountRead);
  161                       }
  162                       baos.flush();
  163   
  164                       // Copy data to ByteArrayInputStream for reading
  165                       bais = new ByteArrayInputStream(baos.toByteArray());
  166                       baos.close();
  167                       baos = null;
  168   
  169                       byte[] decodedData = decodePredictor(predictor, colors, bitsPerPixel, columns, bais);
  170                       bais.close();
  171                       bais = new ByteArrayInputStream(decodedData);
  172   
  173                       // write decoded data to result
  174                       while ((amountRead = bais.read(buffer)) != -1)
  175                       {
  176                           result.write(buffer, 0, amountRead);
  177                       }
  178                       bais.close();
  179                       bais = null;
  180                   }
  181               }
  182   
  183               result.flush();
  184           }
  185           finally
  186           {
  187               if (decompressor != null)
  188               {
  189                   decompressor.close();
  190               }
  191               if (bais != null)
  192               {
  193                   bais.close();
  194               }
  195               if (baos != null)
  196               {
  197                   baos.close();
  198               }
  199           }
  200       }
  201   
  202       private byte[] decodePredictor(int predictor, int colors, int bitsPerComponent, int columns, InputStream data)
  203           throws IOException
  204       {
  205           ByteArrayOutputStream baos = new ByteArrayOutputStream();
  206           byte[] buffer = new byte[2048];
  207   
  208           if (predictor == 1 || predictor == 10)
  209           {
  210               // No prediction or PNG NONE
  211               int i = 0;
  212               while ((i = data.read(buffer)) != -1)
  213               {
  214                   baos.write(buffer, 0, i);
  215               }
  216           }
  217           else
  218           {
  219               // calculate sizes
  220               int bpp = (colors * bitsPerComponent + 7) / 8;
  221               int rowlength = (columns * colors * bitsPerComponent + 7) / 8 + bpp;
  222               byte[] actline = new byte[rowlength];
  223               byte[] lastline = new byte[rowlength];// Initialize lastline with
  224                                                       // Zeros according to
  225                                                       // PNG-specification
  226               boolean done = false;
  227               int linepredictor = predictor;
  228   
  229               while (!done && data.available() > 0)
  230               {
  231                   if (predictor == 15)
  232                   {
  233                       linepredictor = data.read();// read per line predictor
  234                       if (linepredictor == -1)
  235                       {
  236                           done = true;// reached EOF
  237                           break;
  238                       }
  239                       else
  240                       {
  241                           linepredictor += 10; // add 10 to tread value 1 as 11
  242                       }
  243                       // (instead of PRED NONE) and 2
  244                       // as 12 (instead of PRED TIFF)
  245                   }
  246   
  247                   // read line
  248                   int i = 0;
  249                   int offset = bpp;
  250                   while (offset < rowlength && ((i = data.read(actline, offset, rowlength - offset)) != -1))
  251                   {
  252                       offset += i;
  253                   }
  254   
  255                   // Do prediction as specified in PNG-Specification 1.2
  256                   switch (linepredictor)
  257                   {
  258                       case 2:// PRED TIFF SUB
  259                           /**
  260                            * @todo decode tiff
  261                            */
  262                           throw new IOException("TIFF-Predictor not supported");
  263                       case 11:// PRED SUB
  264                           for (int p = bpp; p < rowlength; p++)
  265                           {
  266                               int sub = actline[p] & 0xff;
  267                               int left = actline[p - bpp] & 0xff;
  268                               actline[p] = (byte) (sub + left);
  269                           }
  270                           break;
  271                       case 12:// PRED UP
  272                           for (int p = bpp; p < rowlength; p++)
  273                           {
  274                               int up = actline[p] & 0xff;
  275                               int prior = lastline[p] & 0xff;
  276                               actline[p] = (byte) (up + prior);
  277                           }
  278                           break;
  279                       case 13:// PRED AVG
  280                           for (int p = bpp; p < rowlength; p++)
  281                           {
  282                               int avg = actline[p] & 0xff;
  283                               int left = actline[p - bpp] & 0xff;
  284                               int up = lastline[p] & 0xff;
  285                               actline[p] = (byte) (avg + ((left + up) / 2));
  286                           }
  287                           break;
  288                       case 14:// PRED PAETH
  289                           for (int p = bpp; p < rowlength; p++)
  290                           {
  291                               int paeth = actline[p] & 0xff;
  292                               int a = actline[p - bpp] & 0xff;// left
  293                               int b = lastline[p] & 0xff;// upper
  294                               int c = lastline[p - bpp] & 0xff;// upperleft
  295                               int value = a + b - c;
  296                               int absa = Math.abs(value - a);
  297                               int absb = Math.abs(value - b);
  298                               int absc = Math.abs(value - c);
  299   
  300                               if (absa <= absb && absa <= absc)
  301                               {
  302                                   actline[p] = (byte) (paeth + absa);
  303                               }
  304                               else if (absb <= absc)
  305                               {
  306                                   actline[p] += (byte) (paeth + absb);
  307                               }
  308                               else
  309                               {
  310                                   actline[p] += (byte) (paeth + absc);
  311                               }
  312                           }
  313                           break;
  314                       default:
  315                           break;
  316                   }
  317   
  318                   lastline = (byte[])actline.clone();
  319                   baos.write(actline, bpp, actline.length - bpp);
  320               }
  321           }
  322   
  323           return baos.toByteArray();
  324       }
  325   
  326       /**
  327        * {@inheritDoc}
  328        */
  329       public void encode(InputStream rawData, OutputStream result, COSDictionary options, int filterIndex ) 
  330       throws IOException
  331       {
  332           DeflaterOutputStream out = new DeflaterOutputStream(result);
  333           int amountRead = 0;
  334           int mayRead = rawData.available();
  335           if (mayRead > 0) 
  336           {
  337               byte[] buffer = new byte[Math.min(mayRead,BUFFER_SIZE)];
  338               while ((amountRead = rawData.read(buffer, 0, Math.min(mayRead,BUFFER_SIZE))) != -1)
  339               {
  340                   out.write(buffer, 0, amountRead);
  341               }
  342           }
  343           out.close();
  344           result.flush();
  345       }
  346   }

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