Merge pull request #11601 from Snuffleupagus/rm-nativeImageDecoderSupport
[api-minor] Decode all JPEG images with the built-in PDF.js decoder in `src/core/jpg.js`
This commit is contained in:
commit
3b615e4ca3
@ -87,9 +87,6 @@ function writeSvgToFile(svgElement, filePath) {
|
|||||||
var loadingTask = pdfjsLib.getDocument({
|
var loadingTask = pdfjsLib.getDocument({
|
||||||
data: data,
|
data: data,
|
||||||
fontExtraProperties: true,
|
fontExtraProperties: true,
|
||||||
// Try to export JPEG images directly if they don't need any further
|
|
||||||
// processing.
|
|
||||||
nativeImageDecoderSupport: pdfjsLib.NativeImageDecoding.DISPLAY,
|
|
||||||
});
|
});
|
||||||
loadingTask.promise
|
loadingTask.promise
|
||||||
.then(function (doc) {
|
.then(function (doc) {
|
||||||
|
@ -563,14 +563,6 @@ gulp.task("default_preferences-pre", function () {
|
|||||||
};
|
};
|
||||||
var preprocessor2 = require("./external/builder/preprocessor2.js");
|
var preprocessor2 = require("./external/builder/preprocessor2.js");
|
||||||
return merge([
|
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"], {
|
gulp.src(["web/{app_options,viewer_compatibility}.js"], {
|
||||||
base: ".",
|
base: ".",
|
||||||
}),
|
}),
|
||||||
|
@ -25,7 +25,6 @@ import {
|
|||||||
isArrayEqual,
|
isArrayEqual,
|
||||||
isNum,
|
isNum,
|
||||||
isString,
|
isString,
|
||||||
NativeImageDecoding,
|
|
||||||
OPS,
|
OPS,
|
||||||
stringToPDFString,
|
stringToPDFString,
|
||||||
TextRenderingMode,
|
TextRenderingMode,
|
||||||
@ -80,18 +79,14 @@ import { DecodeStream } from "./stream.js";
|
|||||||
import { getGlyphsUnicode } from "./glyphlist.js";
|
import { getGlyphsUnicode } from "./glyphlist.js";
|
||||||
import { getMetrics } from "./metrics.js";
|
import { getMetrics } from "./metrics.js";
|
||||||
import { isPDFFunction } from "./function.js";
|
import { isPDFFunction } from "./function.js";
|
||||||
import { JpegStream } from "./jpeg_stream.js";
|
|
||||||
import { MurmurHash3_64 } from "./murmurhash3.js";
|
import { MurmurHash3_64 } from "./murmurhash3.js";
|
||||||
import { NativeImageDecoder } from "./image_utils.js";
|
|
||||||
import { OperatorList } from "./operator_list.js";
|
import { OperatorList } from "./operator_list.js";
|
||||||
import { PDFImage } from "./image.js";
|
import { PDFImage } from "./image.js";
|
||||||
|
|
||||||
var PartialEvaluator = (function PartialEvaluatorClosure() {
|
var PartialEvaluator = (function PartialEvaluatorClosure() {
|
||||||
const DefaultPartialEvaluatorOptions = {
|
const DefaultPartialEvaluatorOptions = {
|
||||||
forceDataSchema: false,
|
|
||||||
maxImageSize: -1,
|
maxImageSize: -1,
|
||||||
disableFontFace: false,
|
disableFontFace: false,
|
||||||
nativeImageDecoderSupport: NativeImageDecoding.DECODE,
|
|
||||||
ignoreErrors: false,
|
ignoreErrors: false,
|
||||||
isEvalSupported: true,
|
isEvalSupported: true,
|
||||||
fontExtraProperties: false,
|
fontExtraProperties: false,
|
||||||
@ -450,7 +445,6 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
|
|||||||
operatorList,
|
operatorList,
|
||||||
cacheKey,
|
cacheKey,
|
||||||
imageCache,
|
imageCache,
|
||||||
forceDisableNativeImageDecoder = false,
|
|
||||||
}) {
|
}) {
|
||||||
var dict = image.dict;
|
var dict = image.dict;
|
||||||
const imageRef = dict.objId;
|
const imageRef = dict.objId;
|
||||||
@ -510,13 +504,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
|
|||||||
|
|
||||||
var SMALL_IMAGE_DIMENSIONS = 200;
|
var SMALL_IMAGE_DIMENSIONS = 200;
|
||||||
// Inlining small images into the queue as RGB data
|
// Inlining small images into the queue as RGB data
|
||||||
if (
|
if (isInline && !softMask && !mask && w + h < SMALL_IMAGE_DIMENSIONS) {
|
||||||
isInline &&
|
|
||||||
!softMask &&
|
|
||||||
!mask &&
|
|
||||||
!(image instanceof JpegStream) &&
|
|
||||||
w + h < SMALL_IMAGE_DIMENSIONS
|
|
||||||
) {
|
|
||||||
const imageObj = new PDFImage({
|
const imageObj = new PDFImage({
|
||||||
xref: this.xref,
|
xref: this.xref,
|
||||||
res: resources,
|
res: resources,
|
||||||
@ -531,20 +519,12 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
let nativeImageDecoderSupport = forceDisableNativeImageDecoder
|
|
||||||
? NativeImageDecoding.NONE
|
|
||||||
: this.options.nativeImageDecoderSupport;
|
|
||||||
// If there is no imageMask, create the PDFImage and a lot
|
// If there is no imageMask, create the PDFImage and a lot
|
||||||
// of image processing can be done here.
|
// of image processing can be done here.
|
||||||
let objId = `img_${this.idFactory.createObjId()}`,
|
let objId = `img_${this.idFactory.createObjId()}`,
|
||||||
cacheGlobally = false;
|
cacheGlobally = false;
|
||||||
|
|
||||||
if (this.parsingType3Font) {
|
if (this.parsingType3Font) {
|
||||||
assert(
|
|
||||||
nativeImageDecoderSupport === NativeImageDecoding.NONE,
|
|
||||||
"Type3 image resources should be completely decoded in the worker."
|
|
||||||
);
|
|
||||||
|
|
||||||
objId = `${this.idFactory.getDocId()}_type3res_${objId}`;
|
objId = `${this.idFactory.getDocId()}_type3res_${objId}`;
|
||||||
} else if (imageRef) {
|
} else if (imageRef) {
|
||||||
cacheGlobally = this.globalImageCache.shouldCache(
|
cacheGlobally = this.globalImageCache.shouldCache(
|
||||||
@ -553,102 +533,19 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (cacheGlobally) {
|
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}`;
|
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.
|
// Ensure that the dependency is added before the image is decoded.
|
||||||
operatorList.addDependency(objId);
|
operatorList.addDependency(objId);
|
||||||
args = [objId, w, h];
|
args = [objId, w, h];
|
||||||
|
|
||||||
const imgPromise = PDFImage.buildImage({
|
const imgPromise = PDFImage.buildImage({
|
||||||
handler: this.handler,
|
|
||||||
xref: this.xref,
|
xref: this.xref,
|
||||||
res: resources,
|
res: resources,
|
||||||
image,
|
image,
|
||||||
isInline,
|
isInline,
|
||||||
nativeDecoder: nativeImageDecoder,
|
|
||||||
pdfFunctionFactory: this.pdfFunctionFactory,
|
pdfFunctionFactory: this.pdfFunctionFactory,
|
||||||
})
|
})
|
||||||
.then(imageObj => {
|
.then(imageObj => {
|
||||||
@ -3393,7 +3290,6 @@ class TranslatedFont {
|
|||||||
// the rendering code on the main-thread (see issue10717.pdf).
|
// the rendering code on the main-thread (see issue10717.pdf).
|
||||||
var type3Options = Object.create(evaluator.options);
|
var type3Options = Object.create(evaluator.options);
|
||||||
type3Options.ignoreErrors = false;
|
type3Options.ignoreErrors = false;
|
||||||
type3Options.nativeImageDecoderSupport = NativeImageDecoding.NONE;
|
|
||||||
var type3Evaluator = evaluator.clone(type3Options);
|
var type3Evaluator = evaluator.clone(type3Options);
|
||||||
type3Evaluator.parsingType3Font = true;
|
type3Evaluator.parsingType3Font = true;
|
||||||
|
|
||||||
|
@ -21,23 +21,6 @@ import { JpegStream } from "./jpeg_stream.js";
|
|||||||
import { JpxImage } from "./jpx.js";
|
import { JpxImage } from "./jpx.js";
|
||||||
|
|
||||||
var PDFImage = (function PDFImageClosure() {
|
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
|
* 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.
|
* don't decode to float range [0,1], we decode it in the [0,max] range.
|
||||||
@ -266,51 +249,38 @@ var PDFImage = (function PDFImageClosure() {
|
|||||||
* with a PDFImage when the image is ready to be used.
|
* with a PDFImage when the image is ready to be used.
|
||||||
*/
|
*/
|
||||||
PDFImage.buildImage = function ({
|
PDFImage.buildImage = function ({
|
||||||
handler,
|
|
||||||
xref,
|
xref,
|
||||||
res,
|
res,
|
||||||
image,
|
image,
|
||||||
isInline = false,
|
isInline = false,
|
||||||
nativeDecoder = null,
|
|
||||||
pdfFunctionFactory,
|
pdfFunctionFactory,
|
||||||
}) {
|
}) {
|
||||||
var imagePromise = handleImageData(image, nativeDecoder);
|
const imageData = image;
|
||||||
var smaskPromise;
|
let smaskData = null;
|
||||||
var maskPromise;
|
let maskData = null;
|
||||||
|
|
||||||
var smask = image.dict.get("SMask");
|
const smask = image.dict.get("SMask");
|
||||||
var mask = image.dict.get("Mask");
|
const mask = image.dict.get("Mask");
|
||||||
|
|
||||||
if (smask) {
|
if (smask) {
|
||||||
smaskPromise = handleImageData(smask, nativeDecoder);
|
smaskData = smask;
|
||||||
maskPromise = Promise.resolve(null);
|
} else if (mask) {
|
||||||
} else {
|
if (isStream(mask) || Array.isArray(mask)) {
|
||||||
smaskPromise = Promise.resolve(null);
|
maskData = mask;
|
||||||
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);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
maskPromise = Promise.resolve(null);
|
warn("Unsupported mask format.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Promise.all([imagePromise, smaskPromise, maskPromise]).then(
|
return Promise.resolve(
|
||||||
function ([imageData, smaskData, maskData]) {
|
new PDFImage({
|
||||||
return new PDFImage({
|
xref,
|
||||||
xref,
|
res,
|
||||||
res,
|
image: imageData,
|
||||||
image: imageData,
|
isInline,
|
||||||
isInline,
|
smask: smaskData,
|
||||||
smask: smaskData,
|
mask: maskData,
|
||||||
mask: maskData,
|
pdfFunctionFactory,
|
||||||
pdfFunctionFactory,
|
})
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -15,103 +15,7 @@
|
|||||||
/* eslint no-var: error */
|
/* eslint no-var: error */
|
||||||
|
|
||||||
import { assert, info, shadow } from "../shared/util.js";
|
import { assert, info, shadow } from "../shared/util.js";
|
||||||
import { ColorSpace } from "./colorspace.js";
|
|
||||||
import { JpegStream } from "./jpeg_stream.js";
|
|
||||||
import { RefSetCache } from "./primitives.js";
|
import { RefSetCache } from "./primitives.js";
|
||||||
import { Stream } from "./stream.js";
|
|
||||||
|
|
||||||
class NativeImageDecoder {
|
|
||||||
constructor({
|
|
||||||
xref,
|
|
||||||
resources,
|
|
||||||
handler,
|
|
||||||
forceDataSchema = false,
|
|
||||||
pdfFunctionFactory,
|
|
||||||
}) {
|
|
||||||
this.xref = xref;
|
|
||||||
this.resources = resources;
|
|
||||||
this.handler = handler;
|
|
||||||
this.forceDataSchema = forceDataSchema;
|
|
||||||
this.pdfFunctionFactory = pdfFunctionFactory;
|
|
||||||
}
|
|
||||||
|
|
||||||
canDecode(image) {
|
|
||||||
return (
|
|
||||||
image instanceof JpegStream &&
|
|
||||||
image.maybeValidDimensions &&
|
|
||||||
NativeImageDecoder.isDecodable(
|
|
||||||
image,
|
|
||||||
this.xref,
|
|
||||||
this.resources,
|
|
||||||
this.pdfFunctionFactory
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
decode(image) {
|
|
||||||
// For natively supported JPEGs send them to the main thread for decoding.
|
|
||||||
const dict = image.dict;
|
|
||||||
let colorSpace = dict.get("ColorSpace", "CS");
|
|
||||||
colorSpace = ColorSpace.parse(
|
|
||||||
colorSpace,
|
|
||||||
this.xref,
|
|
||||||
this.resources,
|
|
||||||
this.pdfFunctionFactory
|
|
||||||
);
|
|
||||||
|
|
||||||
return this.handler
|
|
||||||
.sendWithPromise("JpegDecode", [
|
|
||||||
image.getIR(this.forceDataSchema),
|
|
||||||
colorSpace.numComps,
|
|
||||||
])
|
|
||||||
.then(function ({ data, width, height }) {
|
|
||||||
return new Stream(data, 0, data.length, dict);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the image can be decoded and displayed by the browser without any
|
|
||||||
* further processing such as color space conversions.
|
|
||||||
*/
|
|
||||||
static isSupported(image, xref, res, pdfFunctionFactory) {
|
|
||||||
const dict = image.dict;
|
|
||||||
if (dict.has("DecodeParms") || dict.has("DP")) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
const cs = ColorSpace.parse(
|
|
||||||
dict.get("ColorSpace", "CS"),
|
|
||||||
xref,
|
|
||||||
res,
|
|
||||||
pdfFunctionFactory
|
|
||||||
);
|
|
||||||
// isDefaultDecode() of DeviceGray and DeviceRGB needs no `bpc` argument.
|
|
||||||
return (
|
|
||||||
(cs.name === "DeviceGray" || cs.name === "DeviceRGB") &&
|
|
||||||
cs.isDefaultDecode(dict.getArray("Decode", "D"))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the image can be decoded by the browser.
|
|
||||||
*/
|
|
||||||
static isDecodable(image, xref, res, pdfFunctionFactory) {
|
|
||||||
const dict = image.dict;
|
|
||||||
if (dict.has("DecodeParms") || dict.has("DP")) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
const cs = ColorSpace.parse(
|
|
||||||
dict.get("ColorSpace", "CS"),
|
|
||||||
xref,
|
|
||||||
res,
|
|
||||||
pdfFunctionFactory
|
|
||||||
);
|
|
||||||
const bpc = dict.get("BitsPerComponent", "BPC") || 1;
|
|
||||||
return (
|
|
||||||
(cs.numComps === 1 || cs.numComps === 3) &&
|
|
||||||
cs.isDefaultDecode(dict.getArray("Decode", "D"), bpc)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class GlobalImageCache {
|
class GlobalImageCache {
|
||||||
static get NUM_PAGES_THRESHOLD() {
|
static get NUM_PAGES_THRESHOLD() {
|
||||||
@ -207,4 +111,4 @@ class GlobalImageCache {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export { NativeImageDecoder, GlobalImageCache };
|
export { GlobalImageCache };
|
||||||
|
@ -13,17 +13,14 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { createObjectURL, shadow } from "../shared/util.js";
|
|
||||||
import { DecodeStream } from "./stream.js";
|
import { DecodeStream } from "./stream.js";
|
||||||
import { isDict } from "./primitives.js";
|
import { isDict } from "./primitives.js";
|
||||||
import { JpegImage } from "./jpg.js";
|
import { JpegImage } from "./jpg.js";
|
||||||
|
import { shadow } from "../shared/util.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Depending on the type of JPEG a JpegStream is handled in different ways. For
|
* For JPEG's we use a library to decode these images and the stream behaves
|
||||||
* JPEG's that are supported natively such as DeviceGray and DeviceRGB the image
|
* like all the other DecodeStreams.
|
||||||
* data is stored and then loaded by the browser. For unsupported JPEG's we use
|
|
||||||
* a library to decode these images and the stream behaves like all the other
|
|
||||||
* DecodeStreams.
|
|
||||||
*/
|
*/
|
||||||
const JpegStream = (function JpegStreamClosure() {
|
const JpegStream = (function JpegStreamClosure() {
|
||||||
// eslint-disable-next-line no-shadow
|
// eslint-disable-next-line no-shadow
|
||||||
@ -110,150 +107,6 @@ const JpegStream = (function JpegStreamClosure() {
|
|||||||
this.eof = true;
|
this.eof = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
Object.defineProperty(JpegStream.prototype, "maybeValidDimensions", {
|
|
||||||
get: function JpegStream_maybeValidDimensions() {
|
|
||||||
const { dict, stream } = this;
|
|
||||||
const dictHeight = dict.get("Height", "H");
|
|
||||||
const startPos = stream.pos;
|
|
||||||
|
|
||||||
let validDimensions = true,
|
|
||||||
foundSOF = false,
|
|
||||||
b;
|
|
||||||
while ((b = stream.getByte()) !== -1) {
|
|
||||||
if (b !== 0xff) {
|
|
||||||
// Not a valid marker.
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
switch (stream.getByte()) {
|
|
||||||
case 0xc0: // SOF0
|
|
||||||
case 0xc1: // SOF1
|
|
||||||
case 0xc2: // SOF2
|
|
||||||
// These three SOF{n} markers are the only ones that the built-in
|
|
||||||
// PDF.js JPEG decoder currently supports.
|
|
||||||
foundSOF = true;
|
|
||||||
|
|
||||||
stream.pos += 2; // Skip marker length.
|
|
||||||
stream.pos += 1; // Skip precision.
|
|
||||||
const scanLines = stream.getUint16();
|
|
||||||
const samplesPerLine = stream.getUint16();
|
|
||||||
|
|
||||||
// Letting the browser handle the JPEG decoding, on the main-thread,
|
|
||||||
// will cause a *large* increase in peak memory usage since there's
|
|
||||||
// a handful of short-lived copies of the image data. For very big
|
|
||||||
// JPEG images, always let the PDF.js image decoder handle them to
|
|
||||||
// reduce overall memory usage during decoding (see issue 11694).
|
|
||||||
if (scanLines * samplesPerLine > 1e6) {
|
|
||||||
validDimensions = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The "normal" case, where the image data and dictionary agrees.
|
|
||||||
if (scanLines === dictHeight) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// A DNL (Define Number of Lines) marker is expected,
|
|
||||||
// which browsers (usually) cannot decode natively.
|
|
||||||
if (scanLines === 0) {
|
|
||||||
validDimensions = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// The dimensions of the image, among other properties, should
|
|
||||||
// always be taken from the image data *itself* rather than the
|
|
||||||
// XObject dictionary. However there's cases of corrupt images that
|
|
||||||
// browsers cannot decode natively, for example:
|
|
||||||
// - JPEG images with DNL markers, where the SOF `scanLines`
|
|
||||||
// parameter has an unexpected value (see issue 8614).
|
|
||||||
// - JPEG images with too large SOF `scanLines` parameter, where
|
|
||||||
// the EOI marker is encountered prematurely (see issue 10880).
|
|
||||||
// In an attempt to handle these kinds of corrupt images, compare
|
|
||||||
// the dimensions in the image data with the dictionary and *always*
|
|
||||||
// let the PDF.js JPEG decoder (rather than the browser) handle the
|
|
||||||
// image if the difference is larger than one order of magnitude
|
|
||||||
// (since that would generally suggest that something is off).
|
|
||||||
if (scanLines > dictHeight * 10) {
|
|
||||||
validDimensions = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 0xc3: // SOF3
|
|
||||||
/* falls through */
|
|
||||||
case 0xc5: // SOF5
|
|
||||||
case 0xc6: // SOF6
|
|
||||||
case 0xc7: // SOF7
|
|
||||||
/* falls through */
|
|
||||||
case 0xc9: // SOF9
|
|
||||||
case 0xca: // SOF10
|
|
||||||
case 0xcb: // SOF11
|
|
||||||
/* falls through */
|
|
||||||
case 0xcd: // SOF13
|
|
||||||
case 0xce: // SOF14
|
|
||||||
case 0xcf: // SOF15
|
|
||||||
foundSOF = true;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 0xc4: // DHT
|
|
||||||
case 0xcc: // DAC
|
|
||||||
/* falls through */
|
|
||||||
case 0xda: // SOS
|
|
||||||
case 0xdb: // DQT
|
|
||||||
case 0xdc: // DNL
|
|
||||||
case 0xdd: // DRI
|
|
||||||
case 0xde: // DHP
|
|
||||||
case 0xdf: // EXP
|
|
||||||
/* falls through */
|
|
||||||
case 0xe0: // APP0
|
|
||||||
case 0xe1: // APP1
|
|
||||||
case 0xe2: // APP2
|
|
||||||
case 0xe3: // APP3
|
|
||||||
case 0xe4: // APP4
|
|
||||||
case 0xe5: // APP5
|
|
||||||
case 0xe6: // APP6
|
|
||||||
case 0xe7: // APP7
|
|
||||||
case 0xe8: // APP8
|
|
||||||
case 0xe9: // APP9
|
|
||||||
case 0xea: // APP10
|
|
||||||
case 0xeb: // APP11
|
|
||||||
case 0xec: // APP12
|
|
||||||
case 0xed: // APP13
|
|
||||||
case 0xee: // APP14
|
|
||||||
case 0xef: // APP15
|
|
||||||
/* falls through */
|
|
||||||
case 0xfe: // COM
|
|
||||||
const markerLength = stream.getUint16();
|
|
||||||
if (markerLength > 2) {
|
|
||||||
stream.skip(markerLength - 2); // Jump to the next marker.
|
|
||||||
} else {
|
|
||||||
// The marker length is invalid, resetting the stream position.
|
|
||||||
stream.skip(-2);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 0xff: // Fill byte.
|
|
||||||
// Avoid skipping a valid marker, resetting the stream position.
|
|
||||||
stream.skip(-1);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 0xd9: // EOI
|
|
||||||
foundSOF = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (foundSOF) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Finally, don't forget to reset the stream position.
|
|
||||||
stream.pos = startPos;
|
|
||||||
|
|
||||||
return shadow(this, "maybeValidDimensions", validDimensions);
|
|
||||||
},
|
|
||||||
configurable: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
JpegStream.prototype.getIR = function (forceDataSchema = false) {
|
|
||||||
return createObjectURL(this.bytes, "image/jpeg", forceDataSchema);
|
|
||||||
};
|
|
||||||
|
|
||||||
return JpegStream;
|
return JpegStream;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
@ -399,10 +399,8 @@ var WorkerMessageHandler = {
|
|||||||
ensureNotTerminated();
|
ensureNotTerminated();
|
||||||
|
|
||||||
var evaluatorOptions = {
|
var evaluatorOptions = {
|
||||||
forceDataSchema: data.disableCreateObjectURL,
|
|
||||||
maxImageSize: data.maxImageSize,
|
maxImageSize: data.maxImageSize,
|
||||||
disableFontFace: data.disableFontFace,
|
disableFontFace: data.disableFontFace,
|
||||||
nativeImageDecoderSupport: data.nativeImageDecoderSupport,
|
|
||||||
ignoreErrors: data.ignoreErrors,
|
ignoreErrors: data.ignoreErrors,
|
||||||
isEvalSupported: data.isEvalSupported,
|
isEvalSupported: data.isEvalSupported,
|
||||||
fontExtraProperties: data.fontExtraProperties,
|
fontExtraProperties: data.fontExtraProperties,
|
||||||
|
@ -28,7 +28,6 @@ import {
|
|||||||
isArrayBuffer,
|
isArrayBuffer,
|
||||||
isSameOrigin,
|
isSameOrigin,
|
||||||
MissingPDFException,
|
MissingPDFException,
|
||||||
NativeImageDecoding,
|
|
||||||
PasswordException,
|
PasswordException,
|
||||||
setVerbosityLevel,
|
setVerbosityLevel,
|
||||||
shadow,
|
shadow,
|
||||||
@ -44,7 +43,6 @@ import {
|
|||||||
DOMCMapReaderFactory,
|
DOMCMapReaderFactory,
|
||||||
loadScript,
|
loadScript,
|
||||||
PageViewport,
|
PageViewport,
|
||||||
releaseImageResources,
|
|
||||||
RenderingCancelledException,
|
RenderingCancelledException,
|
||||||
StatTimer,
|
StatTimer,
|
||||||
} from "./display_utils.js";
|
} from "./display_utils.js";
|
||||||
@ -116,14 +114,6 @@ function setPDFNetworkStreamFactory(pdfNetworkStreamFactory) {
|
|||||||
* @property {string} [docBaseUrl] - The base URL of the document,
|
* @property {string} [docBaseUrl] - The base URL of the document,
|
||||||
* used when attempting to recover valid absolute URLs for annotations, and
|
* used when attempting to recover valid absolute URLs for annotations, and
|
||||||
* outline items, that (incorrectly) only specify relative URLs.
|
* outline items, that (incorrectly) only specify relative URLs.
|
||||||
* @property {string} [nativeImageDecoderSupport] - Strategy for
|
|
||||||
* decoding certain (simple) JPEG images in the browser. This is useful for
|
|
||||||
* environments without DOM image and canvas support, such as e.g. Node.js.
|
|
||||||
* Valid values are 'decode', 'display' or 'none'; where 'decode' is intended
|
|
||||||
* for browsers with full image/canvas support, 'display' for environments
|
|
||||||
* with limited image support through stubs (useful for SVG conversion),
|
|
||||||
* and 'none' where JPEG images will be decoded entirely by PDF.js.
|
|
||||||
* The default value is 'decode'.
|
|
||||||
* @property {string} [cMapUrl] - The URL where the predefined
|
* @property {string} [cMapUrl] - The URL where the predefined
|
||||||
* Adobe CMaps are located. Include trailing slash.
|
* Adobe CMaps are located. Include trailing slash.
|
||||||
* @property {boolean} [cMapPacked] - Specifies if the Adobe CMaps are
|
* @property {boolean} [cMapPacked] - Specifies if the Adobe CMaps are
|
||||||
@ -164,9 +154,6 @@ function setPDFNetworkStreamFactory(pdfNetworkStreamFactory) {
|
|||||||
* The default value is `false`.
|
* The default value is `false`.
|
||||||
* NOTE: It is also necessary to disable streaming, see above,
|
* NOTE: It is also necessary to disable streaming, see above,
|
||||||
* in order for disabling of pre-fetching to work correctly.
|
* in order for disabling of pre-fetching to work correctly.
|
||||||
* @property {boolean} [disableCreateObjectURL] - Disable the use of
|
|
||||||
* `URL.createObjectURL`, for compatibility with older browsers.
|
|
||||||
* The default value is `false`.
|
|
||||||
* @property {boolean} [pdfBug] - Enables special hooks for debugging
|
* @property {boolean} [pdfBug] - Enables special hooks for debugging
|
||||||
* PDF.js (see `web/debugger.js`). The default value is `false`.
|
* PDF.js (see `web/debugger.js`). The default value is `false`.
|
||||||
*/
|
*/
|
||||||
@ -260,15 +247,6 @@ function getDocument(src) {
|
|||||||
params.fontExtraProperties = params.fontExtraProperties === true;
|
params.fontExtraProperties = params.fontExtraProperties === true;
|
||||||
params.pdfBug = params.pdfBug === true;
|
params.pdfBug = params.pdfBug === true;
|
||||||
|
|
||||||
const NativeImageDecoderValues = Object.values(NativeImageDecoding);
|
|
||||||
if (
|
|
||||||
params.nativeImageDecoderSupport === undefined ||
|
|
||||||
!NativeImageDecoderValues.includes(params.nativeImageDecoderSupport)
|
|
||||||
) {
|
|
||||||
params.nativeImageDecoderSupport =
|
|
||||||
apiCompatibilityParams.nativeImageDecoderSupport ||
|
|
||||||
NativeImageDecoding.DECODE;
|
|
||||||
}
|
|
||||||
if (!Number.isInteger(params.maxImageSize)) {
|
if (!Number.isInteger(params.maxImageSize)) {
|
||||||
params.maxImageSize = -1;
|
params.maxImageSize = -1;
|
||||||
}
|
}
|
||||||
@ -288,10 +266,6 @@ function getDocument(src) {
|
|||||||
if (typeof params.disableAutoFetch !== "boolean") {
|
if (typeof params.disableAutoFetch !== "boolean") {
|
||||||
params.disableAutoFetch = false;
|
params.disableAutoFetch = false;
|
||||||
}
|
}
|
||||||
if (typeof params.disableCreateObjectURL !== "boolean") {
|
|
||||||
params.disableCreateObjectURL =
|
|
||||||
apiCompatibilityParams.disableCreateObjectURL || false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the main-thread verbosity level.
|
// Set the main-thread verbosity level.
|
||||||
setVerbosityLevel(params.verbosity);
|
setVerbosityLevel(params.verbosity);
|
||||||
@ -414,10 +388,8 @@ function _fetchDocument(worker, source, pdfDataRangeTransport, docId) {
|
|||||||
},
|
},
|
||||||
maxImageSize: source.maxImageSize,
|
maxImageSize: source.maxImageSize,
|
||||||
disableFontFace: source.disableFontFace,
|
disableFontFace: source.disableFontFace,
|
||||||
disableCreateObjectURL: source.disableCreateObjectURL,
|
|
||||||
postMessageTransfers: worker.postMessageTransfers,
|
postMessageTransfers: worker.postMessageTransfers,
|
||||||
docBaseUrl: source.docBaseUrl,
|
docBaseUrl: source.docBaseUrl,
|
||||||
nativeImageDecoderSupport: source.nativeImageDecoderSupport,
|
|
||||||
ignoreErrors: source.ignoreErrors,
|
ignoreErrors: source.ignoreErrors,
|
||||||
isEvalSupported: source.isEvalSupported,
|
isEvalSupported: source.isEvalSupported,
|
||||||
fontExtraProperties: source.fontExtraProperties,
|
fontExtraProperties: source.fontExtraProperties,
|
||||||
@ -2309,26 +2281,6 @@ class WorkerTransport {
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case "JpegStream":
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
const img = new Image();
|
|
||||||
img.onload = function () {
|
|
||||||
resolve(img);
|
|
||||||
};
|
|
||||||
img.onerror = function () {
|
|
||||||
// Note that when the browser image loading/decoding fails,
|
|
||||||
// we'll fallback to the built-in PDF.js JPEG decoder; see
|
|
||||||
// `PartialEvaluator.buildPaintImageXObject` in the
|
|
||||||
// `src/core/evaluator.js` file.
|
|
||||||
reject(new Error("Error during JPEG image loading"));
|
|
||||||
|
|
||||||
// Always remember to release the image data if errors occurred.
|
|
||||||
releaseImageResources(img);
|
|
||||||
};
|
|
||||||
img.src = imageData;
|
|
||||||
}).then(img => {
|
|
||||||
pageProxy.objs.resolve(id, img);
|
|
||||||
});
|
|
||||||
case "Image":
|
case "Image":
|
||||||
pageProxy.objs.resolve(id, imageData);
|
pageProxy.objs.resolve(id, imageData);
|
||||||
|
|
||||||
@ -2366,69 +2318,6 @@ class WorkerTransport {
|
|||||||
this._onUnsupportedFeature.bind(this)
|
this._onUnsupportedFeature.bind(this)
|
||||||
);
|
);
|
||||||
|
|
||||||
messageHandler.on("JpegDecode", ([imageUrl, components]) => {
|
|
||||||
if (this.destroyed) {
|
|
||||||
return Promise.reject(new Error("Worker was destroyed"));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof document === "undefined") {
|
|
||||||
// Make sure that this code is not executing in node.js, as
|
|
||||||
// it's using DOM image, and there is no library to support that.
|
|
||||||
return Promise.reject(new Error('"document" is not defined.'));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (components !== 3 && components !== 1) {
|
|
||||||
return Promise.reject(
|
|
||||||
new Error("Only 3 components or 1 component can be returned")
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Promise(function (resolve, reject) {
|
|
||||||
const img = new Image();
|
|
||||||
img.onload = function () {
|
|
||||||
const { width, height } = img;
|
|
||||||
const size = width * height;
|
|
||||||
const rgbaLength = size * 4;
|
|
||||||
const buf = new Uint8ClampedArray(size * components);
|
|
||||||
let tmpCanvas = document.createElement("canvas");
|
|
||||||
tmpCanvas.width = width;
|
|
||||||
tmpCanvas.height = height;
|
|
||||||
let tmpCtx = tmpCanvas.getContext("2d");
|
|
||||||
tmpCtx.drawImage(img, 0, 0);
|
|
||||||
const data = tmpCtx.getImageData(0, 0, width, height).data;
|
|
||||||
|
|
||||||
if (components === 3) {
|
|
||||||
for (let i = 0, j = 0; i < rgbaLength; i += 4, j += 3) {
|
|
||||||
buf[j] = data[i];
|
|
||||||
buf[j + 1] = data[i + 1];
|
|
||||||
buf[j + 2] = data[i + 2];
|
|
||||||
}
|
|
||||||
} else if (components === 1) {
|
|
||||||
for (let i = 0, j = 0; i < rgbaLength; i += 4, j++) {
|
|
||||||
buf[j] = data[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
resolve({ data: buf, width, height });
|
|
||||||
|
|
||||||
// Immediately release the image data once decoding has finished.
|
|
||||||
releaseImageResources(img);
|
|
||||||
// Zeroing the width and height cause Firefox to release graphics
|
|
||||||
// resources immediately, which can greatly reduce memory consumption.
|
|
||||||
tmpCanvas.width = 0;
|
|
||||||
tmpCanvas.height = 0;
|
|
||||||
tmpCanvas = null;
|
|
||||||
tmpCtx = null;
|
|
||||||
};
|
|
||||||
img.onerror = function () {
|
|
||||||
reject(new Error("JpegDecode failed to load image"));
|
|
||||||
|
|
||||||
// Always remember to release the image data if errors occurred.
|
|
||||||
releaseImageResources(img);
|
|
||||||
};
|
|
||||||
img.src = imageUrl;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
messageHandler.on("FetchBuiltInCMap", (data, sink) => {
|
messageHandler.on("FetchBuiltInCMap", (data, sink) => {
|
||||||
if (this.destroyed) {
|
if (this.destroyed) {
|
||||||
sink.error(new Error("Worker was destroyed"));
|
sink.error(new Error("Worker was destroyed"));
|
||||||
@ -2608,9 +2497,7 @@ class WorkerTransport {
|
|||||||
const params = this._params;
|
const params = this._params;
|
||||||
return shadow(this, "loadingParams", {
|
return shadow(this, "loadingParams", {
|
||||||
disableAutoFetch: params.disableAutoFetch,
|
disableAutoFetch: params.disableAutoFetch,
|
||||||
disableCreateObjectURL: params.disableCreateObjectURL,
|
|
||||||
disableFontFace: params.disableFontFace,
|
disableFontFace: params.disableFontFace,
|
||||||
nativeImageDecoderSupport: params.nativeImageDecoderSupport,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2684,14 +2571,6 @@ class PDFObjects {
|
|||||||
}
|
}
|
||||||
|
|
||||||
clear() {
|
clear() {
|
||||||
for (const objId in this._objs) {
|
|
||||||
const { data } = this._objs[objId];
|
|
||||||
|
|
||||||
if (typeof Image !== "undefined" && data instanceof Image) {
|
|
||||||
// Always release the image data when clearing out the cached objects.
|
|
||||||
releaseImageResources(data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this._objs = Object.create(null);
|
this._objs = Object.create(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,27 +17,11 @@ import { isNodeJS } from "../shared/is_node.js";
|
|||||||
|
|
||||||
const compatibilityParams = Object.create(null);
|
const compatibilityParams = Object.create(null);
|
||||||
if (typeof PDFJSDev === "undefined" || PDFJSDev.test("GENERIC")) {
|
if (typeof PDFJSDev === "undefined" || PDFJSDev.test("GENERIC")) {
|
||||||
const userAgent =
|
|
||||||
(typeof navigator !== "undefined" && navigator.userAgent) || "";
|
|
||||||
const isIE = /Trident/.test(userAgent);
|
|
||||||
const isIOSChrome = /CriOS/.test(userAgent);
|
|
||||||
|
|
||||||
// Checks if possible to use URL.createObjectURL()
|
|
||||||
// Support: IE, Chrome on iOS
|
|
||||||
(function checkOnBlobSupport() {
|
|
||||||
// Sometimes IE and Chrome on iOS losing the data created with
|
|
||||||
// createObjectURL(), see issues #3977 and #8081.
|
|
||||||
if (isIE || isIOSChrome) {
|
|
||||||
compatibilityParams.disableCreateObjectURL = true;
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
|
|
||||||
// Support: Node.js
|
// Support: Node.js
|
||||||
(function checkFontFaceAndImage() {
|
(function checkFontFace() {
|
||||||
// Node.js is missing native support for `@font-face` and `Image`.
|
// Node.js is missing native support for `@font-face`.
|
||||||
if (isNodeJS) {
|
if (isNodeJS) {
|
||||||
compatibilityParams.disableFontFace = true;
|
compatibilityParams.disableFontFace = true;
|
||||||
compatibilityParams.nativeImageDecoderSupport = "none";
|
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
}
|
}
|
||||||
|
@ -2113,46 +2113,6 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
|||||||
this.restore();
|
this.restore();
|
||||||
},
|
},
|
||||||
|
|
||||||
paintJpegXObject: function CanvasGraphics_paintJpegXObject(objId, w, h) {
|
|
||||||
const domImage = objId.startsWith("g_")
|
|
||||||
? this.commonObjs.get(objId)
|
|
||||||
: this.objs.get(objId);
|
|
||||||
if (!domImage) {
|
|
||||||
warn("Dependent image isn't ready yet");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.save();
|
|
||||||
|
|
||||||
var ctx = this.ctx;
|
|
||||||
// scale the image to the unit square
|
|
||||||
ctx.scale(1 / w, -1 / h);
|
|
||||||
|
|
||||||
ctx.drawImage(
|
|
||||||
domImage,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
domImage.width,
|
|
||||||
domImage.height,
|
|
||||||
0,
|
|
||||||
-h,
|
|
||||||
w,
|
|
||||||
h
|
|
||||||
);
|
|
||||||
if (this.imageLayer) {
|
|
||||||
var currentTransform = ctx.mozCurrentTransformInverse;
|
|
||||||
var position = this.getCanvasPosition(0, 0);
|
|
||||||
this.imageLayer.appendImage({
|
|
||||||
objId,
|
|
||||||
left: position[0],
|
|
||||||
top: position[1],
|
|
||||||
width: w / currentTransform[0],
|
|
||||||
height: h / currentTransform[3],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
this.restore();
|
|
||||||
},
|
|
||||||
|
|
||||||
paintImageMaskXObject: function CanvasGraphics_paintImageMaskXObject(img) {
|
paintImageMaskXObject: function CanvasGraphics_paintImageMaskXObject(img) {
|
||||||
var ctx = this.ctx;
|
var ctx = this.ctx;
|
||||||
var width = img.width,
|
var width = img.width,
|
||||||
@ -2353,9 +2313,9 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
|||||||
var paintWidth = width,
|
var paintWidth = width,
|
||||||
paintHeight = height;
|
paintHeight = height;
|
||||||
var tmpCanvasId = "prescale1";
|
var tmpCanvasId = "prescale1";
|
||||||
// Vertial or horizontal scaling shall not be more than 2 to not loose the
|
// Vertical or horizontal scaling shall not be more than 2 to not lose the
|
||||||
// pixels during drawImage operation, painting on the temporary canvas(es)
|
// pixels during drawImage operation, painting on the temporary canvas(es)
|
||||||
// that are twice smaller in size
|
// that are twice smaller in size.
|
||||||
while (
|
while (
|
||||||
(widthScale > 2 && paintWidth > 1) ||
|
(widthScale > 2 && paintWidth > 1) ||
|
||||||
(heightScale > 2 && paintHeight > 1)
|
(heightScale > 2 && paintHeight > 1)
|
||||||
|
@ -517,20 +517,6 @@ function deprecated(details) {
|
|||||||
console.log("Deprecated API usage: " + details);
|
console.log("Deprecated API usage: " + details);
|
||||||
}
|
}
|
||||||
|
|
||||||
function releaseImageResources(img) {
|
|
||||||
assert(img instanceof Image, "Invalid `img` parameter.");
|
|
||||||
|
|
||||||
const url = img.src;
|
|
||||||
if (
|
|
||||||
typeof url === "string" &&
|
|
||||||
url.startsWith("blob:") &&
|
|
||||||
URL.revokeObjectURL
|
|
||||||
) {
|
|
||||||
URL.revokeObjectURL(url);
|
|
||||||
}
|
|
||||||
img.removeAttribute("src");
|
|
||||||
}
|
|
||||||
|
|
||||||
let pdfDateStringRegex;
|
let pdfDateStringRegex;
|
||||||
|
|
||||||
class PDFDateString {
|
class PDFDateString {
|
||||||
@ -631,6 +617,5 @@ export {
|
|||||||
isValidFetchUrl,
|
isValidFetchUrl,
|
||||||
loadScript,
|
loadScript,
|
||||||
deprecated,
|
deprecated,
|
||||||
releaseImageResources,
|
|
||||||
PDFDateString,
|
PDFDateString,
|
||||||
};
|
};
|
||||||
|
@ -440,7 +440,7 @@ if (typeof PDFJSDev === "undefined" || PDFJSDev.test("GENERIC")) {
|
|||||||
|
|
||||||
// eslint-disable-next-line no-shadow
|
// eslint-disable-next-line no-shadow
|
||||||
SVGGraphics = class SVGGraphics {
|
SVGGraphics = class SVGGraphics {
|
||||||
constructor(commonObjs, objs, forceDataSchema) {
|
constructor(commonObjs, objs, forceDataSchema = false) {
|
||||||
this.svgFactory = new DOMSVGFactory();
|
this.svgFactory = new DOMSVGFactory();
|
||||||
|
|
||||||
this.current = new SVGExtraState();
|
this.current = new SVGExtraState();
|
||||||
@ -664,9 +664,6 @@ if (typeof PDFJSDev === "undefined" || PDFJSDev.test("GENERIC")) {
|
|||||||
case OPS.paintSolidColorImageMask:
|
case OPS.paintSolidColorImageMask:
|
||||||
this.paintSolidColorImageMask();
|
this.paintSolidColorImageMask();
|
||||||
break;
|
break;
|
||||||
case OPS.paintJpegXObject:
|
|
||||||
this.paintJpegXObject(args[0], args[1], args[2]);
|
|
||||||
break;
|
|
||||||
case OPS.paintImageXObject:
|
case OPS.paintImageXObject:
|
||||||
this.paintImageXObject(args[0]);
|
this.paintImageXObject(args[0]);
|
||||||
break;
|
break;
|
||||||
@ -1559,23 +1556,6 @@ if (typeof PDFJSDev === "undefined" || PDFJSDev.test("GENERIC")) {
|
|||||||
this._ensureTransformGroup().appendChild(rect);
|
this._ensureTransformGroup().appendChild(rect);
|
||||||
}
|
}
|
||||||
|
|
||||||
paintJpegXObject(objId, w, h) {
|
|
||||||
const imgObj = this.objs.get(objId);
|
|
||||||
const imgEl = this.svgFactory.createElement("svg:image");
|
|
||||||
imgEl.setAttributeNS(XLINK_NS, "xlink:href", imgObj.src);
|
|
||||||
imgEl.setAttributeNS(null, "width", pf(w));
|
|
||||||
imgEl.setAttributeNS(null, "height", pf(h));
|
|
||||||
imgEl.setAttributeNS(null, "x", "0");
|
|
||||||
imgEl.setAttributeNS(null, "y", pf(-h));
|
|
||||||
imgEl.setAttributeNS(
|
|
||||||
null,
|
|
||||||
"transform",
|
|
||||||
`scale(${pf(1 / w)} ${pf(-1 / h)})`
|
|
||||||
);
|
|
||||||
|
|
||||||
this._ensureTransformGroup().appendChild(imgEl);
|
|
||||||
}
|
|
||||||
|
|
||||||
paintImageXObject(objId) {
|
paintImageXObject(objId) {
|
||||||
const imgData = this.objs.get(objId);
|
const imgData = this.objs.get(objId);
|
||||||
if (!imgData) {
|
if (!imgData) {
|
||||||
|
@ -39,7 +39,6 @@ import {
|
|||||||
createValidAbsoluteUrl,
|
createValidAbsoluteUrl,
|
||||||
InvalidPDFException,
|
InvalidPDFException,
|
||||||
MissingPDFException,
|
MissingPDFException,
|
||||||
NativeImageDecoding,
|
|
||||||
OPS,
|
OPS,
|
||||||
PasswordResponses,
|
PasswordResponses,
|
||||||
PermissionFlag,
|
PermissionFlag,
|
||||||
@ -143,7 +142,6 @@ export {
|
|||||||
createValidAbsoluteUrl,
|
createValidAbsoluteUrl,
|
||||||
InvalidPDFException,
|
InvalidPDFException,
|
||||||
MissingPDFException,
|
MissingPDFException,
|
||||||
NativeImageDecoding,
|
|
||||||
OPS,
|
OPS,
|
||||||
PasswordResponses,
|
PasswordResponses,
|
||||||
PermissionFlag,
|
PermissionFlag,
|
||||||
|
@ -19,12 +19,6 @@ import "./compatibility.js";
|
|||||||
const IDENTITY_MATRIX = [1, 0, 0, 1, 0, 0];
|
const IDENTITY_MATRIX = [1, 0, 0, 1, 0, 0];
|
||||||
const FONT_IDENTITY_MATRIX = [0.001, 0, 0, 0.001, 0, 0];
|
const FONT_IDENTITY_MATRIX = [0.001, 0, 0, 0.001, 0, 0];
|
||||||
|
|
||||||
const NativeImageDecoding = {
|
|
||||||
NONE: "none",
|
|
||||||
DECODE: "decode",
|
|
||||||
DISPLAY: "display",
|
|
||||||
};
|
|
||||||
|
|
||||||
// Permission flags from Table 22, Section 7.6.3.2 of the PDF specification.
|
// Permission flags from Table 22, Section 7.6.3.2 of the PDF specification.
|
||||||
const PermissionFlag = {
|
const PermissionFlag = {
|
||||||
PRINT: 0x04,
|
PRINT: 0x04,
|
||||||
@ -917,7 +911,6 @@ export {
|
|||||||
AbortException,
|
AbortException,
|
||||||
InvalidPDFException,
|
InvalidPDFException,
|
||||||
MissingPDFException,
|
MissingPDFException,
|
||||||
NativeImageDecoding,
|
|
||||||
PasswordException,
|
PasswordException,
|
||||||
PasswordResponses,
|
PasswordResponses,
|
||||||
PermissionFlag,
|
PermissionFlag,
|
||||||
|
@ -387,7 +387,6 @@ var Driver = (function DriverClosure() {
|
|||||||
const loadingTask = pdfjsLib.getDocument({
|
const loadingTask = pdfjsLib.getDocument({
|
||||||
url: absoluteUrl,
|
url: absoluteUrl,
|
||||||
password: task.password,
|
password: task.password,
|
||||||
nativeImageDecoderSupport: task.nativeImageDecoderSupport,
|
|
||||||
cMapUrl: CMAP_URL,
|
cMapUrl: CMAP_URL,
|
||||||
cMapPacked: CMAP_PACKED,
|
cMapPacked: CMAP_PACKED,
|
||||||
disableRange: task.disableRange,
|
disableRange: task.disableRange,
|
||||||
|
@ -1637,8 +1637,7 @@
|
|||||||
"link": true,
|
"link": true,
|
||||||
"firstPage": 2,
|
"firstPage": 2,
|
||||||
"lastPage": 2,
|
"lastPage": 2,
|
||||||
"type": "eq",
|
"type": "eq"
|
||||||
"nativeImageDecoderSupport": "none"
|
|
||||||
},
|
},
|
||||||
{ "id": "issue10529",
|
{ "id": "issue10529",
|
||||||
"file": "pdfs/issue10529.pdf",
|
"file": "pdfs/issue10529.pdf",
|
||||||
@ -4181,22 +4180,12 @@
|
|||||||
"link": true,
|
"link": true,
|
||||||
"type": "eq"
|
"type": "eq"
|
||||||
},
|
},
|
||||||
{ "id": "issue4926-built-in-jpg",
|
|
||||||
"file": "pdfs/issue4926.pdf",
|
|
||||||
"md5": "ed881c8ea2f9bc4be94ecb7f2b2c149b",
|
|
||||||
"rounds": 1,
|
|
||||||
"link": true,
|
|
||||||
"lastPage": 1,
|
|
||||||
"type": "eq",
|
|
||||||
"nativeImageDecoderSupport": "none"
|
|
||||||
},
|
|
||||||
{ "id": "decodeACSuccessive",
|
{ "id": "decodeACSuccessive",
|
||||||
"file": "pdfs/decodeACSuccessive.pdf",
|
"file": "pdfs/decodeACSuccessive.pdf",
|
||||||
"md5": "7749c032624fe27ab8e8d7d5e9a4a93f",
|
"md5": "7749c032624fe27ab8e8d7d5e9a4a93f",
|
||||||
"rounds": 1,
|
"rounds": 1,
|
||||||
"link": false,
|
"link": false,
|
||||||
"type": "eq",
|
"type": "eq"
|
||||||
"nativeImageDecoderSupport": "none"
|
|
||||||
},
|
},
|
||||||
{ "id": "issue5592",
|
{ "id": "issue5592",
|
||||||
"file": "pdfs/issue5592.pdf",
|
"file": "pdfs/issue5592.pdf",
|
||||||
|
@ -18,7 +18,6 @@ import { setStubs, unsetStubs } from "../../examples/node/domstubs.js";
|
|||||||
import { buildGetDocumentParams } from "./test_utils.js";
|
import { buildGetDocumentParams } from "./test_utils.js";
|
||||||
import { getDocument } from "../../src/display/api.js";
|
import { getDocument } from "../../src/display/api.js";
|
||||||
import { isNodeJS } from "../../src/shared/is_node.js";
|
import { isNodeJS } from "../../src/shared/is_node.js";
|
||||||
import { NativeImageDecoding } from "../../src/shared/util.js";
|
|
||||||
import { SVGGraphics } from "../../src/display/svg.js";
|
import { SVGGraphics } from "../../src/display/svg.js";
|
||||||
|
|
||||||
const XLINK_NS = "http://www.w3.org/1999/xlink";
|
const XLINK_NS = "http://www.w3.org/1999/xlink";
|
||||||
@ -62,11 +61,7 @@ describe("SVGGraphics", function () {
|
|||||||
var loadingTask;
|
var loadingTask;
|
||||||
var page;
|
var page;
|
||||||
beforeAll(function (done) {
|
beforeAll(function (done) {
|
||||||
loadingTask = getDocument(
|
loadingTask = getDocument(buildGetDocumentParams("xobject-image.pdf"));
|
||||||
buildGetDocumentParams("xobject-image.pdf", {
|
|
||||||
nativeImageDecoderSupport: NativeImageDecoding.DISPLAY,
|
|
||||||
})
|
|
||||||
);
|
|
||||||
loadingTask.promise.then(function (doc) {
|
loadingTask.promise.then(function (doc) {
|
||||||
doc.getPage(1).then(function (firstPage) {
|
doc.getPage(1).then(function (firstPage) {
|
||||||
page = firstPage;
|
page = firstPage;
|
||||||
|
@ -2223,7 +2223,7 @@ if (typeof PDFJSDev === "undefined" || PDFJSDev.test("GENERIC")) {
|
|||||||
}
|
}
|
||||||
const file = evt.fileInput.files[0];
|
const file = evt.fileInput.files[0];
|
||||||
|
|
||||||
if (URL.createObjectURL && !AppOptions.get("disableCreateObjectURL")) {
|
if (!AppOptions.get("disableCreateObjectURL")) {
|
||||||
let url = URL.createObjectURL(file);
|
let url = URL.createObjectURL(file);
|
||||||
if (file.name) {
|
if (file.name) {
|
||||||
url = { url, originalUrl: file.name };
|
url = { url, originalUrl: file.name };
|
||||||
|
@ -13,7 +13,6 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { apiCompatibilityParams } from "pdfjs-lib";
|
|
||||||
import { viewerCompatibilityParams } from "./viewer_compatibility.js";
|
import { viewerCompatibilityParams } from "./viewer_compatibility.js";
|
||||||
|
|
||||||
const OptionKind = {
|
const OptionKind = {
|
||||||
@ -43,6 +42,12 @@ const defaultOptions = {
|
|||||||
value: "",
|
value: "",
|
||||||
kind: OptionKind.VIEWER + OptionKind.PREFERENCE,
|
kind: OptionKind.VIEWER + OptionKind.PREFERENCE,
|
||||||
},
|
},
|
||||||
|
disableCreateObjectURL: {
|
||||||
|
/** @type {boolean} */
|
||||||
|
value: false,
|
||||||
|
compatibility: viewerCompatibilityParams.disableCreateObjectURL,
|
||||||
|
kind: OptionKind.VIEWER,
|
||||||
|
},
|
||||||
disableHistory: {
|
disableHistory: {
|
||||||
/** @type {boolean} */
|
/** @type {boolean} */
|
||||||
value: false,
|
value: false,
|
||||||
@ -174,12 +179,6 @@ const defaultOptions = {
|
|||||||
value: false,
|
value: false,
|
||||||
kind: OptionKind.API + OptionKind.PREFERENCE,
|
kind: OptionKind.API + OptionKind.PREFERENCE,
|
||||||
},
|
},
|
||||||
disableCreateObjectURL: {
|
|
||||||
/** @type {boolean} */
|
|
||||||
value: false,
|
|
||||||
compatibility: apiCompatibilityParams.disableCreateObjectURL,
|
|
||||||
kind: OptionKind.API,
|
|
||||||
},
|
|
||||||
disableFontFace: {
|
disableFontFace: {
|
||||||
/** @type {boolean} */
|
/** @type {boolean} */
|
||||||
value: false,
|
value: false,
|
||||||
|
@ -13,11 +13,8 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {
|
import { createObjectURL, createValidAbsoluteUrl } from "pdfjs-lib";
|
||||||
apiCompatibilityParams,
|
import { viewerCompatibilityParams } from "./viewer_compatibility.js";
|
||||||
createObjectURL,
|
|
||||||
createValidAbsoluteUrl,
|
|
||||||
} from "pdfjs-lib";
|
|
||||||
|
|
||||||
if (typeof PDFJSDev !== "undefined" && !PDFJSDev.test("CHROME || GENERIC")) {
|
if (typeof PDFJSDev !== "undefined" && !PDFJSDev.test("CHROME || GENERIC")) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
@ -27,7 +24,7 @@ if (typeof PDFJSDev !== "undefined" && !PDFJSDev.test("CHROME || GENERIC")) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const DISABLE_CREATE_OBJECT_URL =
|
const DISABLE_CREATE_OBJECT_URL =
|
||||||
apiCompatibilityParams.disableCreateObjectURL || false;
|
viewerCompatibilityParams.disableCreateObjectURL || false;
|
||||||
|
|
||||||
function download(blobUrl, filename) {
|
function download(blobUrl, filename) {
|
||||||
const a = document.createElement("a");
|
const a = document.createElement("a");
|
||||||
|
@ -74,14 +74,10 @@ class PDFAttachmentViewer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* NOTE: Should only be used when `URL.createObjectURL` is natively supported.
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
_bindPdfLink(button, content, filename) {
|
_bindPdfLink(button, content, filename) {
|
||||||
if (this.downloadManager.disableCreateObjectURL) {
|
|
||||||
throw new Error(
|
|
||||||
'bindPdfLink: Unsupported "disableCreateObjectURL" value.'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
let blobUrl;
|
let blobUrl;
|
||||||
button.onclick = () => {
|
button.onclick = () => {
|
||||||
if (!blobUrl) {
|
if (!blobUrl) {
|
||||||
|
@ -65,8 +65,7 @@ function PDFPrintService(pdfDocument, pagesOverview, printContainer, l10n) {
|
|||||||
this.pagesOverview = pagesOverview;
|
this.pagesOverview = pagesOverview;
|
||||||
this.printContainer = printContainer;
|
this.printContainer = printContainer;
|
||||||
this.l10n = l10n || NullL10n;
|
this.l10n = l10n || NullL10n;
|
||||||
this.disableCreateObjectURL =
|
this.disableCreateObjectURL = AppOptions.get("disableCreateObjectURL");
|
||||||
pdfDocument.loadingParams.disableCreateObjectURL;
|
|
||||||
this.currentPage = -1;
|
this.currentPage = -1;
|
||||||
// The temporary canvas where renderPage paints one page at a time.
|
// The temporary canvas where renderPage paints one page at a time.
|
||||||
this.scratchCanvas = document.createElement("canvas");
|
this.scratchCanvas = document.createElement("canvas");
|
||||||
|
@ -23,9 +23,21 @@ if (typeof PDFJSDev === "undefined" || PDFJSDev.test("GENERIC")) {
|
|||||||
(typeof navigator !== "undefined" && navigator.maxTouchPoints) || 1;
|
(typeof navigator !== "undefined" && navigator.maxTouchPoints) || 1;
|
||||||
|
|
||||||
const isAndroid = /Android/.test(userAgent);
|
const isAndroid = /Android/.test(userAgent);
|
||||||
|
const isIE = /Trident/.test(userAgent);
|
||||||
const isIOS =
|
const isIOS =
|
||||||
/\b(iPad|iPhone|iPod)(?=;)/.test(userAgent) ||
|
/\b(iPad|iPhone|iPod)(?=;)/.test(userAgent) ||
|
||||||
(platform === "MacIntel" && maxTouchPoints > 1);
|
(platform === "MacIntel" && maxTouchPoints > 1);
|
||||||
|
const isIOSChrome = /CriOS/.test(userAgent);
|
||||||
|
|
||||||
|
// Checks if possible to use URL.createObjectURL()
|
||||||
|
// Support: IE, Chrome on iOS
|
||||||
|
(function checkOnBlobSupport() {
|
||||||
|
// Sometimes IE and Chrome on iOS losing the data created with
|
||||||
|
// createObjectURL(), see issues #3977 and #8081.
|
||||||
|
if (isIE || isIOSChrome) {
|
||||||
|
compatibilityParams.disableCreateObjectURL = true;
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
|
||||||
// Limit canvas size to 5 mega-pixels on mobile.
|
// Limit canvas size to 5 mega-pixels on mobile.
|
||||||
// Support: Android, iOS
|
// Support: Android, iOS
|
||||||
|
Loading…
x
Reference in New Issue
Block a user