blob: 9e22ee96d46d86dae4df4b382db18927accc46d1 [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.pdfbox.jbig2.segments;
import java.io.IOException;
import org.apache.pdfbox.jbig2.Bitmap;
import org.apache.pdfbox.jbig2.Region;
import org.apache.pdfbox.jbig2.SegmentHeader;
import org.apache.pdfbox.jbig2.decoder.arithmetic.ArithmeticDecoder;
import org.apache.pdfbox.jbig2.decoder.arithmetic.CX;
import org.apache.pdfbox.jbig2.decoder.mmr.MMRDecompressor;
import org.apache.pdfbox.jbig2.err.InvalidHeaderValueException;
import org.apache.pdfbox.jbig2.io.SubInputStream;
import org.apache.pdfbox.jbig2.util.log.Logger;
import org.apache.pdfbox.jbig2.util.log.LoggerFactory;
/**
* This class represents a generic region segment.<br>
* Parsing is done as described in 7.4.5.<br>
* Decoding procedure is done as described in 6.2.5.7 and 7.4.6.4.
*/
public class GenericRegion implements Region
{
private final Logger log = LoggerFactory.getLogger(GenericRegion.class);
private SubInputStream subInputStream;
private long dataHeaderOffset;
private long dataHeaderLength;
private long dataOffset;
private long dataLength;
/** Region segment information field, 7.4.1 */
private RegionSegmentInformation regionInfo;
/** Generic region segment flags, 7.4.6.2 */
private boolean useExtTemplates;
private boolean isTPGDon;
private byte gbTemplate;
private boolean isMMREncoded;
/** Generic region segment AT flags, 7.4.6.3 */
private short[] gbAtX;
private short[] gbAtY;
private boolean[] gbAtOverride;
/**
* If true, AT pixels are not on their nominal location and have to be overridden
*/
private boolean override;
/** Decoded data as pixel values (use row stride/width to wrap line) */
private Bitmap regionBitmap;
private ArithmeticDecoder arithDecoder;
private CX cx;
private MMRDecompressor mmrDecompressor;
public GenericRegion()
{
}
public GenericRegion(final SubInputStream subInputStream)
{
this.subInputStream = subInputStream;
this.regionInfo = new RegionSegmentInformation(subInputStream);
}
private void parseHeader() throws IOException, InvalidHeaderValueException
{
regionInfo.parseHeader();
/* Bit 5-7 */
subInputStream.readBits(3); // Dirty read...
/* Bit 4 */
if (subInputStream.readBit() == 1)
{
useExtTemplates = true;
}
/* Bit 3 */
if (subInputStream.readBit() == 1)
{
isTPGDon = true;
}
/* Bit 1-2 */
gbTemplate = (byte) (subInputStream.readBits(2) & 0xf);
/* Bit 0 */
if (subInputStream.readBit() == 1)
{
isMMREncoded = true;
}
if (!isMMREncoded)
{
final int amountOfGbAt;
if (gbTemplate == 0)
{
if (useExtTemplates)
{
amountOfGbAt = 12;
}
else
{
amountOfGbAt = 4;
}
}
else
{
amountOfGbAt = 1;
}
readGbAtPixels(amountOfGbAt);
}
/* Segment data structure */
computeSegmentDataStructure();
this.checkInput();
}
private void readGbAtPixels(final int amountOfGbAt) throws IOException
{
gbAtX = new short[amountOfGbAt];
gbAtY = new short[amountOfGbAt];
for (int i = 0; i < amountOfGbAt; i++)
{
gbAtX[i] = subInputStream.readByte();
gbAtY[i] = subInputStream.readByte();
}
}
private void computeSegmentDataStructure() throws IOException
{
dataOffset = subInputStream.getStreamPosition();
dataHeaderLength = dataOffset - dataHeaderOffset;
dataLength = subInputStream.length() - dataHeaderLength;
}
private void checkInput() throws InvalidHeaderValueException
{
if (isMMREncoded)
{
if (gbTemplate != 0)
{
log.info("gbTemplate should contain the value 0");
}
}
}
/**
* The procedure is described in 6.2.5.7, page 17.
*
* @return The decoded {@link Bitmap} of this region.
*/
public Bitmap getRegionBitmap() throws IOException
{
if (null == regionBitmap)
{
if (isMMREncoded)
{
/*
* MMR DECODER CALL
*/
if (null == mmrDecompressor)
{
mmrDecompressor = new MMRDecompressor(regionInfo.getBitmapWidth(),
regionInfo.getBitmapHeight(),
new SubInputStream(subInputStream, dataOffset, dataLength));
}
/* 6.2.6 */
regionBitmap = mmrDecompressor.uncompress();
}
else
{
/*
* ARITHMETIC DECODER PROCEDURE for generic region segments
*/
updateOverrideFlags();
/* 6.2.5.7 - 1) */
int ltp = 0;
if (arithDecoder == null)
{
arithDecoder = new ArithmeticDecoder(subInputStream);
}
if (cx == null)
{
cx = new CX(65536, 1);
}
/* 6.2.5.7 - 2) */
regionBitmap = new Bitmap(regionInfo.getBitmapWidth(),
regionInfo.getBitmapHeight());
final int paddedWidth = (regionBitmap.getWidth() + 7) & -8;
/* 6.2.5.7 - 3 */
for (int line = 0; line < regionBitmap.getHeight(); line++)
{
/* 6.2.5.7 - 3 b) */
if (isTPGDon)
{
ltp ^= decodeSLTP();
}
/* 6.2.5.7 - 3 c) */
if (ltp == 1)
{
if (line > 0)
{
copyLineAbove(line);
}
}
else
{
/* 3 d) */
// NOT USED ATM - If corresponding pixel of SKIP bitmap is 0, set
// current pixel to 0. Something like that:
// if (useSkip) {
// for (int i = 1; i < rowstride; i++) {
// if (skip[pixel] == 1) {
// gbReg[pixel] = 0;
// }
// pixel++;
// }
// } else {
decodeLine(line, regionBitmap.getWidth(), regionBitmap.getRowStride(),
paddedWidth);
// }
}
}
}
}
// if (JBIG2ImageReader.DEBUG)
// if (header != null && header.getSegmentNr() == 3)
// new Testbild(gbReg.getByteArray(), (int) gbReg.getWidth(), (int) gbReg.getHeight(),
// gbReg.getRowStride());
/* 4 */
return regionBitmap;
}
private int decodeSLTP() throws IOException
{
switch (gbTemplate)
{
case 0:
cx.setIndex(0x9b25);
break;
case 1:
cx.setIndex(0x795);
break;
case 2:
cx.setIndex(0xe5);
break;
case 3:
cx.setIndex(0x195);
break;
}
return arithDecoder.decode(cx);
}
private void decodeLine(final int lineNumber, final int width, final int rowStride,
final int paddedWidth) throws IOException
{
final int byteIndex = regionBitmap.getByteIndex(0, lineNumber);
final int idx = byteIndex - rowStride;
switch (gbTemplate)
{
case 0:
if (!useExtTemplates)
{
decodeTemplate0a(lineNumber, width, rowStride, paddedWidth, byteIndex, idx);
}
else
{
decodeTemplate0b(lineNumber, width, rowStride, paddedWidth, byteIndex, idx);
}
break;
case 1:
decodeTemplate1(lineNumber, width, rowStride, paddedWidth, byteIndex, idx);
break;
case 2:
decodeTemplate2(lineNumber, width, rowStride, paddedWidth, byteIndex, idx);
break;
case 3:
decodeTemplate3(lineNumber, width, rowStride, paddedWidth, byteIndex, idx);
break;
}
}
/**
* Each pixel gets the value from the corresponding pixel of the row above. Line 0 cannot get copied values (source
* will be -1, doesn't exist).
*
* @param lineNumber - Coordinate of the row that should be set.
*/
private void copyLineAbove(final int lineNumber)
{
int targetByteIndex = lineNumber * regionBitmap.getRowStride();
int sourceByteIndex = targetByteIndex - regionBitmap.getRowStride();
for (int i = 0; i < regionBitmap.getRowStride(); i++)
{
// Get the byte that should be copied and put it into Bitmap
regionBitmap.setByte(targetByteIndex++, regionBitmap.getByte(sourceByteIndex++));
}
}
private void decodeTemplate0a(final int lineNumber, final int width, final int rowStride,
final int paddedWidth, int byteIndex, int idx) throws IOException
{
int context;
int overriddenContext = 0;
int line1 = 0;
int line2 = 0;
if (lineNumber >= 1)
{
line1 = regionBitmap.getByteAsInteger(idx);
}
if (lineNumber >= 2)
{
line2 = regionBitmap.getByteAsInteger(idx - rowStride) << 6;
}
context = (line1 & 0xf0) | (line2 & 0x3800);
int nextByte;
for (int x = 0; x < paddedWidth; x = nextByte)
{
/* 6.2.5.7 3d */
byte result = 0;
nextByte = x + 8;
final int minorWidth = width - x > 8 ? 8 : width - x;
if (lineNumber > 0)
{
line1 = (line1 << 8)
| (nextByte < width ? regionBitmap.getByteAsInteger(idx + 1) : 0);
}
if (lineNumber > 1)
{
line2 = (line2 << 8) | (nextByte < width
? regionBitmap.getByteAsInteger(idx - rowStride + 1) << 6 : 0);
}
for (int minorX = 0; minorX < minorWidth; minorX++)
{
final int toShift = 7 - minorX;
if (override)
{
overriddenContext = overrideAtTemplate0a(context, (x + minorX), lineNumber,
result, minorX, toShift);
cx.setIndex(overriddenContext);
}
else
{
cx.setIndex(context);
}
int bit = arithDecoder.decode(cx);
result |= bit << toShift;
context = ((context & 0x7bf7) << 1) | bit | ((line1 >> toShift) & 0x10)
| ((line2 >> toShift) & 0x800);
}
regionBitmap.setByte(byteIndex++, result);
idx++;
}
}
private void decodeTemplate0b(final int lineNumber, final int width, final int rowStride,
final int paddedWidth, int byteIndex, int idx) throws IOException
{
int context;
int overriddenContext = 0;
int line1 = 0;
int line2 = 0;
if (lineNumber >= 1)
{
line1 = regionBitmap.getByteAsInteger(idx);
}
if (lineNumber >= 2)
{
line2 = regionBitmap.getByteAsInteger(idx - rowStride) << 6;
}
context = (line1 & 0xf0) | (line2 & 0x3800);
int nextByte;
for (int x = 0; x < paddedWidth; x = nextByte)
{
/* 6.2.5.7 3d */
byte result = 0;
nextByte = x + 8;
final int minorWidth = width - x > 8 ? 8 : width - x;
if (lineNumber > 0)
{
line1 = (line1 << 8)
| (nextByte < width ? regionBitmap.getByteAsInteger(idx + 1) : 0);
}
if (lineNumber > 1)
{
line2 = (line2 << 8) | (nextByte < width
? regionBitmap.getByteAsInteger(idx - rowStride + 1) << 6 : 0);
}
for (int minorX = 0; minorX < minorWidth; minorX++)
{
final int toShift = 7 - minorX;
if (override)
{
overriddenContext = overrideAtTemplate0b(context, (x + minorX), lineNumber,
result, minorX, toShift);
cx.setIndex(overriddenContext);
}
else
{
cx.setIndex(context);
}
final int bit = arithDecoder.decode(cx);
result |= bit << toShift;
context = ((context & 0x7bf7) << 1) | bit | ((line1 >> toShift) & 0x10)
| ((line2 >> toShift) & 0x800);
}
regionBitmap.setByte(byteIndex++, result);
idx++;
}
}
private void decodeTemplate1(final int lineNumber, int width, final int rowStride,
final int paddedWidth, int byteIndex, int idx) throws IOException
{
int context;
int overriddenContext;
int line1 = 0;
int line2 = 0;
if (lineNumber >= 1)
{
line1 = regionBitmap.getByteAsInteger(idx);
}
if (lineNumber >= 2)
{
line2 = regionBitmap.getByteAsInteger(idx - rowStride) << 5;
}
context = ((line1 >> 1) & 0x1f8) | ((line2 >> 1) & 0x1e00);
int nextByte;
for (int x = 0; x < paddedWidth; x = nextByte)
{
/* 6.2.5.7 3d */
byte result = 0;
nextByte = x + 8;
final int minorWidth = width - x > 8 ? 8 : width - x;
if (lineNumber >= 1)
{
line1 = (line1 << 8)
| (nextByte < width ? regionBitmap.getByteAsInteger(idx + 1) : 0);
}
if (lineNumber >= 2)
{
line2 = (line2 << 8) | (nextByte < width
? regionBitmap.getByteAsInteger(idx - rowStride + 1) << 5 : 0);
}
for (int minorX = 0; minorX < minorWidth; minorX++)
{
if (override)
{
overriddenContext = overrideAtTemplate1(context, x + minorX, lineNumber, result,
minorX);
cx.setIndex(overriddenContext);
}
else
{
cx.setIndex(context);
}
final int bit = arithDecoder.decode(cx);
result |= bit << 7 - minorX;
final int toShift = 8 - minorX;
context = ((context & 0xefb) << 1) | bit | ((line1 >> toShift) & 0x8)
| ((line2 >> toShift) & 0x200);
}
regionBitmap.setByte(byteIndex++, result);
idx++;
}
}
private void decodeTemplate2(final int lineNumber, final int width, final int rowStride,
final int paddedWidth, int byteIndex, int idx) throws IOException
{
int context;
int overriddenContext;
int line1 = 0;
int line2 = 0;
if (lineNumber >= 1)
{
line1 = regionBitmap.getByteAsInteger(idx);
}
if (lineNumber >= 2)
{
line2 = regionBitmap.getByteAsInteger(idx - rowStride) << 4;
}
context = ((line1 >> 3) & 0x7c) | ((line2 >> 3) & 0x380);
int nextByte;
for (int x = 0; x < paddedWidth; x = nextByte)
{
/* 6.2.5.7 3d */
byte result = 0;
nextByte = x + 8;
final int minorWidth = width - x > 8 ? 8 : width - x;
if (lineNumber >= 1)
{
line1 = (line1 << 8)
| (nextByte < width ? regionBitmap.getByteAsInteger(idx + 1) : 0);
}
if (lineNumber >= 2)
{
line2 = (line2 << 8) | (nextByte < width
? regionBitmap.getByteAsInteger(idx - rowStride + 1) << 4 : 0);
}
for (int minorX = 0; minorX < minorWidth; minorX++)
{
if (override)
{
overriddenContext = overrideAtTemplate2(context, x + minorX, lineNumber, result,
minorX);
cx.setIndex(overriddenContext);
}
else
{
cx.setIndex(context);
}
final int bit = arithDecoder.decode(cx);
result |= bit << (7 - minorX);
final int toShift = 10 - minorX;
context = ((context & 0x1bd) << 1) | bit | ((line1 >> toShift) & 0x4)
| ((line2 >> toShift) & 0x80);
}
regionBitmap.setByte(byteIndex++, result);
idx++;
}
}
private void decodeTemplate3(final int lineNumber, final int width, final int rowStride,
final int paddedWidth, int byteIndex, int idx) throws IOException
{
int context;
int overriddenContext;
int line1 = 0;
if (lineNumber >= 1)
{
line1 = regionBitmap.getByteAsInteger(idx);
}
context = (line1 >> 1) & 0x70;
int nextByte;
for (int x = 0; x < paddedWidth; x = nextByte)
{
/* 6.2.5.7 3d */
byte result = 0;
nextByte = x + 8;
final int minorWidth = width - x > 8 ? 8 : width - x;
if (lineNumber >= 1)
{
line1 = (line1 << 8)
| (nextByte < width ? regionBitmap.getByteAsInteger(idx + 1) : 0);
}
for (int minorX = 0; minorX < minorWidth; minorX++)
{
if (override)
{
overriddenContext = overrideAtTemplate3(context, x + minorX, lineNumber, result,
minorX);
cx.setIndex(overriddenContext);
}
else
{
cx.setIndex(context);
}
final int bit = arithDecoder.decode(cx);
result |= bit << (7 - minorX);
context = ((context & 0x1f7) << 1) | bit | ((line1 >> (8 - minorX)) & 0x010);
}
regionBitmap.setByte(byteIndex++, result);
idx++;
}
}
private void updateOverrideFlags()
{
if (gbAtX == null || gbAtY == null)
{
log.info("AT pixels not set");
return;
}
if (gbAtX.length != gbAtY.length)
{
log.info("AT pixel inconsistent, amount of x pixels: " + gbAtX.length
+ ", amount of y pixels:" + gbAtY.length);
return;
}
gbAtOverride = new boolean[gbAtX.length];
switch (gbTemplate)
{
case 0:
if (!useExtTemplates)
{
if (gbAtX[0] != 3 || gbAtY[0] != -1)
setOverrideFlag(0);
if (gbAtX[1] != -3 || gbAtY[1] != -1)
setOverrideFlag(1);
if (gbAtX[2] != 2 || gbAtY[2] != -2)
setOverrideFlag(2);
if (gbAtX[3] != -2 || gbAtY[3] != -2)
setOverrideFlag(3);
}
else
{
if (gbAtX[0] != -2 || gbAtY[0] != 0)
setOverrideFlag(0);
if (gbAtX[1] != 0 || gbAtY[1] != -2)
setOverrideFlag(1);
if (gbAtX[2] != -2 || gbAtY[2] != -1)
setOverrideFlag(2);
if (gbAtX[3] != -1 || gbAtY[3] != -2)
setOverrideFlag(3);
if (gbAtX[4] != 1 || gbAtY[4] != -2)
setOverrideFlag(4);
if (gbAtX[5] != 2 || gbAtY[5] != -1)
setOverrideFlag(5);
if (gbAtX[6] != -3 || gbAtY[6] != 0)
setOverrideFlag(6);
if (gbAtX[7] != -4 || gbAtY[7] != 0)
setOverrideFlag(7);
if (gbAtX[8] != 2 || gbAtY[8] != -2)
setOverrideFlag(8);
if (gbAtX[9] != 3 || gbAtY[9] != -1)
setOverrideFlag(9);
if (gbAtX[10] != -2 || gbAtY[10] != -2)
setOverrideFlag(10);
if (gbAtX[11] != -3 || gbAtY[11] != -1)
setOverrideFlag(11);
}
break;
case 1:
if (gbAtX[0] != 3 || gbAtY[0] != -1)
setOverrideFlag(0);
break;
case 2:
if (gbAtX[0] != 2 || gbAtY[0] != -1)
setOverrideFlag(0);
break;
case 3:
if (gbAtX[0] != 2 || gbAtY[0] != -1)
setOverrideFlag(0);
break;
}
}
private void setOverrideFlag(final int index)
{
gbAtOverride[index] = true;
override = true;
}
private int overrideAtTemplate0a(int context, final int x, final int y, final int result,
final int minorX, final int toShift) throws IOException
{
if (gbAtOverride[0])
{
context &= 0xffef;
if (gbAtY[0] == 0 && gbAtX[0] >= -minorX)
context |= (result >> (toShift - gbAtX[0]) & 0x1) << 4;
else
context |= getPixel(x + gbAtX[0], y + gbAtY[0]) << 4;
}
if (gbAtOverride[1])
{
context &= 0xfbff;
if (gbAtY[1] == 0 && gbAtX[1] >= -minorX)
context |= (result >> (toShift - gbAtX[1]) & 0x1) << 10;
else
context |= getPixel(x + gbAtX[1], y + gbAtY[1]) << 10;
}
if (gbAtOverride[2])
{
context &= 0xf7ff;
if (gbAtY[2] == 0 && gbAtX[2] >= -minorX)
context |= (result >> (toShift - gbAtX[2]) & 0x1) << 11;
else
context |= getPixel(x + gbAtX[2], y + gbAtY[2]) << 11;
}
if (gbAtOverride[3])
{
context &= 0x7fff;
if (gbAtY[3] == 0 && gbAtX[3] >= -minorX)
context |= (result >> (toShift - gbAtX[3]) & 0x1) << 15;
else
context |= getPixel(x + gbAtX[3], y + gbAtY[3]) << 15;
}
return context;
}
private int overrideAtTemplate0b(int context, final int x, final int y, final int result,
final int minorX, final int toShift) throws IOException
{
if (gbAtOverride[0])
{
context &= 0xfffd;
if (gbAtY[0] == 0 && gbAtX[0] >= -minorX)
context |= (result >> (toShift - gbAtX[0]) & 0x1) << 1;
else
context |= getPixel(x + gbAtX[0], y + gbAtY[0]) << 1;
}
if (gbAtOverride[1])
{
context &= 0xdfff;
if (gbAtY[1] == 0 && gbAtX[1] >= -minorX)
context |= (result >> (toShift - gbAtX[1]) & 0x1) << 13;
else
context |= getPixel(x + gbAtX[1], y + gbAtY[1]) << 13;
}
if (gbAtOverride[2])
{
context &= 0xfdff;
if (gbAtY[2] == 0 && gbAtX[2] >= -minorX)
context |= (result >> (toShift - gbAtX[2]) & 0x1) << 9;
else
context |= getPixel(x + gbAtX[2], y + gbAtY[2]) << 9;
}
if (gbAtOverride[3])
{
context &= 0xbfff;
if (gbAtY[3] == 0 && gbAtX[3] >= -minorX)
context |= (result >> (toShift - gbAtX[3]) & 0x1) << 14;
else
context |= getPixel(x + gbAtX[3], y + gbAtY[3]) << 14;
}
if (gbAtOverride[4])
{
context &= 0xefff;
if (gbAtY[4] == 0 && gbAtX[4] >= -minorX)
context |= (result >> (toShift - gbAtX[4]) & 0x1) << 12;
else
context |= getPixel(x + gbAtX[4], y + gbAtY[4]) << 12;
}
if (gbAtOverride[5])
{
context &= 0xffdf;
if (gbAtY[5] == 0 && gbAtX[5] >= -minorX)
context |= (result >> (toShift - gbAtX[5]) & 0x1) << 5;
else
context |= getPixel(x + gbAtX[5], y + gbAtY[5]) << 5;
}
if (gbAtOverride[6])
{
context &= 0xfffb;
if (gbAtY[6] == 0 && gbAtX[6] >= -minorX)
context |= (result >> (toShift - gbAtX[6]) & 0x1) << 2;
else
context |= getPixel(x + gbAtX[6], y + gbAtY[6]) << 2;
}
if (gbAtOverride[7])
{
context &= 0xfff7;
if (gbAtY[7] == 0 && gbAtX[7] >= -minorX)
context |= (result >> (toShift - gbAtX[7]) & 0x1) << 3;
else
context |= getPixel(x + gbAtX[7], y + gbAtY[7]) << 3;
}
if (gbAtOverride[8])
{
context &= 0xf7ff;
if (gbAtY[8] == 0 && gbAtX[8] >= -minorX)
context |= (result >> (toShift - gbAtX[8]) & 0x1) << 11;
else
context |= getPixel(x + gbAtX[8], y + gbAtY[8]) << 11;
}
if (gbAtOverride[9])
{
context &= 0xffef;
if (gbAtY[9] == 0 && gbAtX[9] >= -minorX)
context |= (result >> (toShift - gbAtX[9]) & 0x1) << 4;
else
context |= getPixel(x + gbAtX[9], y + gbAtY[9]) << 4;
}
if (gbAtOverride[10])
{
context &= 0x7fff;
if (gbAtY[10] == 0 && gbAtX[10] >= -minorX)
context |= (result >> (toShift - gbAtX[10]) & 0x1) << 15;
else
context |= getPixel(x + gbAtX[10], y + gbAtY[10]) << 15;
}
if (gbAtOverride[11])
{
context &= 0xfdff;
if (gbAtY[11] == 0 && gbAtX[11] >= -minorX)
context |= (result >> (toShift - gbAtX[11]) & 0x1) << 10;
else
context |= getPixel(x + gbAtX[11], y + gbAtY[11]) << 10;
}
return context;
}
private int overrideAtTemplate1(int context, final int x, final int y, final int result,
final int minorX) throws IOException
{
context &= 0x1ff7;
if (gbAtY[0] == 0 && gbAtX[0] >= -minorX)
return (context | (result >> (7 - (minorX + gbAtX[0])) & 0x1) << 3);
else
return (context | getPixel(x + gbAtX[0], y + gbAtY[0]) << 3);
}
private int overrideAtTemplate2(int context, final int x, final int y, final int result,
final int minorX) throws IOException
{
context &= 0x3fb;
if (gbAtY[0] == 0 && gbAtX[0] >= -minorX)
return (context | (result >> (7 - (minorX + gbAtX[0])) & 0x1) << 2);
else
return (context | getPixel(x + gbAtX[0], y + gbAtY[0]) << 2);
}
private int overrideAtTemplate3(int context, final int x, final int y, final int result,
final int minorX) throws IOException
{
context &= 0x3ef;
if (gbAtY[0] == 0 && gbAtX[0] >= -minorX)
return (context | (result >> (7 - (minorX + gbAtX[0])) & 0x1) << 4);
else
return (context | getPixel(x + gbAtX[0], y + gbAtY[0]) << 4);
}
private byte getPixel(final int x, final int y) throws IOException
{
if (x < 0 || x >= regionBitmap.getWidth())
return 0;
if (y < 0 || y >= regionBitmap.getHeight())
return 0;
return regionBitmap.getPixel(x, y);
}
/**
* Used by {@link SymbolDictionary}.
*
* @param isMMREncoded the data is MMR encoded
* @param dataOffset the offset
* @param dataLength the length of the data
* @param gbh bitmap height
* @param gbw bitmap width
*/
protected void setParameters(final boolean isMMREncoded, final long dataOffset,
final long dataLength, final int gbh, final int gbw)
{
this.isMMREncoded = isMMREncoded;
this.dataOffset = dataOffset;
this.dataLength = dataLength;
this.regionInfo.setBitmapHeight(gbh);
this.regionInfo.setBitmapWidth(gbw);
this.mmrDecompressor = null;
resetBitmap();
}
/**
* @param isMMREncoded the data is MMR encoded
* @param sdTemplate sd template
* @param isTPGDon is TPGDon
* @param useSkip use skip
* @param sdATX x values gbA pixels
* @param sdATY y values gbA pixels
* @param symWidth bitmap width
* @param hcHeight bitmap height
* @param cx context for the arithmetic decoder
* @param arithmeticDecoder the arithmetic decode to be used
*
* Used by {@link SymbolDictionary}.
*/
protected void setParameters(final boolean isMMREncoded, final byte sdTemplate,
final boolean isTPGDon, final boolean useSkip, final short[] sdATX, final short[] sdATY,
final int symWidth, final int hcHeight, final CX cx,
final ArithmeticDecoder arithmeticDecoder)
{
this.isMMREncoded = isMMREncoded;
this.gbTemplate = sdTemplate;
this.isTPGDon = isTPGDon;
this.gbAtX = sdATX;
this.gbAtY = sdATY;
this.regionInfo.setBitmapWidth(symWidth);
this.regionInfo.setBitmapHeight(hcHeight);
if (null != cx)
this.cx = cx;
if (null != arithmeticDecoder)
this.arithDecoder = arithmeticDecoder;
this.mmrDecompressor = null;
resetBitmap();
}
/**
* Used by {@link PatternDictionary} and {@link HalftoneRegion}.
*
* @param isMMREncoded the data is MMR encoded
* @param dataOffset the offset
* @param dataLength the length of the data
* @param gbh bitmap height
* @param gbw bitmap width
* @param gbTemplate gb template
* @param isTPGDon is TPGDon
* @param useSkip use skip
* @param gbAtX x values of gbA pixels
* @param gbAtY y values of gbA pixels
*
*/
protected void setParameters(final boolean isMMREncoded, final long dataOffset,
final long dataLength, final int gbh, final int gbw, final byte gbTemplate,
final boolean isTPGDon, final boolean useSkip, final short[] gbAtX, final short[] gbAtY)
{
this.dataOffset = dataOffset;
this.dataLength = dataLength;
this.regionInfo = new RegionSegmentInformation();
this.regionInfo.setBitmapHeight(gbh);
this.regionInfo.setBitmapWidth(gbw);
this.gbTemplate = gbTemplate;
this.isMMREncoded = isMMREncoded;
this.isTPGDon = isTPGDon;
this.gbAtX = gbAtX;
this.gbAtY = gbAtY;
}
/**
* Simply sets the memory-critical bitmap of this region to {@code null}.
*/
protected void resetBitmap()
{
this.regionBitmap = null;
}
public void init(final SegmentHeader header, final SubInputStream sis)
throws InvalidHeaderValueException, IOException
{
this.subInputStream = sis;
this.regionInfo = new RegionSegmentInformation(subInputStream);
parseHeader();
}
public RegionSegmentInformation getRegionInfo()
{
return regionInfo;
}
protected boolean useExtTemplates()
{
return useExtTemplates;
}
protected boolean isTPGDon()
{
return isTPGDon;
}
protected byte getGbTemplate()
{
return gbTemplate;
}
protected boolean isMMREncoded()
{
return isMMREncoded;
}
protected short[] getGbAtX()
{
return gbAtX;
}
protected short[] getGbAtY()
{
return gbAtY;
}
}