blob: 2236275c572f98c11f7d20aed8d13f786ba358a0 [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;
/**
* 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 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;
private boolean useSkip = false;
private Bitmap hSkip = null;
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();
}
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;
}
/**
* The procedure is described in 6.2.5.7, page 17.
*
* @return The decoded {@link Bitmap} of this region.
*/
@Override
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
{
/* 6.2.5.7 - 3 d) */
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);
}
final int bit;
if (useSkip && hSkip.getPixel(x + minorX, lineNumber) == 1)
{
bit = 0;
}
else
{
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;
if (useSkip && hSkip.getPixel(x + minorX, lineNumber) == 1)
{
bit = 0;
}
else
{
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;
if (useSkip && hSkip.getPixel(x + minorX, lineNumber) == 1)
{
bit = 0;
}
else
{
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;
if (useSkip && hSkip.getPixel(x + minorX, lineNumber) == 1)
{
bit = 0;
}
else
{
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;
if (useSkip && hSkip.getPixel(x + minorX, lineNumber) == 1)
{
bit = 0;
}
else
{
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)
{
return;
}
if (gbAtX.length != 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;
this.useSkip = useSkip;
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 hSkip the HSKIP bitmap
* @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 Bitmap hSkip, 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;
this.useSkip = useSkip;
this.hSkip = hSkip;
}
/**
* Simply sets the memory-critical bitmap of this region to {@code null}.
*/
protected void resetBitmap()
{
this.regionBitmap = null;
}
@Override
public void init(final SegmentHeader header, final SubInputStream sis)
throws InvalidHeaderValueException, IOException
{
this.subInputStream = sis;
this.regionInfo = new RegionSegmentInformation(subInputStream);
parseHeader();
}
@Override
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;
}
}