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.ByteArrayOutputStream;
   20   import java.io.IOException;
   21   import java.io.InputStream;
   22   import java.io.OutputStream;
   23   import java.text.SimpleDateFormat;
   24   import java.util.Date;
   25   
   26   import org.apache.pdfbox.cos.COSArray;
   27   import org.apache.pdfbox.cos.COSBase;
   28   import org.apache.pdfbox.cos.COSDictionary;
   29   import org.apache.pdfbox.cos.COSName;
   30   
   31   /**
   32    * This is a filter for the CCITTFax Decoder.
   33    *
   34    * @author <a href="mailto:ben@benlitchfield.com">Ben Litchfield</a>
   35    * @author Marcel Kammer
   36    * @author Paul King
   37    * @version $Revision: 1.13 $
   38    */
   39   public class CCITTFaxDecodeFilter implements Filter
   40   {
   41       // Filter will write 15 TAG's
   42       // If you add or remove TAG's you will have to modify this value
   43       private static final int TAG_COUNT = 15;
   44   
   45       // HEADERLENGTH(fix 8 Bytes) plus ImageLength(variable)
   46       private int offset = 8;
   47   
   48       // Bytecounter for Bytes that will be written after the TAG-DICTIONARY
   49       private int tailingBytesCount = 0;
   50   
   51       // Bytes to write after TAG-DICTIONARY
   52       private final ByteArrayOutputStream tailer = new ByteArrayOutputStream();
   53   
   54       /**
   55        * Constructor.
   56        */
   57       public CCITTFaxDecodeFilter()
   58       {
   59       }
   60   
   61       /**
   62        * {@inheritDoc}
   63        */
   64       public void decode(InputStream compressedData, OutputStream result, COSDictionary options, int filterIndex) 
   65           throws IOException
   66       {
   67           // log.warn( "Warning: CCITTFaxDecode.decode is not implemented yet,
   68           // skipping this stream." );
   69   
   70   
   71           // Get ImageParams from PDF
   72           COSBase baseObj = options.getDictionaryObject(new String[] {"DecodeParms","DP"});
   73           COSDictionary dict = null;
   74           if( baseObj instanceof COSDictionary )
   75           {
   76               dict = (COSDictionary)baseObj;
   77           }
   78           else if( baseObj instanceof COSArray )
   79           {
   80               COSArray paramArray = (COSArray)baseObj;
   81               if( filterIndex < paramArray.size() )
   82               {
   83                   dict = (COSDictionary)paramArray.getObject( filterIndex );
   84               }
   85               else
   86               {
   87                   throw new IOException( "Error: DecodeParms cannot be null for CCITTFaxDecode" );
   88               }
   89           }
   90           else if( baseObj == null )
   91           {
   92               throw new IOException( "Error: DecodeParms cannot be null for CCITTFaxDecode" );
   93           }
   94           else
   95           {
   96               throw new IOException( "Error: Expected COSArray or COSDictionary and not " 
   97                       + baseObj.getClass().getName() );
   98           }
   99   
  100           int width = options.getInt("Width");
  101           int height = options.getInt("Height");
  102           int length = options.getInt(COSName.LENGTH);
  103           int compressionType = dict.getInt("K");
  104           boolean blackIs1 = dict.getBoolean("BlackIs1", false);
  105   
  106   
  107           // HEADER-INFO and starting point of TAG-DICTIONARY
  108           writeTagHeader(result, length);
  109   
  110           // IMAGE-DATA
  111           int i = 0;
  112           //int sum = 0;
  113           byte[] buffer = new byte[32768];
  114           int lentoread = length;
  115   
  116           while ((lentoread > 0) && ((i = compressedData.read(buffer, 0, Math.min(lentoread, 32768))) != -1))
  117           {
  118               //sum += i;
  119               result.write(buffer, 0, i);
  120               lentoread = lentoread - i;
  121           }
  122   
  123           // If lentoread is > 0 then we need to write out some padding to equal the header
  124           // We'll use what we have in the buffer it's just padding after all
  125           while (lentoread > 0)
  126           {
  127               result.write(buffer, 0, Math.min(lentoread, 32768));
  128               lentoread = lentoread - Math.min(lentoread, 32738);
  129           }
  130           //System.out.println("Gelesen: " + sum);
  131   
  132           // TAG-COUNT
  133           writeTagCount(result);
  134   
  135           // WIDTH 0x0100
  136           writeTagWidth(result, width);
  137   
  138           // HEIGHT 0x0101
  139           writeTagHeight(result, height);
  140   
  141           // BITSPERSAMPLE 0x0102
  142           // Always 1 for CCITTFax
  143           writeTagBitsPerSample(result, 1);
  144   
  145           // COMPRESSION 0x0103
  146           writeTagCompression(result, compressionType);
  147   
  148           // PHOTOMETRIC 0x0106
  149           writeTagPhotometric(result, blackIs1);
  150   
  151           // STRIPOFFSET 0x0111
  152           // HERE ALWAYS 8, because ImageData comes before TAG-DICTIONARY
  153           writeTagStripOffset(result, 8);
  154   
  155           // ORIENTATION 0x0112
  156           writeTagOrientation(result, 1);
  157   
  158           // SamplesPerPixel 0x0115
  159           writeTagSamplesPerPixel(result, 1);
  160   
  161           // RowsPerStrip 0x0116
  162           writeTagRowsPerStrip(result, height);
  163   
  164           // Stripcount 0x0117
  165           writeTagStripByteCount(result, length);
  166   
  167           // XRESOLUTION 0x011A
  168           // HERE: 200 DPI
  169           writeTagXRes(result, 200, 1);
  170   
  171           // YRESOLITION 0x011B
  172           // HERE: 200 DPI
  173           writeTagYRes(result, 200, 1);
  174   
  175           // ResolutionUnit 0x0128
  176           // HERE: DPI
  177           writeTagResolutionUnit(result, 2);
  178   
  179           // SOFTWARE 0x0131
  180           // minimum 4 chars
  181           writeTagSoftware(result, "pdfbox".getBytes());
  182   
  183           // DATE AND TIME 0x0132
  184           writeTagDateTime(result, new Date());
  185   
  186           // END OF TAG-DICT
  187           writeTagTailer(result);
  188       }
  189   
  190       private void writeTagHeader(OutputStream result, int length) throws IOException
  191       {
  192           byte[] header = { 'M', 'M', 0, '*' };// Big-endian
  193           result.write(header);
  194   
  195   
  196           // Add imagelength to offset
  197           offset += length;
  198   
  199           // OFFSET TAG-DICTIONARY
  200           int i1 = offset/16777216;//=value/(256*256*256)
  201           int i2 = (offset-i1*16777216)/65536;
  202           int i3 = (offset-i1*16777216-i2*65536)/256;
  203           int i4 = offset % 256;
  204           result.write(i1);
  205           result.write(i2);
  206           result.write(i3);
  207           result.write(i4);
  208       }
  209   
  210       private void writeTagCount(OutputStream result) throws IOException
  211       {
  212           result.write(TAG_COUNT / 256);
  213           result.write(TAG_COUNT % 256);// tagCount
  214       }
  215   
  216       private void writeTagWidth(OutputStream result, int width) throws IOException
  217       {
  218           // @todo width berechnen
  219   
  220           // TAG-ID 100
  221           result.write(1);
  222           result.write(0);
  223   
  224   
  225           // TAG-TYPE SHORT=3
  226           result.write(0);
  227           result.write(3);
  228   
  229   
  230           // TAG-LENGTH = 1
  231           result.write(0);
  232           result.write(0);
  233           result.write(0);
  234           result.write(1);
  235   
  236   
  237           // TAG-VALUE = width
  238           result.write(width/256);
  239           result.write(width%256);
  240           result.write(0);// SHORT=0
  241           result.write(0);// SHORT=0
  242   
  243       }
  244   
  245       private void writeTagHeight(OutputStream result, int height) throws IOException
  246       {
  247           //@todo height berechnen
  248           // TAG-ID 101
  249           result.write(1);
  250           result.write(1);
  251   
  252   
  253           // TAG-TYPE SHORT=3
  254           result.write(0);
  255           result.write(3);
  256   
  257   
  258           // TAG-LENGTH = 1
  259           result.write(0);
  260           result.write(0);
  261           result.write(0);
  262           result.write(1);
  263   
  264   
  265           // TAG-VALUE
  266           result.write(height/256);
  267           result.write(height%256);
  268           result.write(0);// SHORT=0
  269           result.write(0);// SHORT=0
  270   
  271       }
  272   
  273       private void writeTagBitsPerSample(OutputStream result, int value) throws IOException
  274       {
  275           // TAG-ID 102
  276           result.write(1);
  277           result.write(2);
  278   
  279   
  280           // TAG-TYPE SHORT=3
  281           result.write(0);
  282           result.write(3);
  283   
  284           // TAG-LENGTH = 1
  285           result.write(0);
  286           result.write(0);
  287           result.write(0);
  288           result.write(1);
  289   
  290   
  291           // TAG-VALUE
  292           result.write(value/256);
  293           result.write(value%256);
  294           result.write(0);//SHORT=0
  295           result.write(0);//SHORT=0
  296   
  297       }
  298   
  299       /**
  300        * Write the tag compression.
  301        *
  302        * @param result The stream to write to.
  303        * @param type The type to write.
  304        * @throws IOException If there is an error writing to the stream.
  305        */
  306       public void writeTagCompression(OutputStream result, int type) throws IOException
  307       {
  308           // TAG-ID 103
  309           result.write(1);
  310           result.write(3);
  311   
  312           // TAG-TYPE SHORT=3
  313           result.write(0);
  314           result.write(3);
  315   
  316   
  317           // TAG-LEGNTH = 1
  318           result.write(0);
  319           result.write(0);
  320           result.write(0);
  321           result.write(1);
  322   
  323           // TAG-VALUE
  324           //@todo typ eintragen; hier immer 4
  325           result.write(0);
  326           if (type < 0)
  327           {
  328               result.write(4);// G4
  329           }
  330           else if (type == 0)
  331           {
  332               result.write(3);// G3-1D
  333           }
  334           else
  335           {
  336               result.write(2);// G3-2D
  337           }
  338           result.write(0);
  339           result.write(0);
  340   
  341       }
  342   
  343       private void writeTagPhotometric(OutputStream result, boolean blackIs1) throws IOException
  344       {
  345           // TAG-ID 106
  346           result.write(1);
  347           result.write(6);
  348   
  349   
  350           // TAG-TYPE SHORT
  351           result.write(0);
  352           result.write(3);
  353   
  354   
  355           // TAG-LENGTH = 1
  356           result.write(0);
  357           result.write(0);
  358           result.write(0);
  359           result.write(1);
  360   
  361   
  362           // TAG-VALUE
  363           result.write(0);
  364           if (blackIs1)
  365           {
  366               result.write(1);
  367           }
  368           else
  369           {
  370               result.write(0);
  371           }
  372           result.write(0);// SHORT=0
  373           result.write(0);// SHORT=0
  374   
  375       }
  376   
  377       private void writeTagStripOffset(OutputStream result, int value) throws IOException
  378       {
  379           // TAG-ID 111
  380           result.write(1);
  381           result.write(17);
  382   
  383           // TAG-TYPE LONG=4
  384           result.write(0);
  385           result.write(4);
  386   
  387   
  388           // TAG-LENGTH=1
  389           result.write(0);
  390           result.write(0);
  391           result.write(0);
  392           result.write(1);
  393   
  394   
  395           // TAG-VALUE = 8 //VOR TAG-DICTIONARY
  396           int i1 = value/16777216;//=value/(256*256*256)
  397           int i2 = (value-i1*16777216)/65536;
  398           int i3 = (value-i1*16777216-i2*65536)/256;
  399           int i4 = value % 256;
  400           result.write(i1);
  401           result.write(i2);
  402           result.write(i3);
  403           result.write(i4);
  404   
  405       }
  406   
  407       private void writeTagSamplesPerPixel(OutputStream result, int value) throws IOException
  408       {
  409           // TAG-ID 115
  410           result.write(1);
  411           result.write(21);
  412   
  413   
  414           // TAG-TYPE SHORT=3
  415           result.write(0);
  416           result.write(3);
  417   
  418   
  419           // TAG-LENGTH=1
  420           result.write(0);
  421           result.write(0);
  422           result.write(0);
  423           result.write(1);
  424   
  425   
  426           // TAG-VALUE
  427           result.write(value / 256);
  428           result.write(value % 256);
  429           result.write(0);// SHORT=0
  430           result.write(0);// SHORT=0
  431   
  432       }
  433   
  434       private void writeTagRowsPerStrip(OutputStream result, int value) throws IOException
  435       {
  436           // TAG-ID 116
  437           result.write(1);
  438           result.write(22);
  439   
  440   
  441           // TAG-TYPE SHORT=3
  442           result.write(0);
  443           result.write(3);
  444   
  445   
  446           // TAG-LENGTH=1
  447           result.write(0);
  448           result.write(0);
  449           result.write(0);
  450           result.write(1);
  451   
  452   
  453           // TAG-VALUE
  454           result.write(value / 256);
  455           result.write(value % 256);
  456           result.write(0);// SHORT=0
  457           result.write(0);// SHORT=0
  458   
  459       }
  460   
  461       private void writeTagStripByteCount(OutputStream result, int value) throws IOException
  462       {
  463           //@todo value auswerten
  464           // TAG-ID 117
  465           result.write(1);
  466           result.write(23);
  467   
  468           // TAG-TYPE LONG=4
  469           result.write(0);
  470           result.write(4);
  471   
  472   
  473           // TAG-LENGTH = 1
  474           result.write(0);
  475           result.write(0);
  476           result.write(0);
  477           result.write(1);
  478   
  479           // TAG-VALUE
  480           int i1 = value/16777216;//=value/(256*256*256)
  481           int i2 = (value-i1*16777216)/65536;
  482           int i3 = (value-i1*16777216-i2*65536)/256;
  483           int i4 = value % 256;
  484           result.write(i1);
  485           result.write(i2);
  486           result.write(i3);
  487           result.write(i4);
  488   
  489       }
  490   
  491       private void writeTagXRes(OutputStream result, int value1, int value2) throws IOException
  492       {
  493           // TAG-ID 11A
  494           result.write(1);
  495           result.write(26);
  496   
  497           // TAG-TYPE RATIONAL=5
  498           result.write(0);
  499           result.write(5);
  500   
  501           // TAG-LENGTH=1
  502           result.write(0);
  503           result.write(0);
  504           result.write(0);
  505           result.write(1);
  506   
  507   
  508           // TAG-VALUE=OFFSET TO RATIONAL
  509           int valueOffset = offset + 6 + 12 * TAG_COUNT + tailer.size();
  510           int i1 = valueOffset/16777216;//=value/(256*256*256)
  511           int i2 = (valueOffset-i1*16777216)/65536;
  512           int i3 = (valueOffset-i1*16777216-i2*65536)/256;
  513           int i4 = valueOffset % 256;
  514           result.write(i1);
  515           result.write(i2);
  516           result.write(i3);
  517           result.write(i4);
  518   
  519           i1 = value1 /16777216;
  520           i2 = (value1-i1*16777216)/65536;
  521           i3 = (value1-i1*16777216 - i2*65536)/256;
  522           i4 = value1 % 256;
  523           tailer.write(i1);
  524           tailer.write(i2);
  525           tailer.write(i3);
  526           tailer.write(i4);
  527   
  528           i1 = value2 /16777216;
  529           i2 = (value2-i1*16777216)/65536;
  530           i3 = (value2-i1*16777216 - i2*65536)/256;
  531           i4 = value2 % 256;
  532           tailer.write(i1);
  533           tailer.write(i2);
  534           tailer.write(i3);
  535           tailer.write(i4);
  536   
  537           tailingBytesCount += 8;
  538       }
  539   
  540       private void writeTagYRes(OutputStream result, int value1, int value2) throws IOException
  541       {
  542           // TAG-ID 11B
  543           result.write(1);
  544           result.write(27);
  545   
  546   
  547           // TAG-TYPE RATIONAL=5
  548           result.write(0);
  549           result.write(5);
  550   
  551           // TAG-LENGTH=1
  552           result.write(0);
  553           result.write(0);
  554           result.write(0);
  555           result.write(1);
  556   
  557   
  558           // TAG-VALUE=OFFSET TO RATIONAL
  559           int valueOffset = offset + 6 + 12 * TAG_COUNT + tailer.size();
  560           int i1 = valueOffset/16777216;//=value/(256*256*256)
  561           int i2 = (valueOffset-i1*16777216)/65536;
  562           int i3 = (valueOffset-i1*16777216-i2*65536)/256;
  563           int i4 = valueOffset % 256;
  564           result.write(i1);
  565           result.write(i2);
  566           result.write(i3);
  567           result.write(i4);
  568   
  569           i1 = value1 /16777216;
  570           i2 = (value1-i1*16777216)/65536;
  571           i3 = (value1-i1*16777216 - i2*65536)/256;
  572           i4 = value1 % 256;
  573           tailer.write(i1);
  574           tailer.write(i2);
  575           tailer.write(i3);
  576           tailer.write(i4);
  577   
  578           i1 = value2 /16777216;
  579           i2 = (value2-i1*16777216)/65536;
  580           i3 = (value2-i1*16777216 - i2*65536)/256;
  581           i4 = value2 % 256;
  582           tailer.write(i1);
  583           tailer.write(i2);
  584           tailer.write(i3);
  585           tailer.write(i4);
  586   
  587           tailingBytesCount += 8;
  588       }
  589   
  590       private void writeTagResolutionUnit(OutputStream result, int value) throws IOException
  591       {
  592           // TAG-ID 128
  593           result.write(1);
  594           result.write(40);
  595   
  596           // TAG-TYPE SHORT=3
  597           result.write(0);
  598           result.write(3);
  599   
  600           // TAG-LENGTH = 1
  601           result.write(0);
  602           result.write(0);
  603           result.write(0);
  604           result.write(1);
  605   
  606           // TAG-VALUE
  607           result.write(value/256);
  608           result.write(value%256);
  609           result.write(0);// SHORT=0
  610           result.write(0);// SHORT=0
  611   
  612       }
  613   
  614       private void writeTagOrientation(OutputStream result, int value) throws IOException
  615       {
  616           // TAG-ID 112
  617           result.write(1);
  618           result.write(18);
  619   
  620           // TAG-TYPE SHORT = 3
  621           result.write(0);
  622           result.write(3);
  623   
  624   
  625           // TAG-LENGTH=1
  626           result.write(0);
  627           result.write(0);
  628           result.write(0);
  629           result.write(1);
  630   
  631           // TAG-VALUE
  632           result.write(value / 256);
  633           result.write(value % 256);
  634           result.write(0);// SHORT=0
  635           result.write(0);// SHORT=0
  636   
  637       }
  638   
  639       private void writeTagTailer(OutputStream result) throws IOException
  640       {
  641           // END OF TAG-DICTIONARY
  642           result.write(0);
  643           result.write(0);
  644           result.write(0);
  645           result.write(0);
  646   
  647           // TAILER WITH VALUES OF RATIONALFIELD's
  648           result.write(tailer.toByteArray());
  649       }
  650   
  651       private void writeTagSoftware(OutputStream result, byte[] text) throws IOException
  652       {
  653           // TAG-ID 131
  654           result.write(1);
  655           result.write(49);
  656   
  657           // TAG-TYPE ASCII=2
  658           result.write(0);
  659           result.write(2);
  660   
  661   
  662           // TAG-LENGTH=id.length+1
  663           result.write(0);
  664           result.write(0);
  665           result.write((text.length + 1) / 256);
  666           result.write((text.length + 1) % 256);
  667   
  668           // TAG-VALUE
  669           int valueOffset = offset + 6 + 12 * TAG_COUNT + tailer.size();
  670           int i1 = valueOffset/16777216;//=value/(256*256*256)
  671           int i2 = (valueOffset-i1*16777216)/65536;
  672           int i3 = (valueOffset-i1*16777216-i2*65536)/256;
  673           int i4 = valueOffset % 256;
  674           result.write(i1);
  675           result.write(i2);
  676           result.write(i3);
  677           result.write(i4);
  678   
  679   
  680           tailer.write(text);
  681           tailer.write(0);
  682           tailingBytesCount += text.length + 1;
  683       }
  684   
  685       private void writeTagDateTime(OutputStream result, Date date) throws IOException
  686       {
  687           // TAG-ID 132
  688           result.write(1);
  689           result.write(50);
  690   
  691   
  692           // TAG-TYPE ASCII=2
  693           result.write(0);
  694           result.write(2);
  695   
  696   
  697           // TAG-LENGTH=20
  698           result.write(0);
  699           result.write(0);
  700           result.write(0);
  701           result.write(20);
  702   
  703   
  704           // TAG-VALUE
  705           int valueOffset = offset + 6 + 12 * TAG_COUNT + tailer.size();
  706           int i1 = valueOffset/16777216;//=value/(256*256*256)
  707           int i2 = (valueOffset-i1*16777216)/65536;
  708           int i3 = (valueOffset-i1*16777216-i2*65536)/256;
  709           int i4 = valueOffset % 256;
  710           result.write(i1);
  711           result.write(i2);
  712           result.write(i3);
  713           result.write(i4);
  714   
  715           SimpleDateFormat sdf = new SimpleDateFormat("yyyy:MM:dd HH:mm:ss");
  716           String datetime = sdf.format(date);
  717           tailer.write(datetime.getBytes());
  718           tailer.write(0);
  719   
  720           tailingBytesCount += 20;
  721       }
  722   
  723       /**
  724        * {@inheritDoc}
  725        */
  726       public void encode(InputStream rawData, OutputStream result, COSDictionary options, int filterIndex ) 
  727           throws IOException
  728       {
  729           System.err.println("Warning: CCITTFaxDecode.encode is not implemented yet, skipping this stream.");
  730       }
  731   }

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