Skip to content

Commit 5967f72

Browse files
Merge pull request #21225 from Snuffleupagus/WasmImage
Add an abstract `WasmImage` class, that `JBig2CCITTFaxImage` and `JpxImage` inherit from
2 parents e8d3d19 + 6ff0f86 commit 5967f72

8 files changed

Lines changed: 161 additions & 188 deletions

File tree

src/core/ccitt_stream.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ class CCITTFaxStream extends DecodeStream {
6464
: this.bytes;
6565
}
6666

67-
this.buffer = await JBig2CCITTFaxImage.decode(
67+
this.buffer = await JBig2CCITTFaxImage.instance.decode(
6868
bytes,
6969
this.dict.get("W", "Width"),
7070
this.dict.get("H", "Height"),

src/core/cleanup_helper.js

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,16 @@
1616
import { clearPatternCaches } from "./pattern.js";
1717
import { clearPrimitiveCaches } from "./primitives.js";
1818
import { clearUnicodeCaches } from "./unicode.js";
19-
import { JBig2CCITTFaxImage } from "./jbig2_ccittFax.js";
20-
import { JpxImage } from "./jpx.js";
19+
import { WasmImage } from "./wasm_image.js";
2120

2221
function clearGlobalCaches() {
2322
clearPatternCaches();
2423
clearPrimitiveCaches();
2524
clearUnicodeCaches();
2625

27-
// Remove the global `JBig2CCITTFaxImage`/`JpxImage` instances,
26+
// Remove the global `WasmImage` instances,
2827
// since they may hold references to the WebAssembly modules.
29-
JBig2CCITTFaxImage.cleanup();
30-
JpxImage.cleanup();
28+
WasmImage.cleanup();
3129
}
3230

3331
export { clearGlobalCaches };

src/core/jbig2_ccittFax.js

Lines changed: 9 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -13,102 +13,27 @@
1313
* limitations under the License.
1414
*/
1515

16-
import { BaseException, warn } from "../shared/util.js";
17-
import { fetchBinaryData } from "./core_utils.js";
16+
import { BaseException, shadow } from "../shared/util.js";
1817
import JBig2 from "../../external/jbig2/jbig2.js";
18+
import { WasmImage } from "./wasm_image.js";
1919

2020
class Jbig2Error extends BaseException {
2121
constructor(msg) {
2222
super(msg, "Jbig2Error");
2323
}
2424
}
2525

26-
class JBig2CCITTFaxImage {
27-
static #buffer = null;
26+
class JBig2CCITTFaxImage extends WasmImage {
27+
_filename = "jbig2.wasm";
2828

29-
static #handler = null;
29+
_noWasmFilename = "jbig2_nowasm_fallback.js";
3030

31-
static #modulePromise = null;
32-
33-
static #useWasm = true;
34-
35-
static #useWorkerFetch = true;
36-
37-
static #wasmUrl = null;
38-
39-
static setOptions({ handler, useWasm, useWorkerFetch, wasmUrl }) {
40-
this.#useWasm = useWasm;
41-
this.#useWorkerFetch = useWorkerFetch;
42-
this.#wasmUrl = wasmUrl;
43-
44-
if (!useWorkerFetch) {
45-
this.#handler = handler;
46-
}
31+
static get instance() {
32+
return shadow(this, "instance", new JBig2CCITTFaxImage());
4733
}
4834

49-
static async #getJsModule(fallbackCallback) {
50-
const path =
51-
typeof PDFJSDev === "undefined"
52-
? `../${this.#wasmUrl}jbig2_nowasm_fallback.js`
53-
: `${this.#wasmUrl}jbig2_nowasm_fallback.js`;
54-
55-
let instance = null;
56-
try {
57-
const mod = await (typeof PDFJSDev === "undefined"
58-
? import(path) // eslint-disable-line no-unsanitized/method
59-
: __raw_import__(path));
60-
instance = mod.default();
61-
} catch (e) {
62-
warn(`JBig2CCITTFaxImage#getJsModule: ${e}`);
63-
}
64-
fallbackCallback(instance);
65-
}
66-
67-
static async #instantiateWasm(fallbackCallback, imports, successCallback) {
68-
const filename = "jbig2.wasm";
69-
try {
70-
if (!this.#buffer) {
71-
if (this.#useWorkerFetch) {
72-
this.#buffer = await fetchBinaryData(`${this.#wasmUrl}${filename}`);
73-
} else {
74-
if (typeof PDFJSDev !== "undefined" && PDFJSDev.test("MOZCENTRAL")) {
75-
throw new Error("Only worker-thread fetching supported.");
76-
}
77-
this.#buffer = await this.#handler.sendWithPromise(
78-
"FetchBinaryData",
79-
{ kind: "wasmUrl", filename }
80-
);
81-
}
82-
}
83-
const results = await WebAssembly.instantiate(this.#buffer, imports);
84-
return successCallback(results.instance);
85-
} catch (reason) {
86-
warn(`JBig2CCITTFaxImage#instantiateWasm: ${reason}`);
87-
88-
this.#getJsModule(fallbackCallback);
89-
return null;
90-
} finally {
91-
this.#handler = null;
92-
}
93-
}
94-
95-
static async decode(bytes, width, height, globals, CCITTOptions) {
96-
if (!this.#modulePromise) {
97-
const { promise, resolve } = Promise.withResolvers();
98-
const promises = [promise];
99-
if (!this.#useWasm) {
100-
this.#getJsModule(resolve);
101-
} else {
102-
promises.push(
103-
JBig2({
104-
warn,
105-
instantiateWasm: this.#instantiateWasm.bind(this, resolve),
106-
})
107-
);
108-
}
109-
this.#modulePromise = Promise.race(promises);
110-
}
111-
const module = await this.#modulePromise;
35+
async decode(bytes, width, height, globals, CCITTOptions) {
36+
const module = await this._getModule(JBig2);
11237

11338
if (!module) {
11439
throw new Jbig2Error("JBig2 failed to initialize");
@@ -157,10 +82,6 @@ class JBig2CCITTFaxImage {
15782
}
15883
}
15984
}
160-
161-
static cleanup() {
162-
this.#modulePromise = null;
163-
}
16485
}
16586

16687
export { JBig2CCITTFaxImage, Jbig2Error };

src/core/jbig2_stream.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ class Jbig2Stream extends DecodeStream {
6464
globals = globalsStream.getBytes();
6565
}
6666
}
67-
this.buffer = await JBig2CCITTFaxImage.decode(
67+
this.buffer = await JBig2CCITTFaxImage.instance.decode(
6868
bytes,
6969
this.dict.get("Width"),
7070
this.dict.get("Height"),

src/core/jpx.js

Lines changed: 9 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -13,87 +13,27 @@
1313
* limitations under the License.
1414
*/
1515

16-
import { BaseException, warn } from "../shared/util.js";
17-
import { fetchBinaryData } from "./core_utils.js";
16+
import { BaseException, shadow } from "../shared/util.js";
1817
import OpenJPEG from "../../external/openjpeg/openjpeg.js";
1918
import { Stream } from "./stream.js";
19+
import { WasmImage } from "./wasm_image.js";
2020

2121
class JpxError extends BaseException {
2222
constructor(msg) {
2323
super(msg, "JpxError");
2424
}
2525
}
2626

27-
class JpxImage {
28-
static #buffer = null;
27+
class JpxImage extends WasmImage {
28+
_filename = "openjpeg.wasm";
2929

30-
static #handler = null;
30+
_noWasmFilename = "openjpeg_nowasm_fallback.js";
3131

32-
static #modulePromise = null;
33-
34-
static #useWasm = true;
35-
36-
static #useWorkerFetch = true;
37-
38-
static #wasmUrl = null;
39-
40-
static setOptions({ handler, useWasm, useWorkerFetch, wasmUrl }) {
41-
this.#useWasm = useWasm;
42-
this.#useWorkerFetch = useWorkerFetch;
43-
this.#wasmUrl = wasmUrl;
44-
45-
if (!useWorkerFetch) {
46-
this.#handler = handler;
47-
}
48-
}
49-
50-
static async #getJsModule(fallbackCallback) {
51-
const path =
52-
typeof PDFJSDev === "undefined"
53-
? `../${this.#wasmUrl}openjpeg_nowasm_fallback.js`
54-
: `${this.#wasmUrl}openjpeg_nowasm_fallback.js`;
55-
56-
let instance = null;
57-
try {
58-
const mod = await (typeof PDFJSDev === "undefined"
59-
? import(path) // eslint-disable-line no-unsanitized/method
60-
: __raw_import__(path));
61-
instance = mod.default();
62-
} catch (e) {
63-
warn(`JpxImage#getJsModule: ${e}`);
64-
}
65-
fallbackCallback(instance);
66-
}
67-
68-
static async #instantiateWasm(fallbackCallback, imports, successCallback) {
69-
const filename = "openjpeg.wasm";
70-
try {
71-
if (!this.#buffer) {
72-
if (this.#useWorkerFetch) {
73-
this.#buffer = await fetchBinaryData(`${this.#wasmUrl}${filename}`);
74-
} else {
75-
if (typeof PDFJSDev !== "undefined" && PDFJSDev.test("MOZCENTRAL")) {
76-
throw new Error("Only worker-thread fetching supported.");
77-
}
78-
this.#buffer = await this.#handler.sendWithPromise(
79-
"FetchBinaryData",
80-
{ kind: "wasmUrl", filename }
81-
);
82-
}
83-
}
84-
const results = await WebAssembly.instantiate(this.#buffer, imports);
85-
return successCallback(results.instance);
86-
} catch (reason) {
87-
warn(`JpxImage#instantiateWasm: ${reason}`);
88-
89-
this.#getJsModule(fallbackCallback);
90-
return null;
91-
} finally {
92-
this.#handler = null;
93-
}
32+
static get instance() {
33+
return shadow(this, "instance", new JpxImage());
9434
}
9535

96-
static async decode(
36+
async decode(
9737
bytes,
9838
{
9939
numComponents = 4,
@@ -102,22 +42,7 @@ class JpxImage {
10242
reducePower = 0,
10343
} = {}
10444
) {
105-
if (!this.#modulePromise) {
106-
const { promise, resolve } = Promise.withResolvers();
107-
const promises = [promise];
108-
if (!this.#useWasm) {
109-
this.#getJsModule(resolve);
110-
} else {
111-
promises.push(
112-
OpenJPEG({
113-
warn,
114-
instantiateWasm: this.#instantiateWasm.bind(this, resolve),
115-
})
116-
);
117-
}
118-
this.#modulePromise = Promise.race(promises);
119-
}
120-
const module = await this.#modulePromise;
45+
const module = await this._getModule(OpenJPEG);
12146

12247
if (!module) {
12348
throw new JpxError("OpenJPEG failed to initialize");
@@ -155,10 +80,6 @@ class JpxImage {
15580
}
15681
}
15782

158-
static cleanup() {
159-
this.#modulePromise = null;
160-
}
161-
16283
static parseImageProperties(stream) {
16384
if (typeof PDFJSDev !== "undefined" && PDFJSDev.test("IMAGE_DECODERS")) {
16485
if (stream instanceof ArrayBuffer || ArrayBuffer.isView(stream)) {

src/core/jpx_stream.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ class JpxStream extends DecodeStream {
4949
return this.buffer;
5050
}
5151
bytes ||= this.bytes;
52-
this.buffer = await JpxImage.decode(bytes, decoderOptions);
52+
this.buffer = await JpxImage.instance.decode(bytes, decoderOptions);
5353
this.bufferLength = this.buffer.length;
5454
this.eof = true;
5555

src/core/pdf_manager.js

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,14 @@ import {
2222
} from "../shared/util.js";
2323
import { ChunkedStreamManager } from "./chunked_stream.js";
2424
import { ImageResizer } from "./image_resizer.js";
25-
import { JBig2CCITTFaxImage } from "./jbig2_ccittFax.js";
2625
import { JpegStream } from "./jpeg_stream.js";
27-
import { JpxImage } from "./jpx.js";
2826
import { MissingDataException } from "./core_utils.js";
2927
import { OperatorList } from "./operator_list.js";
3028
import { Pattern } from "./pattern.js";
3129
import { PDFDocument } from "./document.js";
3230
import { PDFFunctionFactory } from "./function.js";
3331
import { Stream } from "./stream.js";
32+
import { WasmImage } from "./wasm_image.js";
3433

3534
function parseDocBaseUrl(url) {
3635
if (url) {
@@ -82,12 +81,11 @@ class BasePdfManager {
8281
OperatorList.setOptions(evaluatorOptions);
8382

8483
const options = { ...evaluatorOptions, handler };
85-
JpxImage.setOptions(options);
8684
IccColorSpace.setOptions(options);
8785
CmykICCBasedCS.setOptions(options);
88-
JBig2CCITTFaxImage.setOptions(options);
8986
PDFFunctionFactory.setOptions(options);
9087
Pattern.setOptions(options);
88+
WasmImage.setOptions(options);
9189
}
9290

9391
get docId() {

0 commit comments

Comments
 (0)