Merge pull request #10727 from Snuffleupagus/type3-image-resources

Support (rare) Type3 fonts which contains image resources (issue 10717)
This commit is contained in:
Tim van der Meij 2019-04-18 23:07:26 +02:00 committed by GitHub
commit 55d9b35d37
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 60 additions and 18 deletions

View File

@ -73,6 +73,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
this.builtInCMapCache = builtInCMapCache;
this.options = options || DefaultPartialEvaluatorOptions;
this.pdfFunctionFactory = pdfFunctionFactory;
this.parsingType3Font = false;
this.fetchBuiltInCMap = async (name) => {
if (this.builtInCMapCache.has(name)) {
@ -293,21 +294,21 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
});
},
buildPaintImageXObject({ resources, image, isInline = false, operatorList,
cacheKey, imageCache,
forceDisableNativeImageDecoder = false, }) {
async buildPaintImageXObject({ resources, image, isInline = false,
operatorList, cacheKey, imageCache,
forceDisableNativeImageDecoder = false, }) {
var dict = image.dict;
var w = dict.get('Width', 'W');
var h = dict.get('Height', 'H');
if (!(w && isNum(w)) || !(h && isNum(h))) {
warn('Image dimensions are missing, or not numbers.');
return Promise.resolve();
return;
}
var maxImageSize = this.options.maxImageSize;
if (maxImageSize !== -1 && w * h > maxImageSize) {
warn('Image exceeded maximum allowed size and was removed.');
return Promise.resolve();
return;
}
var imageMask = (dict.get('ImageMask', 'IM') || false);
@ -343,7 +344,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
args,
};
}
return Promise.resolve();
return;
}
var softMask = (dict.get('SMask', 'SM') || false);
@ -364,14 +365,21 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
// any other kind.
imgData = imageObj.createImageData(/* forceRGBA = */ true);
operatorList.addOp(OPS.paintInlineImageXObject, [imgData]);
return Promise.resolve();
return;
}
const 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.
var objId = 'img_' + this.idFactory.createObjId();
let objId = 'img_' + this.idFactory.createObjId();
if (this.parsingType3Font) {
assert(nativeImageDecoderSupport === NativeImageDecoding.NONE,
'Type3 image resources should be completely decoded in the worker.');
objId = `g_${this.pdfManager.docId}_type3res_${objId}`;
}
if (nativeImageDecoderSupport !== NativeImageDecoding.NONE &&
!softMask && !mask && image instanceof JpegStream &&
@ -428,7 +436,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
operatorList.addDependency(objId);
args = [objId, w, h];
PDFImage.buildImage({
const imgPromise = PDFImage.buildImage({
handler: this.handler,
xref: this.xref,
res: resources,
@ -438,13 +446,30 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
pdfFunctionFactory: this.pdfFunctionFactory,
}).then((imageObj) => {
var imgData = imageObj.createImageData(/* forceRGBA = */ false);
if (this.parsingType3Font) {
return this.handler.sendWithPromise('commonobj',
[objId, 'FontType3Res', imgData], [imgData.data.buffer]);
}
this.handler.send('obj', [objId, this.pageIndex, 'Image', imgData],
[imgData.data.buffer]);
}).catch((reason) => {
warn('Unable to decode image: ' + reason);
if (this.parsingType3Font) {
return this.handler.sendWithPromise('commonobj',
[objId, 'FontType3Res', null]);
}
this.handler.send('obj', [objId, this.pageIndex, 'Image', null]);
});
if (this.parsingType3Font) {
// In the very rare case where a Type3 image resource is being parsed,
// wait for the image to be both decoded *and* sent to simplify the
// rendering code on the main-thread (see issue10717.pdf).
await imgPromise;
}
operatorList.addOp(OPS.paintImageXObject, args);
if (cacheKey) {
imageCache[cacheKey] = {
@ -452,7 +477,6 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
args,
};
}
return Promise.resolve();
},
handleSMask: function PartialEvaluator_handleSmask(smask, resources,
@ -2622,9 +2646,15 @@ var TranslatedFont = (function TranslatedFontClosure() {
// When parsing Type3 glyphs, always ignore them if there are errors.
// Compared to the parsing of e.g. an entire page, it doesn't really
// make sense to only be able to render a Type3 glyph partially.
//
// Also, ensure that any Type3 image resources (which should be very rare
// in practice) are completely decoded on the worker-thread, to simplify
// 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;
var translatedFont = this.font;
var loadCharProcsPromise = Promise.resolve();

View File

@ -2003,6 +2003,7 @@ class WorkerTransport {
});
break;
case 'FontPath':
case 'FontType3Res':
this.commonObjs.resolve(id, exportedData);
break;
default:

View File

@ -805,11 +805,8 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
if (fnId !== OPS.dependency) {
this[fnId].apply(this, argsArray[i]);
} else {
var deps = argsArray[i];
for (var n = 0, nn = deps.length; n < nn; n++) {
var depObjId = deps[n];
var common = depObjId[0] === 'g' && depObjId[1] === '_';
var objsPool = common ? commonObjs : objs;
for (const depObjId of argsArray[i]) {
const objsPool = depObjId.startsWith('g_') ? commonObjs : objs;
// If the promise isn't resolved yet, add the continueCallback
// to the promise and bail out.
@ -1930,7 +1927,8 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
},
paintJpegXObject: function CanvasGraphics_paintJpegXObject(objId, w, h) {
var domImage = this.objs.get(objId);
const domImage = this.processingType3 ? this.commonObjs.get(objId) :
this.objs.get(objId);
if (!domImage) {
warn('Dependent image isn\'t ready yet');
return;
@ -2067,7 +2065,8 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
},
paintImageXObject: function CanvasGraphics_paintImageXObject(objId) {
var imgData = this.objs.get(objId);
const imgData = this.processingType3 ? this.commonObjs.get(objId) :
this.objs.get(objId);
if (!imgData) {
warn('Dependent image isn\'t ready yet');
return;
@ -2079,7 +2078,8 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
paintImageXObjectRepeat:
function CanvasGraphics_paintImageXObjectRepeat(objId, scaleX, scaleY,
positions) {
var imgData = this.objs.get(objId);
const imgData = this.processingType3 ? this.commonObjs.get(objId) :
this.objs.get(objId);
if (!imgData) {
warn('Dependent image isn\'t ready yet');
return;

View File

@ -0,0 +1 @@
https://github.com/mozilla/pdf.js/files/3057353/test.pdf

View File

@ -1252,6 +1252,16 @@
"rounds": 1,
"type": "text"
},
{ "id": "issue10717",
"file": "pdfs/issue10717.pdf",
"md5": "6d2ed03db798cc6beb3c7bdf103f5c1a",
"link": true,
"rounds": 1,
"firstPage": 1,
"lastPage": 2,
"type": "eq",
"about": "Type3 fonts with image resources; both pages need to be tested, otherwise the bug won't manifest."
},
{ "id": "close-path-bug",
"file": "pdfs/close-path-bug.pdf",
"md5": "48dd17ef58393857d2d038d33699cac5",