diff --git a/src/core/image.js b/src/core/image.js index 8861461d2..fe3883a2f 100644 --- a/src/core/image.js +++ b/src/core/image.js @@ -119,7 +119,7 @@ class PDFImage { this.jpxDecoderOptions = { numComponents: 0, isIndexedColormap: false, - smaskInData: dict.has("SMaskInData"), + smaskInData: dict.get("SMaskInData") >= 1, reducePower, }; if (reducePower) { @@ -196,6 +196,25 @@ class PDFImage { if (!this.imageMask) { let colorSpace = dict.getRaw("CS") || dict.getRaw("ColorSpace"); const hasColorSpace = !!colorSpace; + + if ( + this.jpxDecoderOptions?.smaskInData && + dict.get("SMaskInData") === 2 + ) { + this.jpxPremultiplied = true; + if (this.matte) { + const matteColorSpace = ColorSpaceUtils.parse({ + cs: hasColorSpace ? colorSpace : Name.get("DeviceRGB"), + xref, + resources: isInline ? res : null, + pdfFunctionFactory, + globalColorSpaceCache, + localColorSpaceCache, + }); + this.preblendMatte = matteColorSpace.getRgb(this.matte, 0); + } + } + if (!hasColorSpace) { if (this.jpxDecoderOptions) { colorSpace = Name.get("DeviceRGBA"); @@ -654,22 +673,7 @@ class PDFImage { }); } - undoPreblend(buffer, width, height) { - if (typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING")) { - assert( - buffer instanceof Uint8ClampedArray, - 'PDFImage.undoPreblend: Unsupported "buffer" type.' - ); - } - const matte = this.smask?.matte; - if (!matte) { - return; - } - const matteRgb = this.colorSpace.getRgb(matte, 0); - const matteR = matteRgb[0]; - const matteG = matteRgb[1]; - const matteB = matteRgb[2]; - const length = width * height * 4; + static #undoPreblend(buffer, length, matteR, matteG, matteB) { for (let i = 0; i < length; i += 4) { const alpha = buffer[i + 3]; if (alpha === 0) { @@ -687,6 +691,27 @@ class PDFImage { } } + undoPreblend(buffer, width, height) { + if (typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING")) { + assert( + buffer instanceof Uint8ClampedArray, + 'PDFImage.undoPreblend: Unsupported "buffer" type.' + ); + } + const matte = this.smask?.matte; + if (!matte) { + return; + } + const matteRgb = this.colorSpace.getRgb(matte, 0); + PDFImage.#undoPreblend( + buffer, + width * height * 4, + matteRgb[0], + matteRgb[1], + matteRgb[2] + ); + } + async createImageData(forceRGBA = false, isOffscreenCanvasSupported = false) { const drawWidth = this.drawWidth; const drawHeight = this.drawHeight; @@ -717,6 +742,17 @@ class PDFImage { { internal: isOffscreenCanvasSupported && mustBeResized } )); + if (this.jpxPremultiplied) { + const matteRgb = this.preblendMatte; + PDFImage.#undoPreblend( + imgArray, + imgArray.length, + matteRgb?.[0] ?? 0, + matteRgb?.[1] ?? 0, + matteRgb?.[2] ?? 0 + ); + } + if (isOffscreenCanvasSupported) { if (!mustBeResized) { return this.createBitmap( diff --git a/test/pdfs/.gitignore b/test/pdfs/.gitignore index 19c9ff2ad..e25516a81 100644 --- a/test/pdfs/.gitignore +++ b/test/pdfs/.gitignore @@ -945,3 +945,4 @@ !issue20504_skia.pdf !issue21579.pdf !saslprep-r6.pdf +!jpx_smaskindata.pdf diff --git a/test/pdfs/jpx_smaskindata.pdf b/test/pdfs/jpx_smaskindata.pdf new file mode 100644 index 000000000..26d47af90 Binary files /dev/null and b/test/pdfs/jpx_smaskindata.pdf differ diff --git a/test/test_manifest.json b/test/test_manifest.json index b2607f01d..c60a97fdf 100644 --- a/test/test_manifest.json +++ b/test/test_manifest.json @@ -14479,5 +14479,12 @@ "rounds": 1, "type": "eq", "password": "S\u00AASL\u00ADprep" + }, + { + "id": "jpx_smaskindata", + "file": "pdfs/jpx_smaskindata.pdf", + "md5": "f7a8628b14ca176700247f106c16812a", + "rounds": 1, + "type": "eq" } ]