From 8d5d97264e1d00788b6dfe2030e79ec8c7f1495e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B7=B4=E9=87=8C=E5=88=87=E7=BD=97?= Date: Mon, 8 May 2017 11:32:44 +0800 Subject: [PATCH] fix(svg) adjust strategy for decoding JPEG images --- examples/node/domstubs.js | 18 ++++++++++++++++++ examples/node/pdf2svg.js | 5 +++-- src/core/evaluator.js | 9 +++++---- src/core/worker.js | 2 +- src/display/api.js | 34 ++++++++++++++++++++++++++++------ src/display/svg.js | 4 ++-- src/main_loader.js | 1 + src/pdf.js | 1 + src/shared/util.js | 7 +++++++ 9 files changed, 66 insertions(+), 15 deletions(-) diff --git a/examples/node/domstubs.js b/examples/node/domstubs.js index b654d6070..ce4dc7890 100644 --- a/examples/node/domstubs.js +++ b/examples/node/domstubs.js @@ -147,3 +147,21 @@ global.document = { return []; } }; + +function Image () { + this._src = null; + this.onload = null; +} +Image.prototype = { + get src () { + return this._src; + }, + set src (value) { + this._src = value; + if (this.onload) { + this.onload(); + } + } +} + +global.Image = Image; diff --git a/examples/node/pdf2svg.js b/examples/node/pdf2svg.js index 5f09209d7..b9ce96b6f 100644 --- a/examples/node/pdf2svg.js +++ b/examples/node/pdf2svg.js @@ -39,14 +39,15 @@ function writeToFile(svgdump, pageNum) { function getFileNameFromPath(path) { var index = path.lastIndexOf('/'); var extIndex = path.lastIndexOf('.'); - return path.substring(index , extIndex); + return path.substring(index, extIndex); } // Will be using promises to load document, pages and misc data instead of // callback. pdfjsLib.getDocument({ data: data, - disableNativeImageDecoder: true, + // Try to export JPEG images directly if they don't need any further processing. + nativeImageDecoderSupport: pdfjsLib.NativeImageDecoding.DISPLAY }).then(function (doc) { var numPages = doc.numPages; console.log('# Document Loaded'); diff --git a/src/core/evaluator.js b/src/core/evaluator.js index f7014e509..262122f8a 100644 --- a/src/core/evaluator.js +++ b/src/core/evaluator.js @@ -52,6 +52,7 @@ var IDENTITY_MATRIX = sharedUtil.IDENTITY_MATRIX; var UNSUPPORTED_FEATURES = sharedUtil.UNSUPPORTED_FEATURES; var ImageKind = sharedUtil.ImageKind; var OPS = sharedUtil.OPS; +var NativeImageDecoding = sharedUtil.NativeImageDecoding; var TextRenderingMode = sharedUtil.TextRenderingMode; var CMapCompressionType = sharedUtil.CMapCompressionType; var Util = sharedUtil.Util; @@ -113,7 +114,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() { forceDataSchema: false, maxImageSize: -1, disableFontFace: false, - disableNativeImageDecoder: false, + nativeImageDecoderSupport: NativeImageDecoding.DECODE, ignoreErrors: false, }; @@ -461,14 +462,14 @@ var PartialEvaluator = (function PartialEvaluatorClosure() { return; } - var useNativeImageDecoder = !this.options.disableNativeImageDecoder; + var nativeImageDecoderSupport = this.options.nativeImageDecoderSupport; // If there is no imageMask, create the PDFImage and a lot // of image processing can be done here. var objId = 'img_' + this.idFactory.createObjId(); operatorList.addDependency(objId); args = [objId, w, h]; - if (useNativeImageDecoder && + if (nativeImageDecoderSupport !== NativeImageDecoding.NONE && !softMask && !mask && image instanceof JpegStream && NativeImageDecoder.isSupported(image, this.xref, resources)) { // These JPEGs don't need any more processing so we can just send it. @@ -481,7 +482,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() { // Creates native image decoder only if a JPEG image or mask is present. var nativeImageDecoder = null; - if (useNativeImageDecoder && + if (nativeImageDecoderSupport === NativeImageDecoding.DECODE && (image instanceof JpegStream || mask instanceof JpegStream || softMask instanceof JpegStream)) { nativeImageDecoder = new NativeImageDecoder(this.xref, resources, diff --git a/src/core/worker.js b/src/core/worker.js index f52cdefbd..5d7f3c583 100644 --- a/src/core/worker.js +++ b/src/core/worker.js @@ -731,7 +731,7 @@ var WorkerMessageHandler = { forceDataSchema: data.disableCreateObjectURL, maxImageSize: data.maxImageSize === undefined ? -1 : data.maxImageSize, disableFontFace: data.disableFontFace, - disableNativeImageDecoder: data.disableNativeImageDecoder, + nativeImageDecoderSupport: data.nativeImageDecoderSupport, ignoreErrors: data.ignoreErrors, }; diff --git a/src/display/api.js b/src/display/api.js index 16d670d5b..e8f8d99cf 100644 --- a/src/display/api.js +++ b/src/display/api.js @@ -17,9 +17,9 @@ import { createPromiseCapability, deprecated, error, getVerbosityLevel, globalScope, info, InvalidPDFException, isArray, isArrayBuffer, isInt, isSameOrigin, - loadJpegStream, MessageHandler, MissingPDFException, PageViewport, - PasswordException, StatTimer, stringToBytes, UnexpectedResponseException, - UnknownErrorException, Util, warn + loadJpegStream, MessageHandler, MissingPDFException, NativeImageDecoding, + PageViewport, PasswordException, StatTimer, stringToBytes, + UnexpectedResponseException, UnknownErrorException, Util, warn } from '../shared/util'; import { DOMCanvasFactory, DOMCMapReaderFactory, getDefaultSetting, @@ -104,10 +104,18 @@ if (typeof PDFJSDev !== 'undefined' && * @property {string} docBaseUrl - (optional) The base URL of the document, * used when attempting to recover valid absolute URLs for annotations, and * outline items, that (incorrectly) only specify relative URLs. - * @property {boolean} disableNativeImageDecoder - (optional) Disable decoding + * @property {boolean} disableNativeImageDecoder - (deprecated) Disable decoding * of certain (simple) JPEG images in the browser. This is useful for * environments without DOM image support, such as e.g. Node.js. * The default value is `false`. + * @property {string} nativeImageDecoderSupport - (optional) 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 {Object} CMapReaderFactory - (optional) The factory that will be * used when reading built-in CMap files. Providing a custom factory is useful * for environments without `XMLHttpRequest` support, such as e.g. Node.js. @@ -229,10 +237,24 @@ function getDocument(src, pdfDataRangeTransport, } params.rangeChunkSize = params.rangeChunkSize || DEFAULT_RANGE_CHUNK_SIZE; - params.disableNativeImageDecoder = params.disableNativeImageDecoder === true; params.ignoreErrors = params.stopAtErrors !== true; var CMapReaderFactory = params.CMapReaderFactory || DOMCMapReaderFactory; + if (params.disableNativeImageDecoder !== undefined) { + deprecated('parameter disableNativeImageDecoder, ' + + 'use nativeImageDecoderSupport instead'); + } + params.nativeImageDecoderSupport = params.nativeImageDecoderSupport || + (params.disableNativeImageDecoder === true ? NativeImageDecoding.NONE : + NativeImageDecoding.DECODE); + if (params.nativeImageDecoderSupport !== NativeImageDecoding.DECODE && + params.nativeImageDecoderSupport !== NativeImageDecoding.NONE && + params.nativeImageDecoderSupport !== NativeImageDecoding.DISPLAY) { + warn('Invalid parameter nativeImageDecoderSupport: ' + + 'need a state of enum {NativeImageDecoding}'); + params.nativeImageDecoderSupport = NativeImageDecoding.DECODE; + } + if (!worker) { // Worker was not provided -- creating and owning our own. If message port // is specified in global settings, using it. @@ -293,7 +315,7 @@ function _fetchDocument(worker, source, pdfDataRangeTransport, docId) { postMessageTransfers: getDefaultSetting('postMessageTransfers') && !isPostMessageTransfersDisabled, docBaseUrl: source.docBaseUrl, - disableNativeImageDecoder: source.disableNativeImageDecoder, + nativeImageDecoderSupport: source.nativeImageDecoderSupport, ignoreErrors: source.ignoreErrors, }).then(function (workerId) { if (worker.destroyed) { diff --git a/src/display/svg.js b/src/display/svg.js index c772a5eb3..46d037588 100644 --- a/src/display/svg.js +++ b/src/display/svg.js @@ -1029,8 +1029,8 @@ SVGGraphics = (function SVGGraphicsClosure() { var imgObj = this.objs.get(objId); var imgEl = document.createElementNS(NS, 'svg:image'); imgEl.setAttributeNS(XLINK_NS, 'xlink:href', imgObj.src); - imgEl.setAttributeNS(null, 'width', imgObj.width + 'px'); - imgEl.setAttributeNS(null, 'height', imgObj.height + 'px'); + 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', diff --git a/src/main_loader.js b/src/main_loader.js index aef74011a..9529bc61a 100644 --- a/src/main_loader.js +++ b/src/main_loader.js @@ -54,6 +54,7 @@ exports.InvalidPDFException = sharedUtil.InvalidPDFException; exports.MissingPDFException = sharedUtil.MissingPDFException; exports.SVGGraphics = displaySVG.SVGGraphics; + exports.NativeImageDecoding = sharedUtil.NativeImageDecoding; exports.UnexpectedResponseException = sharedUtil.UnexpectedResponseException; exports.OPS = sharedUtil.OPS; exports.UNSUPPORTED_FEATURES = sharedUtil.UNSUPPORTED_FEATURES; diff --git a/src/pdf.js b/src/pdf.js index d9c4f2f33..8389f8b81 100644 --- a/src/pdf.js +++ b/src/pdf.js @@ -42,6 +42,7 @@ exports.PasswordResponses = pdfjsSharedUtil.PasswordResponses; exports.InvalidPDFException = pdfjsSharedUtil.InvalidPDFException; exports.MissingPDFException = pdfjsSharedUtil.MissingPDFException; exports.SVGGraphics = pdfjsDisplaySVG.SVGGraphics; +exports.NativeImageDecoding = pdfjsSharedUtil.NativeImageDecoding; exports.UnexpectedResponseException = pdfjsSharedUtil.UnexpectedResponseException; exports.OPS = pdfjsSharedUtil.OPS; diff --git a/src/shared/util.js b/src/shared/util.js index 867575d2c..46cc9da00 100644 --- a/src/shared/util.js +++ b/src/shared/util.js @@ -22,6 +22,12 @@ var globalScope = (typeof window !== 'undefined') ? window : var FONT_IDENTITY_MATRIX = [0.001, 0, 0, 0.001, 0, 0]; +const NativeImageDecoding = { + NONE: 'none', + DECODE: 'decode', + DISPLAY: 'display' +}; + var TextRenderingMode = { FILL: 0, STROKE: 1, @@ -1369,6 +1375,7 @@ export { MessageHandler, MissingDataException, MissingPDFException, + NativeImageDecoding, NotImplementedException, PageViewport, PasswordException,