org.jpedal.jbig2.segment.symboldictionary.SymbolDictionarySegment Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of OpenViewerFX Show documentation
Show all versions of OpenViewerFX Show documentation
An Open Source JavaFX PDF Viewer
/**
* ===========================================
* Java Pdf Extraction Decoding Access Library
* ===========================================
*
* Project Info: http://www.jpedal.org
* (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.
*
* ---------------
* SymbolDictionarySegment.java
* ---------------
*/
package org.jpedal.jbig2.segment.symboldictionary;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.jpedal.jbig2.JBIG2Exception;
import org.jpedal.jbig2.decoders.ArithmeticDecoderStats;
import org.jpedal.jbig2.decoders.DecodeIntResult;
import org.jpedal.jbig2.decoders.HuffmanDecoder;
import org.jpedal.jbig2.decoders.JBIG2StreamDecoder;
import org.jpedal.jbig2.image.JBIG2Bitmap;
import org.jpedal.jbig2.segment.Segment;
import org.jpedal.jbig2.segment.tables.JBIG2CodeTable;
import org.jpedal.jbig2.util.BinaryOperation;
public class SymbolDictionarySegment extends Segment {
private int noOfExportedSymbols;
private int noOfNewSymbols;
short[] symbolDictionaryAdaptiveTemplateX = new short[4], symbolDictionaryAdaptiveTemplateY = new short[4];
short[] symbolDictionaryRAdaptiveTemplateX = new short[2], symbolDictionaryRAdaptiveTemplateY = new short[2];
private JBIG2Bitmap[] bitmaps;
private SymbolDictionaryFlags symbolDictionaryFlags = new SymbolDictionaryFlags();
private ArithmeticDecoderStats genericRegionStats;
private ArithmeticDecoderStats refinementRegionStats;
public SymbolDictionarySegment(JBIG2StreamDecoder streamDecoder) {
super(streamDecoder);
}
public void readSegment() throws IOException, JBIG2Exception {
if (JBIG2StreamDecoder.debug)
System.out.println("==== Read Segment Symbol Dictionary ====");
/** read symbol dictionary flags */
readSymbolDictionaryFlags();
List codeTables = new ArrayList();
int numberOfInputSymbols = 0;
int noOfReferredToSegments = segmentHeader.getReferredToSegmentCount();
int[] referredToSegments = segmentHeader.getReferredToSegments();
for (int i = 0; i < noOfReferredToSegments; i++) {
Segment seg = decoder.findSegment(referredToSegments[i]);
int type = seg.getSegmentHeader().getSegmentType();
if (type == Segment.SYMBOL_DICTIONARY) {
numberOfInputSymbols += ((SymbolDictionarySegment) seg).noOfExportedSymbols;
} else if (type == Segment.TABLES) {
codeTables.add(seg);
}
}
int symbolCodeLength = 0;
int i = 1;
while (i < numberOfInputSymbols + noOfNewSymbols) {
symbolCodeLength++;
i <<= 1;
}
JBIG2Bitmap[] bitmaps = new JBIG2Bitmap[numberOfInputSymbols + noOfNewSymbols];
int k = 0;
SymbolDictionarySegment inputSymbolDictionary = null;
for (i = 0; i < noOfReferredToSegments; i++) {
Segment seg = decoder.findSegment(referredToSegments[i]);
if (seg.getSegmentHeader().getSegmentType() == Segment.SYMBOL_DICTIONARY) {
inputSymbolDictionary = (SymbolDictionarySegment) seg;
for (int j = 0; j < inputSymbolDictionary.noOfExportedSymbols; j++) {
bitmaps[k++] = inputSymbolDictionary.bitmaps[j];
}
}
}
int[][] huffmanDHTable = null;
int[][] huffmanDWTable = null;
int[][] huffmanBMSizeTable = null;
int[][] huffmanAggInstTable = null;
boolean sdHuffman = symbolDictionaryFlags.getFlagValue(SymbolDictionaryFlags.SD_HUFF) != 0;
int sdHuffmanDifferenceHeight = symbolDictionaryFlags.getFlagValue(SymbolDictionaryFlags.SD_HUFF_DH);
int sdHuffmanDiferrenceWidth = symbolDictionaryFlags.getFlagValue(SymbolDictionaryFlags.SD_HUFF_DW);
int sdHuffBitmapSize = symbolDictionaryFlags.getFlagValue(SymbolDictionaryFlags.SD_HUFF_BM_SIZE);
int sdHuffAggregationInstances = symbolDictionaryFlags.getFlagValue(SymbolDictionaryFlags.SD_HUFF_AGG_INST);
i = 0;
if (sdHuffman) {
if (sdHuffmanDifferenceHeight == 0) {
huffmanDHTable = HuffmanDecoder.huffmanTableD;
} else if (sdHuffmanDifferenceHeight == 1) {
huffmanDHTable = HuffmanDecoder.huffmanTableE;
} else {
huffmanDHTable = ((JBIG2CodeTable) codeTables.get(i++)).getHuffTable();
}
if (sdHuffmanDiferrenceWidth == 0) {
huffmanDWTable = HuffmanDecoder.huffmanTableB;
} else if (sdHuffmanDiferrenceWidth == 1) {
huffmanDWTable = HuffmanDecoder.huffmanTableC;
} else {
huffmanDWTable = ((JBIG2CodeTable) codeTables.get(i++)).getHuffTable();
}
if (sdHuffBitmapSize == 0) {
huffmanBMSizeTable = HuffmanDecoder.huffmanTableA;
} else {
huffmanBMSizeTable = ((JBIG2CodeTable) codeTables.get(i++)).getHuffTable();
}
if (sdHuffAggregationInstances == 0) {
huffmanAggInstTable = HuffmanDecoder.huffmanTableA;
} else {
huffmanAggInstTable = ((JBIG2CodeTable) codeTables.get(i++)).getHuffTable();
}
}
int contextUsed = symbolDictionaryFlags.getFlagValue(SymbolDictionaryFlags.BITMAP_CC_USED);
int sdTemplate = symbolDictionaryFlags.getFlagValue(SymbolDictionaryFlags.SD_TEMPLATE);
if (!sdHuffman) {
if (contextUsed != 0 && inputSymbolDictionary != null) {
arithmeticDecoder.resetGenericStats(sdTemplate, inputSymbolDictionary.genericRegionStats);
} else {
arithmeticDecoder.resetGenericStats(sdTemplate, null);
}
arithmeticDecoder.resetIntStats(symbolCodeLength);
arithmeticDecoder.start();
}
int sdRefinementAggregate = symbolDictionaryFlags.getFlagValue(SymbolDictionaryFlags.SD_REF_AGG);
int sdRefinementTemplate = symbolDictionaryFlags.getFlagValue(SymbolDictionaryFlags.SD_R_TEMPLATE);
if (sdRefinementAggregate != 0) {
if (contextUsed != 0 && inputSymbolDictionary != null) {
arithmeticDecoder.resetRefinementStats(sdRefinementTemplate, inputSymbolDictionary.refinementRegionStats);
} else {
arithmeticDecoder.resetRefinementStats(sdRefinementTemplate, null);
}
}
int deltaWidths[] = new int[noOfNewSymbols];
int deltaHeight = 0;
i = 0;
while (i < noOfNewSymbols) {
int instanceDeltaHeight;
if (sdHuffman) {
instanceDeltaHeight = huffmanDecoder.decodeInt(huffmanDHTable).intResult();
} else {
instanceDeltaHeight = arithmeticDecoder.decodeInt(arithmeticDecoder.iadhStats).intResult();
}
if (instanceDeltaHeight < 0 && -instanceDeltaHeight >= deltaHeight) {
if(JBIG2StreamDecoder.debug)
System.out.println("Bad delta-height value in JBIG2 symbol dictionary");
}
deltaHeight += instanceDeltaHeight;
int symbolWidth = 0;
int totalWidth = 0;
int j = i;
while (true) {
int deltaWidth;
DecodeIntResult decodeIntResult;
if (sdHuffman) {
decodeIntResult = huffmanDecoder.decodeInt(huffmanDWTable);
} else {
decodeIntResult = arithmeticDecoder.decodeInt(arithmeticDecoder.iadwStats);
}
if (!decodeIntResult.booleanResult())
break;
deltaWidth = decodeIntResult.intResult();
if (deltaWidth < 0 && -deltaWidth >= symbolWidth) {
if(JBIG2StreamDecoder.debug)
System.out.println("Bad delta-width value in JBIG2 symbol dictionary");
}
symbolWidth += deltaWidth;
if (sdHuffman && sdRefinementAggregate == 0) {
deltaWidths[i] = symbolWidth;
totalWidth += symbolWidth;
} else if (sdRefinementAggregate == 1) {
int refAggNum;
if (sdHuffman) {
refAggNum = huffmanDecoder.decodeInt(huffmanAggInstTable).intResult();
} else {
refAggNum = arithmeticDecoder.decodeInt(arithmeticDecoder.iaaiStats).intResult();
}
if (refAggNum == 1) {
int symbolID, referenceDX = 0, referenceDY = 0;
if (sdHuffman) {
symbolID = decoder.readBits(symbolCodeLength);
referenceDX = huffmanDecoder.decodeInt(HuffmanDecoder.huffmanTableO).intResult();
referenceDY = huffmanDecoder.decodeInt(HuffmanDecoder.huffmanTableO).intResult();
decoder.consumeRemainingBits();
arithmeticDecoder.start();
} else {
symbolID = (int) arithmeticDecoder.decodeIAID(symbolCodeLength, arithmeticDecoder.iaidStats);
referenceDX = arithmeticDecoder.decodeInt(arithmeticDecoder.iardxStats).intResult();
referenceDY = arithmeticDecoder.decodeInt(arithmeticDecoder.iardyStats).intResult();
}
JBIG2Bitmap referredToBitmap = bitmaps[symbolID];
JBIG2Bitmap bitmap = new JBIG2Bitmap(symbolWidth, deltaHeight, arithmeticDecoder, huffmanDecoder, mmrDecoder);
bitmap.readGenericRefinementRegion(sdRefinementTemplate, false, referredToBitmap, referenceDX, referenceDY, symbolDictionaryRAdaptiveTemplateX,
symbolDictionaryRAdaptiveTemplateY);
bitmaps[numberOfInputSymbols + i] = bitmap;
} else {
JBIG2Bitmap bitmap = new JBIG2Bitmap(symbolWidth, deltaHeight, arithmeticDecoder, huffmanDecoder, mmrDecoder);
bitmap.readTextRegion(sdHuffman, true, refAggNum, 0, numberOfInputSymbols + i, null, symbolCodeLength, bitmaps, 0, 0, false, 1, 0,
HuffmanDecoder.huffmanTableF, HuffmanDecoder.huffmanTableH, HuffmanDecoder.huffmanTableK, HuffmanDecoder.huffmanTableO, HuffmanDecoder.huffmanTableO,
HuffmanDecoder.huffmanTableO, HuffmanDecoder.huffmanTableO, HuffmanDecoder.huffmanTableA, sdRefinementTemplate, symbolDictionaryRAdaptiveTemplateX,
symbolDictionaryRAdaptiveTemplateY, decoder);
bitmaps[numberOfInputSymbols + i] = bitmap;
}
} else {
JBIG2Bitmap bitmap = new JBIG2Bitmap(symbolWidth, deltaHeight, arithmeticDecoder, huffmanDecoder, mmrDecoder);
bitmap.readBitmap(false, sdTemplate, false, false, null, symbolDictionaryAdaptiveTemplateX, symbolDictionaryAdaptiveTemplateY, 0);
bitmaps[numberOfInputSymbols + i] = bitmap;
}
i++;
}
if (sdHuffman && sdRefinementAggregate == 0) {
int bmSize = huffmanDecoder.decodeInt(huffmanBMSizeTable).intResult();
decoder.consumeRemainingBits();
JBIG2Bitmap collectiveBitmap = new JBIG2Bitmap(totalWidth, deltaHeight, arithmeticDecoder, huffmanDecoder, mmrDecoder);
if (bmSize == 0) {
int padding = totalWidth % 8;
int bytesPerRow = (int) Math.ceil(totalWidth / 8d);
//short[] bitmap = new short[totalWidth];
//decoder.readByte(bitmap);
int size = deltaHeight * ((totalWidth + 7) >> 3);
short[] bitmap = new short[size];
decoder.readByte(bitmap);
short[][] logicalMap = new short[deltaHeight][bytesPerRow];
int count = 0;
for (int row = 0; row < deltaHeight; row++) {
for (int col = 0; col < bytesPerRow; col++) {
logicalMap[row][col] = bitmap[count];
count++;
}
}
int collectiveBitmapRow = 0, collectiveBitmapCol = 0;
for (int row = 0; row < deltaHeight; row++) {
for (int col = 0; col < bytesPerRow; col++) {
if (col == (bytesPerRow - 1)) { // this is the last
// byte in the row
short currentByte = logicalMap[row][col];
for (int bitPointer = 7; bitPointer >= padding; bitPointer--) {
short mask = (short) (1 << bitPointer);
int bit = (currentByte & mask) >> bitPointer;
collectiveBitmap.setPixel(collectiveBitmapCol, collectiveBitmapRow, bit);
collectiveBitmapCol++;
}
collectiveBitmapRow++;
collectiveBitmapCol = 0;
} else {
short currentByte = logicalMap[row][col];
for (int bitPointer = 7; bitPointer >= 0; bitPointer--) {
short mask = (short) (1 << bitPointer);
int bit = (currentByte & mask) >> bitPointer;
collectiveBitmap.setPixel(collectiveBitmapCol, collectiveBitmapRow, bit);
collectiveBitmapCol++;
}
}
}
}
} else {
collectiveBitmap.readBitmap(true, 0, false, false, null, null, null, bmSize);
}
int x = 0;
while (j < i){
bitmaps[numberOfInputSymbols + j] = collectiveBitmap.getSlice(x, 0, deltaWidths[j], deltaHeight);
x += deltaWidths[j];
j++;
}
}
}
this.bitmaps = new JBIG2Bitmap[noOfExportedSymbols];
int j = i = 0;
boolean export = false;
while (i < numberOfInputSymbols + noOfNewSymbols) {
int run;
if (sdHuffman) {
run = huffmanDecoder.decodeInt(HuffmanDecoder.huffmanTableA).intResult();
} else {
run = arithmeticDecoder.decodeInt(arithmeticDecoder.iaexStats).intResult();
}
if (export) {
for (int cnt = 0; cnt < run; cnt++) {
this.bitmaps[j++] = bitmaps[i++];
}
} else {
i += run;
}
export = !export;
}
int contextRetained = symbolDictionaryFlags.getFlagValue(SymbolDictionaryFlags.BITMAP_CC_RETAINED);
if (!sdHuffman && contextRetained == 1) {
genericRegionStats = genericRegionStats.copy();
if (sdRefinementAggregate == 1) {
refinementRegionStats = refinementRegionStats.copy();
}
}
/** consume any remaining bits */
decoder.consumeRemainingBits();
}
private void readSymbolDictionaryFlags() throws IOException {
/** extract symbol dictionary flags */
short[] symbolDictionaryFlagsField = new short[2];
decoder.readByte(symbolDictionaryFlagsField);
int flags = BinaryOperation.getInt16(symbolDictionaryFlagsField);
symbolDictionaryFlags.setFlags(flags);
if (JBIG2StreamDecoder.debug)
System.out.println("symbolDictionaryFlags = " + flags);
// symbol dictionary AT flags
int sdHuff = symbolDictionaryFlags.getFlagValue(SymbolDictionaryFlags.SD_HUFF);
int sdTemplate = symbolDictionaryFlags.getFlagValue(SymbolDictionaryFlags.SD_TEMPLATE);
if (sdHuff == 0) {
if (sdTemplate == 0) {
symbolDictionaryAdaptiveTemplateX[0] = readATValue();
symbolDictionaryAdaptiveTemplateY[0] = readATValue();
symbolDictionaryAdaptiveTemplateX[1] = readATValue();
symbolDictionaryAdaptiveTemplateY[1] = readATValue();
symbolDictionaryAdaptiveTemplateX[2] = readATValue();
symbolDictionaryAdaptiveTemplateY[2] = readATValue();
symbolDictionaryAdaptiveTemplateX[3] = readATValue();
symbolDictionaryAdaptiveTemplateY[3] = readATValue();
} else {
symbolDictionaryAdaptiveTemplateX[0] = readATValue();
symbolDictionaryAdaptiveTemplateY[0] = readATValue();
}
}
// symbol dictionary refinement AT flags
int refAgg = symbolDictionaryFlags.getFlagValue(SymbolDictionaryFlags.SD_REF_AGG);
int sdrTemplate = symbolDictionaryFlags.getFlagValue(SymbolDictionaryFlags.SD_R_TEMPLATE);
if (refAgg != 0 && sdrTemplate == 0) {
symbolDictionaryRAdaptiveTemplateX[0] = readATValue();
symbolDictionaryRAdaptiveTemplateY[0] = readATValue();
symbolDictionaryRAdaptiveTemplateX[1] = readATValue();
symbolDictionaryRAdaptiveTemplateY[1] = readATValue();
}
/** extract no of exported symbols */
short[] noOfExportedSymbolsField = new short[4];
decoder.readByte(noOfExportedSymbolsField);
int noOfExportedSymbols = BinaryOperation.getInt32(noOfExportedSymbolsField);
this.noOfExportedSymbols = noOfExportedSymbols;
if (JBIG2StreamDecoder.debug)
System.out.println("noOfExportedSymbols = " + noOfExportedSymbols);
/** extract no of new symbols */
short[] noOfNewSymbolsField = new short[4];
decoder.readByte(noOfNewSymbolsField);
int noOfNewSymbols = BinaryOperation.getInt32(noOfNewSymbolsField);
this.noOfNewSymbols = noOfNewSymbols;
if (JBIG2StreamDecoder.debug)
System.out.println("noOfNewSymbols = " + noOfNewSymbols);
}
public int getNoOfExportedSymbols() {
return noOfExportedSymbols;
}
public void setNoOfExportedSymbols(int noOfExportedSymbols) {
this.noOfExportedSymbols = noOfExportedSymbols;
}
public int getNoOfNewSymbols() {
return noOfNewSymbols;
}
public void setNoOfNewSymbols(int noOfNewSymbols) {
this.noOfNewSymbols = noOfNewSymbols;
}
public JBIG2Bitmap[] getBitmaps() {
return bitmaps;
}
public SymbolDictionaryFlags getSymbolDictionaryFlags() {
return symbolDictionaryFlags;
}
public void setSymbolDictionaryFlags(SymbolDictionaryFlags symbolDictionaryFlags) {
this.symbolDictionaryFlags = symbolDictionaryFlags;
}
private ArithmeticDecoderStats getGenericRegionStats() {
return genericRegionStats;
}
private void setGenericRegionStats(ArithmeticDecoderStats genericRegionStats) {
this.genericRegionStats = genericRegionStats;
}
private void setRefinementRegionStats(ArithmeticDecoderStats refinementRegionStats) {
this.refinementRegionStats = refinementRegionStats;
}
private ArithmeticDecoderStats getRefinementRegionStats() {
return refinementRegionStats;
}
}