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

org.jpedal.jbig2.image.JBIG2Bitmap Maven / Gradle / Ivy

/**
 * ===========================================
 * Java Pdf Extraction Decoding Access Library
 * ===========================================
 * 

* Project Info: http://www.idrsolutions.com * Help section for developers at http://www.idrsolutions.com/java-pdf-library-support/ *

* (C) Copyright 1997-2008, IDRsolutions and Contributors. * Main Developer: Simon Barnett *

* This file is part of JPedal *

* Copyright (c) 2008, IDRsolutions * All rights reserved. *

* Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the IDRsolutions nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. *

* THIS SOFTWARE IS PROVIDED BY IDRsolutions ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL IDRsolutions BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *

* Other JBIG2 image decoding implementations include * jbig2dec (http://jbig2dec.sourceforge.net/) * xpdf (http://www.foolabs.com/xpdf/) *

* The final draft JBIG2 specification can be found at http://www.jpeg.org/public/fcd14492.pdf *

* All three of the above resources were used in the writing of this software, with methodologies, * processes and inspiration taken from all three. *

* --------------- * JBIG2Bitmap.java * --------------- */ package org.jpedal.jbig2.image; import java.awt.image.BufferedImage; import java.awt.image.DataBuffer; import java.awt.image.DataBufferByte; import java.awt.image.Raster; import java.awt.image.WritableRaster; import java.io.IOException; import java.util.Arrays; import org.jpedal.jbig2.JBIG2Exception; import org.jpedal.jbig2.decoders.ArithmeticDecoder; import org.jpedal.jbig2.decoders.DecodeIntResult; import org.jpedal.jbig2.decoders.HuffmanDecoder; import org.jpedal.jbig2.decoders.JBIG2StreamDecoder; import org.jpedal.jbig2.decoders.MMRDecoder; import org.jpedal.jbig2.util.BinaryOperation; public final class JBIG2Bitmap { private int width, height, line; private int bitmapNumber; //private FastBitSet data; //@sam - little task to investigate // private BitSet data; private byte[] newData; // boolean useByteArray=false; //private static int counter = 0; private ArithmeticDecoder arithmeticDecoder; private HuffmanDecoder huffmanDecoder; private MMRDecoder mmrDecoder; public JBIG2Bitmap(int width, int height, ArithmeticDecoder arithmeticDecoder, HuffmanDecoder huffmanDecoder, MMRDecoder mmrDecoder) { this.width = width; this.height = height; this.arithmeticDecoder = arithmeticDecoder; this.huffmanDecoder = huffmanDecoder; this.mmrDecoder = mmrDecoder; this.line = (width + 7) >> 3; // if (useByteArray) this.newData = new byte[line * height]; // else // this.data = new BitSet(width * height); } public void readBitmap(boolean useMMR, int template, boolean typicalPredictionGenericDecodingOn, boolean useSkip, JBIG2Bitmap skipBitmap, short[] adaptiveTemplateX, short[] adaptiveTemplateY, int mmrDataLength) throws IOException, JBIG2Exception { if (useMMR) { //MMRDecoder mmrDecoder = MMRDecoder.getInstance(); mmrDecoder.reset(); int[] referenceLine = new int[width + 2]; int[] codingLine = new int[width + 2]; codingLine[0] = codingLine[1] = width; for (int row = 0; row < height; row++) { int i = 0; for (; codingLine[i] < width; i++) { referenceLine[i] = codingLine[i]; } referenceLine[i] = referenceLine[i + 1] = width; int referenceI = 0; int codingI = 0; int a0 = 0; do { int code1 = mmrDecoder.get2DCode(), code2, code3; switch (code1) { case MMRDecoder.twoDimensionalPass: if (referenceLine[referenceI] < width) { a0 = referenceLine[referenceI + 1]; referenceI += 2; } break; case MMRDecoder.twoDimensionalHorizontal: if ((codingI & 1) != 0) { code1 = 0; do { code1 += code3 = mmrDecoder.getBlackCode(); } while (code3 >= 64); code2 = 0; do { code2 += code3 = mmrDecoder.getWhiteCode(); } while (code3 >= 64); } else { code1 = 0; do { code1 += code3 = mmrDecoder.getWhiteCode(); } while (code3 >= 64); code2 = 0; do { code2 += code3 = mmrDecoder.getBlackCode(); } while (code3 >= 64); } if (code1 > 0 || code2 > 0) { a0 = codingLine[codingI++] = a0 + code1; a0 = codingLine[codingI++] = a0 + code2; while (referenceLine[referenceI] <= a0 && referenceLine[referenceI] < width) { referenceI += 2; } } break; case MMRDecoder.twoDimensionalVertical0: a0 = codingLine[codingI++] = referenceLine[referenceI]; if (referenceLine[referenceI] < width) { referenceI++; } break; case MMRDecoder.twoDimensionalVerticalR1: a0 = codingLine[codingI++] = referenceLine[referenceI] + 1; if (referenceLine[referenceI] < width) { referenceI++; while (referenceLine[referenceI] <= a0 && referenceLine[referenceI] < width) { referenceI += 2; } } break; case MMRDecoder.twoDimensionalVerticalR2: a0 = codingLine[codingI++] = referenceLine[referenceI] + 2; if (referenceLine[referenceI] < width) { referenceI++; while (referenceLine[referenceI] <= a0 && referenceLine[referenceI] < width) { referenceI += 2; } } break; case MMRDecoder.twoDimensionalVerticalR3: a0 = codingLine[codingI++] = referenceLine[referenceI] + 3; if (referenceLine[referenceI] < width) { referenceI++; while (referenceLine[referenceI] <= a0 && referenceLine[referenceI] < width) { referenceI += 2; } } break; case MMRDecoder.twoDimensionalVerticalL1: a0 = codingLine[codingI++] = referenceLine[referenceI] - 1; if (referenceI > 0) { referenceI--; } else { referenceI++; } while (referenceLine[referenceI] <= a0 && referenceLine[referenceI] < width) { referenceI += 2; } break; case MMRDecoder.twoDimensionalVerticalL2: a0 = codingLine[codingI++] = referenceLine[referenceI] - 2; if (referenceI > 0) { referenceI--; } else { referenceI++; } while (referenceLine[referenceI] <= a0 && referenceLine[referenceI] < width) { referenceI += 2; } break; case MMRDecoder.twoDimensionalVerticalL3: a0 = codingLine[codingI++] = referenceLine[referenceI] - 3; if (referenceI > 0) { referenceI--; } else { referenceI++; } while (referenceLine[referenceI] <= a0 && referenceLine[referenceI] < width) { referenceI += 2; } break; default: if (JBIG2StreamDecoder.debug) System.out.println("Illegal code in JBIG2 MMR bitmap data"); break; } } while (a0 < width); codingLine[codingI++] = width; for (int j = 0; codingLine[j] < width; j += 2) { for (int col = codingLine[j]; col < codingLine[j + 1]; col++) { setPixel(col, row, 1); } } } if (mmrDataLength >= 0) { mmrDecoder.skipTo(mmrDataLength); } else { if (mmrDecoder.get24Bits() != 0x001001) { if (JBIG2StreamDecoder.debug) System.out.println("Missing EOFB in JBIG2 MMR bitmap data"); } } } else { //ArithmeticDecoder arithmeticDecoder = ArithmeticDecoder.getInstance(); BitmapPointer cxPtr0 = new BitmapPointer(this), cxPtr1 = new BitmapPointer(this); BitmapPointer atPtr0 = new BitmapPointer(this), atPtr1 = new BitmapPointer(this), atPtr2 = new BitmapPointer(this), atPtr3 = new BitmapPointer(this); long ltpCX = 0; if (typicalPredictionGenericDecodingOn) { switch (template) { case 0: ltpCX = 0x3953; break; case 1: ltpCX = 0x079a; break; case 2: ltpCX = 0x0e3; break; case 3: ltpCX = 0x18a; break; } } boolean ltp = false; long cx, cx0, cx1, cx2; for (int row = 0; row < height; row++) { if (typicalPredictionGenericDecodingOn) { int bit = arithmeticDecoder.decodeBit(ltpCX, arithmeticDecoder.genericRegionStats); if (bit != 0) { ltp = !ltp; } if (ltp) { duplicateRow(row, row - 1); continue; } } int pixel; switch (template) { case 0: cxPtr0.setPointer(0, row - 2); cx0 = cxPtr0.nextPixel(); cx0 = (BinaryOperation.bit32Shift(cx0, 1, BinaryOperation.LEFT_SHIFT)) | cxPtr0.nextPixel(); cxPtr1.setPointer(0, row - 1); cx1 = cxPtr1.nextPixel(); cx1 = (BinaryOperation.bit32Shift(cx1, 1, BinaryOperation.LEFT_SHIFT)) | cxPtr1.nextPixel(); cx1 = (BinaryOperation.bit32Shift(cx1, 1, BinaryOperation.LEFT_SHIFT)) | cxPtr1.nextPixel(); cx2 = 0; atPtr0.setPointer(adaptiveTemplateX[0], row + adaptiveTemplateY[0]); atPtr1.setPointer(adaptiveTemplateX[1], row + adaptiveTemplateY[1]); atPtr2.setPointer(adaptiveTemplateX[2], row + adaptiveTemplateY[2]); atPtr3.setPointer(adaptiveTemplateX[3], row + adaptiveTemplateY[3]); for (int col = 0; col < width; col++) { cx = (BinaryOperation.bit32Shift(cx0, 13, BinaryOperation.LEFT_SHIFT)) | (BinaryOperation.bit32Shift(cx1, 8, BinaryOperation.LEFT_SHIFT)) | (BinaryOperation.bit32Shift(cx2, 4, BinaryOperation.LEFT_SHIFT)) | (atPtr0.nextPixel() << 3) | (atPtr1.nextPixel() << 2) | (atPtr2.nextPixel() << 1) | atPtr3.nextPixel(); if (useSkip && skipBitmap.getPixel(col, row) != 0) { pixel = 0; } else { pixel = arithmeticDecoder.decodeBit(cx, arithmeticDecoder.genericRegionStats); if (pixel != 0) { setPixel(col, row, 1); } } cx0 = ((BinaryOperation.bit32Shift(cx0, 1, BinaryOperation.LEFT_SHIFT)) | cxPtr0.nextPixel()) & 0x07; cx1 = ((BinaryOperation.bit32Shift(cx1, 1, BinaryOperation.LEFT_SHIFT)) | cxPtr1.nextPixel()) & 0x1f; cx2 = ((BinaryOperation.bit32Shift(cx2, 1, BinaryOperation.LEFT_SHIFT)) | pixel) & 0x0f; } break; case 1: cxPtr0.setPointer(0, row - 2); cx0 = cxPtr0.nextPixel(); cx0 = (BinaryOperation.bit32Shift(cx0, 1, BinaryOperation.LEFT_SHIFT)) | cxPtr0.nextPixel(); cx0 = (BinaryOperation.bit32Shift(cx0, 1, BinaryOperation.LEFT_SHIFT)) | cxPtr0.nextPixel(); cxPtr1.setPointer(0, row - 1); cx1 = cxPtr1.nextPixel(); cx1 = (BinaryOperation.bit32Shift(cx1, 1, BinaryOperation.LEFT_SHIFT)) | cxPtr1.nextPixel(); cx1 = (BinaryOperation.bit32Shift(cx1, 1, BinaryOperation.LEFT_SHIFT)) | cxPtr1.nextPixel(); cx2 = 0; atPtr0.setPointer(adaptiveTemplateX[0], row + adaptiveTemplateY[0]); for (int col = 0; col < width; col++) { cx = (BinaryOperation.bit32Shift(cx0, 9, BinaryOperation.LEFT_SHIFT)) | (BinaryOperation.bit32Shift(cx1, 4, BinaryOperation.LEFT_SHIFT)) | (BinaryOperation.bit32Shift(cx2, 1, BinaryOperation.LEFT_SHIFT)) | atPtr0.nextPixel(); if (useSkip && skipBitmap.getPixel(col, row) != 0) { pixel = 0; } else { pixel = arithmeticDecoder.decodeBit(cx, arithmeticDecoder.genericRegionStats); if (pixel != 0) { setPixel(col, row, 1); } } cx0 = ((BinaryOperation.bit32Shift(cx0, 1, BinaryOperation.LEFT_SHIFT)) | cxPtr0.nextPixel()) & 0x0f; cx1 = ((BinaryOperation.bit32Shift(cx1, 1, BinaryOperation.LEFT_SHIFT)) | cxPtr1.nextPixel()) & 0x1f; cx2 = ((BinaryOperation.bit32Shift(cx2, 1, BinaryOperation.LEFT_SHIFT)) | pixel) & 0x07; } break; case 2: cxPtr0.setPointer(0, row - 2); cx0 = cxPtr0.nextPixel(); cx0 = (BinaryOperation.bit32Shift(cx0, 1, BinaryOperation.LEFT_SHIFT)) | cxPtr0.nextPixel(); cxPtr1.setPointer(0, row - 1); cx1 = cxPtr1.nextPixel(); cx1 = (BinaryOperation.bit32Shift(cx1, 1, BinaryOperation.LEFT_SHIFT)) | cxPtr1.nextPixel(); cx2 = 0; atPtr0.setPointer(adaptiveTemplateX[0], row + adaptiveTemplateY[0]); for (int col = 0; col < width; col++) { cx = (BinaryOperation.bit32Shift(cx0, 7, BinaryOperation.LEFT_SHIFT)) | (BinaryOperation.bit32Shift(cx1, 3, BinaryOperation.LEFT_SHIFT)) | (BinaryOperation.bit32Shift(cx2, 1, BinaryOperation.LEFT_SHIFT)) | atPtr0.nextPixel(); if (useSkip && skipBitmap.getPixel(col, row) != 0) { pixel = 0; } else { pixel = arithmeticDecoder.decodeBit(cx, arithmeticDecoder.genericRegionStats); if (pixel != 0) { setPixel(col, row, 1); } } cx0 = ((BinaryOperation.bit32Shift(cx0, 1, BinaryOperation.LEFT_SHIFT)) | cxPtr0.nextPixel()) & 0x07; cx1 = ((BinaryOperation.bit32Shift(cx1, 1, BinaryOperation.LEFT_SHIFT)) | cxPtr1.nextPixel()) & 0x0f; cx2 = ((BinaryOperation.bit32Shift(cx2, 1, BinaryOperation.LEFT_SHIFT)) | pixel) & 0x03; } break; case 3: cxPtr1.setPointer(0, row - 1); cx1 = cxPtr1.nextPixel(); cx1 = (BinaryOperation.bit32Shift(cx1, 1, BinaryOperation.LEFT_SHIFT)) | cxPtr1.nextPixel(); cx2 = 0; atPtr0.setPointer(adaptiveTemplateX[0], row + adaptiveTemplateY[0]); for (int col = 0; col < width; col++) { cx = (BinaryOperation.bit32Shift(cx1, 5, BinaryOperation.LEFT_SHIFT)) | (BinaryOperation.bit32Shift(cx2, 1, BinaryOperation.LEFT_SHIFT)) | atPtr0.nextPixel(); if (useSkip && skipBitmap.getPixel(col, row) != 0) { pixel = 0; } else { pixel = arithmeticDecoder.decodeBit(cx, arithmeticDecoder.genericRegionStats); if (pixel != 0) { setPixel(col, row, 1); } } cx1 = ((BinaryOperation.bit32Shift(cx1, 1, BinaryOperation.LEFT_SHIFT)) | cxPtr1.nextPixel()) & 0x1f; cx2 = ((BinaryOperation.bit32Shift(cx2, 1, BinaryOperation.LEFT_SHIFT)) | pixel) & 0x0f; } break; } } } } public void readGenericRefinementRegion(int template, boolean typicalPredictionGenericRefinementOn, JBIG2Bitmap referredToBitmap, int referenceDX, int referenceDY, short[] adaptiveTemplateX, short[] adaptiveTemplateY) throws IOException, JBIG2Exception { //ArithmeticDecoder arithmeticDecoder = ArithmeticDecoder.getInstance(); BitmapPointer cxPtr0, cxPtr1, cxPtr2, cxPtr3, cxPtr4, cxPtr5, cxPtr6, typicalPredictionGenericRefinementCXPtr0, typicalPredictionGenericRefinementCXPtr1, typicalPredictionGenericRefinementCXPtr2; long ltpCX; if (template != 0) { ltpCX = 0x008; cxPtr0 = new BitmapPointer(this); cxPtr1 = new BitmapPointer(this); cxPtr2 = new BitmapPointer(referredToBitmap); cxPtr3 = new BitmapPointer(referredToBitmap); cxPtr4 = new BitmapPointer(referredToBitmap); cxPtr5 = new BitmapPointer(this); cxPtr6 = new BitmapPointer(this); typicalPredictionGenericRefinementCXPtr0 = new BitmapPointer(referredToBitmap); typicalPredictionGenericRefinementCXPtr1 = new BitmapPointer(referredToBitmap); typicalPredictionGenericRefinementCXPtr2 = new BitmapPointer(referredToBitmap); } else { ltpCX = 0x0010; cxPtr0 = new BitmapPointer(this); cxPtr1 = new BitmapPointer(this); cxPtr2 = new BitmapPointer(referredToBitmap); cxPtr3 = new BitmapPointer(referredToBitmap); cxPtr4 = new BitmapPointer(referredToBitmap); cxPtr5 = new BitmapPointer(this); cxPtr6 = new BitmapPointer(referredToBitmap); typicalPredictionGenericRefinementCXPtr0 = new BitmapPointer(referredToBitmap); typicalPredictionGenericRefinementCXPtr1 = new BitmapPointer(referredToBitmap); typicalPredictionGenericRefinementCXPtr2 = new BitmapPointer(referredToBitmap); } long cx, cx0, cx2, cx3, cx4; long typicalPredictionGenericRefinementCX0, typicalPredictionGenericRefinementCX1, typicalPredictionGenericRefinementCX2; boolean ltp = false; for (int row = 0; row < height; row++) { if (template != 0) { cxPtr0.setPointer(0, row - 1); cx0 = cxPtr0.nextPixel(); cxPtr1.setPointer(-1, row); cxPtr2.setPointer(-referenceDX, row - 1 - referenceDY); cxPtr3.setPointer(-1 - referenceDX, row - referenceDY); cx3 = cxPtr3.nextPixel(); cx3 = (BinaryOperation.bit32Shift(cx3, 1, BinaryOperation.LEFT_SHIFT)) | cxPtr3.nextPixel(); cxPtr4.setPointer(-referenceDX, row + 1 - referenceDY); cx4 = cxPtr4.nextPixel(); typicalPredictionGenericRefinementCX0 = typicalPredictionGenericRefinementCX1 = typicalPredictionGenericRefinementCX2 = 0; if (typicalPredictionGenericRefinementOn) { typicalPredictionGenericRefinementCXPtr0.setPointer(-1 - referenceDX, row - 1 - referenceDY); typicalPredictionGenericRefinementCX0 = typicalPredictionGenericRefinementCXPtr0.nextPixel(); typicalPredictionGenericRefinementCX0 = (BinaryOperation.bit32Shift(typicalPredictionGenericRefinementCX0, 1, BinaryOperation.LEFT_SHIFT)) | typicalPredictionGenericRefinementCXPtr0.nextPixel(); typicalPredictionGenericRefinementCX0 = (BinaryOperation.bit32Shift(typicalPredictionGenericRefinementCX0, 1, BinaryOperation.LEFT_SHIFT)) | typicalPredictionGenericRefinementCXPtr0.nextPixel(); typicalPredictionGenericRefinementCXPtr1.setPointer(-1 - referenceDX, row - referenceDY); typicalPredictionGenericRefinementCX1 = typicalPredictionGenericRefinementCXPtr1.nextPixel(); typicalPredictionGenericRefinementCX1 = (BinaryOperation.bit32Shift(typicalPredictionGenericRefinementCX1, 1, BinaryOperation.LEFT_SHIFT)) | typicalPredictionGenericRefinementCXPtr1.nextPixel(); typicalPredictionGenericRefinementCX1 = (BinaryOperation.bit32Shift(typicalPredictionGenericRefinementCX1, 1, BinaryOperation.LEFT_SHIFT)) | typicalPredictionGenericRefinementCXPtr1.nextPixel(); typicalPredictionGenericRefinementCXPtr2.setPointer(-1 - referenceDX, row + 1 - referenceDY); typicalPredictionGenericRefinementCX2 = typicalPredictionGenericRefinementCXPtr2.nextPixel(); typicalPredictionGenericRefinementCX2 = (BinaryOperation.bit32Shift(typicalPredictionGenericRefinementCX2, 1, BinaryOperation.LEFT_SHIFT)) | typicalPredictionGenericRefinementCXPtr2.nextPixel(); typicalPredictionGenericRefinementCX2 = (BinaryOperation.bit32Shift(typicalPredictionGenericRefinementCX2, 1, BinaryOperation.LEFT_SHIFT)) | typicalPredictionGenericRefinementCXPtr2.nextPixel(); } for (int col = 0; col < width; col++) { cx0 = ((BinaryOperation.bit32Shift(cx0, 1, BinaryOperation.LEFT_SHIFT)) | cxPtr0.nextPixel()) & 7; cx3 = ((BinaryOperation.bit32Shift(cx3, 1, BinaryOperation.LEFT_SHIFT)) | cxPtr3.nextPixel()) & 7; cx4 = ((BinaryOperation.bit32Shift(cx4, 1, BinaryOperation.LEFT_SHIFT)) | cxPtr4.nextPixel()) & 3; if (typicalPredictionGenericRefinementOn) { typicalPredictionGenericRefinementCX0 = ((BinaryOperation.bit32Shift(typicalPredictionGenericRefinementCX0, 1, BinaryOperation.LEFT_SHIFT)) | typicalPredictionGenericRefinementCXPtr0.nextPixel()) & 7; typicalPredictionGenericRefinementCX1 = ((BinaryOperation.bit32Shift(typicalPredictionGenericRefinementCX1, 1, BinaryOperation.LEFT_SHIFT)) | typicalPredictionGenericRefinementCXPtr1.nextPixel()) & 7; typicalPredictionGenericRefinementCX2 = ((BinaryOperation.bit32Shift(typicalPredictionGenericRefinementCX2, 1, BinaryOperation.LEFT_SHIFT)) | typicalPredictionGenericRefinementCXPtr2.nextPixel()) & 7; int decodeBit = arithmeticDecoder.decodeBit(ltpCX, arithmeticDecoder.refinementRegionStats); if (decodeBit != 0) { ltp = !ltp; } if (typicalPredictionGenericRefinementCX0 == 0 && typicalPredictionGenericRefinementCX1 == 0 && typicalPredictionGenericRefinementCX2 == 0) { setPixel(col, row, 0); continue; } else if (typicalPredictionGenericRefinementCX0 == 7 && typicalPredictionGenericRefinementCX1 == 7 && typicalPredictionGenericRefinementCX2 == 7) { setPixel(col, row, 1); continue; } } cx = (BinaryOperation.bit32Shift(cx0, 7, BinaryOperation.LEFT_SHIFT)) | (cxPtr1.nextPixel() << 6) | (cxPtr2.nextPixel() << 5) | (BinaryOperation.bit32Shift(cx3, 2, BinaryOperation.LEFT_SHIFT)) | cx4; int pixel = arithmeticDecoder.decodeBit(cx, arithmeticDecoder.refinementRegionStats); if (pixel == 1) { setPixel(col, row, 1); } } } else { cxPtr0.setPointer(0, row - 1); cx0 = cxPtr0.nextPixel(); cxPtr1.setPointer(-1, row); cxPtr2.setPointer(-referenceDX, row - 1 - referenceDY); cx2 = cxPtr2.nextPixel(); cxPtr3.setPointer(-1 - referenceDX, row - referenceDY); cx3 = cxPtr3.nextPixel(); cx3 = (BinaryOperation.bit32Shift(cx3, 1, BinaryOperation.LEFT_SHIFT)) | cxPtr3.nextPixel(); cxPtr4.setPointer(-1 - referenceDX, row + 1 - referenceDY); cx4 = cxPtr4.nextPixel(); cx4 = (BinaryOperation.bit32Shift(cx4, 1, BinaryOperation.LEFT_SHIFT)) | cxPtr4.nextPixel(); cxPtr5.setPointer(adaptiveTemplateX[0], row + adaptiveTemplateY[0]); cxPtr6.setPointer(adaptiveTemplateX[1] - referenceDX, row + adaptiveTemplateY[1] - referenceDY); typicalPredictionGenericRefinementCX0 = typicalPredictionGenericRefinementCX1 = typicalPredictionGenericRefinementCX2 = 0; if (typicalPredictionGenericRefinementOn) { typicalPredictionGenericRefinementCXPtr0.setPointer(-1 - referenceDX, row - 1 - referenceDY); typicalPredictionGenericRefinementCX0 = typicalPredictionGenericRefinementCXPtr0.nextPixel(); typicalPredictionGenericRefinementCX0 = (BinaryOperation.bit32Shift(typicalPredictionGenericRefinementCX0, 1, BinaryOperation.LEFT_SHIFT)) | typicalPredictionGenericRefinementCXPtr0.nextPixel(); typicalPredictionGenericRefinementCX0 = (BinaryOperation.bit32Shift(typicalPredictionGenericRefinementCX0, 1, BinaryOperation.LEFT_SHIFT)) | typicalPredictionGenericRefinementCXPtr0.nextPixel(); typicalPredictionGenericRefinementCXPtr1.setPointer(-1 - referenceDX, row - referenceDY); typicalPredictionGenericRefinementCX1 = typicalPredictionGenericRefinementCXPtr1.nextPixel(); typicalPredictionGenericRefinementCX1 = (BinaryOperation.bit32Shift(typicalPredictionGenericRefinementCX1, 1, BinaryOperation.LEFT_SHIFT)) | typicalPredictionGenericRefinementCXPtr1.nextPixel(); typicalPredictionGenericRefinementCX1 = (BinaryOperation.bit32Shift(typicalPredictionGenericRefinementCX1, 1, BinaryOperation.LEFT_SHIFT)) | typicalPredictionGenericRefinementCXPtr1.nextPixel(); typicalPredictionGenericRefinementCXPtr2.setPointer(-1 - referenceDX, row + 1 - referenceDY); typicalPredictionGenericRefinementCX2 = typicalPredictionGenericRefinementCXPtr2.nextPixel(); typicalPredictionGenericRefinementCX2 = (BinaryOperation.bit32Shift(typicalPredictionGenericRefinementCX2, 1, BinaryOperation.LEFT_SHIFT)) | typicalPredictionGenericRefinementCXPtr2.nextPixel(); typicalPredictionGenericRefinementCX2 = (BinaryOperation.bit32Shift(typicalPredictionGenericRefinementCX2, 1, BinaryOperation.LEFT_SHIFT)) | typicalPredictionGenericRefinementCXPtr2.nextPixel(); } for (int col = 0; col < width; col++) { cx0 = ((BinaryOperation.bit32Shift(cx0, 1, BinaryOperation.LEFT_SHIFT)) | cxPtr0.nextPixel()) & 3; cx2 = ((BinaryOperation.bit32Shift(cx2, 1, BinaryOperation.LEFT_SHIFT)) | cxPtr2.nextPixel()) & 3; cx3 = ((BinaryOperation.bit32Shift(cx3, 1, BinaryOperation.LEFT_SHIFT)) | cxPtr3.nextPixel()) & 7; cx4 = ((BinaryOperation.bit32Shift(cx4, 1, BinaryOperation.LEFT_SHIFT)) | cxPtr4.nextPixel()) & 7; if (typicalPredictionGenericRefinementOn) { typicalPredictionGenericRefinementCX0 = ((BinaryOperation.bit32Shift(typicalPredictionGenericRefinementCX0, 1, BinaryOperation.LEFT_SHIFT)) | typicalPredictionGenericRefinementCXPtr0.nextPixel()) & 7; typicalPredictionGenericRefinementCX1 = ((BinaryOperation.bit32Shift(typicalPredictionGenericRefinementCX1, 1, BinaryOperation.LEFT_SHIFT)) | typicalPredictionGenericRefinementCXPtr1.nextPixel()) & 7; typicalPredictionGenericRefinementCX2 = ((BinaryOperation.bit32Shift(typicalPredictionGenericRefinementCX2, 1, BinaryOperation.LEFT_SHIFT)) | typicalPredictionGenericRefinementCXPtr2.nextPixel()) & 7; int decodeBit = arithmeticDecoder.decodeBit(ltpCX, arithmeticDecoder.refinementRegionStats); if (decodeBit == 1) { ltp = !ltp; } if (typicalPredictionGenericRefinementCX0 == 0 && typicalPredictionGenericRefinementCX1 == 0 && typicalPredictionGenericRefinementCX2 == 0) { setPixel(col, row, 0); continue; } else if (typicalPredictionGenericRefinementCX0 == 7 && typicalPredictionGenericRefinementCX1 == 7 && typicalPredictionGenericRefinementCX2 == 7) { setPixel(col, row, 1); continue; } } cx = (BinaryOperation.bit32Shift(cx0, 11, BinaryOperation.LEFT_SHIFT)) | (cxPtr1.nextPixel() << 10) | (BinaryOperation.bit32Shift(cx2, 8, BinaryOperation.LEFT_SHIFT)) | (BinaryOperation.bit32Shift(cx3, 5, BinaryOperation.LEFT_SHIFT)) | (BinaryOperation.bit32Shift(cx4, 2, BinaryOperation.LEFT_SHIFT)) | (cxPtr5.nextPixel() << 1) | cxPtr6.nextPixel(); int pixel = arithmeticDecoder.decodeBit(cx, arithmeticDecoder.refinementRegionStats); if (pixel == 1) { setPixel(col, row, 1); } } } } } public void readTextRegion(boolean huffman, boolean symbolRefine, int noOfSymbolInstances, int logStrips, int noOfSymbols, int[][] symbolCodeTable, int symbolCodeLength, JBIG2Bitmap[] symbols, int defaultPixel, int combinationOperator, boolean transposed, int referenceCorner, int sOffset, int[][] huffmanFSTable, int[][] huffmanDSTable, int[][] huffmanDTTable, int[][] huffmanRDWTable, int[][] huffmanRDHTable, int[][] huffmanRDXTable, int[][] huffmanRDYTable, int[][] huffmanRSizeTable, int template, short[] symbolRegionAdaptiveTemplateX, short[] symbolRegionAdaptiveTemplateY, JBIG2StreamDecoder decoder) throws JBIG2Exception, IOException { JBIG2Bitmap symbolBitmap; int strips = 1 << logStrips; clear(defaultPixel); //HuffmanDecoder huffDecoder = HuffmanDecoder.getInstance(); //ArithmeticDecoder arithmeticDecoder = ArithmeticDecoder.getInstance(); int t; if (huffman) { t = huffmanDecoder.decodeInt(huffmanDTTable).intResult(); } else { t = arithmeticDecoder.decodeInt(arithmeticDecoder.iadtStats).intResult(); } t *= -strips; int currentInstance = 0; int firstS = 0; int dt, tt, ds, s; while (currentInstance < noOfSymbolInstances) { if (huffman) { dt = huffmanDecoder.decodeInt(huffmanDTTable).intResult(); } else { dt = arithmeticDecoder.decodeInt(arithmeticDecoder.iadtStats).intResult(); } t += dt * strips; if (huffman) { ds = huffmanDecoder.decodeInt(huffmanFSTable).intResult(); } else { ds = arithmeticDecoder.decodeInt(arithmeticDecoder.iafsStats).intResult(); } firstS += ds; s = firstS; while (true) { if (strips == 1) { dt = 0; } else if (huffman) { dt = decoder.readBits(logStrips); } else { dt = arithmeticDecoder.decodeInt(arithmeticDecoder.iaitStats).intResult(); } tt = t + dt; long symbolID; if (huffman) { if (symbolCodeTable != null) { symbolID = huffmanDecoder.decodeInt(symbolCodeTable).intResult(); } else { symbolID = decoder.readBits(symbolCodeLength); } } else { symbolID = arithmeticDecoder.decodeIAID(symbolCodeLength, arithmeticDecoder.iaidStats); } if (symbolID >= noOfSymbols) { if (JBIG2StreamDecoder.debug) System.out.println("Invalid symbol number in JBIG2 text region"); } else { symbolBitmap = null; int ri; if (symbolRefine) { if (huffman) { ri = decoder.readBit(); } else { ri = arithmeticDecoder.decodeInt(arithmeticDecoder.iariStats).intResult(); } } else { ri = 0; } if (ri != 0) { int refinementDeltaWidth, refinementDeltaHeight, refinementDeltaX, refinementDeltaY; if (huffman) { refinementDeltaWidth = huffmanDecoder.decodeInt(huffmanRDWTable).intResult(); refinementDeltaHeight = huffmanDecoder.decodeInt(huffmanRDHTable).intResult(); refinementDeltaX = huffmanDecoder.decodeInt(huffmanRDXTable).intResult(); refinementDeltaY = huffmanDecoder.decodeInt(huffmanRDYTable).intResult(); decoder.consumeRemainingBits(); arithmeticDecoder.start(); } else { refinementDeltaWidth = arithmeticDecoder.decodeInt(arithmeticDecoder.iardwStats).intResult(); refinementDeltaHeight = arithmeticDecoder.decodeInt(arithmeticDecoder.iardhStats).intResult(); refinementDeltaX = arithmeticDecoder.decodeInt(arithmeticDecoder.iardxStats).intResult(); refinementDeltaY = arithmeticDecoder.decodeInt(arithmeticDecoder.iardyStats).intResult(); } refinementDeltaX = ((refinementDeltaWidth >= 0) ? refinementDeltaWidth : refinementDeltaWidth - 1) / 2 + refinementDeltaX; refinementDeltaY = ((refinementDeltaHeight >= 0) ? refinementDeltaHeight : refinementDeltaHeight - 1) / 2 + refinementDeltaY; symbolBitmap = new JBIG2Bitmap(refinementDeltaWidth + symbols[(int) symbolID].width, refinementDeltaHeight + symbols[(int) symbolID].height, arithmeticDecoder, huffmanDecoder, mmrDecoder); symbolBitmap.readGenericRefinementRegion(template, false, symbols[(int) symbolID], refinementDeltaX, refinementDeltaY, symbolRegionAdaptiveTemplateX, symbolRegionAdaptiveTemplateY); } else { symbolBitmap = symbols[(int) symbolID]; } int bitmapWidth = symbolBitmap.width - 1; int bitmapHeight = symbolBitmap.height - 1; if (transposed) { switch (referenceCorner) { case 0: // bottom left combine(symbolBitmap, tt, s, combinationOperator); break; case 1: // top left combine(symbolBitmap, tt, s, combinationOperator); break; case 2: // bottom right combine(symbolBitmap, (tt - bitmapWidth), s, combinationOperator); break; case 3: // top right combine(symbolBitmap, (tt - bitmapWidth), s, combinationOperator); break; } s += bitmapHeight; } else { switch (referenceCorner) { case 0: // bottom left combine(symbolBitmap, s, (tt - bitmapHeight), combinationOperator); break; case 1: // top left combine(symbolBitmap, s, tt, combinationOperator); break; case 2: // bottom right combine(symbolBitmap, s, (tt - bitmapHeight), combinationOperator); break; case 3: // top right combine(symbolBitmap, s, tt, combinationOperator); break; } s += bitmapWidth; } } currentInstance++; DecodeIntResult decodeIntResult; if (huffman) { decodeIntResult = huffmanDecoder.decodeInt(huffmanDSTable); } else { decodeIntResult = arithmeticDecoder.decodeInt(arithmeticDecoder.iadsStats); } if (!decodeIntResult.booleanResult()) { break; } ds = decodeIntResult.intResult(); s += sOffset + ds; } } } public void clear(int defPixel) { // if (useByteArray) { newData = new byte[newData.length]; byte value = defPixel == 0 ? (byte) 0 : (byte) -128; for (int i = 0; i < newData.length; i++) { newData[i] = value; } // } else { // data.set(0, data.size(), defPixel == 1); // } } public void combine(JBIG2Bitmap bitmap, int x, int y, long combOp) { int srcWidth = bitmap.width; int srcHeight = bitmap.height; int srcRow = 0, srcCol = 0; // int maxRow = y + srcHeight; // int maxCol = x + srcWidth; // // for (int row = y; row < maxRow; row++) { // for (int col = x; col < maxCol; srcCol += 8, col += 8) { // // byte srcPixelByte = bitmap.getPixelByte(srcCol, srcRow); // byte dstPixelByte = getPixelByte(col, row); // byte endPixelByte; // // switch ((int) combOp) { // case 0: // or // endPixelByte = (byte) (dstPixelByte | srcPixelByte); // break; // case 1: // and // endPixelByte = (byte) (dstPixelByte & srcPixelByte); // break; // case 2: // xor // endPixelByte = (byte) (dstPixelByte ^ srcPixelByte); // break; // case 3: // xnor // endPixelByte = (byte) ~(dstPixelByte ^ srcPixelByte); // break; // case 4: // replace // default: // endPixelByte = srcPixelByte; // break; // } // int used = maxCol - col; // if (used < 8) { // // mask bits // endPixelByte = (byte) ((endPixelByte & (0xFF >> (8 - used))) | (dstPixelByte & (0xFF << (used)))); // } // setPixelByte(col, row, endPixelByte); // } // // srcCol = 0; // srcRow++; for (int row = y; row < y + srcHeight; row++) { for (int col = x; col < x + srcWidth; col++) { int srcPixel = bitmap.getPixel(srcCol, srcRow); switch ((int) combOp) { case 0: // or setPixel(col, row, getPixel(col, row, line, newData) | srcPixel); break; case 1: // and setPixel(col, row, getPixel(col, row, line, newData) & srcPixel); break; case 2: // xor setPixel(col, row, getPixel(col, row, line, newData) ^ srcPixel); break; case 3: // xnor if ((getPixel(col, row, line, newData) == 1 && srcPixel == 1) || (getPixel(col, row, line, newData) == 0 && srcPixel == 0)) setPixel(col, row, 1); else setPixel(col, row, 0); break; case 4: // replace setPixel(col, row, srcPixel); break; } srcCol++; } srcCol = 0; srcRow++; } } /** * set a full byte of pixels */ // private void setPixelByte(int col, int row, byte bits) { //data.setByte(row, col, bits); // } /** * get a byte of pixels */ // public byte getPixelByte(int col, int row) { //return data.getByte(row, col); // } private void duplicateRow(int yDest, int ySrc) { // for (int i = 0; i < width;) { // setPixelByte(i, yDest, getPixelByte(i, ySrc)); // i += 8; // } for (int i = 0; i < width; i++) { setPixel(i, yDest, getPixel(i, ySrc, line, newData)); } } public int getWidth() { return width; } public int getHeight() { return height; } public byte[] getData(boolean switchPixelColor) { // byte[] bytes = new byte[height * line]; // // for (int i = 0; i < height; i++) { // System.arraycopy(data.bytes[i], 0, bytes, line * i, line); // } // // for (int i = 0; i < bytes.length; i++) { // // reverse bits // // int value = bytes[i]; // value = (value & 0x0f) << 4 | (value & 0xf0) >> 4; // value = (value & 0x33) << 2 | (value & 0xcc) >> 2; // value = (value & 0x55) << 1 | (value & 0xaa) >> 1; // // if (switchPixelColor) { // value ^= 0xff; // } // // bytes[i] = (byte) (value & 0xFF); // } // // return bytes; byte[] bytes; // if (useByteArray) { bytes = newData; // } else { // bytes = new byte[height * line]; // // int count = 0, offset = 0; // for (int row = 0; row < height; row++) { // for (int col = 0; col < width; col++) { // if (data.get(count)) { // int bite = (count + offset) / 8; // int bit = (count + offset) % 8; // // bytes[bite] |= 1 << (7 - bit); // } // count++; // } // // offset = (line * 8 * (row + 1)) - count; // } // } if (switchPixelColor) { for (int i = 0; i < bytes.length; i++) { bytes[i] ^= 0xff; } } return bytes; } public JBIG2Bitmap getSlice(int x, int y, int width, int height) { // JBIG2Bitmap slice = new JBIG2Bitmap(width, height); // // int sliceRow = 0, sliceCol = 0; // int maxCol = x + width; // // //ShowGUIMessage.showGUIMessage("x", this.getBufferedImage(), "xx"); // // System.out.println(">>> getSlice x = "+x+" y = "+y+ " width = "+width+ " height = "+height); // System.out.println(">>> baseImage width = "+this.width+ " height = "+this.height); // // System.out.println("counter = "+counter); // if(counter == 17){ // System.out.println(); // //ShowGUIMessage.showGUIMessage("x", this.getBufferedImage(), "xx"); // } // // ShowGUIMessage.showGUIMessage("x", this.getBufferedImage(), "xx"); // // for (int row = y; row < height; row++) { // for (int col = x; col < maxCol; col += 8, sliceCol += 8) { // slice.setPixelByte(sliceCol, sliceRow, getPixelByte(col, row)); // //if(counter > 10) // //ShowGUIMessage.showGUIMessage("new", slice.getBufferedImage(), "new"); // } // sliceCol = 0; // sliceRow++; // } // counter++; // // ShowGUIMessage.showGUIMessage("new", slice.getBufferedImage(), "new"); // // return slice; JBIG2Bitmap slice = new JBIG2Bitmap(width, height, arithmeticDecoder, huffmanDecoder, mmrDecoder); int sliceRow = 0, sliceCol = 0; for (int row = y; row < height; row++) { for (int col = x; col < x + width; col++) { //System.out.println("row = "+row +" column = "+col); slice.setPixel(sliceCol, sliceRow, getPixel(col, row, line, newData)); sliceCol++; } sliceCol = 0; sliceRow++; } return slice; } /** private static void setPixel(int col, int row, FastBitSet data, int value) { if (value == 1) data.set(row, col); else data.clear(row, col); }/**/ // private void setPixelByte(int col, int row, FastBitSet data, byte bits) { // data.setByte(row, col, bits); // } // public void setPixel(int col, int row, int value) { // setPixel(col, row, data, value); // } // public int getPixel(int col, int row) { // return data.get(row, col) ? 1 : 0; // } // private void setPixel(int col, int row, BitSet data, int value) { // int index = (row * width) + col; // // data.set(index, value == 1); // } private void newSetPixel(int col, int row, byte[] data, int value) { int index = (row * line) + (col / 8); int b = data[index]; if (value == 0) b = b & ~(1 << 7 - (col % 8)); else b = b | (1 << 7 - (col % 8)); data[index] = (byte) b; } public void setPixel(int col, int row, int value) { // if (useByteArray) newSetPixel(col, row, newData, value); // else // setPixel(col, row, data, value); } private static int getPixel(int col, int row, int line, byte[] data) { return (data[(row * line) + (col / 8)] & 1 << 7 - (col % 8)) != 0 ? 1 : 0; } public int getPixel(int col, int row) { // if (useByteArray) // return getPixel(col,row,line,newData); return (newData[(row * line) + (col / 8)] & 1 << 7 - (col % 8)) != 0 ? 1 : 0; // else // return data.get((row * width) + col) ? 1 : 0; } public void expand(int newHeight, int defaultPixel) { // System.out.println("expand FastBitSet"); // FastBitSet newData = new FastBitSet(width, newHeight); // // for (int row = 0; row < height; row++) { // for (int col = 0; col < width; col += 8) { // setPixelByte(col, row, newData, getPixelByte(col, row)); // } // } // // this.height = newHeight; // this.data = newData; // if (useByteArray) { byte[] newNewData = new byte[newHeight * line]; System.arraycopy(newData, 0, newNewData, 0, height * line); this.height = newHeight; this.newData = newNewData; // } else { // // BitSet newData = new BitSet(newHeight * width); // // for (int row = 0; row < height; row++) { // for (int col = 0; col < width; col++) { // setPixel(col, row, newData, getPixel(col, row)); // } // } // // this.height = newHeight; // this.data = newData; // } } public void setBitmapNumber(int segmentNumber) { this.bitmapNumber = segmentNumber; } public int getBitmapNumber() { return bitmapNumber; } public BufferedImage getBufferedImage() { byte[] bytes = getData(true); if (bytes == null) return null; // make a a DEEP copy so we can't alter int len = bytes.length; byte[] copy = new byte[len]; System.arraycopy(bytes, 0, copy, 0, len); BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_BINARY); /** create an image from the raw data */ DataBuffer db = new DataBufferByte(copy, copy.length); WritableRaster raster = Raster.createPackedRaster(db, width, height, 1, null); image.setData(raster); return image; } static final class FastBitSet { byte[][] bytes; int w, h; public FastBitSet(int width, int height) { bytes = new byte[height][(width + 7) / 8]; this.w = width; this.h = height; //System.out.println("width = "+width+" height = "+height); } // public int getByte(int row, int col) { // // System.out.println("(width + 7) / 8 = " + (width + 7) / 8); // System.out.println("external width = " + width + " external height = " + height); // System.out.println("internal width = " + w + " internal height = " + h); // System.out.println("row = " + row + " column = " + col); // // int offset = col / 8; // int mod = col % 8; // // System.out.println("offset = " + offset + " mod = " + mod+" bytes[row].length = "+bytes[row].length); // // if (mod == 0) // return bytes[row][offset]; // // if(offset == bytes[row].length - 1){ // System.out.println("returning"); // return ((bytes[row][offset] & 0xFF) >> mod); // } // // int left = ((bytes[row][offset] & 0xFF) >> mod); // int right = ((bytes[row][offset + 1] & 0xFF) << (8 - mod)); // // return left | right; // } // public void setByte(int row, int col, int bits) { // int offset = col / 8; // int mod = col % 8; // // System.out.println("setByte offset = " + offset + " mod = " + mod); // // // if (mod == 0) // bytes[row][offset] = (byte) bits; // else { // int mask = 0xFF >> (8 - mod); // System.out.println("setByte mask = " + mask); // bytes[row][offset] = (byte) ((bytes[row][offset] & mask) | ((bits & 0xFF) << mod)); // bytes[row][offset + 1] = (byte) ((bytes[row][offset + 1] & ~mask) | ((bits & 0xFF) >> (8 - mod))); // } // } public byte getByte(int row, int col) { // System.out.println("(width + 7) / 8 = " + (width + 7) / 8); // System.out.println("external width = " + width + " external height = " + height); // System.out.println("internal width = " + w + " internal height = " + h); // System.out.println("row = " + row + " column = " + col); int offset = col / 8; int mod = col % 8; // System.out.println("offset = " + offset + " mod = " + mod+" bytes[row].length = "+bytes[row].length); if (mod == 0) return bytes[row][offset]; // if(offset == bytes[row].length - 1){ // System.out.println("returning"); // return ((bytes[row][offset] & 0xFF) >> mod); // } byte leftMask = (byte) (0xFF >> (8 - mod)); byte rightMask = (byte) (0xFF << mod); byte left = (byte) ((bytes[row][offset] & leftMask) << (8 - mod)); if (offset + 1 >= bytes[row].length) { System.out.println("returning"); return left; } byte right = (byte) ((bytes[row][offset + 1] & rightMask) >> mod); return (byte) (left | right); } public void setByte(int row, int col, byte bits) { int offset = col / 8; int mod = col % 8; //System.out.println("setByte offset = " + offset + " mod = " + mod); if (mod == 0) bytes[row][offset] = (byte) bits; else { byte left = (byte) (bits >> mod); byte leftMask = (byte) (0xFF << (8 - mod)); bytes[row][offset] &= leftMask; bytes[row][offset] |= left; if (offset + 1 >= bytes[row].length) return; byte right = (byte) (bits << (8 - mod)); byte rightMask = (byte) (0xFF >> mod); bytes[row][offset + 1] &= rightMask; bytes[row][offset + 1] |= right; // int mask = 0xFF >> (8 - mod); // System.out.println("setByte mask = " + mask); // bytes[row][offset] = (byte) ((bytes[row][offset] & mask) | ((bits & 0xFF) << mod)); // bytes[row][offset + 1] = (byte) ((bytes[row][offset + 1] & ~mask) | ((bits & 0xFF) >> (8 - mod))); } } public void set(int row, int col) { byte bit = (byte) (1 << (col % 8)); bytes[row][col / 8] |= bit; } public void clear(int row, int col) { byte bit = (byte) (1 << (col % 8)); bytes[row][col / 8] &= ~bit; } public boolean get(int row, int col) { byte bit = (byte) (1 << (col % 8)); return (bytes[row][col / 8] & bit) != 0; } public void reset(boolean set) { for (int i = 0; i < bytes.length; i++) Arrays.fill(bytes[i], set ? (byte) 0xFF : (byte) 0x00); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy