Support rendering appearance streams for annotations
This commit is contained in:
parent
772c7894fb
commit
79831d7ec5
@ -1450,6 +1450,38 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
||||
this.restore();
|
||||
},
|
||||
|
||||
beginAnnotation: function CanvasGraphics_beginAnnotation(rect, transform,
|
||||
matrix, border) {
|
||||
this.save();
|
||||
|
||||
if (rect && isArray(rect) && 4 == rect.length) {
|
||||
var width = rect[2] - rect[0];
|
||||
var height = rect[3] - rect[1];
|
||||
|
||||
if (border) {
|
||||
// TODO(mack): Support different border styles
|
||||
this.save();
|
||||
var rgb = border.rgb;
|
||||
this.setStrokeRGBColor(rgb[0], rgb[1], rgb[2]);
|
||||
this.setLineWidth(border.width);
|
||||
this.rectangle(rect[0], rect[1], width, height);
|
||||
this.stroke();
|
||||
this.restore();
|
||||
}
|
||||
|
||||
this.rectangle(rect[0], rect[1], width, height);
|
||||
this.clip();
|
||||
this.endPath();
|
||||
}
|
||||
|
||||
this.transform.apply(this, transform);
|
||||
this.transform.apply(this, matrix);
|
||||
},
|
||||
|
||||
endAnnotation: function CanvasGraphics_endAnnotation() {
|
||||
this.restore();
|
||||
},
|
||||
|
||||
paintJpegXObject: function CanvasGraphics_paintJpegXObject(objId, w, h) {
|
||||
var domImage = this.objs.get(objId);
|
||||
if (!domImage) {
|
||||
|
110
src/core.js
110
src/core.js
@ -100,7 +100,28 @@ function getPdf(arg, callback) {
|
||||
globalScope.PDFJS.getPdf = getPdf;
|
||||
globalScope.PDFJS.pdfBug = false;
|
||||
|
||||
|
||||
var Page = (function PageClosure() {
|
||||
|
||||
function getDefaultAnnotationAppearance(annotationDict) {
|
||||
var appearanceState = annotationDict.get('AP');
|
||||
if (!isDict(appearanceState)) {
|
||||
return;
|
||||
}
|
||||
|
||||
var appearance;
|
||||
var appearances = appearanceState.get('N');
|
||||
if (isDict(appearances)) {
|
||||
var as = annotationDict.get('AS');
|
||||
if (as && appearances.has(as.name)) {
|
||||
appearance = appearances.get(as.name);
|
||||
}
|
||||
} else {
|
||||
appearance = appearances;
|
||||
}
|
||||
return appearance;
|
||||
}
|
||||
|
||||
function Page(xref, pageIndex, pageDict, ref) {
|
||||
this.pageIndex = pageIndex;
|
||||
this.pageDict = pageDict;
|
||||
@ -198,6 +219,17 @@ var Page = (function PageClosure() {
|
||||
'p' + this.pageIndex + '_');
|
||||
|
||||
var list = pe.getOperatorList(contentStream, resources, dependency);
|
||||
|
||||
var annotations = this.getAnnotationsForDraw();
|
||||
var annotationEvaluator = new PartialEvaluator(
|
||||
xref, handler, this.pageIndex,
|
||||
'p' + this.pageIndex + '_annotation');
|
||||
var annotationsList = annotationEvaluator.getAnnotationsOperatorList(
|
||||
annotations, dependency);
|
||||
|
||||
Util.concatenateToArray(list.fnArray, annotationsList.fnArray);
|
||||
Util.concatenateToArray(list.argsArray, annotationsList.argsArray);
|
||||
|
||||
pe.optimizeQueue(list);
|
||||
return list;
|
||||
},
|
||||
@ -227,7 +259,59 @@ var Page = (function PageClosure() {
|
||||
}
|
||||
return links;
|
||||
},
|
||||
|
||||
getAnnotations: function Page_getAnnotations() {
|
||||
var annotations = this.getAnnotationsBase();
|
||||
var items = [];
|
||||
for (var i = 0, length = annotations.length; i < length; ++i) {
|
||||
items.push(annotations[i].item);
|
||||
}
|
||||
return items;
|
||||
},
|
||||
|
||||
getAnnotationsForDraw: function Page_getAnnotationsForDraw() {
|
||||
var annotations = this.getAnnotationsBase();
|
||||
var items = [];
|
||||
for (var i = 0, length = annotations.length; i < length; ++i) {
|
||||
var item = annotations[i].item;
|
||||
var annotationDict = annotations[i].dict;
|
||||
|
||||
item.annotationFlags = annotationDict.get('F');
|
||||
|
||||
var appearance = getDefaultAnnotationAppearance(annotationDict);
|
||||
if (appearance &&
|
||||
// TODO(mack): The proper implementation requires that the
|
||||
// appearance stream overrides Name, but we're currently
|
||||
// doing it the other way around for 'Text' annotations since we
|
||||
// have special rendering for it
|
||||
item.type !== 'Text') {
|
||||
|
||||
item.appearance = appearance;
|
||||
var appearanceDict = appearance.dict;
|
||||
item.resources = appearanceDict.get('Resources');
|
||||
item.bbox = appearanceDict.get('BBox') || [0, 0, 1, 1];
|
||||
item.matrix = appearanceDict.get('Matrix') || [1, 0, 0, 1, 0 ,0];
|
||||
}
|
||||
|
||||
var border = annotationDict.get('BS');
|
||||
if (isDict(border) && !item.appearance) {
|
||||
var borderWidth = border.has('W') ? border.get('W') : 1;
|
||||
if (borderWidth !== 0) {
|
||||
item.border = {
|
||||
width: borderWidth,
|
||||
type: border.get('S') || 'S',
|
||||
rgb: annotationDict.get('C') || [0, 0, 1]
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
items.push(item);
|
||||
}
|
||||
|
||||
return items;
|
||||
},
|
||||
|
||||
getAnnotationsBase: function Page_getAnnotationsBase() {
|
||||
var xref = this.xref;
|
||||
function getInheritableProperty(annotation, name) {
|
||||
var item = annotation;
|
||||
@ -267,11 +351,13 @@ var Page = (function PageClosure() {
|
||||
var subtype = annotation.get('Subtype');
|
||||
if (!isName(subtype))
|
||||
continue;
|
||||
var rect = annotation.get('Rect');
|
||||
|
||||
var item = {};
|
||||
item.type = subtype.name;
|
||||
item.rect = rect;
|
||||
var rect = annotation.get('Rect');
|
||||
item.rect = Util.normalizeRect(rect);
|
||||
|
||||
var includeAnnotation = true;
|
||||
switch (subtype.name) {
|
||||
case 'Link':
|
||||
var a = annotation.get('A');
|
||||
@ -316,6 +402,14 @@ var Page = (function PageClosure() {
|
||||
var fieldType = getInheritableProperty(annotation, 'FT');
|
||||
if (!isName(fieldType))
|
||||
break;
|
||||
|
||||
// Do not display digital signatures since we do not currently
|
||||
// validate them.
|
||||
if (fieldType.name === 'Sig') {
|
||||
includeAnnotation = false;
|
||||
break;
|
||||
}
|
||||
|
||||
item.fieldType = fieldType.name;
|
||||
// Building the full field name by collecting the field and
|
||||
// its ancestors 'T' properties and joining them using '.'.
|
||||
@ -364,10 +458,18 @@ var Page = (function PageClosure() {
|
||||
annotation.get('Name').name;
|
||||
break;
|
||||
default:
|
||||
TODO('unimplemented annotation type: ' + subtype.name);
|
||||
var appearance = getDefaultAnnotationAppearance(annotation);
|
||||
if (!appearance) {
|
||||
TODO('unimplemented annotation type: ' + subtype.name);
|
||||
}
|
||||
break;
|
||||
}
|
||||
items.push(item);
|
||||
if (includeAnnotation) {
|
||||
items.push({
|
||||
item: item,
|
||||
dict: annotation
|
||||
});
|
||||
}
|
||||
}
|
||||
return items;
|
||||
}
|
||||
|
@ -19,7 +19,7 @@
|
||||
IDENTITY_MATRIX, info, isArray, isCmd, isDict, isEOF, isName, isNum,
|
||||
isStream, isString, JpegStream, Lexer, Metrics, Name, Parser,
|
||||
Pattern, PDFImage, PDFJS, serifFonts, stdFontMap, symbolsFonts,
|
||||
TilingPattern, TODO, warn */
|
||||
TilingPattern, TODO, warn, Util */
|
||||
|
||||
'use strict';
|
||||
|
||||
@ -588,6 +588,73 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
|
||||
return queue;
|
||||
},
|
||||
|
||||
getAnnotationsOperatorList:
|
||||
function PartialEvaluator_getAnnotationsOperatorList(annotations,
|
||||
dependency) {
|
||||
// 12.5.5: Algorithm: Appearance streams
|
||||
function getTransformMatrix(rect, bbox, matrix) {
|
||||
var bounds = Util.getAxialAlignedBoundingBox(bbox, matrix);
|
||||
var minX = bounds[0];
|
||||
var minY = bounds[1];
|
||||
var maxX = bounds[2];
|
||||
var maxY = bounds[3];
|
||||
var width = rect[2] - rect[0];
|
||||
var height = rect[3] - rect[1];
|
||||
var xRatio = width / (maxX - minX);
|
||||
var yRatio = height / (maxY - minY);
|
||||
return [
|
||||
xRatio,
|
||||
0,
|
||||
0,
|
||||
yRatio,
|
||||
rect[0] - minX * xRatio,
|
||||
rect[1] - minY * yRatio
|
||||
];
|
||||
}
|
||||
|
||||
var fnArray = [];
|
||||
var argsArray = [];
|
||||
// deal with annotations
|
||||
for (var i = 0, length = annotations.length; i < length; ++i) {
|
||||
var annotation = annotations[i];
|
||||
|
||||
// check whether we can visualize annotation
|
||||
if (!annotation ||
|
||||
!annotation.annotationFlags ||
|
||||
(annotation.annotationFlags & 0x0022) || // Hidden or NoView
|
||||
!annotation.rect || // rectangle is nessessary
|
||||
!annotation.appearance) { // appearance is nessessary
|
||||
continue;
|
||||
}
|
||||
|
||||
// apply rectangle
|
||||
var rect = annotation.rect;
|
||||
var bbox = annotation.bbox;
|
||||
var matrix = annotation.matrix;
|
||||
var transform = getTransformMatrix(rect, bbox, matrix);
|
||||
var border = annotation.border;
|
||||
|
||||
fnArray.push('beginAnnotation');
|
||||
argsArray.push([rect, transform, matrix, border]);
|
||||
|
||||
if (annotation.appearance) {
|
||||
var list = this.getOperatorList(annotation.appearance,
|
||||
annotation.resources, dependency);
|
||||
|
||||
Util.concatenateToArray(fnArray, list.fnArray);
|
||||
Util.concatenateToArray(argsArray, list.argsArray);
|
||||
}
|
||||
|
||||
fnArray.push('endAnnotation');
|
||||
argsArray.push([]);
|
||||
}
|
||||
|
||||
return {
|
||||
fnArray: fnArray,
|
||||
argsArray: argsArray
|
||||
};
|
||||
},
|
||||
|
||||
optimizeQueue: function PartialEvaluator_optimizeQueue(queue) {
|
||||
var fnArray = queue.fnArray, argsArray = queue.argsArray;
|
||||
// grouping paintInlineImageXObject's into paintInlineImageXObjectGroup
|
||||
|
@ -358,6 +358,10 @@ var Util = PDFJS.Util = (function UtilClosure() {
|
||||
return num < 0 ? -1 : 1;
|
||||
};
|
||||
|
||||
Util.concatenateToArray = function concatenateToArray(arr1, arr2) {
|
||||
return Array.prototype.push.apply(arr1, arr2);
|
||||
};
|
||||
|
||||
return Util;
|
||||
})();
|
||||
|
||||
|
1
test/pdfs/annotation-as.pdf.link
Normal file
1
test/pdfs/annotation-as.pdf.link
Normal file
@ -0,0 +1 @@
|
||||
https://bug741239.bugzilla.mozilla.org/attachment.cgi?id=611315
|
@ -924,6 +924,13 @@
|
||||
"rounds": 1,
|
||||
"type": "eq"
|
||||
},
|
||||
{ "id": "annotation-as",
|
||||
"file": "pdfs/annotation-as.pdf",
|
||||
"md5": "e51500c8adc9edcdcc8ebc6a575c90ab",
|
||||
"rounds": 1,
|
||||
"link": true,
|
||||
"type": "eq"
|
||||
},
|
||||
{ "id": "javauninstall-7",
|
||||
"file": "pdfs/javauninstall-7.pdf",
|
||||
"md5": "c9eb59503923c9125b9660e348618675",
|
||||
|
Loading…
Reference in New Issue
Block a user