Skip to content

Commit

Permalink
Merge pull request #11601 from Snuffleupagus/rm-nativeImageDecoderSup…
Browse files Browse the repository at this point in the history
…port

[api-minor] Decode all JPEG images with the built-in PDF.js decoder in `src/core/jpg.js`
  • Loading branch information
timvandermeij committed May 23, 2020
2 parents cd6d089 + ebef67b commit 3b615e4
Show file tree
Hide file tree
Showing 23 changed files with 57 additions and 682 deletions.
3 changes: 0 additions & 3 deletions examples/node/pdf2svg.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,9 +87,6 @@ function writeSvgToFile(svgElement, filePath) {
var loadingTask = pdfjsLib.getDocument({
data: data,
fontExtraProperties: true,
// Try to export JPEG images directly if they don't need any further
// processing.
nativeImageDecoderSupport: pdfjsLib.NativeImageDecoding.DISPLAY,
});
loadingTask.promise
.then(function (doc) {
Expand Down
8 changes: 0 additions & 8 deletions gulpfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -563,14 +563,6 @@ gulp.task("default_preferences-pre", function () {
};
var preprocessor2 = require("./external/builder/preprocessor2.js");
return merge([
gulp.src(
[
"src/{display,shared}/*.js",
"!src/shared/{cffStandardStrings,fonts_utils}.js",
"src/pdf.js",
],
{ base: "src/" }
),
gulp.src(["web/{app_options,viewer_compatibility}.js"], {
base: ".",
}),
Expand Down
106 changes: 1 addition & 105 deletions src/core/evaluator.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ import {
isArrayEqual,
isNum,
isString,
NativeImageDecoding,
OPS,
stringToPDFString,
TextRenderingMode,
Expand Down Expand Up @@ -80,18 +79,14 @@ import { DecodeStream } from "./stream.js";
import { getGlyphsUnicode } from "./glyphlist.js";
import { getMetrics } from "./metrics.js";
import { isPDFFunction } from "./function.js";
import { JpegStream } from "./jpeg_stream.js";
import { MurmurHash3_64 } from "./murmurhash3.js";
import { NativeImageDecoder } from "./image_utils.js";
import { OperatorList } from "./operator_list.js";
import { PDFImage } from "./image.js";

var PartialEvaluator = (function PartialEvaluatorClosure() {
const DefaultPartialEvaluatorOptions = {
forceDataSchema: false,
maxImageSize: -1,
disableFontFace: false,
nativeImageDecoderSupport: NativeImageDecoding.DECODE,
ignoreErrors: false,
isEvalSupported: true,
fontExtraProperties: false,
Expand Down Expand Up @@ -450,7 +445,6 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
operatorList,
cacheKey,
imageCache,
forceDisableNativeImageDecoder = false,
}) {
var dict = image.dict;
const imageRef = dict.objId;
Expand Down Expand Up @@ -510,13 +504,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {

var SMALL_IMAGE_DIMENSIONS = 200;
// Inlining small images into the queue as RGB data
if (
isInline &&
!softMask &&
!mask &&
!(image instanceof JpegStream) &&
w + h < SMALL_IMAGE_DIMENSIONS
) {
if (isInline && !softMask && !mask && w + h < SMALL_IMAGE_DIMENSIONS) {
const imageObj = new PDFImage({
xref: this.xref,
res: resources,
Expand All @@ -531,20 +519,12 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
return undefined;
}

let nativeImageDecoderSupport = forceDisableNativeImageDecoder
? NativeImageDecoding.NONE
: this.options.nativeImageDecoderSupport;
// If there is no imageMask, create the PDFImage and a lot
// of image processing can be done here.
let objId = `img_${this.idFactory.createObjId()}`,
cacheGlobally = false;

if (this.parsingType3Font) {
assert(
nativeImageDecoderSupport === NativeImageDecoding.NONE,
"Type3 image resources should be completely decoded in the worker."
);

objId = `${this.idFactory.getDocId()}_type3res_${objId}`;
} else if (imageRef) {
cacheGlobally = this.globalImageCache.shouldCache(
Expand All @@ -553,102 +533,19 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
);

if (cacheGlobally) {
// Ensure that the image is *completely* decoded on the worker-thread,
// in order to simplify the caching/rendering code on the main-thread.
nativeImageDecoderSupport = NativeImageDecoding.NONE;

objId = `${this.idFactory.getDocId()}_${objId}`;
}
}

if (
nativeImageDecoderSupport !== NativeImageDecoding.NONE &&
!softMask &&
!mask &&
image instanceof JpegStream &&
image.maybeValidDimensions &&
NativeImageDecoder.isSupported(
image,
this.xref,
resources,
this.pdfFunctionFactory
)
) {
// These JPEGs don't need any more processing so we can just send it.
return this.handler
.sendWithPromise("obj", [
objId,
this.pageIndex,
"JpegStream",
image.getIR(this.options.forceDataSchema),
])
.then(
() => {
// Only add the dependency once we know that the native JPEG
// decoding succeeded, to ensure that rendering will always
// complete.
operatorList.addDependency(objId);
args = [objId, w, h];

operatorList.addOp(OPS.paintJpegXObject, args);
if (cacheKey) {
imageCache[cacheKey] = {
fn: OPS.paintJpegXObject,
args,
};

if (imageRef) {
this.globalImageCache.addPageIndex(imageRef, this.pageIndex);
}
}
},
reason => {
warn(
"Native JPEG decoding failed -- trying to recover: " +
(reason && reason.message)
);
// Try to decode the JPEG image with the built-in decoder instead.
return this.buildPaintImageXObject({
resources,
image,
isInline,
operatorList,
cacheKey,
imageCache,
forceDisableNativeImageDecoder: true,
});
}
);
}

// Creates native image decoder only if a JPEG image or mask is present.
var nativeImageDecoder = null;
if (
nativeImageDecoderSupport === NativeImageDecoding.DECODE &&
(image instanceof JpegStream ||
mask instanceof JpegStream ||
softMask instanceof JpegStream)
) {
nativeImageDecoder = new NativeImageDecoder({
xref: this.xref,
resources,
handler: this.handler,
forceDataSchema: this.options.forceDataSchema,
pdfFunctionFactory: this.pdfFunctionFactory,
});
}

// Ensure that the dependency is added before the image is decoded.
operatorList.addDependency(objId);
args = [objId, w, h];

const imgPromise = PDFImage.buildImage({
handler: this.handler,
xref: this.xref,
res: resources,
image,
isInline,
nativeDecoder: nativeImageDecoder,
pdfFunctionFactory: this.pdfFunctionFactory,
})
.then(imageObj => {
Expand Down Expand Up @@ -3393,7 +3290,6 @@ class TranslatedFont {
// the rendering code on the main-thread (see issue10717.pdf).
var type3Options = Object.create(evaluator.options);
type3Options.ignoreErrors = false;
type3Options.nativeImageDecoderSupport = NativeImageDecoding.NONE;
var type3Evaluator = evaluator.clone(type3Options);
type3Evaluator.parsingType3Font = true;

Expand Down
70 changes: 20 additions & 50 deletions src/core/image.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,23 +21,6 @@ import { JpegStream } from "./jpeg_stream.js";
import { JpxImage } from "./jpx.js";

var PDFImage = (function PDFImageClosure() {
/**
* Decodes the image using native decoder if possible. Resolves the promise
* when the image data is ready.
*/
function handleImageData(image, nativeDecoder) {
if (nativeDecoder && nativeDecoder.canDecode(image)) {
return nativeDecoder.decode(image).catch(reason => {
warn(
"Native image decoding failed -- trying to recover: " +
(reason && reason.message)
);
return image;
});
}
return Promise.resolve(image);
}

/**
* Decode and clamp a value. The formula is different from the spec because we
* don't decode to float range [0,1], we decode it in the [0,max] range.
Expand Down Expand Up @@ -266,51 +249,38 @@ var PDFImage = (function PDFImageClosure() {
* with a PDFImage when the image is ready to be used.
*/
PDFImage.buildImage = function ({
handler,
xref,
res,
image,
isInline = false,
nativeDecoder = null,
pdfFunctionFactory,
}) {
var imagePromise = handleImageData(image, nativeDecoder);
var smaskPromise;
var maskPromise;
const imageData = image;
let smaskData = null;
let maskData = null;

var smask = image.dict.get("SMask");
var mask = image.dict.get("Mask");
const smask = image.dict.get("SMask");
const mask = image.dict.get("Mask");

if (smask) {
smaskPromise = handleImageData(smask, nativeDecoder);
maskPromise = Promise.resolve(null);
} else {
smaskPromise = Promise.resolve(null);
if (mask) {
if (isStream(mask)) {
maskPromise = handleImageData(mask, nativeDecoder);
} else if (Array.isArray(mask)) {
maskPromise = Promise.resolve(mask);
} else {
warn("Unsupported mask format.");
maskPromise = Promise.resolve(null);
}
smaskData = smask;
} else if (mask) {
if (isStream(mask) || Array.isArray(mask)) {
maskData = mask;
} else {
maskPromise = Promise.resolve(null);
warn("Unsupported mask format.");
}
}
return Promise.all([imagePromise, smaskPromise, maskPromise]).then(
function ([imageData, smaskData, maskData]) {
return new PDFImage({
xref,
res,
image: imageData,
isInline,
smask: smaskData,
mask: maskData,
pdfFunctionFactory,
});
}
return Promise.resolve(
new PDFImage({
xref,
res,
image: imageData,
isInline,
smask: smaskData,
mask: maskData,
pdfFunctionFactory,
})
);
};

Expand Down
Loading

0 comments on commit 3b615e4

Please sign in to comment.