Add support of Ink annotation
This commit is contained in:
parent
1cfb723dd4
commit
b5806735d8
@ -106,6 +106,9 @@ class AnnotationFactory {
|
||||
case 'Polygon':
|
||||
return new PolygonAnnotation(parameters);
|
||||
|
||||
case 'Ink':
|
||||
return new InkAnnotation(parameters);
|
||||
|
||||
case 'Highlight':
|
||||
return new HighlightAnnotation(parameters);
|
||||
|
||||
@ -1013,6 +1016,34 @@ class PolygonAnnotation extends PolylineAnnotation {
|
||||
}
|
||||
}
|
||||
|
||||
class InkAnnotation extends Annotation {
|
||||
constructor(parameters) {
|
||||
super(parameters);
|
||||
|
||||
this.data.annotationType = AnnotationType.INK;
|
||||
|
||||
let dict = parameters.dict;
|
||||
const xref = parameters.xref;
|
||||
|
||||
let originalInkLists = dict.getArray('InkList');
|
||||
this.data.inkLists = [];
|
||||
for (let i = 0, ii = originalInkLists.length; i < ii; ++i) {
|
||||
// The raw ink lists array contains arrays of numbers representing
|
||||
// the alternating horizontal and vertical coordinates, respectively,
|
||||
// of each vertex. Convert this to an array of objects with x and y
|
||||
// coordinates.
|
||||
this.data.inkLists.push([]);
|
||||
for (let j = 0, jj = originalInkLists[i].length; j < jj; j += 2) {
|
||||
this.data.inkLists[i].push({
|
||||
x: xref.fetchIfRef(originalInkLists[i][j]),
|
||||
y: xref.fetchIfRef(originalInkLists[i][j + 1]),
|
||||
});
|
||||
}
|
||||
}
|
||||
this._preparePopup(dict);
|
||||
}
|
||||
}
|
||||
|
||||
class HighlightAnnotation extends Annotation {
|
||||
constructor(parameters) {
|
||||
super(parameters);
|
||||
|
@ -83,6 +83,9 @@ class AnnotationElementFactory {
|
||||
case AnnotationType.POLYLINE:
|
||||
return new PolylineAnnotationElement(parameters);
|
||||
|
||||
case AnnotationType.INK:
|
||||
return new InkAnnotationElement(parameters);
|
||||
|
||||
case AnnotationType.POLYGON:
|
||||
return new PolygonAnnotationElement(parameters);
|
||||
|
||||
@ -628,7 +631,14 @@ class PopupAnnotationElement extends AnnotationElement {
|
||||
render() {
|
||||
// Do not render popup annotations for parent elements with these types as
|
||||
// they create the popups themselves (because of custom trigger divs).
|
||||
const IGNORE_TYPES = ['Line', 'Square', 'Circle', 'PolyLine', 'Polygon'];
|
||||
const IGNORE_TYPES = [
|
||||
'Line',
|
||||
'Square',
|
||||
'Circle',
|
||||
'PolyLine',
|
||||
'Polygon',
|
||||
'Ink',
|
||||
];
|
||||
|
||||
this.container.className = 'popupAnnotation';
|
||||
|
||||
@ -1006,6 +1016,73 @@ class PolygonAnnotationElement extends PolylineAnnotationElement {
|
||||
}
|
||||
}
|
||||
|
||||
class InkAnnotationElement extends AnnotationElement {
|
||||
constructor(parameters) {
|
||||
let isRenderable = !!(parameters.data.hasPopup ||
|
||||
parameters.data.title || parameters.data.contents);
|
||||
super(parameters, isRenderable, /* ignoreBorder = */ true);
|
||||
|
||||
this.containerClassName = 'inkAnnotation';
|
||||
|
||||
// Use the polyline SVG element since it allows us to use coordinates
|
||||
// directly and to draw both straight lines and curves.
|
||||
this.svgElementName = 'svg:polyline';
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the ink annotation's HTML element in the empty container.
|
||||
*
|
||||
* @public
|
||||
* @memberof InkAnnotationElement
|
||||
* @returns {HTMLSectionElement}
|
||||
*/
|
||||
render() {
|
||||
this.container.className = this.containerClassName;
|
||||
|
||||
// Create an invisible polyline with the same points that acts as the
|
||||
// trigger for the popup.
|
||||
let data = this.data;
|
||||
let width = data.rect[2] - data.rect[0];
|
||||
let height = data.rect[3] - data.rect[1];
|
||||
let svg = this.svgFactory.create(width, height);
|
||||
|
||||
let inkLists = data.inkLists;
|
||||
for (let i = 0, ii = inkLists.length; i < ii; i++) {
|
||||
let inkList = inkLists[i];
|
||||
let points = [];
|
||||
|
||||
// Convert the ink list to a single points string that the SVG
|
||||
// polyline element expects ("x1,y1 x2,y2 ..."). PDF coordinates are
|
||||
// calculated from a bottom left origin, so transform the polyline
|
||||
// coordinates to a top left origin for the SVG element.
|
||||
for (let j = 0, jj = inkList.length; j < jj; j++) {
|
||||
let x = inkList[j].x - data.rect[0];
|
||||
let y = data.rect[3] - inkList[j].y;
|
||||
points.push(x + ',' + y);
|
||||
}
|
||||
|
||||
points = points.join(' ');
|
||||
|
||||
let borderWidth = data.borderStyle.width;
|
||||
let polyline = this.svgFactory.createElement(this.svgElementName);
|
||||
polyline.setAttribute('points', points);
|
||||
polyline.setAttribute('stroke-width', borderWidth);
|
||||
polyline.setAttribute('stroke', 'transparent');
|
||||
polyline.setAttribute('fill', 'none');
|
||||
|
||||
// Create the popup ourselves so that we can bind it to the polyline
|
||||
// instead of to the entire container (which is the default).
|
||||
this._createPopup(this.container, polyline, data);
|
||||
|
||||
svg.appendChild(polyline);
|
||||
}
|
||||
|
||||
this.container.append(svg);
|
||||
|
||||
return this.container;
|
||||
}
|
||||
}
|
||||
|
||||
class HighlightAnnotationElement extends AnnotationElement {
|
||||
constructor(parameters) {
|
||||
let isRenderable = !!(parameters.data.hasPopup ||
|
||||
|
1
test/pdfs/.gitignore
vendored
1
test/pdfs/.gitignore
vendored
@ -272,6 +272,7 @@
|
||||
!text_clip_cff_cid.pdf
|
||||
!issue4801.pdf
|
||||
!issue5334.pdf
|
||||
!annotation-caret-ink.pdf
|
||||
!bug1186827.pdf
|
||||
!issue215.pdf
|
||||
!issue5044.pdf
|
||||
|
BIN
test/pdfs/annotation-caret-ink.pdf
Normal file
BIN
test/pdfs/annotation-caret-ink.pdf
Normal file
Binary file not shown.
@ -1776,6 +1776,13 @@
|
||||
"lastPage": 1,
|
||||
"type": "load"
|
||||
},
|
||||
{ "id": "annotation-caret-ink",
|
||||
"file": "pdfs/annotation-caret-ink.pdf",
|
||||
"md5": "6218ca235580d1975474c979e0128c2d",
|
||||
"rounds": 1,
|
||||
"type": "eq",
|
||||
"annotations": true
|
||||
},
|
||||
{ "id": "bug1130815-eq",
|
||||
"file": "pdfs/bug1130815.pdf",
|
||||
"md5": "3ff3b550c3af766991b2a1b11d00de85",
|
||||
|
@ -1435,4 +1435,59 @@ describe('annotation', function() {
|
||||
}, done.fail);
|
||||
});
|
||||
});
|
||||
|
||||
describe('InkAnnotation', function() {
|
||||
it('should handle a single ink list', function(done) {
|
||||
const inkDict = new Dict();
|
||||
inkDict.set('Type', Name.get('Annot'));
|
||||
inkDict.set('Subtype', Name.get('Ink'));
|
||||
inkDict.set('InkList', [[1, 1, 1, 2, 2, 2, 3, 3]]);
|
||||
|
||||
const inkRef = new Ref(142, 0);
|
||||
const xref = new XRefMock([
|
||||
{ ref: inkRef, data: inkDict, }
|
||||
]);
|
||||
|
||||
AnnotationFactory.create(xref, inkRef, pdfManagerMock,
|
||||
idFactoryMock).then(({ data, }) => {
|
||||
expect(data.annotationType).toEqual(AnnotationType.INK);
|
||||
expect(data.inkLists.length).toEqual(1);
|
||||
expect(data.inkLists[0]).toEqual([
|
||||
{ x: 1, y: 1, },
|
||||
{ x: 1, y: 2, },
|
||||
{ x: 2, y: 2, },
|
||||
{ x: 3, y: 3, },
|
||||
]);
|
||||
done();
|
||||
}, done.fail);
|
||||
});
|
||||
|
||||
it('should handle multiple ink lists', function(done) {
|
||||
const inkDict = new Dict();
|
||||
inkDict.set('Type', Name.get('Annot'));
|
||||
inkDict.set('Subtype', Name.get('Ink'));
|
||||
inkDict.set('InkList', [
|
||||
[1, 1, 1, 2],
|
||||
[3, 3, 4, 5],
|
||||
]);
|
||||
|
||||
const inkRef = new Ref(143, 0);
|
||||
const xref = new XRefMock([
|
||||
{ ref: inkRef, data: inkDict, }
|
||||
]);
|
||||
|
||||
AnnotationFactory.create(xref, inkRef, pdfManagerMock,
|
||||
idFactoryMock).then(({ data, }) => {
|
||||
expect(data.annotationType).toEqual(AnnotationType.INK);
|
||||
expect(data.inkLists.length).toEqual(2);
|
||||
expect(data.inkLists[0]).toEqual([
|
||||
{ x: 1, y: 1, }, { x: 1, y: 2, }
|
||||
]);
|
||||
expect(data.inkLists[1]).toEqual([
|
||||
{ x: 3, y: 3, }, { x: 4, y: 5, }
|
||||
]);
|
||||
done();
|
||||
}, done.fail);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -188,6 +188,7 @@
|
||||
.annotationLayer .circleAnnotation svg ellipse,
|
||||
.annotationLayer .polylineAnnotation svg polyline,
|
||||
.annotationLayer .polygonAnnotation svg polygon,
|
||||
.annotationLayer .inkAnnotation svg polyline,
|
||||
.annotationLayer .stampAnnotation,
|
||||
.annotationLayer .fileAttachmentAnnotation {
|
||||
cursor: pointer;
|
||||
|
Loading…
Reference in New Issue
Block a user