Skip to content

Commit

Permalink
Add a jpx decoder based on OpenJPEG 2.5.2
Browse files Browse the repository at this point in the history
  • Loading branch information
calixteman committed Apr 16, 2024
1 parent 2e94511 commit b14f97c
Show file tree
Hide file tree
Showing 20 changed files with 184 additions and 2,345 deletions.
1 change: 1 addition & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ external/bcmaps/
external/builder/fixtures/
external/builder/fixtures_esprima/
external/quickjs/
external/openjpeg/
test/tmp/
test/pdfs/
web/locale/
Expand Down
12 changes: 12 additions & 0 deletions external/openjpeg/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
## Build

In order to generate the file `openjpeg.js`:
* git clone https://github.com/mozilla/pdf.js.openjpeg/
* the build requires to have a [Docker](https://www.docker.com/) setup and then:
* `node build.js -C` to build the Docker image
* `node build.js -co /pdf.js/external/openjpeg/` to compile the decoder

## Licensing

[OpenJPEG](https://www.openjpeg.org/) is under [BSD 2-clause "Simplified" License](https://github.com/uclouvain/openjpeg/blob/master/LICENSE)
and [pdf.js.openjpeg](https://github.com/mozilla/pdf.js.openjpeg/) is released under [Apache 2](https://github.com/mozilla/pdf.js.openjpeg/blob/main/LICENSE) license so `openjpeg.js` is released under [Apache 2](https://github.com/mozilla/pdf.js.openjpeg/blob/main/LICENSE) license too.
15 changes: 15 additions & 0 deletions external/openjpeg/openjpeg.js

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions gulpfile.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -1603,6 +1603,7 @@ function buildLib(defines, dir) {
),
gulp.src(["web/*.js", "!web/{pdfjs,viewer}.js"], { base: "." }),
gulp.src("test/unit/*.js", { base: "." }),
gulp.src("external/openjpeg/*.js", { base: "openjpeg/" }),
]);

return buildLibHelper(bundleDefines, inputStream, dir);
Expand Down
5 changes: 5 additions & 0 deletions src/core/cleanup_helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 };
6 changes: 3 additions & 3 deletions src/core/decode_stream.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -82,15 +82,15 @@ 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) {
end = bufEnd;
}
} else {
while (!this.eof) {
this.readBlock();
this.readBlock(ignoreColorSpace);
}
end = this.bufferLength;
}
Expand Down
22 changes: 14 additions & 8 deletions src/core/image.js
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ class PDFImage {
localColorSpaceCache,
}) {
this.image = image;
let jpxDecode = false;
const dict = image.dict;

const filter = dict.get("F", "Filter");
Expand All @@ -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;
Expand Down Expand Up @@ -197,6 +198,7 @@ class PDFImage {
);
}
}

this.colorSpace = ColorSpace.parse({
cs: colorSpace,
xref,
Expand All @@ -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");
Expand Down Expand Up @@ -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
Expand Down
Loading

0 comments on commit b14f97c

Please sign in to comment.