[ 
https://issues.apache.org/jira/browse/PDFBOX-6199?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18077611#comment-18077611
 ] 

Tilman Hausherr edited comment on PDFBOX-6199 at 5/1/26 9:53 AM:
-----------------------------------------------------------------

I wrote a "dumb" version of the decoder:
{code:java}
    private byte getPixelSafe(Bitmap bitmap, int x, int y)
    {
        if (x < 0 || y < 0)
            return 0;
        if (x >= bitmap.getWidth() || y >= bitmap.getHeight())
            return 0;
        return bitmap.getPixel(x, y);
    }

    private void decodeTypicalPredictedLineTemplate1Dumb(final int lineNumber, 
final int width,
            final int rowStride, final int refRowStride, final int paddedWidth,
            final int deltaRefStride, int byteIndex, final int currentLine, int 
refByteIndex)
            throws IOException
    {
        for (int x = 0; x < width; ++x)
        {
            int bit;
            // i)
            // Page 49
            byte b1 = getPixelSafe(referenceBitmap, x - 1, lineNumber - 1);
            byte b2 = getPixelSafe(referenceBitmap, x,     lineNumber - 1);
            byte b3 = getPixelSafe(referenceBitmap, x + 1, lineNumber - 1);
            byte b4 = getPixelSafe(referenceBitmap, x - 1, lineNumber);
            byte b5 = getPixelSafe(referenceBitmap, x    , lineNumber);
            byte b6 = getPixelSafe(referenceBitmap, x + 1, lineNumber);
            byte b7 = getPixelSafe(referenceBitmap, x - 1, lineNumber + 1);
            byte b8 = getPixelSafe(referenceBitmap, x,     lineNumber + 1);
            byte b9 = getPixelSafe(referenceBitmap, x + 1, lineNumber + 1);
            if (b1 == b2 && b2 == b3 && b3 == b4 && b4 == b5 && b5 == b6 && b6 
== b7 && b7 == b8 && b8 == b9)
            {
                bit = b1;
            }
            else
            {
                // Otherwise, explictly decode the current pixel using the 
methodology of steps 3(c)i through 3(c)iii above.
                // Figure 13: 10-pixel refinement template
                byte c1 = getPixelSafe(regionBitmap, x - 1, lineNumber - 1);
                byte c2 = getPixelSafe(regionBitmap, x, lineNumber - 1);
                byte c3 = getPixelSafe(regionBitmap, x + 1, lineNumber - 1);
                byte c4 = getPixelSafe(regionBitmap, x - 1, lineNumber);
                byte c5 = getPixelSafe(referenceBitmap, x, lineNumber - 1);
                byte c6 = getPixelSafe(referenceBitmap, x - 1, lineNumber);
                byte c7 = getPixelSafe(referenceBitmap, x, lineNumber);
                byte c8 = getPixelSafe(referenceBitmap, x + 1, lineNumber);
                byte c9 = getPixelSafe(referenceBitmap, x, lineNumber + 1);
                byte c10 = getPixelSafe(referenceBitmap, x + 1, lineNumber + 1);
                int context = c1 << 9 | c2 << 8 | c3 << 7 | c4 << 6 |  c5 << 5 
|  c6 << 4 | c7 << 3 | c8 << 2 | c9 << 1 | c10;  
                cx.setIndex(context);
                bit = arithDecoder.decode(cx);
            }
            regionBitmap.setPixel(x, lineNumber, (byte) (bit & 1));
        }
    }
{code}
Result when using 8 as the SLTP context:
 !screenshot-4.png! 

This is quite close. Either there's a bug misunderstanding in my code, or 
there's a bug in the non-SLTP decoding.

Update: I traced to see when the dumb method is called last, it is at line 309. 
That is just above from where the problems start.


was (Author: tilman):
I wrote a "dumb" version of the decoder:
{code:java}
    private byte getPixelSafe(Bitmap bitmap, int x, int y)
    {
        if (x < 0 || y < 0)
            return 0;
        if (x >= bitmap.getWidth() || y >= bitmap.getHeight())
            return 0;
        return bitmap.getPixel(x, y);
    }

    private void decodeTypicalPredictedLineTemplate1Dumb(final int lineNumber, 
final int width,
            final int rowStride, final int refRowStride, final int paddedWidth,
            final int deltaRefStride, int byteIndex, final int currentLine, int 
refByteIndex)
            throws IOException
    {
        for (int x = 0; x < width; ++x)
        {
            int bit;
            // i)
            // Page 49
            byte b1 = getPixelSafe(referenceBitmap, x - 1, lineNumber - 1);
            byte b2 = getPixelSafe(referenceBitmap, x,     lineNumber - 1);
            byte b3 = getPixelSafe(referenceBitmap, x + 1, lineNumber - 1);
            byte b4 = getPixelSafe(referenceBitmap, x - 1, lineNumber);
            byte b5 = getPixelSafe(referenceBitmap, x    , lineNumber);
            byte b6 = getPixelSafe(referenceBitmap, x + 1, lineNumber);
            byte b7 = getPixelSafe(referenceBitmap, x - 1, lineNumber + 1);
            byte b8 = getPixelSafe(referenceBitmap, x,     lineNumber + 1);
            byte b9 = getPixelSafe(referenceBitmap, x + 1, lineNumber + 1);
            if (b1 == b2 && b2 == b3 && b3 == b4 && b4 == b5 && b5 == b6 && b6 
== b7 && b7 == b8 && b8 == b9)
            {
                bit = b1;
            }
            else
            {
                // Otherwise, explictly decode the current pixel using the 
methodology of steps 3(c)i through 3(c)iii above.
                // Figure 13: 10-pixel refinement template
                byte c1 = getPixelSafe(regionBitmap, x - 1, lineNumber - 1);
                byte c2 = getPixelSafe(regionBitmap, x, lineNumber - 1);
                byte c3 = getPixelSafe(regionBitmap, x + 1, lineNumber - 1);
                byte c4 = getPixelSafe(regionBitmap, x - 1, lineNumber);
                byte c5 = getPixelSafe(referenceBitmap, x, lineNumber - 1);
                byte c6 = getPixelSafe(referenceBitmap, x - 1, lineNumber);
                byte c7 = getPixelSafe(referenceBitmap, x, lineNumber);
                byte c8 = getPixelSafe(referenceBitmap, x + 1, lineNumber);
                byte c9 = getPixelSafe(referenceBitmap, x, lineNumber + 1);
                byte c10 = getPixelSafe(referenceBitmap, x + 1, lineNumber + 1);
                int context = c1 << 9 | c2 << 8 | c3 << 7 | c4 << 6 |  c5 << 5 
|  c6 << 4 | c7 << 3 | c8 << 2 | c9 << 1 | c10;  
                cx.setIndex(context);
                bit = arithDecoder.decode(cx);
            }
            regionBitmap.setPixel(x, lineNumber, (byte) (bit & 1));
        }
    }
{code}
Result when using 8 as the SLTP context:
 !screenshot-4.png! 

This is quite close. Either there's a bug misunderstanding in my code, or 
there's a bug in the non-SLTP decoding.

> Template 1 handling with TPGRON not supported
> ---------------------------------------------
>
>                 Key: PDFBOX-6199
>                 URL: https://issues.apache.org/jira/browse/PDFBOX-6199
>             Project: PDFBox
>          Issue Type: Sub-task
>          Components: JBIG2
>    Affects Versions: 3.0.4 JBIG2
>            Reporter: Maruan Sahyoun
>            Priority: Minor
>         Attachments: image-2026-04-28-12-27-28-955.png, 
> image-2026-04-28-12-28-19-575.png, image-2026-04-28-12-29-21-038.png, 
> screenshot-1.png, screenshot-2.png, screenshot-3.png, screenshot-4.png
>
>
> {{bitmap-refine-template1-tpgron.jbig2}} tests the folling features of JBIG2:
> - Refinement region
> - Template 1
> - TPGRON
> - Reference bitmap reuse
> We currently produce garbled output when decoding



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to