This is an automated email from the ASF dual-hosted git repository. tilman pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/pdfbox-jbig2.git
commit acc749c405afd2f4c9c521c679a68c70e317c99a Author: Tilman Hausherr <[email protected]> AuthorDate: Mon Jan 26 14:16:26 2026 +0100 PDFBOX-6154: add comments linking to the specification; implement computing HSKIP bitmap --- .../pdfbox/jbig2/segments/HalftoneRegion.java | 69 ++++++++++++++++++---- 1 file changed, 57 insertions(+), 12 deletions(-) diff --git a/src/main/java/org/apache/pdfbox/jbig2/segments/HalftoneRegion.java b/src/main/java/org/apache/pdfbox/jbig2/segments/HalftoneRegion.java index 60df7e0..049af3e 100644 --- a/src/main/java/org/apache/pdfbox/jbig2/segments/HalftoneRegion.java +++ b/src/main/java/org/apache/pdfbox/jbig2/segments/HalftoneRegion.java @@ -74,7 +74,7 @@ public class HalftoneRegion implements Region /** * Previously decoded data from other regions or dictionaries, stored to use as patterns in this region. */ - private ArrayList<Bitmap> patterns; + private ArrayList<Bitmap> patterns; // HPATS public HalftoneRegion() { @@ -97,36 +97,40 @@ public class HalftoneRegion implements Region { regionInfo.parseHeader(); - /* Bit 7 */ + // 7.4.5.1.1 Halftone region segment flags + + /* Bit 7: HDEFPIXEL */ hDefaultPixel = (byte) subInputStream.readBit(); - /* Bit 4-6 */ + /* Bit 4-6: HCOMBOP */ hCombinationOperator = CombinationOperator .translateOperatorCodeToEnum((short) (subInputStream.readBits(3) & 0xf)); - /* Bit 3 */ + /* Bit 3: HENABLESKIP */ if (subInputStream.readBit() == 1) { hSkipEnabled = true; } - /* Bit 1-2 */ + /* Bit 1-2: HTEMPLATE */ hTemplate = (byte) (subInputStream.readBits(2) & 0xf); - /* Bit 0 */ + /* Bit 0: HMMR */ if (subInputStream.readBit() == 1) { isMMREncoded = true; } - hGridWidth = (int) (subInputStream.readBits(32) & 0xffffffff); - hGridHeight = (int) (subInputStream.readBits(32) & 0xffffffff); + // 7.4.5.1.2 Halftone grid position and size + hGridWidth = (int) (subInputStream.readBits(32) & 0xffffffff); // HGW + hGridHeight = (int) (subInputStream.readBits(32) & 0xffffffff); // HGH - hGridX = (int) subInputStream.readBits(32); - hGridY = (int) subInputStream.readBits(32); + hGridX = (int) subInputStream.readBits(32); // HGX + hGridY = (int) subInputStream.readBits(32); // HGY - hRegionX = (int) subInputStream.readBits(16) & 0xffff; - hRegionY = (int) subInputStream.readBits(16) & 0xffff; + // 7.4.5.1.3 Halftone grid vector + hRegionX = (int) subInputStream.readBits(16) & 0xffff; // HRX + hRegionY = (int) subInputStream.readBits(16) & 0xffff; // HRY /* Segment data structure */ computeSegmentDataStructure(); @@ -180,6 +184,22 @@ public class HalftoneRegion implements Region // hSkip = computeHSkip(hPatternHeight, hPatternWidth); // } + // leaving the above comments untouched for now. + Bitmap hSkip; + if (hSkipEnabled) + { + // test files from Serenity: + // bitmap-halftone-skip-grid.jbig2 + // bitmap-halftone-skip-grid-template1.jbig2 + // bitmap-halftone-skip-grid-template2.jbig2 + // bitmap-halftone-skip-grid-template3.jbig2 + int hPatternHeight = (int) patterns.get(0).getHeight(); // HPW + int hPatternWidth = (int) patterns.get(0).getWidth(); // HPH + hSkip = computeHSkip(hPatternWidth, hPatternHeight); + //TODO: what to do with the result bitmap? + throw new IOException("HSKIP not implemented"); + } + /* 3) */ final int bitsPerValue = (int) Math.ceil(Math.log(patterns.size()) / Math.log(2)); @@ -436,4 +456,29 @@ public class HalftoneRegion implements Region { return hDefaultPixel; } + + // 6.6.5.1 Computing HSKIP + private Bitmap computeHSkip(int hPatternWidth, int hPatternHeight) throws IOException + { + Bitmap bitmap = new Bitmap(hGridWidth, hGridHeight); // HSKIP is HGW by HGH pixels + for (int m = 0; m < hGridHeight; ++m) + { + for (int n = 0; n < hGridWidth; ++n) + { + int x = (hGridX + m * hRegionY + n * hRegionX) >> 8; + int y = (hGridY + m * hRegionX - n * hRegionY) >> 8; + // HBW = halftoneRegionBitmap.getWidth() + // HBH = halftoneRegionBitmap.getHeight() + if (x + hPatternWidth <= 0 || x >= halftoneRegionBitmap.getWidth() || y + hPatternHeight <= 0 || y >= halftoneRegionBitmap.getHeight()) + { + bitmap.setPixel(n, m, (byte) 1); + } + else + { + bitmap.setPixel(n, m, (byte) 0); + } + } + } + return bitmap; + } }
