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

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

/*
 * ===========================================
 * 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-2017 IDRsolutions and Contributors.
 *
 * This file is part of JPedal/JPDF2HTML5
 *
 @LICENSE@
 *
 * ---------------
 * CCITTMix.java
 * ---------------
 */
package org.jpedal.io.filter.ccitt;

import org.jpedal.exception.PdfException;
import org.jpedal.objects.raw.PdfObject;
import org.jpedal.utils.LogWriter;

/**
 * handle case with mix of CCITT1D and 2D
 */
public class CCITTMix extends CCITT2D {

    private int fillBits;

    public CCITTMix(final byte[] rawData, final int width, final int height, final PdfObject decodeParms) {

        super(rawData, width, height, decodeParms);

        this.data = rawData;

        is2D = false;

    }

    @Override
    public byte[] decode() {

        try {

            /* Added to stop errors*/
            int[] prev = new int[width + 1];
            int[] curr = new int[width + 1];

            final int[] currentChangeElement = new int[2];

            // The data must start with an EOL code
            if (readEOL(true) != 1) {
                throw new PdfException("TIFFFaxDecoder3");
            }

            //always 1D at first
            decode1DRun(curr);

            //rest of lines either 1 or 2D
            for (int lines = 1; lines < height; lines++) {

                // Every line must begin with an EOL followed by a bit which
                // indicates whether the following scanline is 1D or 2D encoded.
                if (readEOL(false) == 0) {

                    //swap
                    final int[] temp = prev;
                    prev = curr;
                    curr = temp;

                    set2D(prev, curr, changingElemSize, currentChangeElement);

                    curr[currIndex++] = bitOffset;
                    changingElemSize = currIndex;
                } else {
                    decode1DRun(curr);
                }
            }
        } catch (final Exception e) {
            LogWriter.writeLog("Exception: " + e.getMessage());
        }

        //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
        if (!BlackIs1) {
            for (int i = 0; i < buffer.length; i++) {
                buffer[i] = (byte) (255 - buffer[i]);
            }
        }

        return buffer;
    }

    void decode1DRun(final int[] curr) throws Exception {
        int bitOffset = 0;

        int bits, code, isT;
        int current, entry, twoBits;
        boolean isWhite = true;

        // Initialize starting of the changing elements array
        changingElemSize = 0;

        while (bitOffset < columns) {
            while (isWhite) {
                // White run (lookup entry in data and use this to fetch white value from lookuptable
                current = get1DBits(10);

                bitReached += 10;

                entry = white[current];

                // Get the 3 fields from the entry
                isT = entry & 0x0001;
                bits = (entry >>> 1) & 0x0f;
                if (bits == 12) { // Additional Make up code
                    // Get the next 2 bits
                    twoBits = get1DBits(2);

                    bitReached += 2;

                    // Consolidate the 2 new bits and last 2 bits into 4 bits
                    current = ((current << 2) & 0x000c) | twoBits;
                    entry = additionalMakeup[current];
                    bits = (entry >>> 1) & 0x07; // 3 bits 0000 0111
                    code = (entry >>> 4) & 0x0fff; // 12 bits
                    bitOffset += code; // Skip white run

                    outPtr += code;

                    bitReached -= (4 - bits);
                } else if (bits == 0 || bits == 15) { // ERROR
                    throw new Exception(("1Derror"));
                } else {
                    code = (entry >>> 5) & 0x07ff;
                    bitOffset += code;
                    bitReached -= (10 - bits);
                    if (isT == 0) {
                        isWhite = false;
                        curr[changingElemSize++] = bitOffset;
                    }
                    outPtr += code;
                }
            }

            if (bitOffset == columns) {
                break;
            }

            while (!isWhite) {
                // Black run
                current = get1DBits(4);
                entry = initBlack[current];

                bitReached += 4;

                // Get the fields from the entry
                bits = (entry >>> 1) & 0x000f;
                code = (entry >>> 5) & 0x07ff;
                if (code == 100) {
                    current = get1DBits(9);

                    bitReached += 9;

                    entry = black[current];

                    // Get the 3 fields from the entry
                    isT = entry & 0x0001;
                    bits = (entry >>> 1) & 0x000f;
                    code = (entry >>> 5) & 0x07ff;

                    if (bits == 12) {
                        // Additional makeup codes
                        bitReached -= 5;
                        current = get1DBits(4);

                        bitReached += 4;

                        entry = additionalMakeup[current];
                        bits = (entry >>> 1) & 0x07; // 3 bits 0000 0111
                        code = (entry >>> 4) & 0x0fff; // 12 bits

                        out.set(outPtr, outPtr + code, true);
                        outPtr += code;

                        bitOffset += code;
                        bitReached -= (4 - bits);
                    } else if (bits == 15)
                    // EOL code
                    {
                        throw new PdfException(("1D error"));
                    } else {
                        out.set(outPtr, outPtr + code, true);
                        outPtr += code;
                        bitOffset += code;
                        bitReached -= (9 - bits);
                        if (isT == 0) {
                            isWhite = true;
                            curr[changingElemSize++] = bitOffset;
                        }
                    }
                } else if (code == 200) {
                    // Is a Terminating code
                    current = get1DBits(2);

                    bitReached += 2;

                    entry = twoBitBlack[current];
                    code = (entry >>> 5) & 0x07ff;
                    bits = (entry >>> 1) & 0x0f;
                    out.set(outPtr, outPtr + code, true);
                    outPtr += code;
                    bitOffset += code;
                    bitReached -= (2 - bits);
                    isWhite = true;
                    curr[changingElemSize++] = bitOffset;
                } else {
                    // Is a Terminating code
                    out.set(outPtr, outPtr + code, true);
                    outPtr += code;
                    bitOffset += code;
                    bitReached -= (4 - bits);
                    isWhite = true;
                    curr[changingElemSize++] = bitOffset;
                }
            }

            // Check whether this run completed one width
            if (bitOffset == columns) {
                break;
            }

        }
        curr[changingElemSize++] = bitOffset;
    }

    private int readEOL(final boolean isFirstEOL) throws PdfException {

        if (fillBits == 0) {

            //Byte align if necessary
            if (isByteAligned && bitReached % 8 != 0) {
                bitReached += 8 - (bitReached % 8);
            }

            final int next12Bits = get1DBits(12);

            bitReached += 12;
            if (isFirstEOL && next12Bits == 0) {

                final int aa = get1DBits(4);

                bitReached += 4;

                if (aa == 1) { // EOL must be padded: reset the fillBits flag.
                    fillBits = 1;
                    bitReached++;
                    return 1;
                }
            }
            if (next12Bits != 1) {
                throw new PdfException(("EOL error1"));
            }
        } else if (fillBits == 1) {

            final int bitsLeft = 8 - (bitReached & 7);

            final int rr = get1DBits(bitsLeft);

            bitReached += bitsLeft;

            if (rr != 0) {
                throw new PdfException(("EOL error2"));
            }

            if (bitsLeft < 4) {
                final int rr2 = get1DBits(8);

                bitReached += 8;

                if (rr2 != 0) {
                    throw new PdfException("EOL error3");
                }
            }

            int n = get1DBits(8);
            bitReached += 8;

            while (n != 1) {

                // If not all zeros
                if (n != 0) {
                    throw new PdfException("EOL error4");
                }

                n = get1DBits(8);
                bitReached += 8;
            }
        }

        final int r = get1DBits(1);

        bitReached += 1;
        return r;
    }
}





© 2015 - 2024 Weber Informatics LLC | Privacy Policy