All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jpedal.io.filter.ccitt.CCITT1D Maven / Gradle / Ivy

There is a newer version: 20151002
Show newest version
/*
 * ===========================================
 * Java Pdf Extraction Decoding Access Library
 * ===========================================
 *
 * Project Info:  http://www.idrsolutions.com
 * Help section for developers at http://www.idrsolutions.com/support/
 *
 * (C) Copyright 1997-2015 IDRsolutions and Contributors.
 *
 * This file is part of JPedal/JPDF2HTML5
 *
     This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA


 *
 * ---------------
 * CCITT1D.java
 * ---------------
 */
package org.jpedal.io.filter.ccitt;

import java.util.BitSet;

import org.jpedal.objects.raw.PdfDictionary;
import org.jpedal.objects.raw.PdfObject;

/**
 * implement 1D CCITT decoding
 */
public class CCITT1D implements CCITTDecoder{


    /**
     * values set in PdfObject
     */
    boolean BlackIs1,isByteAligned;
    int columns = 1728;

    byte[] data;

    int bitReached;

    private static final int EOL = -1;

    private static final boolean debug = false;

    boolean isWhite = true;
    private boolean isTerminating;

    private boolean isEndOfLine;
    private boolean EOS;

    private int cRTC;
    int width;
    int height;
    private int line;
    

    BitSet out;
    private BitSet inputBits;
    int outPtr;

    private int bytesNeeded;
    int scanlineStride;
    private int inputBitCount;

    // ---------- BLACK --------------

    private static final int[][][] b = {
            {{3, 2, 0},{2, 3, 0}},
            {{2, 1, 0},{3, 4, 0}},


            { //b4
                    {3, 5, 0},
                    {2, 6, 0}
            },

            //b5
            {
                    {3, 7, 0}
            },
            //b6
            {
                    {5, 8, 0},
                    {4, 9, 0}
            },
            //b7
            {
                    {4, 10, 0},
                    {5, 11, 0},
                    {7, 12, 0}
            },
            //b8
            {
                    {4, 13, 0},
                    {7, 14, 0}
            },

            //b9
            {
                    {24, 15, 0}
            },

            //b10
            {
                    {55, 0, 0},
                    {23, 16, 0},
                    {24, 17, 0},
                    {8, 18, 0},
                    {15, 64, 1}
            },

            //b11
            {
                    {103, 19, 0},
                    {104, 20, 0},
                    {108, 21, 0},
                    {55, 22, 0},
                    {40, 23, 0},
                    {23, 24, 0},
                    {24, 25, 0},
                    {8, 1792, 1},
                    {12, 1856, 1},
                    {13, 1920, 1}
            },

            //b12
            {
                    {202, 26, 0},
                    {203, 27, 0},
                    {204, 28, 0},
                    {205, 29, 0},
                    {104, 30, 0},
                    {105, 31, 0},
                    {106, 32, 0},
                    {107, 33, 0},
                    {210, 34, 0},
                    {211, 35, 0},
                    {212, 36, 0},
                    {213, 37, 0},
                    {214, 38, 0},
                    {215, 39, 0},
                    {108, 40, 0},
                    {109, 41, 0},
                    {218, 42, 0},
                    {219, 43, 0},
                    {84, 44, 0},
                    {85, 45, 0},
                    {86, 46, 0},
                    {87, 47, 0},
                    {100, 48, 0},
                    {101, 49, 0},
                    {82, 50, 0},
                    {83, 51, 0},
                    {36, 52, 0},
                    {55, 53, 0},
                    {56, 54, 0},
                    {39, 55, 0},
                    {40, 56, 0},
                    {88, 57, 0},
                    {89, 58, 0},
                    {43, 59, 0},
                    {44, 60, 0},
                    {90, 61, 0},
                    {102, 62, 0},
                    {103, 63, 0},
                    {200, 128, 1},
                    {201, 192, 1},
                    {91, 256, 1},
                    {51, 320, 1},
                    {52, 384, 1},
                    {53, 448, 1},
                    {1, EOL, 1},
                    {18, 1984, 1},
                    {19, 2048, 1},
                    {20, 2112, 1},
                    {21, 2176, 1},
                    {22, 2240, 1},
                    {23, 2304, 1},
                    {28, 2368, 1},
                    {29, 2432, 1},
                    {30, 2496, 1},
                    {31, 2560, 1}
            },

            //b13
            {
                    {108, 512, 1},
                    {109, 576, 1},
                    {74, 640, 1},
                    {75, 704, 1},
                    {76, 768, 1},
                    {77, 832, 1},
                    {114, 896, 1},
                    {115, 960, 1},
                    {116, 1024, 1},
                    {117, 1088, 1},
                    {118, 1152, 1},
                    {119, 1216, 1},
                    {82, 1280, 1},
                    {83, 1344, 1},
                    {84, 1408, 1},
                    {85, 1472, 1},
                    {90, 1536, 1},
                    {91, 1600, 1},
                    {100, 1664, 1},
                    {101, 1728, 1}
            }};

    // ---------- WHITE --------------

    private static final int[][][] w = {{
            {7, 2, 0},
            {8, 3, 0},
            {11, 4, 0},
            {12, 5, 0},
            {14, 6, 0},
            {15, 7, 0}},
            //b5
            {
                    {19, 8, 0},
                    {20, 9, 0},
                    {7, 10, 0},
                    {8, 11, 0},
                    {27, 64, 1},
                    {18, 128, 1}
            },
            //b6
            {
                    {7, 1, 0},
                    {8, 12, 0},
                    {3, 13, 0},
                    {52, 14, 0},
                    {53, 15, 0},
                    {42, 16, 0},
                    {43, 17, 0},
                    {23, 192, 1},
                    {24, 1664, 1}
            },
            //w7
            {
                    {39, 18, 0},
                    {12, 19, 0},
                    {8, 20, 0},
                    {23, 21, 0},
                    {3, 22, 0},
                    {4, 23, 0},
                    {40, 24, 0},
                    {43, 25, 0},
                    {19, 26, 0},
                    {36, 27, 0},
                    {24, 28, 0},
                    {55, 256, 1}
            },

            //w8
            {
                    {53, 0, 0},
                    {2, 29, 0},
                    {3, 30, 0},
                    {26, 31, 0},
                    {27, 32, 0},
                    {18, 33, 0},
                    {19, 34, 0},
                    {20, 35, 0},
                    {21, 36, 0},
                    {22, 37, 0},
                    {23, 38, 0},
                    {40, 39, 0},
                    {41, 40, 0},
                    {42, 41, 0},
                    {43, 42, 0},
                    {44, 43, 0},
                    {45, 44, 0},
                    {4, 45, 0},
                    {5, 46, 0},
                    {10, 47, 0},
                    {11, 48, 0},
                    {82, 49, 0},
                    {83, 50, 0},
                    {84, 51, 0},
                    {85, 52, 0},
                    {36, 53, 0},
                    {37, 54, 0},
                    {88, 55, 0},
                    {89, 56, 0},
                    {90, 57, 0},
                    {91, 58, 0},
                    {74, 59, 0},
                    {75, 60, 0},
                    {50, 61, 0},
                    {51, 62, 0},
                    {52, 63, 0},
                    {54, 320, 1},
                    {55, 384, 1},
                    {100, 448, 1},
                    {101, 512, 1},
                    {104, 576, 1},
                    {103, 640, 1}
            },

            //w9
            {
                    {204, 704, 1},
                    {205, 768, 1},
                    {210, 832, 1},
                    {211, 896, 1},
                    {212, 960, 1},
                    {213, 1024, 1},
                    {214, 1088, 1},
                    {215, 1152, 1},
                    {216, 1216, 1},
                    {217, 1280, 1},
                    {218, 1344, 1},
                    {219, 1408, 1},
                    {152, 1472, 1},
                    {153, 1536, 1},
                    {154, 1600, 1},
                    {155, 1728, 1}
            },

            //w10
            {
            },

            //w11
            {
                    {8, 1792, 1},
                    {12, 1856, 1},
                    {13, 1920, 1}
            },

            //w12
            {
                    {1, EOL, 1},
                    {18, 1984, 1},
                    {19, 2048, 1},
                    {20, 2112, 1},
                    {21, 2176, 1},
                    {22, 2240, 1},
                    {23, 2304, 1},
                    {28, 2368, 1},
                    {29, 2432, 1},
                    {30, 2496, 1},
                    {31, 2560, 1}
            }};


    public CCITT1D(final byte[] rawData, final int width, int height, final PdfObject DecodeParms){

        this.data=rawData;
        this.bitReached = 0;

        columns=width; //default if not set (in theory should be the same if set)

        //and any values from PDFobject
        if(DecodeParms!=null){

            BlackIs1 = DecodeParms.getBoolean(PdfDictionary.BlackIs1);

            final int columnsSet = DecodeParms.getInt(PdfDictionary.Columns);
            if(columnsSet!=-1) {
                columns = columnsSet;
            }

            final int rowsSet = DecodeParms.getInt(PdfDictionary.Rows);
            if(rowsSet>0) //allow for value set to 0 which is impossible! (see abacus/aba_Dossier)
            {
                height = rowsSet;
            }


            isByteAligned = DecodeParms.getBoolean(PdfDictionary.EncodedByteAlign);

            if(debug) {
                System.out.println("BlackIs1=" + BlackIs1 + "\ncolumnsSet=" + columnsSet + "\nisByteAligned=" + isByteAligned + "\nrowsSet=" + rowsSet);
            }
        }

        //and other values which might use defaults set from PdfObject
        this.width = columns;
        this.height=height;

        scanlineStride=(columns + 7) >> 3;

        bytesNeeded= (height * scanlineStride);

        out=new BitSet(bytesNeeded<<3);

        //number of bits in raw compressed data
        inputBitCount=data.length<<3;

        //raw data bits to read for codewords
        inputBits =fromByteArray(data, inputBitCount);

    }

    CCITT1D() {}

    @Override
    public byte[] decode(){

        moveToEOLMarker();

        //read all the tokens and find sub values until End Of Stream
        decode1DRun();

        //put output bits together into byte[] we return
        //put it all together
        final byte[] buffer= createOutputFromBitset();

        //by default blackIs1 is false so black pixels do not need to be set
        // invert image if needed -
        // ultimately will be quicker to add into decode
        //k==0 seems to be reverse of others
        if (BlackIs1) {
            for (int i = 0; i < buffer.length; i++) {
                buffer[i] = (byte) (255 - buffer[i]);  //invert all bytes
            }
        }

        return buffer;

    }

    byte[] createOutputFromBitset() {

        final byte[] output = new byte[bytesNeeded];

        //assemble all tokens into a decompressed output data block
        int bytePtr = 0,bitPtr = 7,mask;
        byte entry = 0;

        for(int j=0;j0){
                if(pixelIsWhite){
                    out.set(outPtr, (outPtr + pixelCount), true);
                }
                outPtr += pixelCount;
            }
        }
    }

    private int getCodeWord() {

        int pixelCount=0,itemFound = -1,maskAdj = 0;

        /**
         * look for valid value starting at 2 bits
         *
         * starting with 2 bits (4 for white)
         * look at next pixels until we find a valid value for next codeword
         */
        int startBitLength=2,endBit=14,code=0,bits=0;
        if(isWhite){ //no values for 2,3 in this case
            startBitLength=4;
            endBit=13;
        }

        //loop to find the valid keys by checking next bit value against tables
        for(int bitLength =startBitLength; bitLength  inputBitCount){
            EOS = true;
        }

        return pixelCount;
    }

    private int processCodeWord(final int itemFound, final int code, final int bits) {

        int pixelCount;
        final boolean isT;

        //values in the table
        if(isWhite){
            pixelCount=w[bits-4][itemFound][1];
            isT=w[bits-4][itemFound][2]==0;
        }else{
            pixelCount=b[bits-2][itemFound][1];
            isT=b[bits-2][itemFound][2]==0;
        }

        if(isT) {
            isTerminating = true;
        }

        if(pixelCount ==-1){
            if(line != 0){
                //
//                pixelCount = width - line;
            }

            line = 0;
            isWhite = true;
            isTerminating = false;
        }

        if (pixelCount != -1) {
            line += pixelCount;

            if(line==width){
                if(isT){
                    line = 0;
                    isEndOfLine = true;
                }

            }else if(line>width){
                line = 0;
                isEndOfLine = true;
            }
        }

        if(bits ==12 && code ==1){
            cRTC++;
            if(cRTC==6){
                EOS = true;
            }
        }else{
            cRTC = 0;
        }

        if(cRTC!=6 && isEndOfLine && isByteAligned){

            //get bits over 8 and align to byte boundary
            final int iPart = (bitReached)%8;
            final int iDrop = 8-(iPart);
            if(iPart>0){
                bitReached += iDrop;
            }
        }

        return pixelCount;
    }

    //2D version
    int get1DBits(final int bitsToGet) {
        return get1DBits(bitsToGet,false);
    }

    private int get1DBits(final int bitsToGet, final boolean is1D) {

        int tmp = 0;

        int maskAdj=0;
        if(is1D && bitsToGet>8) {
            maskAdj++;
        }

        int mask;
        for(int y=0;y< bitsToGet;y++){
            if(inputBits.get(y+ bitReached)){
                mask = 1 << (bitsToGet -y-1-maskAdj);

                tmp |= mask;
            }
        }

        return tmp;
    }

    private static int checkTables(final int possCode, final int bitLength, final boolean isWhite) {

        int itemFound=-1;
        final int[][] table;

        if(isWhite){
            table=w[bitLength-4];
        }else{
            table=b[bitLength-2];
        }

        final int size=table.length;

        for(int z=0; z< size;z++){
            if(possCode== table[z][0]){
                itemFound=z;
                z=size;

            }
        }
        return itemFound;
    }

    private static BitSet fromByteArray(final byte[] bytes, final int bitsNeeded) {

        int bitSetPtr = 0,value;
        byte tmp;

        final BitSet bits = new BitSet(bitsNeeded);
        for (final byte aByte : bytes) {
            tmp = aByte;
            for (int z = 7; z >= 0; z--) {

                value = (tmp & (1 << z));

                if (value >= 1) {
                    bits.set(bitSetPtr, true);
                }

                bitSetPtr++;
            }
        }

        return bits;

    }

    private void moveToEOLMarker(){
        boolean isEOL = false, bit;
        int i = 0;

        while(!isEOL){
            isEOL = true;
            for(i=0;i<12;i++){

                bit=inputBits.get(i + bitReached);

                if(i==11){
                    if(!bit){
                        isEOL = false;
                    }
                }else{
                    if(bit){
                        isEOL = false;
                    }
                }
            }

            bitReached++;

            // if EOL not found in the first 10 bits assume that
            // there is no EOL at the start od the line and start
            // at 0
            if(bitReached > 26){

                bitReached = 0;
                return;
            }
        }

        bitReached = bitReached + i - 1;

    }



}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy