diff --git a/src/core/jbig2.js b/src/core/jbig2.js index e31bd1f5ec15b..3f647738df6d4 100644 --- a/src/core/jbig2.js +++ b/src/core/jbig2.js @@ -1584,6 +1584,20 @@ class SimpleSegmentVisitor { this.buffer = buffer; } + getRetainedBitmapContexts(segmentNumber) { + if (!this.retainedBitmapContexts) { + return null; + } + return this.retainedBitmapContexts[segmentNumber] || null; + } + + setRetainedBitmapContexts(segmentNumber, contexts) { + if (!this.retainedBitmapContexts) { + this.retainedBitmapContexts = {}; + } + this.retainedBitmapContexts[segmentNumber] = contexts; + } + drawBitmap(regionInfo, bitmap) { const pageInfo = this.currentPageInfo; const width = regionInfo.width, @@ -1683,16 +1697,64 @@ class SimpleSegmentVisitor { } const inputSymbols = []; + let lastReferredToSymbolDictionary = null; for (const referredSegment of referredSegments) { const referredSymbols = symbols[referredSegment]; // referredSymbols is undefined when we have a reference to a Tables // segment instead of a SymbolDictionary. if (referredSymbols) { inputSymbols.push(...referredSymbols); + lastReferredToSymbolDictionary = referredSegment; } } const decodingContext = new DecodingContext(data, start, end); + + // Handle bitmap coding context reuse (7.4.2.2 step 3) + if (dictionary.bitmapCodingContextUsed) { + if (lastReferredToSymbolDictionary === null) { + throw new Jbig2Error( + "symbol dictionary uses bitmap coding context, but has no referred-to symbol dictionary" + ); + } + + const retainedContexts = this.getRetainedBitmapContexts( + lastReferredToSymbolDictionary + ); + if (!retainedContexts) { + throw new Jbig2Error( + "symbol dictionary uses bitmap coding context, but referred-to dictionary did not retain contexts" + ); + } + + // Validate that parameters match (7.4.2.2 step 3) + if (retainedContexts.huffman !== dictionary.huffman) { + throw new Jbig2Error( + "symbol dictionary bitmap coding context: SDHUFF values do not match" + ); + } + if (retainedContexts.refinement !== dictionary.refinement) { + throw new Jbig2Error( + "symbol dictionary bitmap coding context: SDREFAGG values do not match" + ); + } + if (retainedContexts.template !== dictionary.template) { + throw new Jbig2Error( + "symbol dictionary bitmap coding context: SDTEMPLATE values do not match" + ); + } + if ( + retainedContexts.refinementTemplate !== dictionary.refinementTemplate + ) { + throw new Jbig2Error( + "symbol dictionary bitmap coding context: SDRTEMPLATE values do not match" + ); + } + + // Reuse the arithmetic coding contexts + decodingContext.contextCache = retainedContexts.contextCache; + } + symbols[currentSegment] = decodeSymbolDictionary( dictionary.huffman, dictionary.refinement, @@ -1707,6 +1769,17 @@ class SimpleSegmentVisitor { decodingContext, huffmanInput ); + + // Handle bitmap coding context retention (7.4.2.2 step 7) + if (dictionary.bitmapCodingContextRetained) { + this.setRetainedBitmapContexts(currentSegment, { + huffman: dictionary.huffman, + refinement: dictionary.refinement, + template: dictionary.template, + refinementTemplate: dictionary.refinementTemplate, + contextCache: decodingContext.contextCache, + }); + } } onImmediateTextRegion(region, referredSegments, data, start, end) { diff --git a/test/pdfs/.gitignore b/test/pdfs/.gitignore index 6080768c93f9e..fd74b89e0a2a5 100644 --- a/test/pdfs/.gitignore +++ b/test/pdfs/.gitignore @@ -752,6 +752,7 @@ !issue20319_1.pdf !issue20319_2.pdf !issue20439.pdf +!bitmap-symbol-context-reuse.pdf !bug1992868.pdf !bug1937438_af_from_latex.pdf !bug1937438_from_word.pdf diff --git a/test/pdfs/bitmap-symbol-context-reuse.pdf b/test/pdfs/bitmap-symbol-context-reuse.pdf new file mode 100644 index 0000000000000..633c3e9a16888 Binary files /dev/null and b/test/pdfs/bitmap-symbol-context-reuse.pdf differ diff --git a/test/test_manifest.json b/test/test_manifest.json index 860497c72ebc9..61c4e7fb4cc28 100644 --- a/test/test_manifest.json +++ b/test/test_manifest.json @@ -2819,6 +2819,13 @@ "rounds": 1, "type": "eq" }, + { + "id": "issue20461", + "file": "pdfs/bitmap-symbol-context-reuse.pdf", + "md5": "3d79e2d087515c2fdbed6fec0ad86e91", + "rounds": 1, + "type": "eq" + }, { "id": "issue20439", "file": "pdfs/issue20439.pdf",