You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pdfbox.apache.org by le...@apache.org on 2017/10/16 18:09:16 UTC
[3/8] pdfbox-jbig2 git commit: initial commit of the JBig2 ImageIO
plugin
http://git-wip-us.apache.org/repos/asf/pdfbox-jbig2/blob/4619d28b/src/main/java/org/apache/pdfbox/jbig2/segments/Table.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/pdfbox/jbig2/segments/Table.java b/src/main/java/org/apache/pdfbox/jbig2/segments/Table.java
new file mode 100644
index 0000000..43924e2
--- /dev/null
+++ b/src/main/java/org/apache/pdfbox/jbig2/segments/Table.java
@@ -0,0 +1,97 @@
+/**
+ * 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.SegmentData;
+import org.apache.pdfbox.jbig2.SegmentHeader;
+import org.apache.pdfbox.jbig2.err.IntegerMaxValueException;
+import org.apache.pdfbox.jbig2.err.InvalidHeaderValueException;
+import org.apache.pdfbox.jbig2.io.SubInputStream;
+
+/**
+ * This class represents a "Table" segment. It handles custom tables, see Annex B.
+ */
+public class Table implements SegmentData {
+
+ private SubInputStream subInputStream;
+
+ /** Code table flags, B.2.1, page 87 */
+ private int htOutOfBand;
+ private int htPS;
+ private int htRS;
+
+ /** Code table lowest value, B.2.2, page 87 */
+ private int htLow;
+
+ /** Code table highest value, B.2.3, page 87 */
+ private int htHigh;
+
+ private void parseHeader() throws IOException, InvalidHeaderValueException, IntegerMaxValueException {
+ int bit;
+
+ /* Bit 7 */
+ if ((bit = subInputStream.readBit()) == 1) {
+ throw new InvalidHeaderValueException("B.2.1 Code table flags: Bit 7 must be zero, but was " + bit);
+ }
+
+ /* Bit 4-6 */
+ htRS = (int) ((subInputStream.readBits(3) + 1) & 0xf);
+
+ /* Bit 1-3 */
+ htPS = (int) ((subInputStream.readBits(3) + 1) & 0xf);
+
+ /* Bit 0 */
+ htOutOfBand = (int) subInputStream.readBit();
+
+ htLow = (int) subInputStream.readBits(32); // & 0xffffffff);
+ htHigh = (int) subInputStream.readBits(32); // & 0xffffffff);
+ }
+
+ public void init(SegmentHeader header, SubInputStream sis) throws InvalidHeaderValueException, IOException,
+ IntegerMaxValueException {
+ subInputStream = sis;
+
+ parseHeader();
+ }
+
+ public int getHtOOB() {
+ return htOutOfBand;
+ }
+
+ public int getHtPS() {
+ return htPS;
+ }
+
+ public int getHtRS() {
+ return htRS;
+ }
+
+ public int getHtLow() {
+ return htLow;
+ }
+
+ public int getHtHigh() {
+ return htHigh;
+ }
+
+ public SubInputStream getSubInputStream() {
+ return subInputStream;
+ }
+}
http://git-wip-us.apache.org/repos/asf/pdfbox-jbig2/blob/4619d28b/src/main/java/org/apache/pdfbox/jbig2/segments/TextRegion.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/pdfbox/jbig2/segments/TextRegion.java b/src/main/java/org/apache/pdfbox/jbig2/segments/TextRegion.java
new file mode 100644
index 0000000..797729c
--- /dev/null
+++ b/src/main/java/org/apache/pdfbox/jbig2/segments/TextRegion.java
@@ -0,0 +1,973 @@
+/**
+ * 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 java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.pdfbox.jbig2.Bitmap;
+import org.apache.pdfbox.jbig2.JBIG2ImageReader;
+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.ArithmeticIntegerDecoder;
+import org.apache.pdfbox.jbig2.decoder.arithmetic.CX;
+import org.apache.pdfbox.jbig2.decoder.huffman.EncodedTable;
+import org.apache.pdfbox.jbig2.decoder.huffman.FixedSizeTable;
+import org.apache.pdfbox.jbig2.decoder.huffman.HuffmanTable;
+import org.apache.pdfbox.jbig2.decoder.huffman.StandardTables;
+import org.apache.pdfbox.jbig2.decoder.huffman.HuffmanTable.Code;
+import org.apache.pdfbox.jbig2.err.IntegerMaxValueException;
+import org.apache.pdfbox.jbig2.err.InvalidHeaderValueException;
+import org.apache.pdfbox.jbig2.image.Bitmaps;
+import org.apache.pdfbox.jbig2.io.SubInputStream;
+import org.apache.pdfbox.jbig2.util.CombinationOperator;
+import org.apache.pdfbox.jbig2.util.log.Logger;
+import org.apache.pdfbox.jbig2.util.log.LoggerFactory;
+
+/**
+ * This class represented the segment type "Text region", 7.4.3, page 56.
+ */
+public class TextRegion implements Region {
+
+ private final Logger log = LoggerFactory.getLogger(TextRegion.class);
+
+ private SubInputStream subInputStream;
+
+ /** Region segment information field, 7.4.1 */
+ private RegionSegmentInformation regionInfo;
+
+ /** Text region segment flags, 7.4.3.1.1 */
+ private short sbrTemplate;
+ private short sbdsOffset; /* 6.4.8 */
+ private short defaultPixel;
+ private CombinationOperator combinationOperator;
+ private short isTransposed;
+ private short referenceCorner;
+ private short logSBStrips;
+ private boolean useRefinement;
+ private boolean isHuffmanEncoded;
+
+ /** Text region segment Huffman flags, 7.4.3.1.2 */
+ private short sbHuffRSize;
+ private short sbHuffRDY;
+ private short sbHuffRDX;
+ private short sbHuffRDHeight;
+ private short sbHuffRDWidth;
+ private short sbHuffDT;
+ private short sbHuffDS;
+ private short sbHuffFS;
+
+ /** Text region refinement AT flags, 7.4.3.1.3 */
+ private short sbrATX[];
+ private short sbrATY[];
+
+ /** Number of symbol instances, 7.4.3.1.4 */
+ private long amountOfSymbolInstances;
+
+ /** Further parameters */
+ private long currentS;
+ private int sbStrips;
+ private int amountOfSymbols;
+
+ private Bitmap regionBitmap;
+ private ArrayList<Bitmap> symbols = new ArrayList<Bitmap>();
+
+ private ArithmeticDecoder arithmeticDecoder;
+ private ArithmeticIntegerDecoder integerDecoder;
+ private GenericRefinementRegion genericRefinementRegion;
+
+ private CX cxIADT;
+ private CX cxIAFS;
+ private CX cxIADS;
+ private CX cxIAIT;
+ private CX cxIARI;
+ private CX cxIARDW;
+ private CX cxIARDH;
+ private CX cxIAID;
+ private CX cxIARDX;
+ private CX cxIARDY;
+ private CX cx;
+
+ /** codeTable including a code to each symbol used in that region */
+ private int symbolCodeLength;
+ private FixedSizeTable symbolCodeTable;
+ private SegmentHeader segmentHeader;
+
+ /** User-supplied tables * */
+ private HuffmanTable fsTable;
+ private HuffmanTable dsTable;
+ private HuffmanTable table;
+ private HuffmanTable rdwTable;
+ private HuffmanTable rdhTable;
+ private HuffmanTable rdxTable;
+ private HuffmanTable rdyTable;
+ private HuffmanTable rSizeTable;
+
+ public TextRegion() {
+ }
+
+ public TextRegion(SubInputStream subInputStream, SegmentHeader segmentHeader) {
+ this.subInputStream = subInputStream;
+ this.regionInfo = new RegionSegmentInformation(subInputStream);
+ this.segmentHeader = segmentHeader;
+ }
+
+ private void parseHeader() throws IOException, InvalidHeaderValueException, IntegerMaxValueException {
+
+ regionInfo.parseHeader();
+
+ readRegionFlags();
+
+ if (isHuffmanEncoded) {
+ readHuffmanFlags();
+ }
+
+ readUseRefinement();
+
+ readAmountOfSymbolInstances();
+
+ /* 7.4.3.1.7 */
+ getSymbols();
+
+ computeSymbolCodeLength();
+
+ this.checkInput();
+ }
+
+ private void readRegionFlags() throws IOException {
+ /* Bit 15 */
+ sbrTemplate = (short) subInputStream.readBit();
+
+ /* Bit 10-14 */
+ sbdsOffset = (short) (subInputStream.readBits(5));
+ if (sbdsOffset > 0x0f) {
+ sbdsOffset -= 0x20;
+ }
+
+ /* Bit 9 */
+ defaultPixel = (short) subInputStream.readBit();
+
+ /* Bit 7-8 */
+ combinationOperator = CombinationOperator.translateOperatorCodeToEnum((short) (subInputStream.readBits(2) & 0x3));
+
+ /* Bit 6 */
+ isTransposed = (short) subInputStream.readBit();
+
+ /* Bit 4-5 */
+ referenceCorner = (short) (subInputStream.readBits(2) & 0x3);
+
+ /* Bit 2-3 */
+ logSBStrips = (short) (subInputStream.readBits(2) & 0x3);
+ sbStrips = (1 << logSBStrips);
+
+ /* Bit 1 */
+ if (subInputStream.readBit() == 1) {
+ useRefinement = true;
+ }
+
+ /* Bit 0 */
+ if (subInputStream.readBit() == 1) {
+ isHuffmanEncoded = true;
+ }
+ }
+
+ private void readHuffmanFlags() throws IOException {
+ /* Bit 15 */
+ subInputStream.readBit(); // Dirty read...
+
+ /* Bit 14 */
+ sbHuffRSize = (short) subInputStream.readBit();
+
+ /* Bit 12-13 */
+ sbHuffRDY = (short) (subInputStream.readBits(2) & 0xf);
+
+ /* Bit 10-11 */
+ sbHuffRDX = (short) (subInputStream.readBits(2) & 0xf);
+
+ /* Bit 8-9 */
+ sbHuffRDHeight = (short) (subInputStream.readBits(2) & 0xf);
+
+ /* Bit 6-7 */
+ sbHuffRDWidth = (short) (subInputStream.readBits(2) & 0xf);
+
+ /* Bit 4-5 */
+ sbHuffDT = (short) (subInputStream.readBits(2) & 0xf);
+
+ /* Bit 2-3 */
+ sbHuffDS = (short) (subInputStream.readBits(2) & 0xf);
+
+ /* Bit 0-1 */
+ sbHuffFS = (short) (subInputStream.readBits(2) & 0xf);
+ }
+
+ private void readUseRefinement() throws IOException {
+ if (useRefinement && sbrTemplate == 0) {
+ sbrATX = new short[2];
+ sbrATY = new short[2];
+
+ /* Byte 0 */
+ sbrATX[0] = subInputStream.readByte();
+
+ /* Byte 1 */
+ sbrATY[0] = subInputStream.readByte();
+
+ /* Byte 2 */
+ sbrATX[1] = subInputStream.readByte();
+
+ /* Byte 3 */
+ sbrATY[1] = subInputStream.readByte();
+ }
+ }
+
+ private void readAmountOfSymbolInstances() throws IOException {
+ amountOfSymbolInstances = subInputStream.readBits(32) & 0xffffffff;
+ }
+
+ private void getSymbols() throws IOException, IntegerMaxValueException, InvalidHeaderValueException {
+ if (segmentHeader.getRtSegments() != null) {
+ initSymbols();
+ }
+ }
+
+ private void computeSymbolCodeLength() throws IOException {
+ if (isHuffmanEncoded) {
+ symbolIDCodeLengths();
+ } else {
+ symbolCodeLength = (int) Math.ceil((Math.log(amountOfSymbols) / Math.log(2)));
+ }
+ }
+
+ private void checkInput() throws InvalidHeaderValueException {
+
+ if (!useRefinement) {
+ if (sbrTemplate != 0) {
+ log.info("sbrTemplate should be 0");
+ sbrTemplate = 0;
+ }
+ }
+
+ if (sbHuffFS == 2 || sbHuffRDWidth == 2 || sbHuffRDHeight == 2 || sbHuffRDX == 2 || sbHuffRDY == 2) {
+ throw new InvalidHeaderValueException("Huffman flag value of text region segment is not permitted");
+ }
+
+ if (!useRefinement) {
+ if (sbHuffRSize != 0) {
+ log.info("sbHuffRSize should be 0");
+ sbHuffRSize = 0;
+ }
+ if (sbHuffRDY != 0) {
+ log.info("sbHuffRDY should be 0");
+ sbHuffRDY = 0;
+ }
+ if (sbHuffRDX != 0) {
+ log.info("sbHuffRDX should be 0");
+ sbHuffRDX = 0;
+ }
+ if (sbHuffRDWidth != 0) {
+ log.info("sbHuffRDWidth should be 0");
+ sbHuffRDWidth = 0;
+ }
+ if (sbHuffRDHeight != 0) {
+ log.info("sbHuffRDHeight should be 0");
+ sbHuffRDHeight = 0;
+ }
+ }
+ }
+
+ public Bitmap getRegionBitmap() throws IOException, IntegerMaxValueException, InvalidHeaderValueException {
+
+ if (!isHuffmanEncoded) {
+ setCodingStatistics();
+ }
+
+ createRegionBitmap();
+ decodeSymbolInstances();
+
+ /* 4) */
+ return regionBitmap;
+ }
+
+ private void setCodingStatistics() throws IOException {
+ if (cxIADT == null)
+ cxIADT = new CX(512, 1);
+
+ if (cxIAFS == null)
+ cxIAFS = new CX(512, 1);
+
+ if (cxIADS == null)
+ cxIADS = new CX(512, 1);
+
+ if (cxIAIT == null)
+ cxIAIT = new CX(512, 1);
+
+ if (cxIARI == null)
+ cxIARI = new CX(512, 1);
+
+ if (cxIARDW == null)
+ cxIARDW = new CX(512, 1);
+
+ if (cxIARDH == null)
+ cxIARDH = new CX(512, 1);
+
+ if (cxIAID == null)
+ cxIAID = new CX(1 << symbolCodeLength, 1);
+
+ if (cxIARDX == null)
+ cxIARDX = new CX(512, 1);
+
+ if (cxIARDY == null)
+ cxIARDY = new CX(512, 1);
+
+ if (arithmeticDecoder == null)
+ arithmeticDecoder = new ArithmeticDecoder(subInputStream);
+
+ if (integerDecoder == null)
+ integerDecoder = new ArithmeticIntegerDecoder(arithmeticDecoder);
+ }
+
+ private void createRegionBitmap() {
+
+ /* 6.4.5 */
+ final int width = regionInfo.getBitmapWidth();
+ final int height = regionInfo.getBitmapHeight();
+ regionBitmap = new Bitmap(width, height);
+
+ /* 1) */
+ if (defaultPixel != 0) {
+ Arrays.fill(regionBitmap.getByteArray(), (byte) 0xff);
+ }
+ }
+
+ private final long decodeStripT() throws IOException, InvalidHeaderValueException {
+
+ long stripT = 0;
+ /* 2) */
+ if (isHuffmanEncoded) {
+ /* 6.4.6 */
+ if (sbHuffDT == 3) {
+ // TODO test user-specified table
+ if (table == null) {
+ int dtNr = 0;
+
+ if (sbHuffFS == 3) {
+ dtNr++;
+ }
+
+ if (sbHuffDS == 3) {
+ dtNr++;
+ }
+
+ table = getUserTable(dtNr);
+ }
+ stripT = table.decode(subInputStream);
+ } else {
+ stripT = StandardTables.getTable(11 + sbHuffDT).decode(subInputStream);
+ }
+ } else {
+ stripT = integerDecoder.decode(cxIADT);
+ }
+
+ return stripT * -(sbStrips);
+ }
+
+ private void decodeSymbolInstances() throws IOException, InvalidHeaderValueException, IntegerMaxValueException {
+
+ long stripT = decodeStripT();
+
+ /* Last two sentences of 6.4.5 2) */
+ long firstS = 0;
+ int instanceCounter = 0;
+
+ /* 6.4.5 3 a) */
+ while (instanceCounter < amountOfSymbolInstances) {
+
+ final long dT = decodeDT();
+ stripT += dT;
+ long dfS = 0;
+
+ /* 3 c) symbol instances in the strip */
+ boolean first = true;
+ currentS = 0;
+
+ // do until OOB
+ for (;;) {
+ /* 3 c) i) - first symbol instance in the strip */
+ if (first) {
+ /* 6.4.7 */
+ dfS = decodeDfS();
+ firstS += dfS;
+ currentS = firstS;
+ first = false;
+ /* 3 c) ii) - the remaining symbol instances in the strip */
+ } else {
+ /* 6.4.8 */
+ final long idS = decodeIdS();
+ /*
+ * If result is OOB, then all the symbol instances in this strip have been decoded;
+ * proceed to step 3 d) respectively 3 b)
+ */
+ if (idS == Long.MAX_VALUE)
+ break;
+
+ currentS += (idS + sbdsOffset);
+ }
+
+ /* 3 c) iii) */
+ final long currentT = decodeCurrentT();
+ final long t = stripT + currentT;
+
+ /* 3 c) iv) */
+ final long id = decodeID();
+
+ /* 3 c) v) */
+ final long r = decodeRI();
+ /* 6.4.11 */
+ final Bitmap ib = decodeIb(r, id);
+
+ /* vi) */
+ blit(ib, t);
+
+ instanceCounter++;
+ }
+ }
+ }
+
+ private final long decodeDT() throws IOException {
+ /* 3) b) */
+ /* 6.4.6 */
+ long dT;
+ if (isHuffmanEncoded) {
+ if (sbHuffDT == 3) {
+ dT = table.decode(subInputStream);
+ } else {
+ dT = StandardTables.getTable(11 + sbHuffDT).decode(subInputStream);
+ }
+ } else {
+ dT = integerDecoder.decode(cxIADT);
+ }
+
+ return (dT * sbStrips);
+ }
+
+ private final long decodeDfS() throws IOException, InvalidHeaderValueException {
+ if (isHuffmanEncoded) {
+ if (sbHuffFS == 3) {
+ if (fsTable == null) {
+ fsTable = getUserTable(0);
+ }
+ return fsTable.decode(subInputStream);
+ } else {
+ return StandardTables.getTable(6 + sbHuffFS).decode(subInputStream);
+ }
+ } else {
+ return integerDecoder.decode(cxIAFS);
+ }
+ }
+
+ private final long decodeIdS() throws IOException, InvalidHeaderValueException {
+ if (isHuffmanEncoded) {
+ if (sbHuffDS == 3) {
+ // TODO test user-specified table
+ if (dsTable == null) {
+ int dsNr = 0;
+ if (sbHuffFS == 3) {
+ dsNr++;
+ }
+
+ dsTable = getUserTable(dsNr);
+ }
+ return dsTable.decode(subInputStream);
+
+ } else {
+ return StandardTables.getTable(8 + sbHuffDS).decode(subInputStream);
+ }
+ } else {
+ return integerDecoder.decode(cxIADS);
+ }
+ }
+
+ private final long decodeCurrentT() throws IOException {
+ if (sbStrips != 1) {
+ if (isHuffmanEncoded) {
+ return subInputStream.readBits(logSBStrips);
+ } else {
+ return integerDecoder.decode(cxIAIT);
+ }
+ }
+
+ return 0;
+ }
+
+ private final long decodeID() throws IOException {
+ if (isHuffmanEncoded) {
+ if (symbolCodeTable == null) {
+ return subInputStream.readBits(symbolCodeLength);
+ }
+
+ return symbolCodeTable.decode(subInputStream);
+ } else {
+ return integerDecoder.decodeIAID(cxIAID, symbolCodeLength);
+ }
+ }
+
+ private final long decodeRI() throws IOException {
+ if (useRefinement) {
+ if (isHuffmanEncoded) {
+ return subInputStream.readBit();
+ } else {
+ return integerDecoder.decode(cxIARI);
+ }
+ }
+ return 0;
+ }
+
+ private final Bitmap decodeIb(long r, long id) throws IOException, InvalidHeaderValueException,
+ IntegerMaxValueException {
+ Bitmap ib;
+
+ if (r == 0) {
+ ib = symbols.get((int) id);
+ } else {
+ /* 1) - 4) */
+ final long rdw = decodeRdw();
+ final long rdh = decodeRdh();
+ final long rdx = decodeRdx();
+ final long rdy = decodeRdy();
+
+ /* 5) */
+ /* long symInRefSize = 0; */
+ if (isHuffmanEncoded) {
+ /* symInRefSize = */decodeSymInRefSize();
+ subInputStream.skipBits();
+ }
+
+ /* 6) */
+ final Bitmap ibo = symbols.get((int) id);
+ final int wo = ibo.getWidth();
+ final int ho = ibo.getHeight();
+
+ final int genericRegionReferenceDX = (int) ((rdw >> 1) + rdx);
+ final int genericRegionReferenceDY = (int) ((rdh >> 1) + rdy);
+
+ if (genericRefinementRegion == null) {
+ genericRefinementRegion = new GenericRefinementRegion(subInputStream);
+ }
+
+ genericRefinementRegion.setParameters(cx, arithmeticDecoder, sbrTemplate, (int) (wo + rdw), (int) (ho + rdh),
+ ibo, genericRegionReferenceDX, genericRegionReferenceDY, false, sbrATX, sbrATY);
+
+ ib = genericRefinementRegion.getRegionBitmap();
+
+ /* 7 */
+ if (isHuffmanEncoded) {
+ subInputStream.skipBits();
+ }
+ }
+ return ib;
+ }
+
+ private final long decodeRdw() throws IOException, InvalidHeaderValueException {
+ if (isHuffmanEncoded) {
+ if (sbHuffRDWidth == 3) {
+ // TODO test user-specified table
+ if (rdwTable == null) {
+ int rdwNr = 0;
+ if (sbHuffFS == 3) {
+ rdwNr++;
+ }
+
+ if (sbHuffDS == 3) {
+ rdwNr++;
+ }
+
+ if (sbHuffDT == 3) {
+ rdwNr++;
+ }
+
+ rdwTable = getUserTable(rdwNr);
+ }
+ return rdwTable.decode(subInputStream);
+
+ } else {
+ return StandardTables.getTable(14 + sbHuffRDWidth).decode(subInputStream);
+ }
+ } else {
+ return integerDecoder.decode(cxIARDW);
+ }
+ }
+
+ private final long decodeRdh() throws IOException, InvalidHeaderValueException {
+ if (isHuffmanEncoded) {
+ if (sbHuffRDHeight == 3) {
+ if (rdhTable == null) {
+ int rdhNr = 0;
+
+ if (sbHuffFS == 3) {
+ rdhNr++;
+ }
+
+ if (sbHuffDS == 3) {
+ rdhNr++;
+ }
+
+ if (sbHuffDT == 3) {
+ rdhNr++;
+ }
+
+ if (sbHuffRDWidth == 3) {
+ rdhNr++;
+ }
+
+ rdhTable = getUserTable(rdhNr);
+ }
+ return rdhTable.decode(subInputStream);
+ } else {
+ return StandardTables.getTable(14 + sbHuffRDHeight).decode(subInputStream);
+ }
+ } else {
+ return integerDecoder.decode(cxIARDH);
+ }
+ }
+
+ private final long decodeRdx() throws IOException, InvalidHeaderValueException {
+ if (isHuffmanEncoded) {
+ if (sbHuffRDX == 3) {
+ if (rdxTable == null) {
+ int rdxNr = 0;
+ if (sbHuffFS == 3) {
+ rdxNr++;
+ }
+
+ if (sbHuffDS == 3) {
+ rdxNr++;
+ }
+
+ if (sbHuffDT == 3) {
+ rdxNr++;
+ }
+
+ if (sbHuffRDWidth == 3) {
+ rdxNr++;
+ }
+
+ if (sbHuffRDHeight == 3) {
+ rdxNr++;
+ }
+
+ rdxTable = getUserTable(rdxNr);
+ }
+ return rdxTable.decode(subInputStream);
+ } else {
+ return StandardTables.getTable(14 + sbHuffRDX).decode(subInputStream);
+ }
+ } else {
+ return integerDecoder.decode(cxIARDX);
+ }
+ }
+
+ private final long decodeRdy() throws IOException, InvalidHeaderValueException {
+ if (isHuffmanEncoded) {
+ if (sbHuffRDY == 3) {
+ if (rdyTable == null) {
+ int rdyNr = 0;
+ if (sbHuffFS == 3) {
+ rdyNr++;
+ }
+
+ if (sbHuffDS == 3) {
+ rdyNr++;
+ }
+
+ if (sbHuffDT == 3) {
+ rdyNr++;
+ }
+
+ if (sbHuffRDWidth == 3) {
+ rdyNr++;
+ }
+
+ if (sbHuffRDHeight == 3) {
+ rdyNr++;
+ }
+
+ if (sbHuffRDX == 3) {
+ rdyNr++;
+ }
+
+ rdyTable = getUserTable(rdyNr);
+ }
+ return rdyTable.decode(subInputStream);
+ } else {
+ return StandardTables.getTable(14 + sbHuffRDY).decode(subInputStream);
+ }
+ } else {
+ return integerDecoder.decode(cxIARDY);
+ }
+ }
+
+ private final long decodeSymInRefSize() throws IOException, InvalidHeaderValueException {
+ if (sbHuffRSize == 0) {
+ return StandardTables.getTable(1).decode(subInputStream);
+ } else {
+ if (rSizeTable == null) {
+ int rSizeNr = 0;
+
+ if (sbHuffFS == 3) {
+ rSizeNr++;
+ }
+
+ if (sbHuffDS == 3) {
+ rSizeNr++;
+ }
+
+ if (sbHuffDT == 3) {
+ rSizeNr++;
+ }
+
+ if (sbHuffRDWidth == 3) {
+ rSizeNr++;
+ }
+
+ if (sbHuffRDHeight == 3) {
+ rSizeNr++;
+ }
+
+ if (sbHuffRDX == 3) {
+ rSizeNr++;
+ }
+
+ if (sbHuffRDY == 3) {
+ rSizeNr++;
+ }
+
+ rSizeTable = getUserTable(rSizeNr);
+ }
+ return rSizeTable.decode(subInputStream);
+ }
+
+ }
+
+ private final void blit(Bitmap ib, long t) {
+ if (isTransposed == 0 && (referenceCorner == 2 || referenceCorner == 3)) {
+ currentS += ib.getWidth() - 1;
+ } else if (isTransposed == 1 && (referenceCorner == 0 || referenceCorner == 2)) {
+ currentS += ib.getHeight() - 1;
+ }
+
+ /* vii) */
+ long s = currentS;
+
+ /* viii) */
+ if (isTransposed == 1) {
+ final long swap = t;
+ t = s;
+ s = swap;
+ }
+
+ if (referenceCorner != 1) {
+ if (referenceCorner == 0) {
+ // BL
+ t -= ib.getHeight() - 1;
+ } else if (referenceCorner == 2) {
+ // BR
+ t -= ib.getHeight() - 1;
+ s -= ib.getWidth() - 1;
+ } else if (referenceCorner == 3) {
+ // TR
+ s -= ib.getWidth() - 1;
+ }
+ }
+
+ Bitmaps.blit(ib, regionBitmap, (int) s, (int) t, combinationOperator);
+
+ /* x) */
+ if (isTransposed == 0 && (referenceCorner == 0 || referenceCorner == 1)) {
+ currentS += ib.getWidth() - 1;
+ }
+
+ if (isTransposed == 1 && (referenceCorner == 1 || referenceCorner == 3)) {
+ currentS += ib.getHeight() - 1;
+ }
+
+ }
+
+ private void initSymbols() throws IOException, IntegerMaxValueException, InvalidHeaderValueException {
+ for (final SegmentHeader segment : segmentHeader.getRtSegments()) {
+ if (segment.getSegmentType() == 0) {
+ final SymbolDictionary sd = (SymbolDictionary) segment.getSegmentData();
+
+ sd.cxIAID = cxIAID;
+ symbols.addAll(sd.getDictionary());
+ }
+ }
+ amountOfSymbols = symbols.size();
+ }
+
+ private HuffmanTable getUserTable(final int tablePosition) throws InvalidHeaderValueException, IOException {
+ int tableCounter = 0;
+
+ for (final SegmentHeader referredToSegmentHeader : segmentHeader.getRtSegments()) {
+ if (referredToSegmentHeader.getSegmentType() == 53) {
+ if (tableCounter == tablePosition) {
+ final Table t = (Table) referredToSegmentHeader.getSegmentData();
+ return new EncodedTable(t);
+ } else {
+ tableCounter++;
+ }
+ }
+ }
+ return null;
+ }
+
+ private void symbolIDCodeLengths() throws IOException {
+ /* 1) - 2) */
+ final List<Code> runCodeTable = new ArrayList<Code>();
+
+ for (int i = 0; i < 35; i++) {
+ final int prefLen = (int) (subInputStream.readBits(4) & 0xf);
+ if (prefLen > 0) {
+ runCodeTable.add(new Code(prefLen, 0, i, false));
+ }
+ }
+
+ if (JBIG2ImageReader.DEBUG)
+ log.debug(HuffmanTable.codeTableToString(runCodeTable));
+
+ HuffmanTable ht = new FixedSizeTable(runCodeTable);
+
+ /* 3) - 5) */
+ long previousCodeLength = 0;
+
+ int counter = 0;
+ final List<Code> sbSymCodes = new ArrayList<Code>();
+ while (counter < amountOfSymbols) {
+ final long code = ht.decode(subInputStream);
+ if (code < 32) {
+ if (code > 0) {
+ sbSymCodes.add(new Code((int) code, 0, counter, false));
+ }
+
+ previousCodeLength = code;
+ counter++;
+ } else {
+
+ long runLength = 0;
+ long currCodeLength = 0;
+ if (code == 32) {
+ runLength = 3 + subInputStream.readBits(2);
+ if (counter > 0) {
+ currCodeLength = previousCodeLength;
+ }
+ } else if (code == 33) {
+ runLength = 3 + subInputStream.readBits(3);
+ } else if (code == 34) {
+ runLength = 11 + subInputStream.readBits(7);
+ }
+
+ for (int j = 0; j < runLength; j++) {
+ if (currCodeLength > 0) {
+ sbSymCodes.add(new Code((int) currCodeLength, 0, counter, false));
+ }
+ counter++;
+ }
+ }
+ }
+
+ /* 6) - Skip over remaining bits in the last Byte read */
+ subInputStream.skipBits();
+
+ /* 7) */
+ symbolCodeTable = new FixedSizeTable(sbSymCodes);
+
+ }
+
+ public void init(SegmentHeader header, SubInputStream sis) throws InvalidHeaderValueException,
+ IntegerMaxValueException, IOException {
+ this.segmentHeader = header;
+ this.subInputStream = sis;
+ this.regionInfo = new RegionSegmentInformation(subInputStream);
+ parseHeader();
+ }
+
+ protected void setContexts(CX cx, CX cxIADT, CX cxIAFS, CX cxIADS, CX cxIAIT, CX cxIAID, CX cxIARDW, CX cxIARDH,
+ CX cxIARDX, CX cxIARDY) {
+ this.cx = cx;
+
+ this.cxIADT = cxIADT;
+ this.cxIAFS = cxIAFS;
+ this.cxIADS = cxIADS;
+ this.cxIAIT = cxIAIT;
+
+ this.cxIAID = cxIAID;
+
+ this.cxIARDW = cxIARDW;
+ this.cxIARDH = cxIARDH;
+ this.cxIARDX = cxIARDX;
+ this.cxIARDY = cxIARDY;
+ }
+
+ protected void setParameters(ArithmeticDecoder arithmeticDecoder, ArithmeticIntegerDecoder iDecoder,
+ boolean isHuffmanEncoded, boolean sbRefine, int sbw, int sbh, long sbNumInstances, int sbStrips, int sbNumSyms,
+ short sbDefaultPixel, short sbCombinationOperator, short transposed, short refCorner, short sbdsOffset,
+ short sbHuffFS, short sbHuffDS, short sbHuffDT, short sbHuffRDWidth, short sbHuffRDHeight, short sbHuffRDX,
+ short sbHuffRDY, short sbHuffRSize, short sbrTemplate, short sbrATX[], short sbrATY[], ArrayList<Bitmap> sbSyms,
+ int sbSymCodeLen) {
+
+ this.arithmeticDecoder = arithmeticDecoder;
+
+ this.integerDecoder = iDecoder;
+
+ this.isHuffmanEncoded = isHuffmanEncoded;
+ this.useRefinement = sbRefine;
+
+ this.regionInfo.setBitmapWidth(sbw);
+ this.regionInfo.setBitmapHeight(sbh);
+
+ this.amountOfSymbolInstances = sbNumInstances;
+ this.sbStrips = sbStrips;
+ this.amountOfSymbols = sbNumSyms;
+ this.defaultPixel = sbDefaultPixel;
+ this.combinationOperator = CombinationOperator.translateOperatorCodeToEnum(sbCombinationOperator);
+ this.isTransposed = transposed;
+ this.referenceCorner = refCorner;
+ this.sbdsOffset = sbdsOffset;
+
+ this.sbHuffFS = sbHuffFS;
+ this.sbHuffDS = sbHuffDS;
+ this.sbHuffDT = sbHuffDT;
+ this.sbHuffRDWidth = sbHuffRDWidth;
+ this.sbHuffRDHeight = sbHuffRDHeight;
+ this.sbHuffRDX = sbHuffRDX;
+ this.sbHuffRDY = sbHuffRDY;
+ this.sbHuffRSize = sbHuffRSize;
+
+ this.sbrTemplate = sbrTemplate;
+ this.sbrATX = sbrATX;
+ this.sbrATY = sbrATY;
+
+ this.symbols = sbSyms;
+ this.symbolCodeLength = sbSymCodeLen;
+ }
+
+ public RegionSegmentInformation getRegionInfo() {
+ return regionInfo;
+ }
+}
http://git-wip-us.apache.org/repos/asf/pdfbox-jbig2/blob/4619d28b/src/main/java/org/apache/pdfbox/jbig2/util/CombinationOperator.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/pdfbox/jbig2/util/CombinationOperator.java b/src/main/java/org/apache/pdfbox/jbig2/util/CombinationOperator.java
new file mode 100644
index 0000000..1d40717
--- /dev/null
+++ b/src/main/java/org/apache/pdfbox/jbig2/util/CombinationOperator.java
@@ -0,0 +1,40 @@
+/**
+ * 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.util;
+
+/**
+ * This enumeration keeps the available logical operator defined in the JBIG2 ISO standard.
+ */
+public enum CombinationOperator {
+ OR, AND, XOR, XNOR, REPLACE;
+
+ public static CombinationOperator translateOperatorCodeToEnum(short combinationOperatorCode) {
+ switch (combinationOperatorCode){
+ case 0 :
+ return OR;
+ case 1 :
+ return AND;
+ case 2 :
+ return XOR;
+ case 3 :
+ return XNOR;
+ default :
+ return REPLACE;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/pdfbox-jbig2/blob/4619d28b/src/main/java/org/apache/pdfbox/jbig2/util/DictionaryViewer.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/pdfbox/jbig2/util/DictionaryViewer.java b/src/main/java/org/apache/pdfbox/jbig2/util/DictionaryViewer.java
new file mode 100644
index 0000000..2659082
--- /dev/null
+++ b/src/main/java/org/apache/pdfbox/jbig2/util/DictionaryViewer.java
@@ -0,0 +1,59 @@
+/**
+ * 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.util;
+
+import java.util.List;
+
+import org.apache.pdfbox.jbig2.Bitmap;
+import org.apache.pdfbox.jbig2.TestImage;
+import org.apache.pdfbox.jbig2.image.Bitmaps;
+
+/**
+ * This class is for debug purpose only. The {@code DictionaryViewer} is able to show a single
+ * bitmap or all symbol bitmaps.
+ */
+class DictionaryViewer {
+
+ public static void show(Bitmap b) {
+ new TestImage(Bitmaps.asBufferedImage(b));
+ }
+
+ public static void show(List<Bitmap> symbols) {
+ int width = 0;
+ int height = 0;
+
+ for (Bitmap b : symbols) {
+ width += b.getWidth();
+
+ if (b.getHeight() > height) {
+ height = b.getHeight();
+ }
+ }
+
+ Bitmap result = new Bitmap(width, height);
+
+ int xOffset = 0;
+
+ for (Bitmap b : symbols) {
+ Bitmaps.blit(b, result, xOffset, 0, CombinationOperator.REPLACE);
+ xOffset += b.getWidth();
+ }
+
+ new TestImage(Bitmaps.asBufferedImage(result));
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/pdfbox-jbig2/blob/4619d28b/src/main/java/org/apache/pdfbox/jbig2/util/ServiceLookup.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/pdfbox/jbig2/util/ServiceLookup.java b/src/main/java/org/apache/pdfbox/jbig2/util/ServiceLookup.java
new file mode 100644
index 0000000..0c3f78e
--- /dev/null
+++ b/src/main/java/org/apache/pdfbox/jbig2/util/ServiceLookup.java
@@ -0,0 +1,43 @@
+/**
+ * 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.util;
+
+import java.util.Iterator;
+import java.util.ServiceLoader;
+
+public class ServiceLookup<B> {
+
+ public Iterator<B> getServices(Class<B> cls) {
+ return getServices(cls, null);
+ }
+
+ public Iterator<B> getServices(Class<B> cls, ClassLoader clsLoader) {
+ Iterator<B> services = ServiceLoader.load(cls).iterator();
+
+ if (!services.hasNext()) {
+ services = ServiceLoader.load(cls, cls.getClass().getClassLoader()).iterator();
+ }
+
+ if (!services.hasNext() && clsLoader != null) {
+ services = ServiceLoader.load(cls, clsLoader).iterator();
+ }
+
+ return services;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/pdfbox-jbig2/blob/4619d28b/src/main/java/org/apache/pdfbox/jbig2/util/Utils.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/pdfbox/jbig2/util/Utils.java b/src/main/java/org/apache/pdfbox/jbig2/util/Utils.java
new file mode 100644
index 0000000..ae2ae7a
--- /dev/null
+++ b/src/main/java/org/apache/pdfbox/jbig2/util/Utils.java
@@ -0,0 +1,101 @@
+/**
+ * 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.util;
+
+import java.awt.Rectangle;
+import java.awt.geom.Rectangle2D;
+
+public class Utils {
+
+ /**
+ * Create a rectangle with the same area as the given input rectangle but with all of its edges
+ * snapped (rounded) to the integer grid. The resulting rectangle is guaranteed to cover
+ * <em>all</em> of the input rectangle's area, so that
+ * <code>enlargeToGrid(r).contains(r) == true</code> holds. This can be depicted as the edges
+ * being stretched in an outward direction.
+ *
+ * @param r
+ * @return
+ */
+ public static Rectangle enlargeRectToGrid(Rectangle2D r) {
+ final int x0 = floor(r.getMinX());
+ final int y0 = floor(r.getMinY());
+ final int x1 = ceil(r.getMaxX());
+ final int y1 = ceil(r.getMaxY());
+ return new Rectangle(x0, y0, x1 - x0, y1 - y0);
+ }
+
+ /**
+ * Return a new rectangle which covers the area of the given rectangle with an additional margin
+ * on the sides.
+ *
+ * @param r
+ * @param marginX
+ */
+ public static Rectangle2D dilateRect(Rectangle2D r, double marginX, double marginY) {
+ return new Rectangle2D.Double(r.getX() - marginX, r.getY() - marginY, r.getWidth() + 2 * marginX, r.getHeight() + 2
+ * marginY);
+ }
+
+ /**
+ * Clamp the value into the range [min..max].
+ *
+ * @param value
+ * @param min
+ * @param max
+ * @return the clamped value
+ */
+ public static double clamp(double value, double min, double max) {
+ return Math.min(max, Math.max(value, min));
+ }
+
+ private static final int BIG_ENOUGH_INT = 16 * 1024;
+ private static final double BIG_ENOUGH_FLOOR = BIG_ENOUGH_INT;
+ private static final double BIG_ENOUGH_ROUND = BIG_ENOUGH_INT + 0.5;
+
+ /**
+ * A fast implementation of {@link Math#floor(double)}.
+ *
+ * @param x the argument
+ * @return
+ */
+ public static int floor(double x) {
+ return (int) (x + BIG_ENOUGH_FLOOR) - BIG_ENOUGH_INT;
+ }
+
+ /**
+ * A fast implementation of {@link Math#round(double)}.
+ *
+ * @param x the argument
+ * @return
+ */
+ public static int round(double x) {
+ return (int) (x + BIG_ENOUGH_ROUND) - BIG_ENOUGH_INT;
+ }
+
+ /**
+ * A fast implementation of {@link Math#ceil(double)}.
+ *
+ * @param x the argument
+ * @return
+ */
+ public static int ceil(double x) {
+ return BIG_ENOUGH_INT - (int) (BIG_ENOUGH_FLOOR - x);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/pdfbox-jbig2/blob/4619d28b/src/main/java/org/apache/pdfbox/jbig2/util/cache/Cache.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/pdfbox/jbig2/util/cache/Cache.java b/src/main/java/org/apache/pdfbox/jbig2/util/cache/Cache.java
new file mode 100644
index 0000000..41038cf
--- /dev/null
+++ b/src/main/java/org/apache/pdfbox/jbig2/util/cache/Cache.java
@@ -0,0 +1,47 @@
+/**
+ * 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.util.cache;
+
+public interface Cache {
+
+/**
+ *
+ * @param key
+ * @param value
+ * @param sizeEstimate
+ *
+ * @return the old object, that was replaced if present. Otherwise {@code null}.
+ */
+ Object put(Object key, Object value, int sizeEstimate);
+
+ Object get(Object key);
+
+ /**
+ * Removes all mappings from a map (optional operation).
+ *
+ * @throws UnsupportedOperationException if {@code clear()} is not supported by the map.
+ */
+ void clear();
+
+ /**
+ *
+ * @param key
+ * @return the removed object, if present. Otherwise {@code null}.
+ */
+ Object remove(Object key);
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/pdfbox-jbig2/blob/4619d28b/src/main/java/org/apache/pdfbox/jbig2/util/cache/CacheBridge.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/pdfbox/jbig2/util/cache/CacheBridge.java b/src/main/java/org/apache/pdfbox/jbig2/util/cache/CacheBridge.java
new file mode 100644
index 0000000..19338b1
--- /dev/null
+++ b/src/main/java/org/apache/pdfbox/jbig2/util/cache/CacheBridge.java
@@ -0,0 +1,24 @@
+/**
+ * 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.util.cache;
+
+public interface CacheBridge {
+
+ Cache getCache();
+
+}
http://git-wip-us.apache.org/repos/asf/pdfbox-jbig2/blob/4619d28b/src/main/java/org/apache/pdfbox/jbig2/util/cache/CacheFactory.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/pdfbox/jbig2/util/cache/CacheFactory.java b/src/main/java/org/apache/pdfbox/jbig2/util/cache/CacheFactory.java
new file mode 100644
index 0000000..718c04a
--- /dev/null
+++ b/src/main/java/org/apache/pdfbox/jbig2/util/cache/CacheFactory.java
@@ -0,0 +1,55 @@
+/**
+ * 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.util.cache;
+
+import java.util.Iterator;
+
+import org.apache.pdfbox.jbig2.util.ServiceLookup;
+
+/**
+ * Retrieves a {@link Cache} via registered {@link CacheBridge} through
+ * <code>META-INF/services</code> lookup.
+ */
+public class CacheFactory {
+
+ private static CacheBridge cacheBridge;
+
+ private static ClassLoader clsLoader;
+
+ public static Cache getCache(ClassLoader clsLoader) {
+ if (null == cacheBridge) {
+ final ServiceLookup<CacheBridge> serviceLookup = new ServiceLookup<CacheBridge>();
+ final Iterator<CacheBridge> cacheBridgeServices = serviceLookup.getServices(CacheBridge.class, clsLoader);
+
+ if (!cacheBridgeServices.hasNext()) {
+ throw new IllegalStateException("No implementation of " + CacheBridge.class
+ + " was avaliable using META-INF/services lookup");
+ }
+ cacheBridge = cacheBridgeServices.next();
+ }
+ return cacheBridge.getCache();
+ }
+
+ public static Cache getCache() {
+ return getCache(clsLoader != null ? clsLoader : CacheBridge.class.getClassLoader());
+ }
+
+ public static void setClassLoader(ClassLoader clsLoader) {
+ CacheFactory.clsLoader = clsLoader;
+ }
+}
http://git-wip-us.apache.org/repos/asf/pdfbox-jbig2/blob/4619d28b/src/main/java/org/apache/pdfbox/jbig2/util/cache/SoftReferenceCache.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/pdfbox/jbig2/util/cache/SoftReferenceCache.java b/src/main/java/org/apache/pdfbox/jbig2/util/cache/SoftReferenceCache.java
new file mode 100644
index 0000000..35a1407
--- /dev/null
+++ b/src/main/java/org/apache/pdfbox/jbig2/util/cache/SoftReferenceCache.java
@@ -0,0 +1,50 @@
+/**
+ * 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.util.cache;
+
+import java.lang.ref.SoftReference;
+import java.util.HashMap;
+
+public class SoftReferenceCache implements Cache {
+
+ private HashMap<Object, SoftReference<?>> cache = new HashMap<Object, SoftReference<?>>();
+
+ public Object put(Object key, Object value, int sizeEstimate) {
+ SoftReference<Object> softReference = new SoftReference<Object>(value);
+ SoftReference<?> oldValue = cache.put(key, softReference);
+ return getValueNullSafe(oldValue);
+ }
+
+ public Object get(Object key) {
+ SoftReference<?> softReference = cache.get(key);
+ return getValueNullSafe(softReference);
+ }
+
+ public void clear() {
+ cache.clear();
+ }
+
+ public Object remove(Object key) {
+ SoftReference<?> removedObj = cache.remove(key);
+ return getValueNullSafe(removedObj);
+ }
+
+ private Object getValueNullSafe(SoftReference<?> softReference) {
+ return softReference == null ? null : softReference.get();
+ }
+}
http://git-wip-us.apache.org/repos/asf/pdfbox-jbig2/blob/4619d28b/src/main/java/org/apache/pdfbox/jbig2/util/cache/SoftReferenceCacheBridge.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/pdfbox/jbig2/util/cache/SoftReferenceCacheBridge.java b/src/main/java/org/apache/pdfbox/jbig2/util/cache/SoftReferenceCacheBridge.java
new file mode 100644
index 0000000..59f039f
--- /dev/null
+++ b/src/main/java/org/apache/pdfbox/jbig2/util/cache/SoftReferenceCacheBridge.java
@@ -0,0 +1,28 @@
+/**
+ * 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.util.cache;
+
+public class SoftReferenceCacheBridge implements CacheBridge {
+
+ private static final SoftReferenceCache cache = new SoftReferenceCache();
+
+ public Cache getCache() {
+ return cache;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/pdfbox-jbig2/blob/4619d28b/src/main/java/org/apache/pdfbox/jbig2/util/log/JDKLogger.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/pdfbox/jbig2/util/log/JDKLogger.java b/src/main/java/org/apache/pdfbox/jbig2/util/log/JDKLogger.java
new file mode 100644
index 0000000..70f3e0e
--- /dev/null
+++ b/src/main/java/org/apache/pdfbox/jbig2/util/log/JDKLogger.java
@@ -0,0 +1,88 @@
+/**
+ * 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.util.log;
+
+import java.util.logging.Level;
+
+public class JDKLogger implements Logger {
+ final java.util.logging.Logger wrappedLogger;
+
+ public JDKLogger(java.util.logging.Logger logger) {
+ wrappedLogger = logger;
+ }
+
+ public void debug(String msg) {
+ wrappedLogger.log(Level.FINE, msg);
+ }
+
+ public void debug(String msg, Throwable t) {
+ wrappedLogger.log(Level.FINE, msg, t);
+ }
+
+ public void info(String msg) {
+ wrappedLogger.log(Level.INFO, msg);
+ }
+
+ public void info(String msg, Throwable t) {
+ wrappedLogger.log(Level.INFO, msg, t);
+ }
+
+ public void warn(String msg) {
+ wrappedLogger.log(Level.WARNING, msg);
+ }
+
+ public void warn(String msg, Throwable t) {
+ wrappedLogger.log(Level.WARNING, msg, t);
+ }
+
+ public void fatal(String msg) {
+ wrappedLogger.log(Level.SEVERE, msg);
+ }
+
+ public void fatal(String msg, Throwable t) {
+ wrappedLogger.log(Level.SEVERE, msg, t);
+ }
+
+ public void error(String msg) {
+ wrappedLogger.log(Level.SEVERE, msg);
+ }
+
+ public void error(String msg, Throwable t) {
+ wrappedLogger.log(Level.SEVERE, msg, t);
+ }
+
+ public boolean isDebugEnabled() {
+ return wrappedLogger.isLoggable(Level.FINE);
+ }
+
+ public boolean isInfoEnabled() {
+ return wrappedLogger.isLoggable(Level.INFO);
+ }
+
+ public boolean isWarnEnabled() {
+ return wrappedLogger.isLoggable(Level.WARNING);
+ }
+
+ public boolean isFatalEnabled() {
+ return wrappedLogger.isLoggable(Level.SEVERE);
+ }
+
+ public boolean isErrorEnabled() {
+ return wrappedLogger.isLoggable(Level.SEVERE);
+ }
+}
http://git-wip-us.apache.org/repos/asf/pdfbox-jbig2/blob/4619d28b/src/main/java/org/apache/pdfbox/jbig2/util/log/JDKLoggerBridge.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/pdfbox/jbig2/util/log/JDKLoggerBridge.java b/src/main/java/org/apache/pdfbox/jbig2/util/log/JDKLoggerBridge.java
new file mode 100644
index 0000000..bc82d9e
--- /dev/null
+++ b/src/main/java/org/apache/pdfbox/jbig2/util/log/JDKLoggerBridge.java
@@ -0,0 +1,26 @@
+/**
+ * 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.util.log;
+
+public class JDKLoggerBridge implements LoggerBridge {
+
+ public Logger getLogger(Class<?> classToBeLogged) {
+ return new JDKLogger(java.util.logging.Logger.getLogger(classToBeLogged.getName()));
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/pdfbox-jbig2/blob/4619d28b/src/main/java/org/apache/pdfbox/jbig2/util/log/Logger.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/pdfbox/jbig2/util/log/Logger.java b/src/main/java/org/apache/pdfbox/jbig2/util/log/Logger.java
new file mode 100644
index 0000000..941ea61
--- /dev/null
+++ b/src/main/java/org/apache/pdfbox/jbig2/util/log/Logger.java
@@ -0,0 +1,135 @@
+/**
+ * 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.util.log;
+
+public interface Logger {
+
+
+ /**
+ * Log a message at the DEBUG level.
+ *
+ * @param msg the message string to be logged
+ */
+ public void debug(String msg);
+
+ /**
+ * Log an exception ({@link Throwable}) at the DEBUG level with an accompanying message.
+ *
+ * @param msg the message accompanying the exception.
+ * @param t the exception ({@link Throwable}) to log.
+ */
+ public void debug(String msg, Throwable t);
+
+ /**
+ * Log a message at the INFO level.
+ *
+ * @param msg the message string to be logged
+ */
+ public void info(String msg);
+
+ /**
+ * Log an exception ({@link Throwable}) at the INFO level with an accompanying message.
+ *
+ * @param msg the message accompanying the exception
+ * @param t the exception ({@link Throwable}) to log
+ */
+ public void info(String msg, Throwable t);
+
+ /**
+ * Log a message at the WARN level.
+ *
+ * @param msg the message string to be logged
+ */
+ public void warn(String msg);
+
+ /**
+ * Log an exception ({@link Throwable}) at the WARN level with an accompanying message.
+ *
+ * @param msg the message accompanying the exception
+ * @param t the exception ({@link Throwable}) to log
+ */
+ public void warn(String msg, Throwable t);
+
+ /**
+ * Log a message at the WARN level.
+ *
+ * @param msg the message string to be logged
+ */
+ public void fatal(String msg);
+
+ /**
+ * Log an exception ({@link Throwable}) at the WARN level with an accompanying message.
+ *
+ * @param msg the message accompanying the exception
+ * @param t the exception ({@link Throwable}) to log
+ */
+ public void fatal(String msg, Throwable t);
+
+ /**
+ * Log a message at the ERROR level.
+ *
+ * @param msg the message string to be logged
+ */
+ public void error(String msg);
+
+ /**
+ * Log an exception ({@link Throwable}) at the ERROR level with an accompanying message.
+ *
+ * @param msg the message accompanying the exception
+ * @param t the exception ({@link Throwable}) to log
+ */
+ public void error(String msg, Throwable t);
+
+ /**
+ * Is the logger instance enabled for the DEBUG level?
+ *
+ * @return True if this Logger is enabled for the DEBUG level, false otherwise.
+ *
+ */
+ public boolean isDebugEnabled();
+
+ /**
+ * Is the logger instance enabled for the INFO level?
+ *
+ * @return True if this Logger is enabled for the INFO level, false otherwise.
+ */
+ public boolean isInfoEnabled();
+
+ /**
+ * Is the logger instance enabled for the WARN level?
+ *
+ * @return True if this Logger is enabled for the WARN level, false otherwise.
+ */
+ public boolean isWarnEnabled();
+
+ /**
+ * Is the logger instance enabled for the FATAL level?
+ *
+ * @return True if this Logger is enabled for the FATAL level, false otherwise.
+ */
+ public boolean isFatalEnabled();
+
+ /**
+ * Is the logger instance enabled for the ERROR level?
+ *
+ * @return True if this Logger is enabled for the ERROR level, false otherwise.
+ */
+ public boolean isErrorEnabled();
+
+
+}
http://git-wip-us.apache.org/repos/asf/pdfbox-jbig2/blob/4619d28b/src/main/java/org/apache/pdfbox/jbig2/util/log/LoggerBridge.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/pdfbox/jbig2/util/log/LoggerBridge.java b/src/main/java/org/apache/pdfbox/jbig2/util/log/LoggerBridge.java
new file mode 100644
index 0000000..6dd033c
--- /dev/null
+++ b/src/main/java/org/apache/pdfbox/jbig2/util/log/LoggerBridge.java
@@ -0,0 +1,24 @@
+/**
+ * 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.util.log;
+
+public interface LoggerBridge {
+
+ Logger getLogger(Class<?> clazz);
+
+}
http://git-wip-us.apache.org/repos/asf/pdfbox-jbig2/blob/4619d28b/src/main/java/org/apache/pdfbox/jbig2/util/log/LoggerFactory.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/pdfbox/jbig2/util/log/LoggerFactory.java b/src/main/java/org/apache/pdfbox/jbig2/util/log/LoggerFactory.java
new file mode 100644
index 0000000..2eea946
--- /dev/null
+++ b/src/main/java/org/apache/pdfbox/jbig2/util/log/LoggerFactory.java
@@ -0,0 +1,55 @@
+/**
+ * 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.util.log;
+
+import java.util.Iterator;
+
+import org.apache.pdfbox.jbig2.util.ServiceLookup;
+
+/**
+ * Retrieves a {@link Logger} via registered {@link LoggerBridge} through META-INF/services lookup.
+ */
+public class LoggerFactory {
+
+ private static LoggerBridge loggerBridge;
+
+ private static ClassLoader clsLoader;
+
+ public static Logger getLogger(Class<?> cls, ClassLoader clsLoader) {
+ if (null == loggerBridge) {
+ final ServiceLookup<LoggerBridge> serviceLookup = new ServiceLookup<LoggerBridge>();
+ final Iterator<LoggerBridge> loggerBridgeServices = serviceLookup.getServices(LoggerBridge.class, clsLoader);
+
+ if (!loggerBridgeServices.hasNext()) {
+ throw new IllegalStateException("No implementation of " + LoggerBridge.class
+ + " was avaliable using META-INF/services lookup");
+ }
+ loggerBridge = loggerBridgeServices.next();
+ }
+ return loggerBridge.getLogger(cls);
+ }
+
+ public static Logger getLogger(Class<?> cls) {
+ return getLogger(cls, clsLoader != null ? clsLoader : LoggerBridge.class.getClassLoader());
+ }
+
+ public static void setClassLoader(ClassLoader clsLoader) {
+ LoggerFactory.clsLoader = clsLoader;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/pdfbox-jbig2/blob/4619d28b/src/main/resources/META-INF/services/javax.imageio.spi.ImageReaderSpi
----------------------------------------------------------------------
diff --git a/src/main/resources/META-INF/services/javax.imageio.spi.ImageReaderSpi b/src/main/resources/META-INF/services/javax.imageio.spi.ImageReaderSpi
new file mode 100644
index 0000000..8f70796
--- /dev/null
+++ b/src/main/resources/META-INF/services/javax.imageio.spi.ImageReaderSpi
@@ -0,0 +1,18 @@
+#
+# 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.
+#
+
+org.apache.pdfbox.jbig2.JBIG2ImageReaderSpi
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/pdfbox-jbig2/blob/4619d28b/src/main/resources/META-INF/services/org.apache.pdfbox.jbig2.util.cache.CacheBridge
----------------------------------------------------------------------
diff --git a/src/main/resources/META-INF/services/org.apache.pdfbox.jbig2.util.cache.CacheBridge b/src/main/resources/META-INF/services/org.apache.pdfbox.jbig2.util.cache.CacheBridge
new file mode 100644
index 0000000..fa9ad12
--- /dev/null
+++ b/src/main/resources/META-INF/services/org.apache.pdfbox.jbig2.util.cache.CacheBridge
@@ -0,0 +1,18 @@
+#
+# 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.
+#
+
+org.apache.pdfbox.jbig2.util.cache.SoftReferenceCacheBridge
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/pdfbox-jbig2/blob/4619d28b/src/main/resources/META-INF/services/org.apache.pdfbox.jbig2.util.log.LoggerBridge
----------------------------------------------------------------------
diff --git a/src/main/resources/META-INF/services/org.apache.pdfbox.jbig2.util.log.LoggerBridge b/src/main/resources/META-INF/services/org.apache.pdfbox.jbig2.util.log.LoggerBridge
new file mode 100644
index 0000000..03e4159
--- /dev/null
+++ b/src/main/resources/META-INF/services/org.apache.pdfbox.jbig2.util.log.LoggerBridge
@@ -0,0 +1,18 @@
+#
+# 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.
+#
+
+org.apache.pdfbox.jbig2.util.log.JDKLoggerBridge
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/pdfbox-jbig2/blob/4619d28b/src/test/java/org/apache/pdfbox/jbig2/BitmapTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/pdfbox/jbig2/BitmapTest.java b/src/test/java/org/apache/pdfbox/jbig2/BitmapTest.java
new file mode 100644
index 0000000..4be8be0
--- /dev/null
+++ b/src/test/java/org/apache/pdfbox/jbig2/BitmapTest.java
@@ -0,0 +1,98 @@
+/**
+ * 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;
+
+import static org.junit.Assert.*;
+
+import org.apache.pdfbox.jbig2.Bitmap;
+
+import junit.framework.Assert;
+
+import org.junit.Test;
+
+public class BitmapTest {
+
+ @Test
+ public void getPixelAndSetPixelTest() {
+ final Bitmap bitmap = new Bitmap(37, 49);
+ assertEquals(0, bitmap.getPixel(3, 19));
+
+ bitmap.setPixel(3, 19, (byte) 1);
+
+ assertEquals(1, bitmap.getPixel(3, 19));
+ }
+
+ @Test
+ public void getByteAndSetByteTest() {
+ Bitmap bitmap = new Bitmap(16, 16);
+
+ byte value = (byte) 4;
+ bitmap.setByte(0, value);
+ bitmap.setByte(31, value);
+
+ assertEquals(value, bitmap.getByte(0));
+ assertEquals(value, bitmap.getByte(31));
+ }
+
+ @Test(expected = IndexOutOfBoundsException.class)
+ public void getByteThrowsExceptionTest() {
+ Bitmap bitmap = new Bitmap(16, 16);
+ bitmap.getByte(32);
+ }
+
+ @Test(expected = IndexOutOfBoundsException.class)
+ public void setByteThrowsExceptionTest() {
+ Bitmap bitmap = new Bitmap(16, 16);
+ bitmap.setByte(32, (byte) 0);
+ }
+
+ @Test
+ public void getByteAsIntegerTest() {
+ Bitmap bitmap = new Bitmap(16, 16);
+
+ byte byteValue = (byte) 4;
+ int integerValue = byteValue;
+ bitmap.setByte(0, byteValue);
+ bitmap.setByte(31, byteValue);
+
+ Assert.assertEquals(integerValue, bitmap.getByteAsInteger(0));
+ Assert.assertEquals(integerValue, bitmap.getByteAsInteger(31));
+
+ }
+
+ @Test(expected = IndexOutOfBoundsException.class)
+ public void getByteAsIntegerThrowsExceptionTest() {
+ Bitmap bitmap = new Bitmap(16, 16);
+ bitmap.getByte(32);
+ }
+
+ @Test
+ public void getHeightTest() {
+ int height = 16;
+ Bitmap bitmap = new Bitmap(1, height);
+ Assert.assertEquals(height, bitmap.getHeight());
+ }
+
+ @Test
+ public void getWidthTest() {
+ int width = 16;
+ Bitmap bitmap = new Bitmap(width, 1);
+ Assert.assertEquals(width, bitmap.getWidth());
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/pdfbox-jbig2/blob/4619d28b/src/test/java/org/apache/pdfbox/jbig2/ChecksumCalculator.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/pdfbox/jbig2/ChecksumCalculator.java b/src/test/java/org/apache/pdfbox/jbig2/ChecksumCalculator.java
new file mode 100644
index 0000000..debc7b9
--- /dev/null
+++ b/src/test/java/org/apache/pdfbox/jbig2/ChecksumCalculator.java
@@ -0,0 +1,60 @@
+/**
+ * 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;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Arrays;
+
+import javax.imageio.stream.ImageInputStream;
+
+import org.apache.pdfbox.jbig2.Bitmap;
+import org.apache.pdfbox.jbig2.JBIG2Document;
+import org.apache.pdfbox.jbig2.err.JBIG2Exception;
+import org.apache.pdfbox.jbig2.io.DefaultInputStreamFactory;
+import org.junit.Ignore;
+import org.junit.Test;
+
+@Ignore
+public class ChecksumCalculator {
+
+ @Ignore
+ @Test
+ public void computeChecksum() throws NoSuchAlgorithmException, IOException, JBIG2Exception {
+ String filepath = "/images/sampledata_page3.jb2";
+ int pageNumber = 1;
+
+ InputStream is = getClass().getResourceAsStream(filepath);
+ DefaultInputStreamFactory disf = new DefaultInputStreamFactory();
+ ImageInputStream iis = disf.getInputStream(is);
+ JBIG2Document doc = new JBIG2Document(iis);
+ Bitmap bitmap = doc.getPage(pageNumber).getBitmap();
+
+ byte[] md5 = md5(bitmap);
+ for (byte b : md5) {
+ System.out.print(b);
+ }
+ System.out.println(Arrays.toString(md5));
+ }
+
+ public static byte[] md5(Bitmap b) throws NoSuchAlgorithmException {
+ return MessageDigest.getInstance("MD5").digest(b.getByteArray());
+ }
+}
http://git-wip-us.apache.org/repos/asf/pdfbox-jbig2/blob/4619d28b/src/test/java/org/apache/pdfbox/jbig2/ChecksumTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/pdfbox/jbig2/ChecksumTest.java b/src/test/java/org/apache/pdfbox/jbig2/ChecksumTest.java
new file mode 100644
index 0000000..3dd208c
--- /dev/null
+++ b/src/test/java/org/apache/pdfbox/jbig2/ChecksumTest.java
@@ -0,0 +1,175 @@
+/**
+ * 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;
+
+import java.io.InputStream;
+import java.security.MessageDigest;
+import java.util.Arrays;
+import java.util.Collection;
+
+import javax.imageio.stream.ImageInputStream;
+
+import junit.framework.Assert;
+
+import org.apache.pdfbox.jbig2.Bitmap;
+import org.apache.pdfbox.jbig2.JBIG2Document;
+import org.apache.pdfbox.jbig2.io.DefaultInputStreamFactory;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class ChecksumTest {
+
+ @Parameters
+ public static Collection<Object[]> data() {
+ return Arrays.asList(new Object[][]{
+ {
+ "/images/042_1.jb2", "69-26-6629-1793-107941058147-58-79-37-31-79"
+ }, {
+ "/images/042_2.jb2", "69-26-6629-1793-107941058147-58-79-37-31-79"
+ }, {
+ "/images/042_3.jb2", "69-26-6629-1793-107941058147-58-79-37-31-79"
+ }, {
+ "/images/042_4.jb2", "69-26-6629-1793-107941058147-58-79-37-31-79"
+ }, {
+ "/images/042_5.jb2", "69-26-6629-1793-107941058147-58-79-37-31-79"
+ }, {
+ "/images/042_6.jb2", "69-26-6629-1793-107941058147-58-79-37-31-79"
+ }, {
+ "/images/042_7.jb2", "69-26-6629-1793-107941058147-58-79-37-31-79"
+ }, {
+ "/images/042_8.jb2", "69-26-6629-1793-107941058147-58-79-37-31-79"
+ }, {
+ "/images/042_9.jb2", "69-26-6629-1793-107941058147-58-79-37-31-79"
+ }, {
+ "/images/042_10.jb2", "69-26-6629-1793-107941058147-58-79-37-31-79"
+ }, {
+ "/images/042_11.jb2", "69-26-6629-1793-107941058147-58-79-37-31-79"
+ }, {
+ "/images/042_12.jb2", "69-26-6629-1793-107941058147-58-79-37-31-79"
+ },
+ // { "/images/042_13.jb2",
+ // "69-26-6629-1793-107941058147-58-79-37-31-79" },
+ // { "/images/042_14.jb2",
+ // "69-26-6629-1793-107941058147-58-79-37-31-79" },
+ {
+ "/images/042_15.jb2", "69-26-6629-1793-107941058147-58-79-37-31-79"
+ }, {
+ "/images/042_16.jb2", "69-26-6629-1793-107941058147-58-79-37-31-79"
+ }, {
+ "/images/042_17.jb2", "69-26-6629-1793-107941058147-58-79-37-31-79"
+ }, {
+ "/images/042_18.jb2", "69-26-6629-1793-107941058147-58-79-37-31-79"
+ }, {
+ "/images/042_19.jb2", "69-26-6629-1793-107941058147-58-79-37-31-79"
+ }, {
+ "/images/042_20.jb2", "69-26-6629-1793-107941058147-58-79-37-31-79"
+ }, {
+ "/images/042_21.jb2", "69-26-6629-1793-107941058147-58-79-37-31-79"
+ }, {
+ "/images/042_22.jb2", "69-26-6629-1793-107941058147-58-79-37-31-79"
+ }, {
+ "/images/042_23.jb2", "69-26-6629-1793-107941058147-58-79-37-31-79"
+ }, {
+ "/images/042_24.jb2", "69-26-6629-1793-107941058147-58-79-37-31-79"
+ }, {
+ "/images/042_25.jb2", "69-26-6629-1793-107941058147-58-79-37-31-79"
+ }, {
+ "/images/amb_1.jb2", "58311272494-318210035-125100-344625-126-79"
+ }, {
+ "/images/amb_2.jb2", "58311272494-318210035-125100-344625-126-79"
+ }, {
+ "/images/002.jb2", "-12713-4587-92-651657111-57121-1582564895"
+ }, {
+ "/images/003.jb2", "-37-108-89-33-78-5019-966-96-124-9675-1-108-24"
+ }, {
+ "/images/004.jb2", "-10709436-24-59-48-217114-37-85-3126-24"
+ }, {
+ "/images/005.jb2", "712610586-1224021396100112-102-77-1177851"
+ }, {
+ "/images/006.jb2", "-8719-116-83-83-35-3425-64-528667602154-25"
+ }, {
+ "/images/007.jb2", "6171-125-109-20-128-71925295955793-127-41-122"
+ }, {
+ "/images/sampledata_page1.jb2", "104-68-555325117-4757-48527676-9775-8432"
+ }, {
+ "/images/sampledata_page2.jb2", "104-68-555325117-4757-48527676-9775-8432"
+ }, {
+ "/images/sampledata_page3.jb2", "-7825-56-41-30-19-719536-3678580-61-2586"
+ }, {
+ "/images/20123110001.jb2", "60-96-101-2458-3335024-5468-5-11068-78-80"
+ }, {
+ "/images/20123110002.jb2", "-28-921048181-117-48-96126-110-9-2865611113"
+ }, {
+ "/images/20123110003.jb2", "-3942-239351-28-56-729169-5839122-439231"
+ }, {
+ "/images/20123110004.jb2", "-49-101-28-20-57-4-24-17-9352104-106-118-122-122"
+ }, {
+ "/images/20123110005.jb2", "-48221261779-94-838820-127-114110-2-88-80-106"
+ }, {
+ "/images/20123110006.jb2", "81-11870-63-30124-1614-45838-53-123-41639"
+ }, {
+ "/images/20123110007.jb2", "12183-49124728346-29-124-9-10775-63-44116103"
+ }, {
+ "/images/20123110008.jb2", "15-74-49-45958458-67-2545-96-119-122-60100-35"
+ }, {
+ "/images/20123110009.jb2", "36115-114-28-123-3-70-87-113-4197-8512396113-65"
+ }, {
+ "/images/20123110010.jb2", "-109-1069-61-1576-67-43122406037-75-1091115"
+ }
+ });
+ }
+
+ private final String filepath;
+ private final String checksum;
+
+ public ChecksumTest(String filepath, String cksum) {
+ this.filepath = filepath;
+ this.checksum = cksum;
+ }
+
+ @Test
+ public void compareChecksum() throws Throwable {
+ int imageIndex = 1;
+
+ InputStream is = getClass().getResourceAsStream(filepath);
+ System.out.println("####################################");
+ System.out.println("File: " + filepath);
+ DefaultInputStreamFactory disf = new DefaultInputStreamFactory();
+ ImageInputStream iis = disf.getInputStream(is);
+
+ JBIG2Document doc = new JBIG2Document(iis);
+
+ long time = System.currentTimeMillis();
+ Bitmap b = doc.getPage(imageIndex).getBitmap();
+ long duration = System.currentTimeMillis() - time;
+
+ byte[] digest = MessageDigest.getInstance("MD5").digest(b.getByteArray());
+
+ StringBuilder stringBuilder = new StringBuilder();
+ for (byte toAppend : digest) {
+ stringBuilder.append(toAppend);
+ }
+ System.out.println("Completed decoding in " + duration + " ms");
+ System.out.println("####################################\n");
+
+ Assert.assertEquals(checksum, stringBuilder.toString());
+ }
+}
http://git-wip-us.apache.org/repos/asf/pdfbox-jbig2/blob/4619d28b/src/test/java/org/apache/pdfbox/jbig2/GithubIssuesTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/pdfbox/jbig2/GithubIssuesTest.java b/src/test/java/org/apache/pdfbox/jbig2/GithubIssuesTest.java
new file mode 100644
index 0000000..96aa2a2
--- /dev/null
+++ b/src/test/java/org/apache/pdfbox/jbig2/GithubIssuesTest.java
@@ -0,0 +1,70 @@
+/**
+ * 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;
+
+import static org.apache.pdfbox.jbig2.ChecksumCalculator.*;
+import static org.apache.pdfbox.jbig2.JBIG2DocumentFacade.*;
+
+import java.io.InputStream;
+
+import javax.imageio.ImageIO;
+import javax.imageio.stream.ImageInputStream;
+
+import org.apache.pdfbox.jbig2.Bitmap;
+import org.apache.pdfbox.jbig2.JBIG2Document;
+import org.apache.pdfbox.jbig2.JBIG2Page;
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * Collection of tests for <a href="https://github.com/levigo/jbig2-imageio/issues">Github
+ * issues</a>.
+ */
+public class GithubIssuesTest {
+
+ /**
+ * <a href="https://github.com/levigo/jbig2-imageio/issues/21">Github issue 21s</a>
+ */
+ @Test
+ public void issue21() throws Exception {
+ final byte[] md5Expected = new byte[]{
+ 83, 74, -69, -60, -122, -99, 21, 126, -115, 13, 9, 107, -31, -109, 77, -119
+ };
+
+ final InputStream imageStream = getClass().getResourceAsStream("/com/levigo/jbig2/github/21.jb2");
+ final InputStream globalsStream = getClass().getResourceAsStream("/com/levigo/jbig2/github/21.glob");
+ final ImageInputStream globalsIIS = ImageIO.createImageInputStream(globalsStream);
+ final ImageInputStream imageIIS = ImageIO.createImageInputStream(imageStream);
+
+ byte[] md5Actual = null;
+ try {
+ final JBIG2Document doc = doc(imageIIS, globalsIIS);
+ final JBIG2Page page = doc.getPage(1);
+ final Bitmap bitmap = page.getBitmap();
+ md5Actual = md5(bitmap);
+ } finally {
+ Assert.assertArrayEquals(md5Expected, md5Actual);
+
+ globalsIIS.close();
+ globalsStream.close();
+ imageIIS.close();
+ imageStream.close();
+ }
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/pdfbox-jbig2/blob/4619d28b/src/test/java/org/apache/pdfbox/jbig2/JBIG2DocumentFacade.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/pdfbox/jbig2/JBIG2DocumentFacade.java b/src/test/java/org/apache/pdfbox/jbig2/JBIG2DocumentFacade.java
new file mode 100644
index 0000000..e38c09d
--- /dev/null
+++ b/src/test/java/org/apache/pdfbox/jbig2/JBIG2DocumentFacade.java
@@ -0,0 +1,53 @@
+/**
+ * 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;
+
+import java.io.IOException;
+
+import javax.imageio.stream.ImageInputStream;
+
+import org.apache.pdfbox.jbig2.Bitmap;
+import org.apache.pdfbox.jbig2.JBIG2Document;
+import org.apache.pdfbox.jbig2.JBIG2Globals;
+import org.apache.pdfbox.jbig2.JBIG2Page;
+import org.apache.pdfbox.jbig2.err.JBIG2Exception;
+
+public class JBIG2DocumentFacade extends JBIG2Document {
+
+ public static JBIG2Document doc(ImageInputStream doc, ImageInputStream globals) throws IOException {
+ final JBIG2Document globalsDoc = new JBIG2Document(globals);
+ return new JBIG2Document(doc, globalsDoc.getGlobalSegments());
+ }
+
+ public JBIG2DocumentFacade(ImageInputStream input) throws IOException {
+ super(input);
+ }
+
+ public JBIG2DocumentFacade(ImageInputStream input, JBIG2Globals globals) throws IOException {
+ super(input, globals);
+ }
+
+ public JBIG2Page getPage(int pageNumber) {
+ return super.getPage(pageNumber);
+ }
+
+ public Bitmap getPageBitmap(int pageNumber) throws JBIG2Exception, IOException {
+ return getPage(pageNumber).getBitmap();
+ }
+
+}