Merge pull request #7506 from Snuffleupagus/annotation-missing-subtype

Prevent errors when parsing Annotations with missing (or invalid) /Subtype entries (issue 7446)
This commit is contained in:
Tim van der Meij 2016-07-25 16:25:29 +02:00 committed by GitHub
commit 336b26a39d
5 changed files with 106 additions and 35 deletions

View File

@ -74,13 +74,14 @@ AnnotationFactory.prototype = /** @lends AnnotationFactory.prototype */ {
// Determine the annotation's subtype. // Determine the annotation's subtype.
var subtype = dict.get('Subtype'); var subtype = dict.get('Subtype');
subtype = isName(subtype) ? subtype.name : ''; subtype = isName(subtype) ? subtype.name : null;
// Return the right annotation object based on the subtype and field type. // Return the right annotation object based on the subtype and field type.
var parameters = { var parameters = {
xref: xref, xref: xref,
dict: dict, dict: dict,
ref: ref ref: ref,
subtype: subtype,
}; };
switch (subtype) { switch (subtype) {
@ -116,8 +117,12 @@ AnnotationFactory.prototype = /** @lends AnnotationFactory.prototype */ {
return new FileAttachmentAnnotation(parameters); return new FileAttachmentAnnotation(parameters);
default: default:
warn('Unimplemented annotation type "' + subtype + '", ' + if (!subtype) {
'falling back to base annotation'); warn('Annotation is missing the required /Subtype.');
} else {
warn('Unimplemented annotation type "' + subtype + '", ' +
'falling back to base annotation.');
}
return new Annotation(parameters); return new Annotation(parameters);
} }
} }
@ -181,7 +186,7 @@ var Annotation = (function AnnotationClosure() {
// Expose public properties using a data object. // Expose public properties using a data object.
this.data = {}; this.data = {};
this.data.id = params.ref.toString(); this.data.id = params.ref.toString();
this.data.subtype = dict.get('Subtype').name; this.data.subtype = params.subtype;
this.data.annotationFlags = this.flags; this.data.annotationFlags = this.flags;
this.data.rect = this.rectangle; this.data.rect = this.rectangle;
this.data.color = this.color; this.data.color = this.color;

View File

@ -31,6 +31,7 @@
!issue7403.pdf !issue7403.pdf
!issue7426.pdf !issue7426.pdf
!issue7439.pdf !issue7439.pdf
!issue7446.pdf
!issue7492.pdf !issue7492.pdf
!filled-background.pdf !filled-background.pdf
!ArabicCIDTrueType.pdf !ArabicCIDTrueType.pdf

51
test/pdfs/issue7446.pdf Normal file
View File

@ -0,0 +1,51 @@
%PDF-1.7
%%μῦ
1 0 obj
<</Type/Catalog/Pages 2 0 R>>
endobj
2 0 obj
<</Type/Pages/MediaBox[0 0 200 200]/Count 1/Kids[3 0 R]>>
endobj
3 0 obj
<</Type/Page/Parent 2 0 R/Annots[6 0 R]/Resources<</Font<</F1 4 0 R>>>>/Contents 5 0 R>>
endobj
4 0 obj
<</Type/Font/Subtype/Type1/BaseFont/Times-Roman>>
endobj
5 0 obj
<</Length 68>>
stream
BT
10 10 TD
/F1 12 Tf
(Renders even with a broken annotation) Tj
ET
endstream
endobj
6 0 obj
<</Type/Annot/Rect[266 116 430 204]/Contents( This annotation is broken )>>
endobj
xref
0 7
0000000000 65536 f
0000000018 00000 n
0000000064 00000 n
0000000138 00000 n
0000000243 00000 n
0000000309 00000 n
0000000426 00000 n
trailer
<</Size 7/Root 1 0 R>>
startxref
518
%%EOF

View File

@ -1131,6 +1131,14 @@
"link": false, "link": false,
"type": "eq" "type": "eq"
}, },
{ "id": "issue7446",
"file": "pdfs/issue7446.pdf",
"md5": "1b5bdd8a806e6ab9eda7c1c707b75fc6",
"rounds": 1,
"link": false,
"type": "load",
"about": "Annotation without the required /Subtype."
},
{ "id": "issue7492-eq", { "id": "issue7492-eq",
"file": "pdfs/issue7492.pdf", "file": "pdfs/issue7492.pdf",
"md5": "7b0b28919c1088a2a5a0aeedbaa4c3ca", "md5": "7b0b28919c1088a2a5a0aeedbaa4c3ca",

View File

@ -26,11 +26,35 @@ describe('Annotation layer', function() {
annotationFactory = null; annotationFactory = null;
}); });
describe('AnnotationFactory', function () {
it('should handle missing /Subtype', function () {
var annotationDict = new Dict();
annotationDict.set('Type', Name.get('Annot'));
var xrefMock = new XrefMock([annotationDict]);
var annotationRef = new Ref(1, 0);
var annotation = annotationFactory.create(xrefMock, annotationRef);
var data = annotation.data;
expect(data.annotationType).toBeUndefined();
});
});
describe('Annotation', function() { describe('Annotation', function() {
var dict, ref;
beforeAll(function (done) {
dict = new Dict();
ref = new Ref(1, 0);
done();
});
afterAll(function () {
dict = ref = null;
});
it('should set and get flags', function() { it('should set and get flags', function() {
var dict = new Dict(); var annotation = new Annotation({ dict: dict, ref: ref });
dict.set('Subtype', '');
var annotation = new Annotation({ dict: dict, ref: 0 });
annotation.setFlags(13); annotation.setFlags(13);
expect(annotation.hasFlag(AnnotationFlag.INVISIBLE)).toEqual(true); expect(annotation.hasFlag(AnnotationFlag.INVISIBLE)).toEqual(true);
@ -40,81 +64,63 @@ describe('Annotation layer', function() {
}); });
it('should be viewable and not printable by default', function() { it('should be viewable and not printable by default', function() {
var dict = new Dict(); var annotation = new Annotation({ dict: dict, ref: ref });
dict.set('Subtype', '');
var annotation = new Annotation({ dict: dict, ref: 0 });
expect(annotation.viewable).toEqual(true); expect(annotation.viewable).toEqual(true);
expect(annotation.printable).toEqual(false); expect(annotation.printable).toEqual(false);
}); });
it('should set and get a valid rectangle', function() { it('should set and get a valid rectangle', function() {
var dict = new Dict(); var annotation = new Annotation({ dict: dict, ref: ref });
dict.set('Subtype', '');
var annotation = new Annotation({ dict: dict, ref: 0 });
annotation.setRectangle([117, 694, 164.298, 720]); annotation.setRectangle([117, 694, 164.298, 720]);
expect(annotation.rectangle).toEqual([117, 694, 164.298, 720]); expect(annotation.rectangle).toEqual([117, 694, 164.298, 720]);
}); });
it('should not set and get an invalid rectangle', function() { it('should not set and get an invalid rectangle', function() {
var dict = new Dict(); var annotation = new Annotation({ dict: dict, ref: ref });
dict.set('Subtype', '');
var annotation = new Annotation({ dict: dict, ref: 0 });
annotation.setRectangle([117, 694, 164.298]); annotation.setRectangle([117, 694, 164.298]);
expect(annotation.rectangle).toEqual([0, 0, 0, 0]); expect(annotation.rectangle).toEqual([0, 0, 0, 0]);
}); });
it('should reject a color if it is not an array', function() { it('should reject a color if it is not an array', function() {
var dict = new Dict(); var annotation = new Annotation({ dict: dict, ref: ref });
dict.set('Subtype', '');
var annotation = new Annotation({ dict: dict, ref: 0 });
annotation.setColor('red'); annotation.setColor('red');
expect(annotation.color).toEqual(new Uint8Array([0, 0, 0])); expect(annotation.color).toEqual(new Uint8Array([0, 0, 0]));
}); });
it('should set and get a transparent color', function() { it('should set and get a transparent color', function() {
var dict = new Dict(); var annotation = new Annotation({ dict: dict, ref: ref });
dict.set('Subtype', '');
var annotation = new Annotation({ dict: dict, ref: 0 });
annotation.setColor([]); annotation.setColor([]);
expect(annotation.color).toEqual(null); expect(annotation.color).toEqual(null);
}); });
it('should set and get a grayscale color', function() { it('should set and get a grayscale color', function() {
var dict = new Dict(); var annotation = new Annotation({ dict: dict, ref: ref });
dict.set('Subtype', '');
var annotation = new Annotation({ dict: dict, ref: 0 });
annotation.setColor([0.4]); annotation.setColor([0.4]);
expect(annotation.color).toEqual(new Uint8Array([102, 102, 102])); expect(annotation.color).toEqual(new Uint8Array([102, 102, 102]));
}); });
it('should set and get an RGB color', function() { it('should set and get an RGB color', function() {
var dict = new Dict(); var annotation = new Annotation({ dict: dict, ref: ref });
dict.set('Subtype', '');
var annotation = new Annotation({ dict: dict, ref: 0 });
annotation.setColor([0, 0, 1]); annotation.setColor([0, 0, 1]);
expect(annotation.color).toEqual(new Uint8Array([0, 0, 255])); expect(annotation.color).toEqual(new Uint8Array([0, 0, 255]));
}); });
it('should set and get a CMYK color', function() { it('should set and get a CMYK color', function() {
var dict = new Dict(); var annotation = new Annotation({ dict: dict, ref: ref });
dict.set('Subtype', '');
var annotation = new Annotation({ dict: dict, ref: 0 });
annotation.setColor([0.1, 0.92, 0.84, 0.02]); annotation.setColor([0.1, 0.92, 0.84, 0.02]);
expect(annotation.color).toEqual(new Uint8Array([233, 59, 47])); expect(annotation.color).toEqual(new Uint8Array([233, 59, 47]));
}); });
it('should not set and get an invalid color', function() { it('should not set and get an invalid color', function() {
var dict = new Dict(); var annotation = new Annotation({ dict: dict, ref: ref });
dict.set('Subtype', '');
var annotation = new Annotation({ dict: dict, ref: 0 });
annotation.setColor([0.4, 0.6]); annotation.setColor([0.4, 0.6]);
expect(annotation.color).toEqual(new Uint8Array([0, 0, 0])); expect(annotation.color).toEqual(new Uint8Array([0, 0, 0]));