Skip to content

Commit ac925f4

Browse files
committed
Downscale jpeg2000 images, if needed, while decoding them
It fixes #19517.
1 parent 06f4491 commit ac925f4

File tree

9 files changed

+62
-15
lines changed

9 files changed

+62
-15
lines changed

external/openjpeg/openjpeg.js

Lines changed: 1 addition & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

external/openjpeg/openjpeg.wasm

-69 Bytes
Binary file not shown.

external/openjpeg/openjpeg_nowasm_fallback.js

Lines changed: 9 additions & 10 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/core/image.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,11 +112,22 @@ class PDFImage {
112112
bitsPerComponent: image.bitsPerComponent,
113113
} = JpxImage.parseImageProperties(image.stream));
114114
image.stream.reset();
115+
const reducePower = ImageResizer.getReducePowerForJPX(
116+
image.width,
117+
image.height,
118+
image.numComps
119+
);
115120
this.jpxDecoderOptions = {
116121
numComponents: 0,
117122
isIndexedColormap: false,
118123
smaskInData: dict.has("SMaskInData"),
124+
reducePower,
119125
};
126+
if (reducePower) {
127+
const factor = 2 ** reducePower;
128+
image.width = Math.ceil(image.width / factor);
129+
image.height = Math.ceil(image.height / factor);
130+
}
120131
break;
121132
case "JBIG2Decode":
122133
image.bitsPerComponent = 1;

src/core/image_resizer.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,30 @@ class ImageResizer {
9696
return area > maxArea;
9797
}
9898

99+
static getReducePowerForJPX(width, height, componentsCount) {
100+
const area = width * height;
101+
// The maximum memory we've in the wasm runtime is 2GB.
102+
// Each component is 4 bytes and we can't allocate all the memory just for
103+
// the buffers so we limit the size to 1GB / (componentsCount * 4).
104+
// We could use more than 2GB by setting MAXIMUM_MEMORY but it would take
105+
// too much time to decode a big image.
106+
const maxJPXArea = 2 ** 30 / (componentsCount * 4);
107+
if (!this.needsToBeResized(width, height)) {
108+
if (area > maxJPXArea) {
109+
// The image is too large, we need to rescale it.
110+
return Math.ceil(Math.log2(area / maxJPXArea));
111+
}
112+
return 0;
113+
}
114+
const { MAX_DIM, MAX_AREA } = this;
115+
const minFactor = Math.max(
116+
width / MAX_DIM,
117+
height / MAX_DIM,
118+
Math.sqrt(area / Math.min(maxJPXArea, MAX_AREA))
119+
);
120+
return Math.ceil(Math.log2(minFactor));
121+
}
122+
99123
static get MAX_DIM() {
100124
return shadow(
101125
this,

src/core/jpx.js

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,12 @@ class JpxImage {
9292

9393
static async decode(
9494
bytes,
95-
{ numComponents = 4, isIndexedColormap = false, smaskInData = false } = {}
95+
{
96+
numComponents = 4,
97+
isIndexedColormap = false,
98+
smaskInData = false,
99+
reducePower = 0,
100+
} = {}
96101
) {
97102
if (!this.#modulePromise) {
98103
const { promise, resolve } = Promise.withResolvers();
@@ -119,13 +124,14 @@ class JpxImage {
119124
try {
120125
const size = bytes.length;
121126
ptr = module._malloc(size);
122-
module.HEAPU8.set(bytes, ptr);
127+
module.writeArrayToMemory(bytes, ptr);
123128
const ret = module._jp2_decode(
124129
ptr,
125130
size,
126131
numComponents > 0 ? numComponents : 0,
127132
!!isIndexedColormap,
128-
!!smaskInData
133+
!!smaskInData,
134+
reducePower
129135
);
130136
if (ret) {
131137
const { errorMessages } = module;

test/pdfs/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -724,3 +724,4 @@
724724
!issue16742.pdf
725725
!chrome-text-selection-markedContent.pdf
726726
!bug1963407.pdf
727+
!issue19517.pdf

test/pdfs/issue19517.pdf

5.97 MB
Binary file not shown.

test/test_manifest.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12107,5 +12107,12 @@
1210712107
"value": "Hello World"
1210812108
}
1210912109
}
12110+
},
12111+
{
12112+
"id": "issue19517",
12113+
"file": "pdfs/issue19517.pdf",
12114+
"md5": "2abe67c8b34522feb6b85d252dde9d3e",
12115+
"rounds": 1,
12116+
"type": "eq"
1211012117
}
1211112118
]

0 commit comments

Comments
 (0)