mirror of
https://github.com/mozilla/pdf.js.git
synced 2025-04-22 16:18:08 +02:00
[api-minor] Add a jpx decoder based on OpenJPEG 2.5.2
The decoder is compiled in WASM: https://github.com/mozilla/pdf.js.openjpeg Fixes #17289, #17061, #16485, #13051, #6365, #4648, #12213.
This commit is contained in:
parent
2e94511330
commit
2e83cfbbc1
20 changed files with 172 additions and 2347 deletions
|
@ -16,11 +16,16 @@
|
|||
import { clearPatternCaches } from "./pattern.js";
|
||||
import { clearPrimitiveCaches } from "./primitives.js";
|
||||
import { clearUnicodeCaches } from "./unicode.js";
|
||||
import { JpxImage } from "./jpx.js";
|
||||
|
||||
function clearGlobalCaches() {
|
||||
clearPatternCaches();
|
||||
clearPrimitiveCaches();
|
||||
clearUnicodeCaches();
|
||||
|
||||
// Remove the global `JpxImage` instance, since it may hold a reference to
|
||||
// the WebAssembly module.
|
||||
JpxImage.cleanup();
|
||||
}
|
||||
|
||||
export { clearGlobalCaches };
|
||||
|
|
|
@ -73,7 +73,7 @@ class DecodeStream extends BaseStream {
|
|||
return this.buffer[this.pos++];
|
||||
}
|
||||
|
||||
getBytes(length) {
|
||||
getBytes(length, ignoreColorSpace = false) {
|
||||
const pos = this.pos;
|
||||
let end;
|
||||
|
||||
|
@ -82,7 +82,7 @@ class DecodeStream extends BaseStream {
|
|||
end = pos + length;
|
||||
|
||||
while (!this.eof && this.bufferLength < end) {
|
||||
this.readBlock();
|
||||
this.readBlock(ignoreColorSpace);
|
||||
}
|
||||
const bufEnd = this.bufferLength;
|
||||
if (end > bufEnd) {
|
||||
|
@ -90,7 +90,7 @@ class DecodeStream extends BaseStream {
|
|||
}
|
||||
} else {
|
||||
while (!this.eof) {
|
||||
this.readBlock();
|
||||
this.readBlock(ignoreColorSpace);
|
||||
}
|
||||
end = this.bufferLength;
|
||||
}
|
||||
|
|
|
@ -104,6 +104,7 @@ class PDFImage {
|
|||
localColorSpaceCache,
|
||||
}) {
|
||||
this.image = image;
|
||||
let jpxDecode = false;
|
||||
const dict = image.dict;
|
||||
|
||||
const filter = dict.get("F", "Filter");
|
||||
|
@ -118,14 +119,14 @@ class PDFImage {
|
|||
}
|
||||
switch (filterName) {
|
||||
case "JPXDecode":
|
||||
const jpxImage = new JpxImage();
|
||||
jpxImage.parseImageProperties(image.stream);
|
||||
({
|
||||
width: image.width,
|
||||
height: image.height,
|
||||
componentsCount: image.numComps,
|
||||
bitsPerComponent: image.bitsPerComponent,
|
||||
} = JpxImage.parseImageProperties(image.stream));
|
||||
image.stream.reset();
|
||||
|
||||
image.width = jpxImage.width;
|
||||
image.height = jpxImage.height;
|
||||
image.bitsPerComponent = jpxImage.bitsPerComponent;
|
||||
image.numComps = jpxImage.componentsCount;
|
||||
jpxDecode = true;
|
||||
break;
|
||||
case "JBIG2Decode":
|
||||
image.bitsPerComponent = 1;
|
||||
|
@ -197,6 +198,7 @@ class PDFImage {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
this.colorSpace = ColorSpace.parse({
|
||||
cs: colorSpace,
|
||||
xref,
|
||||
|
@ -205,6 +207,10 @@ class PDFImage {
|
|||
localColorSpaceCache,
|
||||
});
|
||||
this.numComps = this.colorSpace.numComps;
|
||||
|
||||
// If the jpx image has a color space then it musn't be used in order to
|
||||
// be able to use the color space that comes from the pdf.
|
||||
this.ignoreColorSpace = jpxDecode && this.colorSpace.name === "Indexed";
|
||||
}
|
||||
|
||||
this.decode = dict.getArray("D", "Decode");
|
||||
|
@ -984,7 +990,7 @@ class PDFImage {
|
|||
this.image.drawHeight = drawHeight || this.height;
|
||||
this.image.forceRGBA = !!forceRGBA;
|
||||
this.image.forceRGB = !!forceRGB;
|
||||
const imageBytes = this.image.getBytes(length);
|
||||
const imageBytes = this.image.getBytes(length, this.ignoreColorSpace);
|
||||
|
||||
// If imageBytes came from a DecodeStream, we're safe to transfer it
|
||||
// (and thus detach its underlying buffer) because it will constitute
|
||||
|
|
2326
src/core/jpx.js
2326
src/core/jpx.js
File diff suppressed because it is too large
Load diff
|
@ -41,44 +41,12 @@ class JpxStream extends DecodeStream {
|
|||
// directly insert all of its data into `this.buffer`.
|
||||
}
|
||||
|
||||
readBlock() {
|
||||
readBlock(ignoreColorSpace) {
|
||||
if (this.eof) {
|
||||
return;
|
||||
}
|
||||
const jpxImage = new JpxImage();
|
||||
jpxImage.parse(this.bytes);
|
||||
|
||||
const width = jpxImage.width;
|
||||
const height = jpxImage.height;
|
||||
const componentsCount = jpxImage.componentsCount;
|
||||
const tileCount = jpxImage.tiles.length;
|
||||
if (tileCount === 1) {
|
||||
this.buffer = jpxImage.tiles[0].items;
|
||||
} else {
|
||||
const data = new Uint8ClampedArray(width * height * componentsCount);
|
||||
|
||||
for (let k = 0; k < tileCount; k++) {
|
||||
const tileComponents = jpxImage.tiles[k];
|
||||
const tileWidth = tileComponents.width;
|
||||
const tileHeight = tileComponents.height;
|
||||
const tileLeft = tileComponents.left;
|
||||
const tileTop = tileComponents.top;
|
||||
|
||||
const src = tileComponents.items;
|
||||
let srcPosition = 0;
|
||||
let dataPosition = (width * tileTop + tileLeft) * componentsCount;
|
||||
const imgRowSize = width * componentsCount;
|
||||
const tileRowSize = tileWidth * componentsCount;
|
||||
|
||||
for (let j = 0; j < tileHeight; j++) {
|
||||
const rowBytes = src.subarray(srcPosition, srcPosition + tileRowSize);
|
||||
data.set(rowBytes, dataPosition);
|
||||
srcPosition += tileRowSize;
|
||||
dataPosition += imgRowSize;
|
||||
}
|
||||
}
|
||||
this.buffer = data;
|
||||
}
|
||||
this.buffer = JpxImage.decode(this.bytes, ignoreColorSpace);
|
||||
this.bufferLength = this.buffer.length;
|
||||
this.eof = true;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue