Skip to content

Commit 5c8f55e

Browse files
committed
Some jpx images can have a mask
It fixes #18896.
1 parent e1f9fa4 commit 5c8f55e

File tree

4 files changed

+93
-1
lines changed

4 files changed

+93
-1
lines changed

src/core/colorspace.js

+82
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
import {
1717
assert,
18+
FeatureTest,
1819
FormatError,
1920
info,
2021
shadow,
@@ -60,6 +61,61 @@ function resizeRgbImage(src, dest, w1, h1, w2, h2, alpha01) {
6061
}
6162
}
6263

64+
function resizeRgbaImage(src, dest, w1, h1, w2, h2, alpha01) {
65+
const xRatio = w1 / w2;
66+
const yRatio = h1 / h2;
67+
let newIndex = 0;
68+
const xScaled = new Uint16Array(w2);
69+
70+
if (alpha01 === 1) {
71+
for (let i = 0; i < w2; i++) {
72+
xScaled[i] = Math.floor(i * xRatio);
73+
}
74+
const src32 = new Uint32Array(src.buffer);
75+
const dest32 = new Uint32Array(dest.buffer);
76+
const rgbMask = FeatureTest.isLittleEndian ? 0x00ffffff : 0xffffff00;
77+
for (let i = 0; i < h2; i++) {
78+
const buf = src32.subarray(Math.floor(i * yRatio) * w1);
79+
for (let j = 0; j < w2; j++) {
80+
dest32[newIndex++] |= buf[xScaled[j]] & rgbMask;
81+
}
82+
}
83+
} else {
84+
const COMPONENTS = 4;
85+
const w1Scanline = w1 * COMPONENTS;
86+
for (let i = 0; i < w2; i++) {
87+
xScaled[i] = Math.floor(i * xRatio) * COMPONENTS;
88+
}
89+
for (let i = 0; i < h2; i++) {
90+
const buf = src.subarray(Math.floor(i * yRatio) * w1Scanline);
91+
for (let j = 0; j < w2; j++) {
92+
const oldIndex = xScaled[j];
93+
dest[newIndex++] = buf[oldIndex];
94+
dest[newIndex++] = buf[oldIndex + 1];
95+
dest[newIndex++] = buf[oldIndex + 2];
96+
}
97+
}
98+
}
99+
}
100+
101+
function copyRgbaImage(src, dest, alpha01) {
102+
if (alpha01 === 1) {
103+
const src32 = new Uint32Array(src.buffer);
104+
const dest32 = new Uint32Array(dest.buffer);
105+
const rgbMask = FeatureTest.isLittleEndian ? 0x00ffffff : 0xffffff00;
106+
for (let i = 0, ii = src32.length; i < ii; i++) {
107+
dest32[i] |= src32[i] & rgbMask;
108+
}
109+
} else {
110+
let j = 0;
111+
for (let i = 0, ii = src.length; i < ii; i += 4) {
112+
dest[j++] = src[i];
113+
dest[j++] = src[i + 1];
114+
dest[j++] = src[i + 2];
115+
}
116+
}
117+
}
118+
63119
class ColorSpace {
64120
constructor(name, numComps) {
65121
if (
@@ -806,6 +862,32 @@ class DeviceRgbaCS extends ColorSpace {
806862
isPassthrough(bits) {
807863
return bits === 8;
808864
}
865+
866+
fillRgb(
867+
dest,
868+
originalWidth,
869+
originalHeight,
870+
width,
871+
height,
872+
actualHeight,
873+
bpc,
874+
comps,
875+
alpha01
876+
) {
877+
if (originalHeight !== height || originalWidth !== width) {
878+
resizeRgbaImage(
879+
comps,
880+
dest,
881+
originalWidth,
882+
originalHeight,
883+
width,
884+
height,
885+
alpha01
886+
);
887+
} else {
888+
copyRgbaImage(comps, dest, alpha01);
889+
}
890+
}
809891
}
810892

811893
/**

src/core/image.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -705,7 +705,7 @@ class PDFImage {
705705
isOffscreenCanvasSupported &&
706706
ImageResizer.needsToBeResized(drawWidth, drawHeight);
707707

708-
if (this.colorSpace.name === "DeviceRGBA") {
708+
if (!this.mask && this.colorSpace.name === "DeviceRGBA") {
709709
imgData.kind = ImageKind.RGBA_32BPP;
710710
const imgArray = (imgData.data = await this.getImageBytes(
711711
originalHeight * originalWidth * 4,

test/pdfs/issue18896.pdf.link

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
https://github.com/user-attachments/files/17365176/issue18896.pdf

test/test_manifest.json

+9
Original file line numberDiff line numberDiff line change
@@ -10700,5 +10700,14 @@
1070010700
"rounds": 1,
1070110701
"type": "eq",
1070210702
"talos": false
10703+
},
10704+
{
10705+
"id": "issue18896",
10706+
"file": "pdfs/issue18896.pdf",
10707+
"md5": "4acb4df0f38c976dce5e841e6de1f875",
10708+
"rounds": 1,
10709+
"type": "eq",
10710+
"link": true,
10711+
"talos": false
1070310712
}
1070410713
]

0 commit comments

Comments
 (0)