Skip to content

Commit 2554aa1

Browse files
committed
[api-minor] Add a getDocument option to disable ImageDecoder usage
This allows end-users to forcibly disable `ImageDecoder` usage, even if the browser appears to support it (similar to the pre-existing option for `OffscreenCanvas`).
1 parent fe5967c commit 2554aa1

File tree

6 files changed

+50
-31
lines changed

6 files changed

+50
-31
lines changed

src/core/evaluator.js

+5-8
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ import { getGlyphsUnicode } from "./glyphlist.js";
7272
import { getMetrics } from "./metrics.js";
7373
import { getUnicodeForGlyph } from "./unicode.js";
7474
import { ImageResizer } from "./image_resizer.js";
75+
import { JpegStream } from "./jpeg_stream.js";
7576
import { MurmurHash3_64 } from "../shared/murmurhash3.js";
7677
import { OperatorList } from "./operator_list.js";
7778
import { PDFImage } from "./image.js";
@@ -83,6 +84,7 @@ const DefaultPartialEvaluatorOptions = Object.freeze({
8384
ignoreErrors: false,
8485
isEvalSupported: true,
8586
isOffscreenCanvasSupported: false,
87+
isImageDecoderSupported: false,
8688
isChrome: false,
8789
canvasMaxAreaInBytes: -1,
8890
fontExtraProperties: false,
@@ -233,14 +235,9 @@ class PartialEvaluator {
233235

234236
this._regionalImageCache = new RegionalImageCache();
235237
this._fetchBuiltInCMapBound = this.fetchBuiltInCMap.bind(this);
236-
if (typeof PDFJSDev !== "undefined" && PDFJSDev.test("MOZCENTRAL")) {
237-
ImageResizer.setMaxArea(this.options.canvasMaxAreaInBytes);
238-
} else {
239-
ImageResizer.setOptions({
240-
isChrome: this.options.isChrome,
241-
maxArea: this.options.canvasMaxAreaInBytes,
242-
});
243-
}
238+
239+
ImageResizer.setOptions(this.options);
240+
JpegStream.setOptions(this.options);
244241
}
245242

246243
/**

src/core/image_resizer.js

+14-17
Original file line numberDiff line numberDiff line change
@@ -34,23 +34,20 @@ const MAX_ERROR = 128;
3434
class ImageResizer {
3535
static #goodSquareLength = MIN_IMAGE_DIM;
3636

37-
static #isChrome = false;
37+
static #isImageDecoderSupported = FeatureTest.isImageDecoderSupported;
3838

3939
constructor(imgData, isMask) {
4040
this._imgData = imgData;
4141
this._isMask = isMask;
4242
}
4343

4444
static get canUseImageDecoder() {
45-
// TODO: remove the isChrome, once Chrome doesn't crash anymore with
46-
// issue6741.pdf.
47-
// https://issues.chromium.org/issues/374807001.
4845
return shadow(
4946
this,
5047
"canUseImageDecoder",
51-
this.#isChrome || typeof ImageDecoder === "undefined"
52-
? Promise.resolve(false)
53-
: ImageDecoder.isTypeSupported("image/bmp")
48+
this.#isImageDecoderSupported
49+
? ImageDecoder.isTypeSupported("image/bmp")
50+
: Promise.resolve(false)
5451
);
5552
}
5653

@@ -121,19 +118,19 @@ class ImageResizer {
121118
}
122119
}
123120

124-
static setMaxArea(area) {
121+
static setOptions({
122+
isChrome = false,
123+
isImageDecoderSupported = false,
124+
maxArea = -1,
125+
}) {
125126
if (!this._hasMaxArea) {
126127
// Divide by 4 to have the value in pixels.
127-
this.MAX_AREA = area >> 2;
128+
this.MAX_AREA = maxArea >> 2;
128129
}
129-
}
130-
131-
static setOptions(opts) {
132-
if (typeof PDFJSDev !== "undefined" && PDFJSDev.test("MOZCENTRAL")) {
133-
throw new Error("Not implemented: setOptions");
134-
}
135-
this.setMaxArea(opts.maxArea ?? -1);
136-
this.#isChrome = opts.isChrome ?? false;
130+
// TODO: remove the isChrome, once Chrome doesn't crash anymore with
131+
// issue6741.pdf.
132+
// https://issues.chromium.org/issues/374807001.
133+
this.#isImageDecoderSupported = isImageDecoderSupported && !isChrome;
137134
}
138135

139136
static _areGoodDims(width, height) {

src/core/jpeg_stream.js

+10-4
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
* limitations under the License.
1414
*/
1515

16-
import { shadow, warn } from "../shared/util.js";
16+
import { FeatureTest, shadow, warn } from "../shared/util.js";
1717
import { DecodeStream } from "./decode_stream.js";
1818
import { Dict } from "./primitives.js";
1919
import { JpegImage } from "./jpg.js";
@@ -23,6 +23,8 @@ import { JpegImage } from "./jpg.js";
2323
* like all the other DecodeStreams.
2424
*/
2525
class JpegStream extends DecodeStream {
26+
static #isImageDecoderSupported = FeatureTest.isImageDecoderSupported;
27+
2628
constructor(stream, maybeLength, params) {
2729
super(maybeLength);
2830

@@ -36,12 +38,16 @@ class JpegStream extends DecodeStream {
3638
return shadow(
3739
this,
3840
"canUseImageDecoder",
39-
typeof ImageDecoder === "undefined"
40-
? Promise.resolve(false)
41-
: ImageDecoder.isTypeSupported("image/jpeg")
41+
this.#isImageDecoderSupported
42+
? ImageDecoder.isTypeSupported("image/jpeg")
43+
: Promise.resolve(false)
4244
);
4345
}
4446

47+
static setOptions({ isImageDecoderSupported = false }) {
48+
this.#isImageDecoderSupported = isImageDecoderSupported;
49+
}
50+
4551
get bytes() {
4652
// If `this.maybeLength` is null, we'll get the entire stream.
4753
return shadow(this, "bytes", this.stream.getBytes(this.maybeLength));

src/core/pdf_manager.js

+4-2
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,12 @@ class BasePdfManager {
4848
this._password = args.password;
4949
this.enableXfa = args.enableXfa;
5050

51-
// Check `OffscreenCanvas` support once, rather than repeatedly throughout
52-
// the worker-thread code.
51+
// Check `OffscreenCanvas` and `ImageDecoder` support once,
52+
// rather than repeatedly throughout the worker-thread code.
5353
args.evaluatorOptions.isOffscreenCanvasSupported &&=
5454
FeatureTest.isOffscreenCanvasSupported;
55+
args.evaluatorOptions.isImageDecoderSupported &&=
56+
FeatureTest.isImageDecoderSupported;
5557
this.evaluatorOptions = Object.freeze(args.evaluatorOptions);
5658
}
5759

src/display/api.js

+9
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,10 @@ const DefaultStandardFontDataFactory =
177177
* `OffscreenCanvas` in the worker. Primarily used to improve performance of
178178
* image conversion/rendering.
179179
* The default value is `true` in web environments and `false` in Node.js.
180+
* @property {boolean} [isImageDecoderSupported] - Determines if we can use
181+
* `ImageDecoder` in the worker. Primarily used to improve performance of
182+
* image conversion/rendering.
183+
* The default value is `true` in web environments and `false` in Node.js.
180184
* @property {boolean} [isChrome] - Determines if we can use bmp ImageDecoder.
181185
* NOTE: Temporary option until [https://issues.chromium.org/issues/374807001]
182186
* is fixed.
@@ -284,6 +288,10 @@ function getDocument(src = {}) {
284288
typeof src.isOffscreenCanvasSupported === "boolean"
285289
? src.isOffscreenCanvasSupported
286290
: !isNodeJS;
291+
const isImageDecoderSupported =
292+
typeof src.isImageDecoderSupported === "boolean"
293+
? src.isImageDecoderSupported
294+
: !isNodeJS;
287295
const isChrome =
288296
typeof src.isChrome === "boolean"
289297
? src.isChrome
@@ -395,6 +403,7 @@ function getDocument(src = {}) {
395403
ignoreErrors,
396404
isEvalSupported,
397405
isOffscreenCanvasSupported,
406+
isImageDecoderSupported,
398407
isChrome,
399408
canvasMaxAreaInBytes,
400409
fontExtraProperties,

src/shared/util.js

+8
Original file line numberDiff line numberDiff line change
@@ -623,6 +623,14 @@ class FeatureTest {
623623
);
624624
}
625625

626+
static get isImageDecoderSupported() {
627+
return shadow(
628+
this,
629+
"isImageDecoderSupported",
630+
typeof ImageDecoder !== "undefined"
631+
);
632+
}
633+
626634
static get platform() {
627635
if (
628636
(typeof PDFJSDev !== "undefined" && PDFJSDev.test("MOZCENTRAL")) ||

0 commit comments

Comments
 (0)