mirror of
https://github.com/mozilla/pdf.js.git
synced 2026-02-07 16:11:12 +01:00
Use the ccittfax decoder from pdfium
The decoder is a dependency of the jbig2 one and is already included in pdf.js, so we just need to wire it up. It improves the performance of documents using ccittfax images.
This commit is contained in:
parent
471adfd023
commit
88c2051698
2
external/jbig2/jbig2.js
vendored
2
external/jbig2/jbig2.js
vendored
File diff suppressed because one or more lines are too long
BIN
external/jbig2/jbig2.wasm
vendored
BIN
external/jbig2/jbig2.wasm
vendored
Binary file not shown.
@ -465,20 +465,33 @@ const blackTable3 = [
|
||||
* @param {Object} [options] - Decoding options.
|
||||
*/
|
||||
class CCITTFaxDecoder {
|
||||
constructor(source, options = {}) {
|
||||
constructor(
|
||||
source,
|
||||
options = {
|
||||
K: 0,
|
||||
EndOfLine: false,
|
||||
EncodedByteAlign: false,
|
||||
Columns: 1728,
|
||||
Rows: 0,
|
||||
EndOfBlock: true,
|
||||
BlackIs1: false,
|
||||
}
|
||||
) {
|
||||
if (typeof source?.next !== "function") {
|
||||
throw new Error('CCITTFaxDecoder - invalid "source" parameter.');
|
||||
}
|
||||
this.source = source;
|
||||
this.eof = false;
|
||||
|
||||
this.encoding = options.K || 0;
|
||||
this.eoline = options.EndOfLine || false;
|
||||
this.byteAlign = options.EncodedByteAlign || false;
|
||||
this.columns = options.Columns || 1728;
|
||||
this.rows = options.Rows || 0;
|
||||
this.eoblock = options.EndOfBlock ?? true;
|
||||
this.black = options.BlackIs1 || false;
|
||||
({
|
||||
K: this.encoding,
|
||||
EndOfLine: this.eoline,
|
||||
EncodedByteAlign: this.byteAlign,
|
||||
Columns: this.columns,
|
||||
Rows: this.rows,
|
||||
EndOfBlock: this.eoblock,
|
||||
BlackIs1: this.black,
|
||||
} = options);
|
||||
|
||||
this.codingLine = new Uint32Array(this.columns + 1);
|
||||
this.refLine = new Uint32Array(this.columns + 2);
|
||||
|
||||
@ -13,52 +13,115 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { shadow, warn } from "../shared/util.js";
|
||||
import { CCITTFaxDecoder } from "./ccitt.js";
|
||||
import { DecodeStream } from "./decode_stream.js";
|
||||
import { Dict } from "./primitives.js";
|
||||
import { JBig2CCITTFaxWasmImage } from "./jbig2_ccittFax_wasm.js";
|
||||
|
||||
class CCITTFaxStream extends DecodeStream {
|
||||
constructor(str, maybeLength, params) {
|
||||
super(maybeLength);
|
||||
|
||||
this.stream = str;
|
||||
this.maybeLength = maybeLength;
|
||||
this.dict = str.dict;
|
||||
|
||||
if (!(params instanceof Dict)) {
|
||||
params = Dict.empty;
|
||||
}
|
||||
|
||||
const source = {
|
||||
next() {
|
||||
return str.getByte();
|
||||
},
|
||||
this.params = {
|
||||
K: params.get("K") || 0,
|
||||
EndOfLine: !!params.get("EndOfLine"),
|
||||
EncodedByteAlign: !!params.get("EncodedByteAlign"),
|
||||
Columns: params.get("Columns") || 1728,
|
||||
Rows: params.get("Rows") || 0,
|
||||
EndOfBlock: !!(params.get("EndOfBlock") ?? true),
|
||||
BlackIs1: !!params.get("BlackIs1"),
|
||||
};
|
||||
this.ccittFaxDecoder = new CCITTFaxDecoder(source, {
|
||||
K: params.get("K"),
|
||||
EndOfLine: params.get("EndOfLine"),
|
||||
EncodedByteAlign: params.get("EncodedByteAlign"),
|
||||
Columns: params.get("Columns"),
|
||||
Rows: params.get("Rows"),
|
||||
EndOfBlock: params.get("EndOfBlock"),
|
||||
BlackIs1: params.get("BlackIs1"),
|
||||
});
|
||||
}
|
||||
|
||||
get bytes() {
|
||||
// If `this.maybeLength` is null, we'll get the entire stream.
|
||||
return shadow(this, "bytes", this.stream.getBytes(this.maybeLength));
|
||||
}
|
||||
|
||||
readBlock() {
|
||||
while (!this.eof) {
|
||||
const c = this.ccittFaxDecoder.readNextChar();
|
||||
if (c === -1) {
|
||||
this.eof = true;
|
||||
return;
|
||||
}
|
||||
this.ensureBuffer(this.bufferLength + 1);
|
||||
this.buffer[this.bufferLength++] = c;
|
||||
}
|
||||
this.decodeImageFallback();
|
||||
}
|
||||
|
||||
get isImageStream() {
|
||||
return true;
|
||||
}
|
||||
|
||||
get isAsyncDecoder() {
|
||||
return true;
|
||||
}
|
||||
|
||||
async decodeImage(bytes, length, _decoderOptions) {
|
||||
if (this.eof) {
|
||||
return this.buffer;
|
||||
}
|
||||
if (!bytes) {
|
||||
bytes = this.stream.isAsync
|
||||
? (await this.stream.asyncGetBytes()) || this.bytes
|
||||
: this.bytes;
|
||||
}
|
||||
|
||||
try {
|
||||
this.buffer = await JBig2CCITTFaxWasmImage.decode(
|
||||
bytes,
|
||||
this.dict.get("W", "Width"),
|
||||
this.dict.get("H", "Height"),
|
||||
null,
|
||||
this.params
|
||||
);
|
||||
} catch {
|
||||
warn("CCITTFaxStream: Falling back to JS CCITTFax decoder.");
|
||||
return this.decodeImageFallback(bytes, length);
|
||||
}
|
||||
this.bufferLength = this.buffer.length;
|
||||
this.eof = true;
|
||||
|
||||
return this.buffer;
|
||||
}
|
||||
|
||||
decodeImageFallback(bytes, length) {
|
||||
if (this.eof) {
|
||||
return this.buffer;
|
||||
}
|
||||
const { params } = this;
|
||||
if (!bytes) {
|
||||
this.stream.reset();
|
||||
bytes = this.bytes;
|
||||
}
|
||||
let pos = 0;
|
||||
const source = {
|
||||
next() {
|
||||
return bytes[pos++] ?? -1;
|
||||
},
|
||||
};
|
||||
if (length && this.buffer.byteLength < length) {
|
||||
this.buffer = new Uint8Array(length);
|
||||
}
|
||||
this.ccittFaxDecoder = new CCITTFaxDecoder(source, params);
|
||||
let outPos = 0;
|
||||
while (!this.eof) {
|
||||
const c = this.ccittFaxDecoder.readNextChar();
|
||||
if (c === -1) {
|
||||
this.eof = true;
|
||||
break;
|
||||
}
|
||||
if (!length) {
|
||||
this.ensureBuffer(outPos + 1);
|
||||
}
|
||||
this.buffer[outPos++] = c;
|
||||
}
|
||||
|
||||
this.bufferLength = this.buffer.length;
|
||||
return this.buffer.subarray(0, length || this.bufferLength);
|
||||
}
|
||||
}
|
||||
|
||||
export { CCITTFaxStream };
|
||||
|
||||
@ -102,12 +102,12 @@ class DecodeStream extends BaseStream {
|
||||
async getImageData(length, decoderOptions) {
|
||||
if (!this.canAsyncDecodeImageFromBuffer) {
|
||||
if (this.isAsyncDecoder) {
|
||||
return this.decodeImage(null, decoderOptions);
|
||||
return this.decodeImage(null, length, decoderOptions);
|
||||
}
|
||||
return this.getBytes(length, decoderOptions);
|
||||
}
|
||||
const data = await this.stream.asyncGetBytes();
|
||||
return this.decodeImage(data, decoderOptions);
|
||||
return this.decodeImage(data, length, decoderOptions);
|
||||
}
|
||||
|
||||
reset() {
|
||||
|
||||
@ -23,7 +23,7 @@ class JBig2Error extends BaseException {
|
||||
}
|
||||
}
|
||||
|
||||
class JBig2WasmImage {
|
||||
class JBig2CCITTFaxWasmImage {
|
||||
static #buffer = null;
|
||||
|
||||
static #handler = null;
|
||||
@ -69,7 +69,7 @@ class JBig2WasmImage {
|
||||
}
|
||||
}
|
||||
|
||||
static async decode(bytes, width, height, globals) {
|
||||
static async decode(bytes, width, height, globals, CCITTOptions) {
|
||||
if (!this.#modulePromise) {
|
||||
const { promise, resolve } = Promise.withResolvers();
|
||||
const promises = [promise];
|
||||
@ -95,13 +95,28 @@ class JBig2WasmImage {
|
||||
const size = bytes.length;
|
||||
ptr = module._malloc(size);
|
||||
module.writeArrayToMemory(bytes, ptr);
|
||||
const globalsSize = globals ? globals.length : 0;
|
||||
if (globalsSize > 0) {
|
||||
globalsPtr = module._malloc(globalsSize);
|
||||
module.writeArrayToMemory(globals, globalsPtr);
|
||||
}
|
||||
|
||||
module._jbig2_decode(ptr, size, width, height, globalsPtr, globalsSize);
|
||||
if (CCITTOptions) {
|
||||
module._ccitt_decode(
|
||||
ptr,
|
||||
size,
|
||||
width,
|
||||
height,
|
||||
CCITTOptions.K,
|
||||
CCITTOptions.EndOfLine ? 1 : 0,
|
||||
CCITTOptions.EncodedByteAlign ? 1 : 0,
|
||||
CCITTOptions.BlackIs1 ? 1 : 0,
|
||||
CCITTOptions.Columns,
|
||||
CCITTOptions.Rows
|
||||
);
|
||||
} else {
|
||||
const globalsSize = globals ? globals.length : 0;
|
||||
if (globalsSize > 0) {
|
||||
globalsPtr = module._malloc(globalsSize);
|
||||
module.writeArrayToMemory(globals, globalsPtr);
|
||||
}
|
||||
module._jbig2_decode(ptr, size, width, height, globalsPtr, globalsSize);
|
||||
}
|
||||
if (!module.imageData) {
|
||||
throw new JBig2Error("Unknown error");
|
||||
}
|
||||
@ -124,4 +139,4 @@ class JBig2WasmImage {
|
||||
}
|
||||
}
|
||||
|
||||
export { JBig2Error, JBig2WasmImage };
|
||||
export { JBig2CCITTFaxWasmImage, JBig2Error };
|
||||
@ -17,8 +17,8 @@ import { shadow, warn } from "../shared/util.js";
|
||||
import { BaseStream } from "./base_stream.js";
|
||||
import { DecodeStream } from "./decode_stream.js";
|
||||
import { Dict } from "./primitives.js";
|
||||
import { JBig2CCITTFaxWasmImage } from "./jbig2_ccittFax_wasm.js";
|
||||
import { Jbig2Image } from "./jbig2.js";
|
||||
import { JBig2WasmImage } from "./jbig2_wasm.js";
|
||||
|
||||
/**
|
||||
* For JBIG2's we use a library to decode these images and
|
||||
@ -45,7 +45,7 @@ class Jbig2Stream extends DecodeStream {
|
||||
}
|
||||
|
||||
readBlock() {
|
||||
this.decodeImage();
|
||||
this.decodeImageFallback();
|
||||
}
|
||||
|
||||
get isAsyncDecoder() {
|
||||
@ -56,7 +56,7 @@ class Jbig2Stream extends DecodeStream {
|
||||
return true;
|
||||
}
|
||||
|
||||
async decodeImage(bytes, _decoderOptions) {
|
||||
async decodeImage(bytes, length, _decoderOptions) {
|
||||
if (this.eof) {
|
||||
return this.buffer;
|
||||
}
|
||||
@ -69,7 +69,7 @@ class Jbig2Stream extends DecodeStream {
|
||||
globals = globalsStream.getBytes();
|
||||
}
|
||||
}
|
||||
this.buffer = await JBig2WasmImage.decode(
|
||||
this.buffer = await JBig2CCITTFaxWasmImage.decode(
|
||||
bytes,
|
||||
this.dict.get("Width"),
|
||||
this.dict.get("Height"),
|
||||
@ -77,7 +77,7 @@ class Jbig2Stream extends DecodeStream {
|
||||
);
|
||||
} catch {
|
||||
warn("Jbig2Stream: Falling back to JS JBIG2 decoder.");
|
||||
return this.decodeImageFallback(bytes);
|
||||
return this.decodeImageFallback(bytes, length);
|
||||
}
|
||||
this.bufferLength = this.buffer.length;
|
||||
this.eof = true;
|
||||
@ -85,7 +85,7 @@ class Jbig2Stream extends DecodeStream {
|
||||
return this.buffer;
|
||||
}
|
||||
|
||||
async decodeImageFallback(bytes) {
|
||||
decodeImageFallback(bytes, _length) {
|
||||
if (this.eof) {
|
||||
return this.buffer;
|
||||
}
|
||||
|
||||
@ -49,7 +49,7 @@ class JpxStream extends DecodeStream {
|
||||
return true;
|
||||
}
|
||||
|
||||
async decodeImage(bytes, decoderOptions) {
|
||||
async decodeImage(bytes, _length, decoderOptions) {
|
||||
if (this.eof) {
|
||||
return this.buffer;
|
||||
}
|
||||
|
||||
@ -22,7 +22,7 @@ import {
|
||||
} from "../shared/util.js";
|
||||
import { ChunkedStreamManager } from "./chunked_stream.js";
|
||||
import { ImageResizer } from "./image_resizer.js";
|
||||
import { JBig2WasmImage } from "./jbig2_wasm.js";
|
||||
import { JBig2CCITTFaxWasmImage } from "./jbig2_ccittFax_wasm.js";
|
||||
import { JpegStream } from "./jpeg_stream.js";
|
||||
import { JpxImage } from "./jpx.js";
|
||||
import { MissingDataException } from "./core_utils.js";
|
||||
@ -82,7 +82,7 @@ class BasePdfManager {
|
||||
JpxImage.setOptions(options);
|
||||
IccColorSpace.setOptions(options);
|
||||
CmykICCBasedCS.setOptions(options);
|
||||
JBig2WasmImage.setOptions(options);
|
||||
JBig2CCITTFaxWasmImage.setOptions(options);
|
||||
}
|
||||
|
||||
get docId() {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user