1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 |
|
22 | "use strict";
|
23 |
|
24 | Object.defineProperty(exports, "__esModule", {
|
25 | value: true
|
26 | });
|
27 | exports.MarkupAnnotation = exports.AnnotationFactory = exports.AnnotationBorderStyle = exports.Annotation = void 0;
|
28 | exports.getQuadPoints = getQuadPoints;
|
29 |
|
30 | var _util = require("../shared/util.js");
|
31 |
|
32 | var _core_utils = require("./core_utils.js");
|
33 |
|
34 | var _default_appearance = require("./default_appearance.js");
|
35 |
|
36 | var _primitives = require("./primitives.js");
|
37 |
|
38 | var _writer = require("./writer.js");
|
39 |
|
40 | var _base_stream = require("./base_stream.js");
|
41 |
|
42 | var _bidi = require("./bidi.js");
|
43 |
|
44 | var _catalog = require("./catalog.js");
|
45 |
|
46 | var _colorspace = require("./colorspace.js");
|
47 |
|
48 | var _file_spec = require("./file_spec.js");
|
49 |
|
50 | var _object_loader = require("./object_loader.js");
|
51 |
|
52 | var _operator_list = require("./operator_list.js");
|
53 |
|
54 | var _stream = require("./stream.js");
|
55 |
|
56 | var _factory = require("./xfa/factory.js");
|
57 |
|
58 | class AnnotationFactory {
|
59 | static create(xref, ref, pdfManager, idFactory, collectFields) {
|
60 | return Promise.all([pdfManager.ensureCatalog("acroForm"), pdfManager.ensureCatalog("baseUrl"), pdfManager.ensureDoc("xfaDatasets"), collectFields ? this._getPageIndex(xref, ref, pdfManager) : -1]).then(([acroForm, baseUrl, xfaDatasets, pageIndex]) => pdfManager.ensure(this, "_create", [xref, ref, pdfManager, idFactory, acroForm, xfaDatasets, collectFields, pageIndex]));
|
61 | }
|
62 |
|
63 | static _create(xref, ref, pdfManager, idFactory, acroForm, xfaDatasets, collectFields, pageIndex = -1) {
|
64 | const dict = xref.fetchIfRef(ref);
|
65 |
|
66 | if (!(dict instanceof _primitives.Dict)) {
|
67 | return undefined;
|
68 | }
|
69 |
|
70 | const id = ref instanceof _primitives.Ref ? ref.toString() : `annot_${idFactory.createObjId()}`;
|
71 | let subtype = dict.get("Subtype");
|
72 | subtype = subtype instanceof _primitives.Name ? subtype.name : null;
|
73 | const parameters = {
|
74 | xref,
|
75 | ref,
|
76 | dict,
|
77 | subtype,
|
78 | id,
|
79 | pdfManager,
|
80 | acroForm: acroForm instanceof _primitives.Dict ? acroForm : _primitives.Dict.empty,
|
81 | xfaDatasets,
|
82 | collectFields,
|
83 | pageIndex
|
84 | };
|
85 |
|
86 | switch (subtype) {
|
87 | case "Link":
|
88 | return new LinkAnnotation(parameters);
|
89 |
|
90 | case "Text":
|
91 | return new TextAnnotation(parameters);
|
92 |
|
93 | case "Widget":
|
94 | let fieldType = (0, _core_utils.getInheritableProperty)({
|
95 | dict,
|
96 | key: "FT"
|
97 | });
|
98 | fieldType = fieldType instanceof _primitives.Name ? fieldType.name : null;
|
99 |
|
100 | switch (fieldType) {
|
101 | case "Tx":
|
102 | return new TextWidgetAnnotation(parameters);
|
103 |
|
104 | case "Btn":
|
105 | return new ButtonWidgetAnnotation(parameters);
|
106 |
|
107 | case "Ch":
|
108 | return new ChoiceWidgetAnnotation(parameters);
|
109 |
|
110 | case "Sig":
|
111 | return new SignatureWidgetAnnotation(parameters);
|
112 | }
|
113 |
|
114 | (0, _util.warn)(`Unimplemented widget field type "${fieldType}", ` + "falling back to base field type.");
|
115 | return new WidgetAnnotation(parameters);
|
116 |
|
117 | case "Popup":
|
118 | return new PopupAnnotation(parameters);
|
119 |
|
120 | case "FreeText":
|
121 | return new FreeTextAnnotation(parameters);
|
122 |
|
123 | case "Line":
|
124 | return new LineAnnotation(parameters);
|
125 |
|
126 | case "Square":
|
127 | return new SquareAnnotation(parameters);
|
128 |
|
129 | case "Circle":
|
130 | return new CircleAnnotation(parameters);
|
131 |
|
132 | case "PolyLine":
|
133 | return new PolylineAnnotation(parameters);
|
134 |
|
135 | case "Polygon":
|
136 | return new PolygonAnnotation(parameters);
|
137 |
|
138 | case "Caret":
|
139 | return new CaretAnnotation(parameters);
|
140 |
|
141 | case "Ink":
|
142 | return new InkAnnotation(parameters);
|
143 |
|
144 | case "Highlight":
|
145 | return new HighlightAnnotation(parameters);
|
146 |
|
147 | case "Underline":
|
148 | return new UnderlineAnnotation(parameters);
|
149 |
|
150 | case "Squiggly":
|
151 | return new SquigglyAnnotation(parameters);
|
152 |
|
153 | case "StrikeOut":
|
154 | return new StrikeOutAnnotation(parameters);
|
155 |
|
156 | case "Stamp":
|
157 | return new StampAnnotation(parameters);
|
158 |
|
159 | case "FileAttachment":
|
160 | return new FileAttachmentAnnotation(parameters);
|
161 |
|
162 | default:
|
163 | if (!collectFields) {
|
164 | if (!subtype) {
|
165 | (0, _util.warn)("Annotation is missing the required /Subtype.");
|
166 | } else {
|
167 | (0, _util.warn)(`Unimplemented annotation type "${subtype}", ` + "falling back to base annotation.");
|
168 | }
|
169 | }
|
170 |
|
171 | return new Annotation(parameters);
|
172 | }
|
173 | }
|
174 |
|
175 | static async _getPageIndex(xref, ref, pdfManager) {
|
176 | try {
|
177 | const annotDict = await xref.fetchIfRefAsync(ref);
|
178 |
|
179 | if (!(annotDict instanceof _primitives.Dict)) {
|
180 | return -1;
|
181 | }
|
182 |
|
183 | const pageRef = annotDict.getRaw("P");
|
184 |
|
185 | if (!(pageRef instanceof _primitives.Ref)) {
|
186 | return -1;
|
187 | }
|
188 |
|
189 | const pageIndex = await pdfManager.ensureCatalog("getPageIndex", [pageRef]);
|
190 | return pageIndex;
|
191 | } catch (ex) {
|
192 | (0, _util.warn)(`_getPageIndex: "${ex}".`);
|
193 | return -1;
|
194 | }
|
195 | }
|
196 |
|
197 | static async saveNewAnnotations(evaluator, task, annotations) {
|
198 | const xref = evaluator.xref;
|
199 | let baseFontRef;
|
200 | const dependencies = [];
|
201 | const promises = [];
|
202 |
|
203 | for (const annotation of annotations) {
|
204 | switch (annotation.annotationType) {
|
205 | case _util.AnnotationEditorType.FREETEXT:
|
206 | if (!baseFontRef) {
|
207 | const baseFont = new _primitives.Dict(xref);
|
208 | baseFont.set("BaseFont", _primitives.Name.get("Helvetica"));
|
209 | baseFont.set("Type", _primitives.Name.get("Font"));
|
210 | baseFont.set("Subtype", _primitives.Name.get("Type1"));
|
211 | baseFont.set("Encoding", _primitives.Name.get("WinAnsiEncoding"));
|
212 | const buffer = [];
|
213 | baseFontRef = xref.getNewRef();
|
214 | (0, _writer.writeObject)(baseFontRef, baseFont, buffer, null);
|
215 | dependencies.push({
|
216 | ref: baseFontRef,
|
217 | data: buffer.join("")
|
218 | });
|
219 | }
|
220 |
|
221 | promises.push(FreeTextAnnotation.createNewAnnotation(xref, annotation, dependencies, {
|
222 | evaluator,
|
223 | task,
|
224 | baseFontRef
|
225 | }));
|
226 | break;
|
227 |
|
228 | case _util.AnnotationEditorType.INK:
|
229 | promises.push(InkAnnotation.createNewAnnotation(xref, annotation, dependencies));
|
230 | }
|
231 | }
|
232 |
|
233 | return {
|
234 | annotations: await Promise.all(promises),
|
235 | dependencies
|
236 | };
|
237 | }
|
238 |
|
239 | static async printNewAnnotations(evaluator, task, annotations) {
|
240 | if (!annotations) {
|
241 | return null;
|
242 | }
|
243 |
|
244 | const xref = evaluator.xref;
|
245 | const promises = [];
|
246 |
|
247 | for (const annotation of annotations) {
|
248 | switch (annotation.annotationType) {
|
249 | case _util.AnnotationEditorType.FREETEXT:
|
250 | promises.push(FreeTextAnnotation.createNewPrintAnnotation(xref, annotation, {
|
251 | evaluator,
|
252 | task
|
253 | }));
|
254 | break;
|
255 |
|
256 | case _util.AnnotationEditorType.INK:
|
257 | promises.push(InkAnnotation.createNewPrintAnnotation(xref, annotation));
|
258 | break;
|
259 | }
|
260 | }
|
261 |
|
262 | return Promise.all(promises);
|
263 | }
|
264 |
|
265 | }
|
266 |
|
267 | exports.AnnotationFactory = AnnotationFactory;
|
268 |
|
269 | function getRgbColor(color, defaultColor = new Uint8ClampedArray(3)) {
|
270 | if (!Array.isArray(color)) {
|
271 | return defaultColor;
|
272 | }
|
273 |
|
274 | const rgbColor = defaultColor || new Uint8ClampedArray(3);
|
275 |
|
276 | switch (color.length) {
|
277 | case 0:
|
278 | return null;
|
279 |
|
280 | case 1:
|
281 | _colorspace.ColorSpace.singletons.gray.getRgbItem(color, 0, rgbColor, 0);
|
282 |
|
283 | return rgbColor;
|
284 |
|
285 | case 3:
|
286 | _colorspace.ColorSpace.singletons.rgb.getRgbItem(color, 0, rgbColor, 0);
|
287 |
|
288 | return rgbColor;
|
289 |
|
290 | case 4:
|
291 | _colorspace.ColorSpace.singletons.cmyk.getRgbItem(color, 0, rgbColor, 0);
|
292 |
|
293 | return rgbColor;
|
294 |
|
295 | default:
|
296 | return defaultColor;
|
297 | }
|
298 | }
|
299 |
|
300 | function getQuadPoints(dict, rect) {
|
301 | if (!dict.has("QuadPoints")) {
|
302 | return null;
|
303 | }
|
304 |
|
305 | const quadPoints = dict.getArray("QuadPoints");
|
306 |
|
307 | if (!Array.isArray(quadPoints) || quadPoints.length === 0 || quadPoints.length % 8 > 0) {
|
308 | return null;
|
309 | }
|
310 |
|
311 | const quadPointsLists = [];
|
312 |
|
313 | for (let i = 0, ii = quadPoints.length / 8; i < ii; i++) {
|
314 | quadPointsLists.push([]);
|
315 |
|
316 | for (let j = i * 8, jj = i * 8 + 8; j < jj; j += 2) {
|
317 | const x = quadPoints[j];
|
318 | const y = quadPoints[j + 1];
|
319 |
|
320 | if (rect !== null && (x < rect[0] || x > rect[2] || y < rect[1] || y > rect[3])) {
|
321 | return null;
|
322 | }
|
323 |
|
324 | quadPointsLists[i].push({
|
325 | x,
|
326 | y
|
327 | });
|
328 | }
|
329 | }
|
330 |
|
331 | return quadPointsLists.map(quadPointsList => {
|
332 | const [minX, maxX, minY, maxY] = quadPointsList.reduce(([mX, MX, mY, MY], quadPoint) => [Math.min(mX, quadPoint.x), Math.max(MX, quadPoint.x), Math.min(mY, quadPoint.y), Math.max(MY, quadPoint.y)], [Number.MAX_VALUE, Number.MIN_VALUE, Number.MAX_VALUE, Number.MIN_VALUE]);
|
333 | return [{
|
334 | x: minX,
|
335 | y: maxY
|
336 | }, {
|
337 | x: maxX,
|
338 | y: maxY
|
339 | }, {
|
340 | x: minX,
|
341 | y: minY
|
342 | }, {
|
343 | x: maxX,
|
344 | y: minY
|
345 | }];
|
346 | });
|
347 | }
|
348 |
|
349 | function getTransformMatrix(rect, bbox, matrix) {
|
350 | const [minX, minY, maxX, maxY] = _util.Util.getAxialAlignedBoundingBox(bbox, matrix);
|
351 |
|
352 | if (minX === maxX || minY === maxY) {
|
353 | return [1, 0, 0, 1, rect[0], rect[1]];
|
354 | }
|
355 |
|
356 | const xRatio = (rect[2] - rect[0]) / (maxX - minX);
|
357 | const yRatio = (rect[3] - rect[1]) / (maxY - minY);
|
358 | return [xRatio, 0, 0, yRatio, rect[0] - minX * xRatio, rect[1] - minY * yRatio];
|
359 | }
|
360 |
|
361 | class Annotation {
|
362 | constructor(params) {
|
363 | const dict = params.dict;
|
364 | this.setTitle(dict.get("T"));
|
365 | this.setContents(dict.get("Contents"));
|
366 | this.setModificationDate(dict.get("M"));
|
367 | this.setFlags(dict.get("F"));
|
368 | this.setRectangle(dict.getArray("Rect"));
|
369 | this.setColor(dict.getArray("C"));
|
370 | this.setBorderStyle(dict);
|
371 | this.setAppearance(dict);
|
372 | this.setOptionalContent(dict);
|
373 | const MK = dict.get("MK");
|
374 | this.setBorderAndBackgroundColors(MK);
|
375 | this.setRotation(MK);
|
376 | this._streams = [];
|
377 |
|
378 | if (this.appearance) {
|
379 | this._streams.push(this.appearance);
|
380 | }
|
381 |
|
382 | this.data = {
|
383 | annotationFlags: this.flags,
|
384 | borderStyle: this.borderStyle,
|
385 | color: this.color,
|
386 | backgroundColor: this.backgroundColor,
|
387 | borderColor: this.borderColor,
|
388 | rotation: this.rotation,
|
389 | contentsObj: this._contents,
|
390 | hasAppearance: !!this.appearance,
|
391 | id: params.id,
|
392 | modificationDate: this.modificationDate,
|
393 | rect: this.rectangle,
|
394 | subtype: params.subtype,
|
395 | hasOwnCanvas: false
|
396 | };
|
397 |
|
398 | if (params.collectFields) {
|
399 | const kids = dict.get("Kids");
|
400 |
|
401 | if (Array.isArray(kids)) {
|
402 | const kidIds = [];
|
403 |
|
404 | for (const kid of kids) {
|
405 | if (kid instanceof _primitives.Ref) {
|
406 | kidIds.push(kid.toString());
|
407 | }
|
408 | }
|
409 |
|
410 | if (kidIds.length !== 0) {
|
411 | this.data.kidIds = kidIds;
|
412 | }
|
413 | }
|
414 |
|
415 | this.data.actions = (0, _core_utils.collectActions)(params.xref, dict, _util.AnnotationActionEventType);
|
416 | this.data.fieldName = this._constructFieldName(dict);
|
417 | this.data.pageIndex = params.pageIndex;
|
418 | }
|
419 |
|
420 | this._fallbackFontDict = null;
|
421 | }
|
422 |
|
423 | _hasFlag(flags, flag) {
|
424 | return !!(flags & flag);
|
425 | }
|
426 |
|
427 | _isViewable(flags) {
|
428 | return !this._hasFlag(flags, _util.AnnotationFlag.INVISIBLE) && !this._hasFlag(flags, _util.AnnotationFlag.NOVIEW);
|
429 | }
|
430 |
|
431 | _isPrintable(flags) {
|
432 | return this._hasFlag(flags, _util.AnnotationFlag.PRINT) && !this._hasFlag(flags, _util.AnnotationFlag.INVISIBLE);
|
433 | }
|
434 |
|
435 | mustBeViewed(annotationStorage) {
|
436 | const storageEntry = annotationStorage && annotationStorage.get(this.data.id);
|
437 |
|
438 | if (storageEntry && storageEntry.hidden !== undefined) {
|
439 | return !storageEntry.hidden;
|
440 | }
|
441 |
|
442 | return this.viewable && !this._hasFlag(this.flags, _util.AnnotationFlag.HIDDEN);
|
443 | }
|
444 |
|
445 | mustBePrinted(annotationStorage) {
|
446 | const storageEntry = annotationStorage && annotationStorage.get(this.data.id);
|
447 |
|
448 | if (storageEntry && storageEntry.print !== undefined) {
|
449 | return storageEntry.print;
|
450 | }
|
451 |
|
452 | return this.printable;
|
453 | }
|
454 |
|
455 | get viewable() {
|
456 | if (this.data.quadPoints === null) {
|
457 | return false;
|
458 | }
|
459 |
|
460 | if (this.flags === 0) {
|
461 | return true;
|
462 | }
|
463 |
|
464 | return this._isViewable(this.flags);
|
465 | }
|
466 |
|
467 | get printable() {
|
468 | if (this.data.quadPoints === null) {
|
469 | return false;
|
470 | }
|
471 |
|
472 | if (this.flags === 0) {
|
473 | return false;
|
474 | }
|
475 |
|
476 | return this._isPrintable(this.flags);
|
477 | }
|
478 |
|
479 | _parseStringHelper(data) {
|
480 | const str = typeof data === "string" ? (0, _util.stringToPDFString)(data) : "";
|
481 | const dir = str && (0, _bidi.bidi)(str).dir === "rtl" ? "rtl" : "ltr";
|
482 | return {
|
483 | str,
|
484 | dir
|
485 | };
|
486 | }
|
487 |
|
488 | setTitle(title) {
|
489 | this._title = this._parseStringHelper(title);
|
490 | }
|
491 |
|
492 | setContents(contents) {
|
493 | this._contents = this._parseStringHelper(contents);
|
494 | }
|
495 |
|
496 | setModificationDate(modificationDate) {
|
497 | this.modificationDate = typeof modificationDate === "string" ? modificationDate : null;
|
498 | }
|
499 |
|
500 | setFlags(flags) {
|
501 | this.flags = Number.isInteger(flags) && flags > 0 ? flags : 0;
|
502 | }
|
503 |
|
504 | hasFlag(flag) {
|
505 | return this._hasFlag(this.flags, flag);
|
506 | }
|
507 |
|
508 | setRectangle(rectangle) {
|
509 | if (Array.isArray(rectangle) && rectangle.length === 4) {
|
510 | this.rectangle = _util.Util.normalizeRect(rectangle);
|
511 | } else {
|
512 | this.rectangle = [0, 0, 0, 0];
|
513 | }
|
514 | }
|
515 |
|
516 | setColor(color) {
|
517 | this.color = getRgbColor(color);
|
518 | }
|
519 |
|
520 | setLineEndings(lineEndings) {
|
521 | this.lineEndings = ["None", "None"];
|
522 |
|
523 | if (Array.isArray(lineEndings) && lineEndings.length === 2) {
|
524 | for (let i = 0; i < 2; i++) {
|
525 | const obj = lineEndings[i];
|
526 |
|
527 | if (obj instanceof _primitives.Name) {
|
528 | switch (obj.name) {
|
529 | case "None":
|
530 | continue;
|
531 |
|
532 | case "Square":
|
533 | case "Circle":
|
534 | case "Diamond":
|
535 | case "OpenArrow":
|
536 | case "ClosedArrow":
|
537 | case "Butt":
|
538 | case "ROpenArrow":
|
539 | case "RClosedArrow":
|
540 | case "Slash":
|
541 | this.lineEndings[i] = obj.name;
|
542 | continue;
|
543 | }
|
544 | }
|
545 |
|
546 | (0, _util.warn)(`Ignoring invalid lineEnding: ${obj}`);
|
547 | }
|
548 | }
|
549 | }
|
550 |
|
551 | setRotation(mk) {
|
552 | this.rotation = 0;
|
553 |
|
554 | if (mk instanceof _primitives.Dict) {
|
555 | let angle = mk.get("R") || 0;
|
556 |
|
557 | if (Number.isInteger(angle) && angle !== 0) {
|
558 | angle %= 360;
|
559 |
|
560 | if (angle < 0) {
|
561 | angle += 360;
|
562 | }
|
563 |
|
564 | if (angle % 90 === 0) {
|
565 | this.rotation = angle;
|
566 | }
|
567 | }
|
568 | }
|
569 | }
|
570 |
|
571 | setBorderAndBackgroundColors(mk) {
|
572 | if (mk instanceof _primitives.Dict) {
|
573 | this.borderColor = getRgbColor(mk.getArray("BC"), null);
|
574 | this.backgroundColor = getRgbColor(mk.getArray("BG"), null);
|
575 | } else {
|
576 | this.borderColor = this.backgroundColor = null;
|
577 | }
|
578 | }
|
579 |
|
580 | setBorderStyle(borderStyle) {
|
581 | this.borderStyle = new AnnotationBorderStyle();
|
582 |
|
583 | if (!(borderStyle instanceof _primitives.Dict)) {
|
584 | return;
|
585 | }
|
586 |
|
587 | if (borderStyle.has("BS")) {
|
588 | const dict = borderStyle.get("BS");
|
589 | const dictType = dict.get("Type");
|
590 |
|
591 | if (!dictType || (0, _primitives.isName)(dictType, "Border")) {
|
592 | this.borderStyle.setWidth(dict.get("W"), this.rectangle);
|
593 | this.borderStyle.setStyle(dict.get("S"));
|
594 | this.borderStyle.setDashArray(dict.getArray("D"));
|
595 | }
|
596 | } else if (borderStyle.has("Border")) {
|
597 | const array = borderStyle.getArray("Border");
|
598 |
|
599 | if (Array.isArray(array) && array.length >= 3) {
|
600 | this.borderStyle.setHorizontalCornerRadius(array[0]);
|
601 | this.borderStyle.setVerticalCornerRadius(array[1]);
|
602 | this.borderStyle.setWidth(array[2], this.rectangle);
|
603 |
|
604 | if (array.length === 4) {
|
605 | this.borderStyle.setDashArray(array[3], true);
|
606 | }
|
607 | }
|
608 | } else {
|
609 | this.borderStyle.setWidth(0);
|
610 | }
|
611 | }
|
612 |
|
613 | setAppearance(dict) {
|
614 | this.appearance = null;
|
615 | const appearanceStates = dict.get("AP");
|
616 |
|
617 | if (!(appearanceStates instanceof _primitives.Dict)) {
|
618 | return;
|
619 | }
|
620 |
|
621 | const normalAppearanceState = appearanceStates.get("N");
|
622 |
|
623 | if (normalAppearanceState instanceof _base_stream.BaseStream) {
|
624 | this.appearance = normalAppearanceState;
|
625 | return;
|
626 | }
|
627 |
|
628 | if (!(normalAppearanceState instanceof _primitives.Dict)) {
|
629 | return;
|
630 | }
|
631 |
|
632 | const as = dict.get("AS");
|
633 |
|
634 | if (!(as instanceof _primitives.Name) || !normalAppearanceState.has(as.name)) {
|
635 | return;
|
636 | }
|
637 |
|
638 | this.appearance = normalAppearanceState.get(as.name);
|
639 | }
|
640 |
|
641 | setOptionalContent(dict) {
|
642 | this.oc = null;
|
643 | const oc = dict.get("OC");
|
644 |
|
645 | if (oc instanceof _primitives.Name) {
|
646 | (0, _util.warn)("setOptionalContent: Support for /Name-entry is not implemented.");
|
647 | } else if (oc instanceof _primitives.Dict) {
|
648 | this.oc = oc;
|
649 | }
|
650 | }
|
651 |
|
652 | loadResources(keys, appearance) {
|
653 | return appearance.dict.getAsync("Resources").then(resources => {
|
654 | if (!resources) {
|
655 | return undefined;
|
656 | }
|
657 |
|
658 | const objectLoader = new _object_loader.ObjectLoader(resources, keys, resources.xref);
|
659 | return objectLoader.load().then(function () {
|
660 | return resources;
|
661 | });
|
662 | });
|
663 | }
|
664 |
|
665 | async getOperatorList(evaluator, task, intent, renderForms, annotationStorage) {
|
666 | const data = this.data;
|
667 | let appearance = this.appearance;
|
668 | const isUsingOwnCanvas = !!(this.data.hasOwnCanvas && intent & _util.RenderingIntentFlag.DISPLAY);
|
669 |
|
670 | if (!appearance) {
|
671 | if (!isUsingOwnCanvas) {
|
672 | return {
|
673 | opList: new _operator_list.OperatorList(),
|
674 | separateForm: false,
|
675 | separateCanvas: false
|
676 | };
|
677 | }
|
678 |
|
679 | appearance = new _stream.StringStream("");
|
680 | appearance.dict = new _primitives.Dict();
|
681 | }
|
682 |
|
683 | const appearanceDict = appearance.dict;
|
684 | const resources = await this.loadResources(["ExtGState", "ColorSpace", "Pattern", "Shading", "XObject", "Font"], appearance);
|
685 | const bbox = appearanceDict.getArray("BBox") || [0, 0, 1, 1];
|
686 | const matrix = appearanceDict.getArray("Matrix") || [1, 0, 0, 1, 0, 0];
|
687 | const transform = getTransformMatrix(data.rect, bbox, matrix);
|
688 | const opList = new _operator_list.OperatorList();
|
689 | let optionalContent;
|
690 |
|
691 | if (this.oc) {
|
692 | optionalContent = await evaluator.parseMarkedContentProps(this.oc, null);
|
693 | }
|
694 |
|
695 | if (optionalContent !== undefined) {
|
696 | opList.addOp(_util.OPS.beginMarkedContentProps, ["OC", optionalContent]);
|
697 | }
|
698 |
|
699 | opList.addOp(_util.OPS.beginAnnotation, [data.id, data.rect, transform, matrix, isUsingOwnCanvas]);
|
700 | await evaluator.getOperatorList({
|
701 | stream: appearance,
|
702 | task,
|
703 | resources,
|
704 | operatorList: opList,
|
705 | fallbackFontDict: this._fallbackFontDict
|
706 | });
|
707 | opList.addOp(_util.OPS.endAnnotation, []);
|
708 |
|
709 | if (optionalContent !== undefined) {
|
710 | opList.addOp(_util.OPS.endMarkedContent, []);
|
711 | }
|
712 |
|
713 | this.reset();
|
714 | return {
|
715 | opList,
|
716 | separateForm: false,
|
717 | separateCanvas: isUsingOwnCanvas
|
718 | };
|
719 | }
|
720 |
|
721 | async save(evaluator, task, annotationStorage) {
|
722 | return null;
|
723 | }
|
724 |
|
725 | getFieldObject() {
|
726 | if (this.data.kidIds) {
|
727 | return {
|
728 | id: this.data.id,
|
729 | actions: this.data.actions,
|
730 | name: this.data.fieldName,
|
731 | strokeColor: this.data.borderColor,
|
732 | fillColor: this.data.backgroundColor,
|
733 | type: "",
|
734 | kidIds: this.data.kidIds,
|
735 | page: this.data.pageIndex,
|
736 | rotation: this.rotation
|
737 | };
|
738 | }
|
739 |
|
740 | return null;
|
741 | }
|
742 |
|
743 | reset() {
|
744 | for (const stream of this._streams) {
|
745 | stream.reset();
|
746 | }
|
747 | }
|
748 |
|
749 | _constructFieldName(dict) {
|
750 | if (!dict.has("T") && !dict.has("Parent")) {
|
751 | (0, _util.warn)("Unknown field name, falling back to empty field name.");
|
752 | return "";
|
753 | }
|
754 |
|
755 | if (!dict.has("Parent")) {
|
756 | return (0, _util.stringToPDFString)(dict.get("T"));
|
757 | }
|
758 |
|
759 | const fieldName = [];
|
760 |
|
761 | if (dict.has("T")) {
|
762 | fieldName.unshift((0, _util.stringToPDFString)(dict.get("T")));
|
763 | }
|
764 |
|
765 | let loopDict = dict;
|
766 | const visited = new _primitives.RefSet();
|
767 |
|
768 | if (dict.objId) {
|
769 | visited.put(dict.objId);
|
770 | }
|
771 |
|
772 | while (loopDict.has("Parent")) {
|
773 | loopDict = loopDict.get("Parent");
|
774 |
|
775 | if (!(loopDict instanceof _primitives.Dict) || loopDict.objId && visited.has(loopDict.objId)) {
|
776 | break;
|
777 | }
|
778 |
|
779 | if (loopDict.objId) {
|
780 | visited.put(loopDict.objId);
|
781 | }
|
782 |
|
783 | if (loopDict.has("T")) {
|
784 | fieldName.unshift((0, _util.stringToPDFString)(loopDict.get("T")));
|
785 | }
|
786 | }
|
787 |
|
788 | return fieldName.join(".");
|
789 | }
|
790 |
|
791 | }
|
792 |
|
793 | exports.Annotation = Annotation;
|
794 |
|
795 | class AnnotationBorderStyle {
|
796 | constructor() {
|
797 | this.width = 1;
|
798 | this.style = _util.AnnotationBorderStyleType.SOLID;
|
799 | this.dashArray = [3];
|
800 | this.horizontalCornerRadius = 0;
|
801 | this.verticalCornerRadius = 0;
|
802 | }
|
803 |
|
804 | setWidth(width, rect = [0, 0, 0, 0]) {
|
805 | if (width instanceof _primitives.Name) {
|
806 | this.width = 0;
|
807 | return;
|
808 | }
|
809 |
|
810 | if (typeof width === "number") {
|
811 | if (width > 0) {
|
812 | const maxWidth = (rect[2] - rect[0]) / 2;
|
813 | const maxHeight = (rect[3] - rect[1]) / 2;
|
814 |
|
815 | if (maxWidth > 0 && maxHeight > 0 && (width > maxWidth || width > maxHeight)) {
|
816 | (0, _util.warn)(`AnnotationBorderStyle.setWidth - ignoring width: ${width}`);
|
817 | width = 1;
|
818 | }
|
819 | }
|
820 |
|
821 | this.width = width;
|
822 | }
|
823 | }
|
824 |
|
825 | setStyle(style) {
|
826 | if (!(style instanceof _primitives.Name)) {
|
827 | return;
|
828 | }
|
829 |
|
830 | switch (style.name) {
|
831 | case "S":
|
832 | this.style = _util.AnnotationBorderStyleType.SOLID;
|
833 | break;
|
834 |
|
835 | case "D":
|
836 | this.style = _util.AnnotationBorderStyleType.DASHED;
|
837 | break;
|
838 |
|
839 | case "B":
|
840 | this.style = _util.AnnotationBorderStyleType.BEVELED;
|
841 | break;
|
842 |
|
843 | case "I":
|
844 | this.style = _util.AnnotationBorderStyleType.INSET;
|
845 | break;
|
846 |
|
847 | case "U":
|
848 | this.style = _util.AnnotationBorderStyleType.UNDERLINE;
|
849 | break;
|
850 |
|
851 | default:
|
852 | break;
|
853 | }
|
854 | }
|
855 |
|
856 | setDashArray(dashArray, forceStyle = false) {
|
857 | if (Array.isArray(dashArray) && dashArray.length > 0) {
|
858 | let isValid = true;
|
859 | let allZeros = true;
|
860 |
|
861 | for (const element of dashArray) {
|
862 | const validNumber = +element >= 0;
|
863 |
|
864 | if (!validNumber) {
|
865 | isValid = false;
|
866 | break;
|
867 | } else if (element > 0) {
|
868 | allZeros = false;
|
869 | }
|
870 | }
|
871 |
|
872 | if (isValid && !allZeros) {
|
873 | this.dashArray = dashArray;
|
874 |
|
875 | if (forceStyle) {
|
876 | this.setStyle(_primitives.Name.get("D"));
|
877 | }
|
878 | } else {
|
879 | this.width = 0;
|
880 | }
|
881 | } else if (dashArray) {
|
882 | this.width = 0;
|
883 | }
|
884 | }
|
885 |
|
886 | setHorizontalCornerRadius(radius) {
|
887 | if (Number.isInteger(radius)) {
|
888 | this.horizontalCornerRadius = radius;
|
889 | }
|
890 | }
|
891 |
|
892 | setVerticalCornerRadius(radius) {
|
893 | if (Number.isInteger(radius)) {
|
894 | this.verticalCornerRadius = radius;
|
895 | }
|
896 | }
|
897 |
|
898 | }
|
899 |
|
900 | exports.AnnotationBorderStyle = AnnotationBorderStyle;
|
901 |
|
902 | class MarkupAnnotation extends Annotation {
|
903 | constructor(parameters) {
|
904 | super(parameters);
|
905 | const dict = parameters.dict;
|
906 |
|
907 | if (dict.has("IRT")) {
|
908 | const rawIRT = dict.getRaw("IRT");
|
909 | this.data.inReplyTo = rawIRT instanceof _primitives.Ref ? rawIRT.toString() : null;
|
910 | const rt = dict.get("RT");
|
911 | this.data.replyType = rt instanceof _primitives.Name ? rt.name : _util.AnnotationReplyType.REPLY;
|
912 | }
|
913 |
|
914 | if (this.data.replyType === _util.AnnotationReplyType.GROUP) {
|
915 | const parent = dict.get("IRT");
|
916 | this.setTitle(parent.get("T"));
|
917 | this.data.titleObj = this._title;
|
918 | this.setContents(parent.get("Contents"));
|
919 | this.data.contentsObj = this._contents;
|
920 |
|
921 | if (!parent.has("CreationDate")) {
|
922 | this.data.creationDate = null;
|
923 | } else {
|
924 | this.setCreationDate(parent.get("CreationDate"));
|
925 | this.data.creationDate = this.creationDate;
|
926 | }
|
927 |
|
928 | if (!parent.has("M")) {
|
929 | this.data.modificationDate = null;
|
930 | } else {
|
931 | this.setModificationDate(parent.get("M"));
|
932 | this.data.modificationDate = this.modificationDate;
|
933 | }
|
934 |
|
935 | this.data.hasPopup = parent.has("Popup");
|
936 |
|
937 | if (!parent.has("C")) {
|
938 | this.data.color = null;
|
939 | } else {
|
940 | this.setColor(parent.getArray("C"));
|
941 | this.data.color = this.color;
|
942 | }
|
943 | } else {
|
944 | this.data.titleObj = this._title;
|
945 | this.setCreationDate(dict.get("CreationDate"));
|
946 | this.data.creationDate = this.creationDate;
|
947 | this.data.hasPopup = dict.has("Popup");
|
948 |
|
949 | if (!dict.has("C")) {
|
950 | this.data.color = null;
|
951 | }
|
952 | }
|
953 |
|
954 | if (dict.has("RC")) {
|
955 | this.data.richText = _factory.XFAFactory.getRichTextAsHtml(dict.get("RC"));
|
956 | }
|
957 | }
|
958 |
|
959 | setCreationDate(creationDate) {
|
960 | this.creationDate = typeof creationDate === "string" ? creationDate : null;
|
961 | }
|
962 |
|
963 | _setDefaultAppearance({
|
964 | xref,
|
965 | extra,
|
966 | strokeColor,
|
967 | fillColor,
|
968 | blendMode,
|
969 | strokeAlpha,
|
970 | fillAlpha,
|
971 | pointsCallback
|
972 | }) {
|
973 | let minX = Number.MAX_VALUE;
|
974 | let minY = Number.MAX_VALUE;
|
975 | let maxX = Number.MIN_VALUE;
|
976 | let maxY = Number.MIN_VALUE;
|
977 | const buffer = ["q"];
|
978 |
|
979 | if (extra) {
|
980 | buffer.push(extra);
|
981 | }
|
982 |
|
983 | if (strokeColor) {
|
984 | buffer.push(`${strokeColor[0]} ${strokeColor[1]} ${strokeColor[2]} RG`);
|
985 | }
|
986 |
|
987 | if (fillColor) {
|
988 | buffer.push(`${fillColor[0]} ${fillColor[1]} ${fillColor[2]} rg`);
|
989 | }
|
990 |
|
991 | let pointsArray = this.data.quadPoints;
|
992 |
|
993 | if (!pointsArray) {
|
994 | pointsArray = [[{
|
995 | x: this.rectangle[0],
|
996 | y: this.rectangle[3]
|
997 | }, {
|
998 | x: this.rectangle[2],
|
999 | y: this.rectangle[3]
|
1000 | }, {
|
1001 | x: this.rectangle[0],
|
1002 | y: this.rectangle[1]
|
1003 | }, {
|
1004 | x: this.rectangle[2],
|
1005 | y: this.rectangle[1]
|
1006 | }]];
|
1007 | }
|
1008 |
|
1009 | for (const points of pointsArray) {
|
1010 | const [mX, MX, mY, MY] = pointsCallback(buffer, points);
|
1011 | minX = Math.min(minX, mX);
|
1012 | maxX = Math.max(maxX, MX);
|
1013 | minY = Math.min(minY, mY);
|
1014 | maxY = Math.max(maxY, MY);
|
1015 | }
|
1016 |
|
1017 | buffer.push("Q");
|
1018 | const formDict = new _primitives.Dict(xref);
|
1019 | const appearanceStreamDict = new _primitives.Dict(xref);
|
1020 | appearanceStreamDict.set("Subtype", _primitives.Name.get("Form"));
|
1021 | const appearanceStream = new _stream.StringStream(buffer.join(" "));
|
1022 | appearanceStream.dict = appearanceStreamDict;
|
1023 | formDict.set("Fm0", appearanceStream);
|
1024 | const gsDict = new _primitives.Dict(xref);
|
1025 |
|
1026 | if (blendMode) {
|
1027 | gsDict.set("BM", _primitives.Name.get(blendMode));
|
1028 | }
|
1029 |
|
1030 | if (typeof strokeAlpha === "number") {
|
1031 | gsDict.set("CA", strokeAlpha);
|
1032 | }
|
1033 |
|
1034 | if (typeof fillAlpha === "number") {
|
1035 | gsDict.set("ca", fillAlpha);
|
1036 | }
|
1037 |
|
1038 | const stateDict = new _primitives.Dict(xref);
|
1039 | stateDict.set("GS0", gsDict);
|
1040 | const resources = new _primitives.Dict(xref);
|
1041 | resources.set("ExtGState", stateDict);
|
1042 | resources.set("XObject", formDict);
|
1043 | const appearanceDict = new _primitives.Dict(xref);
|
1044 | appearanceDict.set("Resources", resources);
|
1045 | const bbox = this.data.rect = [minX, minY, maxX, maxY];
|
1046 | appearanceDict.set("BBox", bbox);
|
1047 | this.appearance = new _stream.StringStream("/GS0 gs /Fm0 Do");
|
1048 | this.appearance.dict = appearanceDict;
|
1049 |
|
1050 | this._streams.push(this.appearance, appearanceStream);
|
1051 | }
|
1052 |
|
1053 | static async createNewAnnotation(xref, annotation, dependencies, params) {
|
1054 | const annotationRef = xref.getNewRef();
|
1055 | const apRef = xref.getNewRef();
|
1056 | const annotationDict = this.createNewDict(annotation, xref, {
|
1057 | apRef
|
1058 | });
|
1059 | const ap = await this.createNewAppearanceStream(annotation, xref, params);
|
1060 | const buffer = [];
|
1061 | let transform = xref.encrypt ? xref.encrypt.createCipherTransform(apRef.num, apRef.gen) : null;
|
1062 | (0, _writer.writeObject)(apRef, ap, buffer, transform);
|
1063 | dependencies.push({
|
1064 | ref: apRef,
|
1065 | data: buffer.join("")
|
1066 | });
|
1067 | buffer.length = 0;
|
1068 | transform = xref.encrypt ? xref.encrypt.createCipherTransform(annotationRef.num, annotationRef.gen) : null;
|
1069 | (0, _writer.writeObject)(annotationRef, annotationDict, buffer, transform);
|
1070 | return {
|
1071 | ref: annotationRef,
|
1072 | data: buffer.join("")
|
1073 | };
|
1074 | }
|
1075 |
|
1076 | static async createNewPrintAnnotation(xref, annotation, params) {
|
1077 | const ap = await this.createNewAppearanceStream(annotation, xref, params);
|
1078 | const annotationDict = this.createNewDict(annotation, xref, {
|
1079 | ap
|
1080 | });
|
1081 | return new this.prototype.constructor({
|
1082 | dict: annotationDict,
|
1083 | xref
|
1084 | });
|
1085 | }
|
1086 |
|
1087 | }
|
1088 |
|
1089 | exports.MarkupAnnotation = MarkupAnnotation;
|
1090 |
|
1091 | class WidgetAnnotation extends Annotation {
|
1092 | constructor(params) {
|
1093 | super(params);
|
1094 | const dict = params.dict;
|
1095 | const data = this.data;
|
1096 | this.ref = params.ref;
|
1097 | data.annotationType = _util.AnnotationType.WIDGET;
|
1098 |
|
1099 | if (data.fieldName === undefined) {
|
1100 | data.fieldName = this._constructFieldName(dict);
|
1101 | }
|
1102 |
|
1103 | if (data.actions === undefined) {
|
1104 | data.actions = (0, _core_utils.collectActions)(params.xref, dict, _util.AnnotationActionEventType);
|
1105 | }
|
1106 |
|
1107 | let fieldValue = (0, _core_utils.getInheritableProperty)({
|
1108 | dict,
|
1109 | key: "V",
|
1110 | getArray: true
|
1111 | });
|
1112 | data.fieldValue = this._decodeFormValue(fieldValue);
|
1113 | const defaultFieldValue = (0, _core_utils.getInheritableProperty)({
|
1114 | dict,
|
1115 | key: "DV",
|
1116 | getArray: true
|
1117 | });
|
1118 | data.defaultFieldValue = this._decodeFormValue(defaultFieldValue);
|
1119 |
|
1120 | if (fieldValue === undefined && params.xfaDatasets) {
|
1121 | const path = this._title.str;
|
1122 |
|
1123 | if (path) {
|
1124 | this._hasValueFromXFA = true;
|
1125 | data.fieldValue = fieldValue = params.xfaDatasets.getValue(path);
|
1126 | }
|
1127 | }
|
1128 |
|
1129 | if (fieldValue === undefined && data.defaultFieldValue !== null) {
|
1130 | data.fieldValue = data.defaultFieldValue;
|
1131 | }
|
1132 |
|
1133 | data.alternativeText = (0, _util.stringToPDFString)(dict.get("TU") || "");
|
1134 | const defaultAppearance = (0, _core_utils.getInheritableProperty)({
|
1135 | dict,
|
1136 | key: "DA"
|
1137 | }) || params.acroForm.get("DA");
|
1138 | this._defaultAppearance = typeof defaultAppearance === "string" ? defaultAppearance : "";
|
1139 | data.defaultAppearanceData = (0, _default_appearance.parseDefaultAppearance)(this._defaultAppearance);
|
1140 | const fieldType = (0, _core_utils.getInheritableProperty)({
|
1141 | dict,
|
1142 | key: "FT"
|
1143 | });
|
1144 | data.fieldType = fieldType instanceof _primitives.Name ? fieldType.name : null;
|
1145 | const localResources = (0, _core_utils.getInheritableProperty)({
|
1146 | dict,
|
1147 | key: "DR"
|
1148 | });
|
1149 | const acroFormResources = params.acroForm.get("DR");
|
1150 | const appearanceResources = this.appearance && this.appearance.dict.get("Resources");
|
1151 | this._fieldResources = {
|
1152 | localResources,
|
1153 | acroFormResources,
|
1154 | appearanceResources,
|
1155 | mergedResources: _primitives.Dict.merge({
|
1156 | xref: params.xref,
|
1157 | dictArray: [localResources, appearanceResources, acroFormResources],
|
1158 | mergeSubDicts: true
|
1159 | })
|
1160 | };
|
1161 | data.fieldFlags = (0, _core_utils.getInheritableProperty)({
|
1162 | dict,
|
1163 | key: "Ff"
|
1164 | });
|
1165 |
|
1166 | if (!Number.isInteger(data.fieldFlags) || data.fieldFlags < 0) {
|
1167 | data.fieldFlags = 0;
|
1168 | }
|
1169 |
|
1170 | data.readOnly = this.hasFieldFlag(_util.AnnotationFieldFlag.READONLY);
|
1171 | data.required = this.hasFieldFlag(_util.AnnotationFieldFlag.REQUIRED);
|
1172 | data.hidden = this._hasFlag(data.annotationFlags, _util.AnnotationFlag.HIDDEN);
|
1173 | }
|
1174 |
|
1175 | _decodeFormValue(formValue) {
|
1176 | if (Array.isArray(formValue)) {
|
1177 | return formValue.filter(item => typeof item === "string").map(item => (0, _util.stringToPDFString)(item));
|
1178 | } else if (formValue instanceof _primitives.Name) {
|
1179 | return (0, _util.stringToPDFString)(formValue.name);
|
1180 | } else if (typeof formValue === "string") {
|
1181 | return (0, _util.stringToPDFString)(formValue);
|
1182 | }
|
1183 |
|
1184 | return null;
|
1185 | }
|
1186 |
|
1187 | hasFieldFlag(flag) {
|
1188 | return !!(this.data.fieldFlags & flag);
|
1189 | }
|
1190 |
|
1191 | static _getRotationMatrix(rotation, width, height) {
|
1192 | switch (rotation) {
|
1193 | case 90:
|
1194 | return [0, 1, -1, 0, width, 0];
|
1195 |
|
1196 | case 180:
|
1197 | return [-1, 0, 0, -1, width, height];
|
1198 |
|
1199 | case 270:
|
1200 | return [0, -1, 1, 0, 0, height];
|
1201 |
|
1202 | default:
|
1203 | throw new Error("Invalid rotation");
|
1204 | }
|
1205 | }
|
1206 |
|
1207 | getRotationMatrix(annotationStorage) {
|
1208 | const storageEntry = annotationStorage ? annotationStorage.get(this.data.id) : undefined;
|
1209 | let rotation = storageEntry && storageEntry.rotation;
|
1210 |
|
1211 | if (rotation === undefined) {
|
1212 | rotation = this.rotation;
|
1213 | }
|
1214 |
|
1215 | if (rotation === 0) {
|
1216 | return _util.IDENTITY_MATRIX;
|
1217 | }
|
1218 |
|
1219 | const width = this.data.rect[2] - this.data.rect[0];
|
1220 | const height = this.data.rect[3] - this.data.rect[1];
|
1221 | return WidgetAnnotation._getRotationMatrix(rotation, width, height);
|
1222 | }
|
1223 |
|
1224 | getBorderAndBackgroundAppearances(annotationStorage) {
|
1225 | const storageEntry = annotationStorage ? annotationStorage.get(this.data.id) : undefined;
|
1226 | let rotation = storageEntry && storageEntry.rotation;
|
1227 |
|
1228 | if (rotation === undefined) {
|
1229 | rotation = this.rotation;
|
1230 | }
|
1231 |
|
1232 | if (!this.backgroundColor && !this.borderColor) {
|
1233 | return "";
|
1234 | }
|
1235 |
|
1236 | const width = this.data.rect[2] - this.data.rect[0];
|
1237 | const height = this.data.rect[3] - this.data.rect[1];
|
1238 | const rect = rotation === 0 || rotation === 180 ? `0 0 ${width} ${height} re` : `0 0 ${height} ${width} re`;
|
1239 | let str = "";
|
1240 |
|
1241 | if (this.backgroundColor) {
|
1242 | str = `${(0, _default_appearance.getPdfColor)(this.backgroundColor, true)} ${rect} f `;
|
1243 | }
|
1244 |
|
1245 | if (this.borderColor) {
|
1246 | const borderWidth = this.borderStyle.width || 1;
|
1247 | str += `${borderWidth} w ${(0, _default_appearance.getPdfColor)(this.borderColor, false)} ${rect} S `;
|
1248 | }
|
1249 |
|
1250 | return str;
|
1251 | }
|
1252 |
|
1253 | async getOperatorList(evaluator, task, intent, renderForms, annotationStorage) {
|
1254 | if (renderForms && !(this instanceof SignatureWidgetAnnotation)) {
|
1255 | return {
|
1256 | opList: new _operator_list.OperatorList(),
|
1257 | separateForm: true,
|
1258 | separateCanvas: false
|
1259 | };
|
1260 | }
|
1261 |
|
1262 | if (!this._hasText) {
|
1263 | return super.getOperatorList(evaluator, task, intent, renderForms, annotationStorage);
|
1264 | }
|
1265 |
|
1266 | const content = await this._getAppearance(evaluator, task, annotationStorage);
|
1267 |
|
1268 | if (this.appearance && content === null) {
|
1269 | return super.getOperatorList(evaluator, task, intent, renderForms, annotationStorage);
|
1270 | }
|
1271 |
|
1272 | const opList = new _operator_list.OperatorList();
|
1273 |
|
1274 | if (!this._defaultAppearance || content === null) {
|
1275 | return {
|
1276 | opList,
|
1277 | separateForm: false,
|
1278 | separateCanvas: false
|
1279 | };
|
1280 | }
|
1281 |
|
1282 | const matrix = [1, 0, 0, 1, 0, 0];
|
1283 | const bbox = [0, 0, this.data.rect[2] - this.data.rect[0], this.data.rect[3] - this.data.rect[1]];
|
1284 | const transform = getTransformMatrix(this.data.rect, bbox, matrix);
|
1285 | let optionalContent;
|
1286 |
|
1287 | if (this.oc) {
|
1288 | optionalContent = await evaluator.parseMarkedContentProps(this.oc, null);
|
1289 | }
|
1290 |
|
1291 | if (optionalContent !== undefined) {
|
1292 | opList.addOp(_util.OPS.beginMarkedContentProps, ["OC", optionalContent]);
|
1293 | }
|
1294 |
|
1295 | opList.addOp(_util.OPS.beginAnnotation, [this.data.id, this.data.rect, transform, this.getRotationMatrix(annotationStorage), false]);
|
1296 | const stream = new _stream.StringStream(content);
|
1297 | await evaluator.getOperatorList({
|
1298 | stream,
|
1299 | task,
|
1300 | resources: this._fieldResources.mergedResources,
|
1301 | operatorList: opList
|
1302 | });
|
1303 | opList.addOp(_util.OPS.endAnnotation, []);
|
1304 |
|
1305 | if (optionalContent !== undefined) {
|
1306 | opList.addOp(_util.OPS.endMarkedContent, []);
|
1307 | }
|
1308 |
|
1309 | return {
|
1310 | opList,
|
1311 | separateForm: false,
|
1312 | separateCanvas: false
|
1313 | };
|
1314 | }
|
1315 |
|
1316 | _getMKDict(rotation) {
|
1317 | const mk = new _primitives.Dict(null);
|
1318 |
|
1319 | if (rotation) {
|
1320 | mk.set("R", rotation);
|
1321 | }
|
1322 |
|
1323 | if (this.borderColor) {
|
1324 | mk.set("BC", Array.from(this.borderColor).map(c => c / 255));
|
1325 | }
|
1326 |
|
1327 | if (this.backgroundColor) {
|
1328 | mk.set("BG", Array.from(this.backgroundColor).map(c => c / 255));
|
1329 | }
|
1330 |
|
1331 | return mk.size > 0 ? mk : null;
|
1332 | }
|
1333 |
|
1334 | async save(evaluator, task, annotationStorage) {
|
1335 | const storageEntry = annotationStorage ? annotationStorage.get(this.data.id) : undefined;
|
1336 | let value = storageEntry && storageEntry.value;
|
1337 | let rotation = storageEntry && storageEntry.rotation;
|
1338 |
|
1339 | if (value === this.data.fieldValue || value === undefined) {
|
1340 | if (!this._hasValueFromXFA && rotation === undefined) {
|
1341 | return null;
|
1342 | }
|
1343 |
|
1344 | value = value || this.data.fieldValue;
|
1345 | }
|
1346 |
|
1347 | if (rotation === undefined && !this._hasValueFromXFA && Array.isArray(value) && Array.isArray(this.data.fieldValue) && value.length === this.data.fieldValue.length && value.every((x, i) => x === this.data.fieldValue[i])) {
|
1348 | return null;
|
1349 | }
|
1350 |
|
1351 | if (rotation === undefined) {
|
1352 | rotation = this.rotation;
|
1353 | }
|
1354 |
|
1355 | let appearance = await this._getAppearance(evaluator, task, annotationStorage);
|
1356 |
|
1357 | if (appearance === null) {
|
1358 | return null;
|
1359 | }
|
1360 |
|
1361 | const {
|
1362 | xref
|
1363 | } = evaluator;
|
1364 | const dict = xref.fetchIfRef(this.ref);
|
1365 |
|
1366 | if (!(dict instanceof _primitives.Dict)) {
|
1367 | return null;
|
1368 | }
|
1369 |
|
1370 | const bbox = [0, 0, this.data.rect[2] - this.data.rect[0], this.data.rect[3] - this.data.rect[1]];
|
1371 | const xfa = {
|
1372 | path: (0, _util.stringToPDFString)(dict.get("T") || ""),
|
1373 | value
|
1374 | };
|
1375 | const newRef = xref.getNewRef();
|
1376 | const AP = new _primitives.Dict(xref);
|
1377 | AP.set("N", newRef);
|
1378 | const encrypt = xref.encrypt;
|
1379 | let originalTransform = null;
|
1380 | let newTransform = null;
|
1381 |
|
1382 | if (encrypt) {
|
1383 | originalTransform = encrypt.createCipherTransform(this.ref.num, this.ref.gen);
|
1384 | newTransform = encrypt.createCipherTransform(newRef.num, newRef.gen);
|
1385 | appearance = newTransform.encryptString(appearance);
|
1386 | }
|
1387 |
|
1388 | const encoder = val => (0, _util.isAscii)(val) ? val : (0, _util.stringToUTF16BEString)(val);
|
1389 |
|
1390 | dict.set("V", Array.isArray(value) ? value.map(encoder) : encoder(value));
|
1391 | dict.set("AP", AP);
|
1392 | dict.set("M", `D:${(0, _util.getModificationDate)()}`);
|
1393 |
|
1394 | const maybeMK = this._getMKDict(rotation);
|
1395 |
|
1396 | if (maybeMK) {
|
1397 | dict.set("MK", maybeMK);
|
1398 | }
|
1399 |
|
1400 | const appearanceDict = new _primitives.Dict(xref);
|
1401 | appearanceDict.set("Length", appearance.length);
|
1402 | appearanceDict.set("Subtype", _primitives.Name.get("Form"));
|
1403 | appearanceDict.set("Resources", this._getSaveFieldResources(xref));
|
1404 | appearanceDict.set("BBox", bbox);
|
1405 | const rotationMatrix = this.getRotationMatrix(annotationStorage);
|
1406 |
|
1407 | if (rotationMatrix !== _util.IDENTITY_MATRIX) {
|
1408 | appearanceDict.set("Matrix", rotationMatrix);
|
1409 | }
|
1410 |
|
1411 | const bufferOriginal = [`${this.ref.num} ${this.ref.gen} obj\n`];
|
1412 | (0, _writer.writeDict)(dict, bufferOriginal, originalTransform);
|
1413 | bufferOriginal.push("\nendobj\n");
|
1414 | const bufferNew = [`${newRef.num} ${newRef.gen} obj\n`];
|
1415 | (0, _writer.writeDict)(appearanceDict, bufferNew, newTransform);
|
1416 | bufferNew.push(" stream\n", appearance, "\nendstream\nendobj\n");
|
1417 | return [{
|
1418 | ref: this.ref,
|
1419 | data: bufferOriginal.join(""),
|
1420 | xfa
|
1421 | }, {
|
1422 | ref: newRef,
|
1423 | data: bufferNew.join(""),
|
1424 | xfa: null
|
1425 | }];
|
1426 | }
|
1427 |
|
1428 | async _getAppearance(evaluator, task, annotationStorage) {
|
1429 | const isPassword = this.hasFieldFlag(_util.AnnotationFieldFlag.PASSWORD);
|
1430 |
|
1431 | if (isPassword) {
|
1432 | return null;
|
1433 | }
|
1434 |
|
1435 | const storageEntry = annotationStorage ? annotationStorage.get(this.data.id) : undefined;
|
1436 | let value, rotation;
|
1437 |
|
1438 | if (storageEntry) {
|
1439 | value = storageEntry.formattedValue || storageEntry.value;
|
1440 | rotation = storageEntry.rotation;
|
1441 | }
|
1442 |
|
1443 | if (rotation === undefined && value === undefined) {
|
1444 | if (!this._hasValueFromXFA || this.appearance) {
|
1445 | return null;
|
1446 | }
|
1447 | }
|
1448 |
|
1449 | if (value === undefined) {
|
1450 | value = this.data.fieldValue;
|
1451 |
|
1452 | if (!value) {
|
1453 | return "";
|
1454 | }
|
1455 | }
|
1456 |
|
1457 | if (Array.isArray(value) && value.length === 1) {
|
1458 | value = value[0];
|
1459 | }
|
1460 |
|
1461 | (0, _util.assert)(typeof value === "string", "Expected `value` to be a string.");
|
1462 | value = value.trim();
|
1463 |
|
1464 | if (value === "") {
|
1465 | return "";
|
1466 | }
|
1467 |
|
1468 | if (rotation === undefined) {
|
1469 | rotation = this.rotation;
|
1470 | }
|
1471 |
|
1472 | let lineCount = -1;
|
1473 |
|
1474 | if (this.data.multiLine) {
|
1475 | lineCount = value.split(/\r\n|\r|\n/).length;
|
1476 | }
|
1477 |
|
1478 | const defaultPadding = 2;
|
1479 | const hPadding = defaultPadding;
|
1480 | let totalHeight = this.data.rect[3] - this.data.rect[1];
|
1481 | let totalWidth = this.data.rect[2] - this.data.rect[0];
|
1482 |
|
1483 | if (rotation === 90 || rotation === 270) {
|
1484 | [totalWidth, totalHeight] = [totalHeight, totalWidth];
|
1485 | }
|
1486 |
|
1487 | if (!this._defaultAppearance) {
|
1488 | this.data.defaultAppearanceData = (0, _default_appearance.parseDefaultAppearance)(this._defaultAppearance = "/Helvetica 0 Tf 0 g");
|
1489 | }
|
1490 |
|
1491 | const font = await WidgetAnnotation._getFontData(evaluator, task, this.data.defaultAppearanceData, this._fieldResources.mergedResources);
|
1492 |
|
1493 | const [defaultAppearance, fontSize] = this._computeFontSize(totalHeight - defaultPadding, totalWidth - 2 * hPadding, value, font, lineCount);
|
1494 |
|
1495 | let descent = font.descent;
|
1496 |
|
1497 | if (isNaN(descent)) {
|
1498 | descent = 0;
|
1499 | }
|
1500 |
|
1501 | const defaultVPadding = Math.min(Math.floor((totalHeight - fontSize) / 2), defaultPadding);
|
1502 | const vPadding = defaultVPadding + Math.abs(descent) * fontSize;
|
1503 | const alignment = this.data.textAlignment;
|
1504 |
|
1505 | if (this.data.multiLine) {
|
1506 | return this._getMultilineAppearance(defaultAppearance, value, font, fontSize, totalWidth, totalHeight, alignment, hPadding, vPadding, annotationStorage);
|
1507 | }
|
1508 |
|
1509 | const encodedString = font.encodeString(value).join("");
|
1510 |
|
1511 | if (this.data.comb) {
|
1512 | return this._getCombAppearance(defaultAppearance, font, encodedString, totalWidth, hPadding, vPadding, annotationStorage);
|
1513 | }
|
1514 |
|
1515 | const colors = this.getBorderAndBackgroundAppearances(annotationStorage);
|
1516 |
|
1517 | if (alignment === 0 || alignment > 2) {
|
1518 | return `/Tx BMC q ${colors}BT ` + defaultAppearance + ` 1 0 0 1 ${hPadding} ${vPadding} Tm (${(0, _util.escapeString)(encodedString)}) Tj` + " ET Q EMC";
|
1519 | }
|
1520 |
|
1521 | const renderedText = this._renderText(encodedString, font, fontSize, totalWidth, alignment, hPadding, vPadding);
|
1522 |
|
1523 | return `/Tx BMC q ${colors}BT ` + defaultAppearance + ` 1 0 0 1 0 0 Tm ${renderedText}` + " ET Q EMC";
|
1524 | }
|
1525 |
|
1526 | static async _getFontData(evaluator, task, appearanceData, resources) {
|
1527 | const operatorList = new _operator_list.OperatorList();
|
1528 | const initialState = {
|
1529 | font: null,
|
1530 |
|
1531 | clone() {
|
1532 | return this;
|
1533 | }
|
1534 |
|
1535 | };
|
1536 | const {
|
1537 | fontName,
|
1538 | fontSize
|
1539 | } = appearanceData;
|
1540 | await evaluator.handleSetFont(resources, [fontName && _primitives.Name.get(fontName), fontSize], null, operatorList, task, initialState, null);
|
1541 | return initialState.font;
|
1542 | }
|
1543 |
|
1544 | _getTextWidth(text, font) {
|
1545 | return font.charsToGlyphs(text).reduce((width, glyph) => width + glyph.width, 0) / 1000;
|
1546 | }
|
1547 |
|
1548 | _computeFontSize(height, width, text, font, lineCount) {
|
1549 | let {
|
1550 | fontSize
|
1551 | } = this.data.defaultAppearanceData;
|
1552 |
|
1553 | if (!fontSize) {
|
1554 | const roundWithTwoDigits = x => Math.floor(x * 100) / 100;
|
1555 |
|
1556 | if (lineCount === -1) {
|
1557 | const textWidth = this._getTextWidth(text, font);
|
1558 |
|
1559 | fontSize = roundWithTwoDigits(Math.min(height / _util.LINE_FACTOR, width / textWidth));
|
1560 | } else {
|
1561 | const lines = text.split(/\r\n?|\n/);
|
1562 | const cachedLines = [];
|
1563 |
|
1564 | for (const line of lines) {
|
1565 | const encoded = font.encodeString(line).join("");
|
1566 | const glyphs = font.charsToGlyphs(encoded);
|
1567 | const positions = font.getCharPositions(encoded);
|
1568 | cachedLines.push({
|
1569 | line: encoded,
|
1570 | glyphs,
|
1571 | positions
|
1572 | });
|
1573 | }
|
1574 |
|
1575 | const isTooBig = fsize => {
|
1576 | let totalHeight = 0;
|
1577 |
|
1578 | for (const cache of cachedLines) {
|
1579 | const chunks = this._splitLine(null, font, fsize, width, cache);
|
1580 |
|
1581 | totalHeight += chunks.length * fsize;
|
1582 |
|
1583 | if (totalHeight > height) {
|
1584 | return true;
|
1585 | }
|
1586 | }
|
1587 |
|
1588 | return false;
|
1589 | };
|
1590 |
|
1591 | fontSize = 12;
|
1592 | let lineHeight = fontSize * _util.LINE_FACTOR;
|
1593 | let numberOfLines = Math.round(height / lineHeight);
|
1594 | numberOfLines = Math.max(numberOfLines, lineCount);
|
1595 |
|
1596 | while (true) {
|
1597 | lineHeight = height / numberOfLines;
|
1598 | fontSize = roundWithTwoDigits(lineHeight / _util.LINE_FACTOR);
|
1599 |
|
1600 | if (isTooBig(fontSize)) {
|
1601 | numberOfLines++;
|
1602 | continue;
|
1603 | }
|
1604 |
|
1605 | break;
|
1606 | }
|
1607 | }
|
1608 |
|
1609 | const {
|
1610 | fontName,
|
1611 | fontColor
|
1612 | } = this.data.defaultAppearanceData;
|
1613 | this._defaultAppearance = (0, _default_appearance.createDefaultAppearance)({
|
1614 | fontSize,
|
1615 | fontName,
|
1616 | fontColor
|
1617 | });
|
1618 | }
|
1619 |
|
1620 | return [this._defaultAppearance, fontSize];
|
1621 | }
|
1622 |
|
1623 | _renderText(text, font, fontSize, totalWidth, alignment, hPadding, vPadding) {
|
1624 | let shift;
|
1625 |
|
1626 | if (alignment === 1) {
|
1627 | const width = this._getTextWidth(text, font) * fontSize;
|
1628 | shift = (totalWidth - width) / 2;
|
1629 | } else if (alignment === 2) {
|
1630 | const width = this._getTextWidth(text, font) * fontSize;
|
1631 | shift = totalWidth - width - hPadding;
|
1632 | } else {
|
1633 | shift = hPadding;
|
1634 | }
|
1635 |
|
1636 | shift = (0, _core_utils.numberToString)(shift);
|
1637 | vPadding = (0, _core_utils.numberToString)(vPadding);
|
1638 | return `${shift} ${vPadding} Td (${(0, _util.escapeString)(text)}) Tj`;
|
1639 | }
|
1640 |
|
1641 | _getSaveFieldResources(xref) {
|
1642 | const {
|
1643 | localResources,
|
1644 | appearanceResources,
|
1645 | acroFormResources
|
1646 | } = this._fieldResources;
|
1647 | const fontName = this.data.defaultAppearanceData && this.data.defaultAppearanceData.fontName;
|
1648 |
|
1649 | if (!fontName) {
|
1650 | return localResources || _primitives.Dict.empty;
|
1651 | }
|
1652 |
|
1653 | for (const resources of [localResources, appearanceResources]) {
|
1654 | if (resources instanceof _primitives.Dict) {
|
1655 | const localFont = resources.get("Font");
|
1656 |
|
1657 | if (localFont instanceof _primitives.Dict && localFont.has(fontName)) {
|
1658 | return resources;
|
1659 | }
|
1660 | }
|
1661 | }
|
1662 |
|
1663 | if (acroFormResources instanceof _primitives.Dict) {
|
1664 | const acroFormFont = acroFormResources.get("Font");
|
1665 |
|
1666 | if (acroFormFont instanceof _primitives.Dict && acroFormFont.has(fontName)) {
|
1667 | const subFontDict = new _primitives.Dict(xref);
|
1668 | subFontDict.set(fontName, acroFormFont.getRaw(fontName));
|
1669 | const subResourcesDict = new _primitives.Dict(xref);
|
1670 | subResourcesDict.set("Font", subFontDict);
|
1671 | return _primitives.Dict.merge({
|
1672 | xref,
|
1673 | dictArray: [subResourcesDict, localResources],
|
1674 | mergeSubDicts: true
|
1675 | });
|
1676 | }
|
1677 | }
|
1678 |
|
1679 | return localResources || _primitives.Dict.empty;
|
1680 | }
|
1681 |
|
1682 | getFieldObject() {
|
1683 | return null;
|
1684 | }
|
1685 |
|
1686 | }
|
1687 |
|
1688 | class TextWidgetAnnotation extends WidgetAnnotation {
|
1689 | constructor(params) {
|
1690 | super(params);
|
1691 | this._hasText = true;
|
1692 | const dict = params.dict;
|
1693 |
|
1694 | if (typeof this.data.fieldValue !== "string") {
|
1695 | this.data.fieldValue = "";
|
1696 | }
|
1697 |
|
1698 | let alignment = (0, _core_utils.getInheritableProperty)({
|
1699 | dict,
|
1700 | key: "Q"
|
1701 | });
|
1702 |
|
1703 | if (!Number.isInteger(alignment) || alignment < 0 || alignment > 2) {
|
1704 | alignment = null;
|
1705 | }
|
1706 |
|
1707 | this.data.textAlignment = alignment;
|
1708 | let maximumLength = (0, _core_utils.getInheritableProperty)({
|
1709 | dict,
|
1710 | key: "MaxLen"
|
1711 | });
|
1712 |
|
1713 | if (!Number.isInteger(maximumLength) || maximumLength < 0) {
|
1714 | maximumLength = null;
|
1715 | }
|
1716 |
|
1717 | this.data.maxLen = maximumLength;
|
1718 | this.data.multiLine = this.hasFieldFlag(_util.AnnotationFieldFlag.MULTILINE);
|
1719 | this.data.comb = this.hasFieldFlag(_util.AnnotationFieldFlag.COMB) && !this.hasFieldFlag(_util.AnnotationFieldFlag.MULTILINE) && !this.hasFieldFlag(_util.AnnotationFieldFlag.PASSWORD) && !this.hasFieldFlag(_util.AnnotationFieldFlag.FILESELECT) && this.data.maxLen !== null;
|
1720 | this.data.doNotScroll = this.hasFieldFlag(_util.AnnotationFieldFlag.DONOTSCROLL);
|
1721 | }
|
1722 |
|
1723 | _getCombAppearance(defaultAppearance, font, text, width, hPadding, vPadding, annotationStorage) {
|
1724 | const combWidth = (0, _core_utils.numberToString)(width / this.data.maxLen);
|
1725 | const buf = [];
|
1726 | const positions = font.getCharPositions(text);
|
1727 |
|
1728 | for (const [start, end] of positions) {
|
1729 | buf.push(`(${(0, _util.escapeString)(text.substring(start, end))}) Tj`);
|
1730 | }
|
1731 |
|
1732 | const colors = this.getBorderAndBackgroundAppearances(annotationStorage);
|
1733 | const renderedComb = buf.join(` ${combWidth} 0 Td `);
|
1734 | return `/Tx BMC q ${colors}BT ` + defaultAppearance + ` 1 0 0 1 ${hPadding} ${vPadding} Tm ${renderedComb}` + " ET Q EMC";
|
1735 | }
|
1736 |
|
1737 | _getMultilineAppearance(defaultAppearance, text, font, fontSize, width, height, alignment, hPadding, vPadding, annotationStorage) {
|
1738 | const lines = text.split(/\r\n?|\n/);
|
1739 | const buf = [];
|
1740 | const totalWidth = width - 2 * hPadding;
|
1741 |
|
1742 | for (const line of lines) {
|
1743 | const chunks = this._splitLine(line, font, fontSize, totalWidth);
|
1744 |
|
1745 | for (const chunk of chunks) {
|
1746 | const padding = buf.length === 0 ? hPadding : 0;
|
1747 | buf.push(this._renderText(chunk, font, fontSize, width, alignment, padding, -fontSize));
|
1748 | }
|
1749 | }
|
1750 |
|
1751 | const renderedText = buf.join("\n");
|
1752 | const colors = this.getBorderAndBackgroundAppearances(annotationStorage);
|
1753 | return `/Tx BMC q ${colors}BT ` + defaultAppearance + ` 1 0 0 1 0 ${height} Tm ${renderedText}` + " ET Q EMC";
|
1754 | }
|
1755 |
|
1756 | _splitLine(line, font, fontSize, width, cache = {}) {
|
1757 | line = cache.line || font.encodeString(line).join("");
|
1758 | const glyphs = cache.glyphs || font.charsToGlyphs(line);
|
1759 |
|
1760 | if (glyphs.length <= 1) {
|
1761 | return [line];
|
1762 | }
|
1763 |
|
1764 | const positions = cache.positions || font.getCharPositions(line);
|
1765 | const scale = fontSize / 1000;
|
1766 | const chunks = [];
|
1767 | let lastSpacePosInStringStart = -1,
|
1768 | lastSpacePosInStringEnd = -1,
|
1769 | lastSpacePos = -1,
|
1770 | startChunk = 0,
|
1771 | currentWidth = 0;
|
1772 |
|
1773 | for (let i = 0, ii = glyphs.length; i < ii; i++) {
|
1774 | const [start, end] = positions[i];
|
1775 | const glyph = glyphs[i];
|
1776 | const glyphWidth = glyph.width * scale;
|
1777 |
|
1778 | if (glyph.unicode === " ") {
|
1779 | if (currentWidth + glyphWidth > width) {
|
1780 | chunks.push(line.substring(startChunk, start));
|
1781 | startChunk = start;
|
1782 | currentWidth = glyphWidth;
|
1783 | lastSpacePosInStringStart = -1;
|
1784 | lastSpacePos = -1;
|
1785 | } else {
|
1786 | currentWidth += glyphWidth;
|
1787 | lastSpacePosInStringStart = start;
|
1788 | lastSpacePosInStringEnd = end;
|
1789 | lastSpacePos = i;
|
1790 | }
|
1791 | } else {
|
1792 | if (currentWidth + glyphWidth > width) {
|
1793 | if (lastSpacePosInStringStart !== -1) {
|
1794 | chunks.push(line.substring(startChunk, lastSpacePosInStringEnd));
|
1795 | startChunk = lastSpacePosInStringEnd;
|
1796 | i = lastSpacePos + 1;
|
1797 | lastSpacePosInStringStart = -1;
|
1798 | currentWidth = 0;
|
1799 | } else {
|
1800 | chunks.push(line.substring(startChunk, start));
|
1801 | startChunk = start;
|
1802 | currentWidth = glyphWidth;
|
1803 | }
|
1804 | } else {
|
1805 | currentWidth += glyphWidth;
|
1806 | }
|
1807 | }
|
1808 | }
|
1809 |
|
1810 | if (startChunk < line.length) {
|
1811 | chunks.push(line.substring(startChunk, line.length));
|
1812 | }
|
1813 |
|
1814 | return chunks;
|
1815 | }
|
1816 |
|
1817 | getFieldObject() {
|
1818 | return {
|
1819 | id: this.data.id,
|
1820 | value: this.data.fieldValue,
|
1821 | defaultValue: this.data.defaultFieldValue || "",
|
1822 | multiline: this.data.multiLine,
|
1823 | password: this.hasFieldFlag(_util.AnnotationFieldFlag.PASSWORD),
|
1824 | charLimit: this.data.maxLen,
|
1825 | comb: this.data.comb,
|
1826 | editable: !this.data.readOnly,
|
1827 | hidden: this.data.hidden,
|
1828 | name: this.data.fieldName,
|
1829 | rect: this.data.rect,
|
1830 | actions: this.data.actions,
|
1831 | page: this.data.pageIndex,
|
1832 | strokeColor: this.data.borderColor,
|
1833 | fillColor: this.data.backgroundColor,
|
1834 | rotation: this.rotation,
|
1835 | type: "text"
|
1836 | };
|
1837 | }
|
1838 |
|
1839 | }
|
1840 |
|
1841 | class ButtonWidgetAnnotation extends WidgetAnnotation {
|
1842 | constructor(params) {
|
1843 | super(params);
|
1844 | this.checkedAppearance = null;
|
1845 | this.uncheckedAppearance = null;
|
1846 | this.data.checkBox = !this.hasFieldFlag(_util.AnnotationFieldFlag.RADIO) && !this.hasFieldFlag(_util.AnnotationFieldFlag.PUSHBUTTON);
|
1847 | this.data.radioButton = this.hasFieldFlag(_util.AnnotationFieldFlag.RADIO) && !this.hasFieldFlag(_util.AnnotationFieldFlag.PUSHBUTTON);
|
1848 | this.data.pushButton = this.hasFieldFlag(_util.AnnotationFieldFlag.PUSHBUTTON);
|
1849 | this.data.isTooltipOnly = false;
|
1850 |
|
1851 | if (this.data.checkBox) {
|
1852 | this._processCheckBox(params);
|
1853 | } else if (this.data.radioButton) {
|
1854 | this._processRadioButton(params);
|
1855 | } else if (this.data.pushButton) {
|
1856 | this.data.hasOwnCanvas = true;
|
1857 |
|
1858 | this._processPushButton(params);
|
1859 | } else {
|
1860 | (0, _util.warn)("Invalid field flags for button widget annotation");
|
1861 | }
|
1862 | }
|
1863 |
|
1864 | async getOperatorList(evaluator, task, intent, renderForms, annotationStorage) {
|
1865 | if (this.data.pushButton) {
|
1866 | return super.getOperatorList(evaluator, task, intent, false, annotationStorage);
|
1867 | }
|
1868 |
|
1869 | let value = null;
|
1870 | let rotation = null;
|
1871 |
|
1872 | if (annotationStorage) {
|
1873 | const storageEntry = annotationStorage.get(this.data.id);
|
1874 | value = storageEntry ? storageEntry.value : null;
|
1875 | rotation = storageEntry ? storageEntry.rotation : null;
|
1876 | }
|
1877 |
|
1878 | if (value === null && this.appearance) {
|
1879 | return super.getOperatorList(evaluator, task, intent, renderForms, annotationStorage);
|
1880 | }
|
1881 |
|
1882 | if (value === null || value === undefined) {
|
1883 | if (this.data.checkBox) {
|
1884 | value = this.data.fieldValue === this.data.exportValue;
|
1885 | } else {
|
1886 | value = this.data.fieldValue === this.data.buttonValue;
|
1887 | }
|
1888 | }
|
1889 |
|
1890 | const appearance = value ? this.checkedAppearance : this.uncheckedAppearance;
|
1891 |
|
1892 | if (appearance) {
|
1893 | const savedAppearance = this.appearance;
|
1894 |
|
1895 | const savedMatrix = appearance.dict.getArray("Matrix") || _util.IDENTITY_MATRIX;
|
1896 |
|
1897 | if (rotation) {
|
1898 | appearance.dict.set("Matrix", this.getRotationMatrix(annotationStorage));
|
1899 | }
|
1900 |
|
1901 | this.appearance = appearance;
|
1902 | const operatorList = super.getOperatorList(evaluator, task, intent, renderForms, annotationStorage);
|
1903 | this.appearance = savedAppearance;
|
1904 | appearance.dict.set("Matrix", savedMatrix);
|
1905 | return operatorList;
|
1906 | }
|
1907 |
|
1908 | return {
|
1909 | opList: new _operator_list.OperatorList(),
|
1910 | separateForm: false,
|
1911 | separateCanvas: false
|
1912 | };
|
1913 | }
|
1914 |
|
1915 | async save(evaluator, task, annotationStorage) {
|
1916 | if (this.data.checkBox) {
|
1917 | return this._saveCheckbox(evaluator, task, annotationStorage);
|
1918 | }
|
1919 |
|
1920 | if (this.data.radioButton) {
|
1921 | return this._saveRadioButton(evaluator, task, annotationStorage);
|
1922 | }
|
1923 |
|
1924 | return null;
|
1925 | }
|
1926 |
|
1927 | async _saveCheckbox(evaluator, task, annotationStorage) {
|
1928 | if (!annotationStorage) {
|
1929 | return null;
|
1930 | }
|
1931 |
|
1932 | const storageEntry = annotationStorage.get(this.data.id);
|
1933 | let rotation = storageEntry && storageEntry.rotation;
|
1934 | let value = storageEntry && storageEntry.value;
|
1935 |
|
1936 | if (rotation === undefined) {
|
1937 | if (value === undefined) {
|
1938 | return null;
|
1939 | }
|
1940 |
|
1941 | const defaultValue = this.data.fieldValue === this.data.exportValue;
|
1942 |
|
1943 | if (defaultValue === value) {
|
1944 | return null;
|
1945 | }
|
1946 | }
|
1947 |
|
1948 | const dict = evaluator.xref.fetchIfRef(this.ref);
|
1949 |
|
1950 | if (!(dict instanceof _primitives.Dict)) {
|
1951 | return null;
|
1952 | }
|
1953 |
|
1954 | if (rotation === undefined) {
|
1955 | rotation = this.rotation;
|
1956 | }
|
1957 |
|
1958 | if (value === undefined) {
|
1959 | value = this.data.fieldValue === this.data.exportValue;
|
1960 | }
|
1961 |
|
1962 | const xfa = {
|
1963 | path: (0, _util.stringToPDFString)(dict.get("T") || ""),
|
1964 | value: value ? this.data.exportValue : ""
|
1965 | };
|
1966 |
|
1967 | const name = _primitives.Name.get(value ? this.data.exportValue : "Off");
|
1968 |
|
1969 | dict.set("V", name);
|
1970 | dict.set("AS", name);
|
1971 | dict.set("M", `D:${(0, _util.getModificationDate)()}`);
|
1972 |
|
1973 | const maybeMK = this._getMKDict(rotation);
|
1974 |
|
1975 | if (maybeMK) {
|
1976 | dict.set("MK", maybeMK);
|
1977 | }
|
1978 |
|
1979 | const encrypt = evaluator.xref.encrypt;
|
1980 | let originalTransform = null;
|
1981 |
|
1982 | if (encrypt) {
|
1983 | originalTransform = encrypt.createCipherTransform(this.ref.num, this.ref.gen);
|
1984 | }
|
1985 |
|
1986 | const buffer = [`${this.ref.num} ${this.ref.gen} obj\n`];
|
1987 | (0, _writer.writeDict)(dict, buffer, originalTransform);
|
1988 | buffer.push("\nendobj\n");
|
1989 | return [{
|
1990 | ref: this.ref,
|
1991 | data: buffer.join(""),
|
1992 | xfa
|
1993 | }];
|
1994 | }
|
1995 |
|
1996 | async _saveRadioButton(evaluator, task, annotationStorage) {
|
1997 | if (!annotationStorage) {
|
1998 | return null;
|
1999 | }
|
2000 |
|
2001 | const storageEntry = annotationStorage.get(this.data.id);
|
2002 | let rotation = storageEntry && storageEntry.rotation;
|
2003 | let value = storageEntry && storageEntry.value;
|
2004 |
|
2005 | if (rotation === undefined) {
|
2006 | if (value === undefined) {
|
2007 | return null;
|
2008 | }
|
2009 |
|
2010 | const defaultValue = this.data.fieldValue === this.data.buttonValue;
|
2011 |
|
2012 | if (defaultValue === value) {
|
2013 | return null;
|
2014 | }
|
2015 | }
|
2016 |
|
2017 | const dict = evaluator.xref.fetchIfRef(this.ref);
|
2018 |
|
2019 | if (!(dict instanceof _primitives.Dict)) {
|
2020 | return null;
|
2021 | }
|
2022 |
|
2023 | if (value === undefined) {
|
2024 | value = this.data.fieldValue === this.data.buttonValue;
|
2025 | }
|
2026 |
|
2027 | if (rotation === undefined) {
|
2028 | rotation = this.rotation;
|
2029 | }
|
2030 |
|
2031 | const xfa = {
|
2032 | path: (0, _util.stringToPDFString)(dict.get("T") || ""),
|
2033 | value: value ? this.data.buttonValue : ""
|
2034 | };
|
2035 |
|
2036 | const name = _primitives.Name.get(value ? this.data.buttonValue : "Off");
|
2037 |
|
2038 | let parentBuffer = null;
|
2039 | const encrypt = evaluator.xref.encrypt;
|
2040 |
|
2041 | if (value) {
|
2042 | if (this.parent instanceof _primitives.Ref) {
|
2043 | const parent = evaluator.xref.fetch(this.parent);
|
2044 | let parentTransform = null;
|
2045 |
|
2046 | if (encrypt) {
|
2047 | parentTransform = encrypt.createCipherTransform(this.parent.num, this.parent.gen);
|
2048 | }
|
2049 |
|
2050 | parent.set("V", name);
|
2051 | parentBuffer = [`${this.parent.num} ${this.parent.gen} obj\n`];
|
2052 | (0, _writer.writeDict)(parent, parentBuffer, parentTransform);
|
2053 | parentBuffer.push("\nendobj\n");
|
2054 | } else if (this.parent instanceof _primitives.Dict) {
|
2055 | this.parent.set("V", name);
|
2056 | }
|
2057 | }
|
2058 |
|
2059 | dict.set("AS", name);
|
2060 | dict.set("M", `D:${(0, _util.getModificationDate)()}`);
|
2061 |
|
2062 | const maybeMK = this._getMKDict(rotation);
|
2063 |
|
2064 | if (maybeMK) {
|
2065 | dict.set("MK", maybeMK);
|
2066 | }
|
2067 |
|
2068 | let originalTransform = null;
|
2069 |
|
2070 | if (encrypt) {
|
2071 | originalTransform = encrypt.createCipherTransform(this.ref.num, this.ref.gen);
|
2072 | }
|
2073 |
|
2074 | const buffer = [`${this.ref.num} ${this.ref.gen} obj\n`];
|
2075 | (0, _writer.writeDict)(dict, buffer, originalTransform);
|
2076 | buffer.push("\nendobj\n");
|
2077 | const newRefs = [{
|
2078 | ref: this.ref,
|
2079 | data: buffer.join(""),
|
2080 | xfa
|
2081 | }];
|
2082 |
|
2083 | if (parentBuffer !== null) {
|
2084 | newRefs.push({
|
2085 | ref: this.parent,
|
2086 | data: parentBuffer.join(""),
|
2087 | xfa: null
|
2088 | });
|
2089 | }
|
2090 |
|
2091 | return newRefs;
|
2092 | }
|
2093 |
|
2094 | _getDefaultCheckedAppearance(params, type) {
|
2095 | const width = this.data.rect[2] - this.data.rect[0];
|
2096 | const height = this.data.rect[3] - this.data.rect[1];
|
2097 | const bbox = [0, 0, width, height];
|
2098 | const FONT_RATIO = 0.8;
|
2099 | const fontSize = Math.min(width, height) * FONT_RATIO;
|
2100 | let metrics, char;
|
2101 |
|
2102 | if (type === "check") {
|
2103 | metrics = {
|
2104 | width: 0.755 * fontSize,
|
2105 | height: 0.705 * fontSize
|
2106 | };
|
2107 | char = "\x33";
|
2108 | } else if (type === "disc") {
|
2109 | metrics = {
|
2110 | width: 0.791 * fontSize,
|
2111 | height: 0.705 * fontSize
|
2112 | };
|
2113 | char = "\x6C";
|
2114 | } else {
|
2115 | (0, _util.unreachable)(`_getDefaultCheckedAppearance - unsupported type: ${type}`);
|
2116 | }
|
2117 |
|
2118 | const xShift = (0, _core_utils.numberToString)((width - metrics.width) / 2);
|
2119 | const yShift = (0, _core_utils.numberToString)((height - metrics.height) / 2);
|
2120 | const appearance = `q BT /PdfJsZaDb ${fontSize} Tf 0 g ${xShift} ${yShift} Td (${char}) Tj ET Q`;
|
2121 | const appearanceStreamDict = new _primitives.Dict(params.xref);
|
2122 | appearanceStreamDict.set("FormType", 1);
|
2123 | appearanceStreamDict.set("Subtype", _primitives.Name.get("Form"));
|
2124 | appearanceStreamDict.set("Type", _primitives.Name.get("XObject"));
|
2125 | appearanceStreamDict.set("BBox", bbox);
|
2126 | appearanceStreamDict.set("Matrix", [1, 0, 0, 1, 0, 0]);
|
2127 | appearanceStreamDict.set("Length", appearance.length);
|
2128 | const resources = new _primitives.Dict(params.xref);
|
2129 | const font = new _primitives.Dict(params.xref);
|
2130 | font.set("PdfJsZaDb", this.fallbackFontDict);
|
2131 | resources.set("Font", font);
|
2132 | appearanceStreamDict.set("Resources", resources);
|
2133 | this.checkedAppearance = new _stream.StringStream(appearance);
|
2134 | this.checkedAppearance.dict = appearanceStreamDict;
|
2135 |
|
2136 | this._streams.push(this.checkedAppearance);
|
2137 | }
|
2138 |
|
2139 | _processCheckBox(params) {
|
2140 | const customAppearance = params.dict.get("AP");
|
2141 |
|
2142 | if (!(customAppearance instanceof _primitives.Dict)) {
|
2143 | return;
|
2144 | }
|
2145 |
|
2146 | const normalAppearance = customAppearance.get("N");
|
2147 |
|
2148 | if (!(normalAppearance instanceof _primitives.Dict)) {
|
2149 | return;
|
2150 | }
|
2151 |
|
2152 | const asValue = this._decodeFormValue(params.dict.get("AS"));
|
2153 |
|
2154 | if (typeof asValue === "string") {
|
2155 | this.data.fieldValue = asValue;
|
2156 | }
|
2157 |
|
2158 | const yes = this.data.fieldValue !== null && this.data.fieldValue !== "Off" ? this.data.fieldValue : "Yes";
|
2159 | const exportValues = normalAppearance.getKeys();
|
2160 |
|
2161 | if (exportValues.length === 0) {
|
2162 | exportValues.push("Off", yes);
|
2163 | } else if (exportValues.length === 1) {
|
2164 | if (exportValues[0] === "Off") {
|
2165 | exportValues.push(yes);
|
2166 | } else {
|
2167 | exportValues.unshift("Off");
|
2168 | }
|
2169 | } else if (exportValues.includes(yes)) {
|
2170 | exportValues.length = 0;
|
2171 | exportValues.push("Off", yes);
|
2172 | } else {
|
2173 | const otherYes = exportValues.find(v => v !== "Off");
|
2174 | exportValues.length = 0;
|
2175 | exportValues.push("Off", otherYes);
|
2176 | }
|
2177 |
|
2178 | if (!exportValues.includes(this.data.fieldValue)) {
|
2179 | this.data.fieldValue = "Off";
|
2180 | }
|
2181 |
|
2182 | this.data.exportValue = exportValues[1];
|
2183 | this.checkedAppearance = normalAppearance.get(this.data.exportValue) || null;
|
2184 | this.uncheckedAppearance = normalAppearance.get("Off") || null;
|
2185 |
|
2186 | if (this.checkedAppearance) {
|
2187 | this._streams.push(this.checkedAppearance);
|
2188 | } else {
|
2189 | this._getDefaultCheckedAppearance(params, "check");
|
2190 | }
|
2191 |
|
2192 | if (this.uncheckedAppearance) {
|
2193 | this._streams.push(this.uncheckedAppearance);
|
2194 | }
|
2195 |
|
2196 | this._fallbackFontDict = this.fallbackFontDict;
|
2197 | }
|
2198 |
|
2199 | _processRadioButton(params) {
|
2200 | this.data.fieldValue = this.data.buttonValue = null;
|
2201 | const fieldParent = params.dict.get("Parent");
|
2202 |
|
2203 | if (fieldParent instanceof _primitives.Dict) {
|
2204 | this.parent = params.dict.getRaw("Parent");
|
2205 | const fieldParentValue = fieldParent.get("V");
|
2206 |
|
2207 | if (fieldParentValue instanceof _primitives.Name) {
|
2208 | this.data.fieldValue = this._decodeFormValue(fieldParentValue);
|
2209 | }
|
2210 | }
|
2211 |
|
2212 | const appearanceStates = params.dict.get("AP");
|
2213 |
|
2214 | if (!(appearanceStates instanceof _primitives.Dict)) {
|
2215 | return;
|
2216 | }
|
2217 |
|
2218 | const normalAppearance = appearanceStates.get("N");
|
2219 |
|
2220 | if (!(normalAppearance instanceof _primitives.Dict)) {
|
2221 | return;
|
2222 | }
|
2223 |
|
2224 | for (const key of normalAppearance.getKeys()) {
|
2225 | if (key !== "Off") {
|
2226 | this.data.buttonValue = this._decodeFormValue(key);
|
2227 | break;
|
2228 | }
|
2229 | }
|
2230 |
|
2231 | this.checkedAppearance = normalAppearance.get(this.data.buttonValue) || null;
|
2232 | this.uncheckedAppearance = normalAppearance.get("Off") || null;
|
2233 |
|
2234 | if (this.checkedAppearance) {
|
2235 | this._streams.push(this.checkedAppearance);
|
2236 | } else {
|
2237 | this._getDefaultCheckedAppearance(params, "disc");
|
2238 | }
|
2239 |
|
2240 | if (this.uncheckedAppearance) {
|
2241 | this._streams.push(this.uncheckedAppearance);
|
2242 | }
|
2243 |
|
2244 | this._fallbackFontDict = this.fallbackFontDict;
|
2245 | }
|
2246 |
|
2247 | _processPushButton(params) {
|
2248 | if (!params.dict.has("A") && !params.dict.has("AA") && !this.data.alternativeText) {
|
2249 | (0, _util.warn)("Push buttons without action dictionaries are not supported");
|
2250 | return;
|
2251 | }
|
2252 |
|
2253 | this.data.isTooltipOnly = !params.dict.has("A") && !params.dict.has("AA");
|
2254 |
|
2255 | _catalog.Catalog.parseDestDictionary({
|
2256 | destDict: params.dict,
|
2257 | resultObj: this.data,
|
2258 | docBaseUrl: params.pdfManager.docBaseUrl
|
2259 | });
|
2260 | }
|
2261 |
|
2262 | getFieldObject() {
|
2263 | let type = "button";
|
2264 | let exportValues;
|
2265 |
|
2266 | if (this.data.checkBox) {
|
2267 | type = "checkbox";
|
2268 | exportValues = this.data.exportValue;
|
2269 | } else if (this.data.radioButton) {
|
2270 | type = "radiobutton";
|
2271 | exportValues = this.data.buttonValue;
|
2272 | }
|
2273 |
|
2274 | return {
|
2275 | id: this.data.id,
|
2276 | value: this.data.fieldValue || "Off",
|
2277 | defaultValue: this.data.defaultFieldValue,
|
2278 | exportValues,
|
2279 | editable: !this.data.readOnly,
|
2280 | name: this.data.fieldName,
|
2281 | rect: this.data.rect,
|
2282 | hidden: this.data.hidden,
|
2283 | actions: this.data.actions,
|
2284 | page: this.data.pageIndex,
|
2285 | strokeColor: this.data.borderColor,
|
2286 | fillColor: this.data.backgroundColor,
|
2287 | rotation: this.rotation,
|
2288 | type
|
2289 | };
|
2290 | }
|
2291 |
|
2292 | get fallbackFontDict() {
|
2293 | const dict = new _primitives.Dict();
|
2294 | dict.set("BaseFont", _primitives.Name.get("ZapfDingbats"));
|
2295 | dict.set("Type", _primitives.Name.get("FallbackType"));
|
2296 | dict.set("Subtype", _primitives.Name.get("FallbackType"));
|
2297 | dict.set("Encoding", _primitives.Name.get("ZapfDingbatsEncoding"));
|
2298 | return (0, _util.shadow)(this, "fallbackFontDict", dict);
|
2299 | }
|
2300 |
|
2301 | }
|
2302 |
|
2303 | class ChoiceWidgetAnnotation extends WidgetAnnotation {
|
2304 | constructor(params) {
|
2305 | super(params);
|
2306 | this.data.options = [];
|
2307 | const options = (0, _core_utils.getInheritableProperty)({
|
2308 | dict: params.dict,
|
2309 | key: "Opt"
|
2310 | });
|
2311 |
|
2312 | if (Array.isArray(options)) {
|
2313 | const xref = params.xref;
|
2314 |
|
2315 | for (let i = 0, ii = options.length; i < ii; i++) {
|
2316 | const option = xref.fetchIfRef(options[i]);
|
2317 | const isOptionArray = Array.isArray(option);
|
2318 | this.data.options[i] = {
|
2319 | exportValue: this._decodeFormValue(isOptionArray ? xref.fetchIfRef(option[0]) : option),
|
2320 | displayValue: this._decodeFormValue(isOptionArray ? xref.fetchIfRef(option[1]) : option)
|
2321 | };
|
2322 | }
|
2323 | }
|
2324 |
|
2325 | if (typeof this.data.fieldValue === "string") {
|
2326 | this.data.fieldValue = [this.data.fieldValue];
|
2327 | } else if (!this.data.fieldValue) {
|
2328 | this.data.fieldValue = [];
|
2329 | }
|
2330 |
|
2331 | this.data.combo = this.hasFieldFlag(_util.AnnotationFieldFlag.COMBO);
|
2332 | this.data.multiSelect = this.hasFieldFlag(_util.AnnotationFieldFlag.MULTISELECT);
|
2333 | this._hasText = true;
|
2334 | }
|
2335 |
|
2336 | getFieldObject() {
|
2337 | const type = this.data.combo ? "combobox" : "listbox";
|
2338 | const value = this.data.fieldValue.length > 0 ? this.data.fieldValue[0] : null;
|
2339 | return {
|
2340 | id: this.data.id,
|
2341 | value,
|
2342 | defaultValue: this.data.defaultFieldValue,
|
2343 | editable: !this.data.readOnly,
|
2344 | name: this.data.fieldName,
|
2345 | rect: this.data.rect,
|
2346 | numItems: this.data.fieldValue.length,
|
2347 | multipleSelection: this.data.multiSelect,
|
2348 | hidden: this.data.hidden,
|
2349 | actions: this.data.actions,
|
2350 | items: this.data.options,
|
2351 | page: this.data.pageIndex,
|
2352 | strokeColor: this.data.borderColor,
|
2353 | fillColor: this.data.backgroundColor,
|
2354 | rotation: this.rotation,
|
2355 | type
|
2356 | };
|
2357 | }
|
2358 |
|
2359 | async _getAppearance(evaluator, task, annotationStorage) {
|
2360 | if (this.data.combo) {
|
2361 | return super._getAppearance(evaluator, task, annotationStorage);
|
2362 | }
|
2363 |
|
2364 | if (!annotationStorage) {
|
2365 | return null;
|
2366 | }
|
2367 |
|
2368 | const storageEntry = annotationStorage.get(this.data.id);
|
2369 |
|
2370 | if (!storageEntry) {
|
2371 | return null;
|
2372 | }
|
2373 |
|
2374 | const rotation = storageEntry.rotation;
|
2375 | let exportedValue = storageEntry.value;
|
2376 |
|
2377 | if (rotation === undefined && exportedValue === undefined) {
|
2378 | return null;
|
2379 | }
|
2380 |
|
2381 | if (exportedValue === undefined) {
|
2382 | exportedValue = this.data.fieldValue;
|
2383 | } else if (!Array.isArray(exportedValue)) {
|
2384 | exportedValue = [exportedValue];
|
2385 | }
|
2386 |
|
2387 | const defaultPadding = 2;
|
2388 | const hPadding = defaultPadding;
|
2389 | let totalHeight = this.data.rect[3] - this.data.rect[1];
|
2390 | let totalWidth = this.data.rect[2] - this.data.rect[0];
|
2391 |
|
2392 | if (rotation === 90 || rotation === 270) {
|
2393 | [totalWidth, totalHeight] = [totalHeight, totalWidth];
|
2394 | }
|
2395 |
|
2396 | const lineCount = this.data.options.length;
|
2397 | const valueIndices = [];
|
2398 |
|
2399 | for (let i = 0; i < lineCount; i++) {
|
2400 | const {
|
2401 | exportValue
|
2402 | } = this.data.options[i];
|
2403 |
|
2404 | if (exportedValue.includes(exportValue)) {
|
2405 | valueIndices.push(i);
|
2406 | }
|
2407 | }
|
2408 |
|
2409 | if (!this._defaultAppearance) {
|
2410 | this.data.defaultAppearanceData = (0, _default_appearance.parseDefaultAppearance)(this._defaultAppearance = "/Helvetica 0 Tf 0 g");
|
2411 | }
|
2412 |
|
2413 | const font = await WidgetAnnotation._getFontData(evaluator, task, this.data.defaultAppearanceData, this._fieldResources.mergedResources);
|
2414 | let defaultAppearance;
|
2415 | let {
|
2416 | fontSize
|
2417 | } = this.data.defaultAppearanceData;
|
2418 |
|
2419 | if (!fontSize) {
|
2420 | const lineHeight = (totalHeight - defaultPadding) / lineCount;
|
2421 | let lineWidth = -1;
|
2422 | let value;
|
2423 |
|
2424 | for (const {
|
2425 | displayValue
|
2426 | } of this.data.options) {
|
2427 | const width = this._getTextWidth(displayValue, font);
|
2428 |
|
2429 | if (width > lineWidth) {
|
2430 | lineWidth = width;
|
2431 | value = displayValue;
|
2432 | }
|
2433 | }
|
2434 |
|
2435 | [defaultAppearance, fontSize] = this._computeFontSize(lineHeight, totalWidth - 2 * hPadding, value, font, -1);
|
2436 | } else {
|
2437 | defaultAppearance = this._defaultAppearance;
|
2438 | }
|
2439 |
|
2440 | const lineHeight = fontSize * _util.LINE_FACTOR;
|
2441 | const vPadding = (lineHeight - fontSize) / 2;
|
2442 | const numberOfVisibleLines = Math.floor(totalHeight / lineHeight);
|
2443 | let firstIndex;
|
2444 |
|
2445 | if (valueIndices.length === 1) {
|
2446 | const valuePosition = valueIndices[0];
|
2447 | const indexInPage = valuePosition % numberOfVisibleLines;
|
2448 | firstIndex = valuePosition - indexInPage;
|
2449 | } else {
|
2450 | firstIndex = valueIndices.length ? valueIndices[0] : 0;
|
2451 | }
|
2452 |
|
2453 | const end = Math.min(firstIndex + numberOfVisibleLines + 1, lineCount);
|
2454 | const buf = ["/Tx BMC q", `1 1 ${totalWidth} ${totalHeight} re W n`];
|
2455 |
|
2456 | if (valueIndices.length) {
|
2457 | buf.push("0.600006 0.756866 0.854904 rg");
|
2458 |
|
2459 | for (const index of valueIndices) {
|
2460 | if (firstIndex <= index && index < end) {
|
2461 | buf.push(`1 ${totalHeight - (index - firstIndex + 1) * lineHeight} ${totalWidth} ${lineHeight} re f`);
|
2462 | }
|
2463 | }
|
2464 | }
|
2465 |
|
2466 | buf.push("BT", defaultAppearance, `1 0 0 1 0 ${totalHeight} Tm`);
|
2467 |
|
2468 | for (let i = firstIndex; i < end; i++) {
|
2469 | const {
|
2470 | displayValue
|
2471 | } = this.data.options[i];
|
2472 | const hpadding = i === firstIndex ? hPadding : 0;
|
2473 | const vpadding = i === firstIndex ? vPadding : 0;
|
2474 | buf.push(this._renderText(displayValue, font, fontSize, totalWidth, 0, hpadding, -lineHeight + vpadding));
|
2475 | }
|
2476 |
|
2477 | buf.push("ET Q EMC");
|
2478 | return buf.join("\n");
|
2479 | }
|
2480 |
|
2481 | }
|
2482 |
|
2483 | class SignatureWidgetAnnotation extends WidgetAnnotation {
|
2484 | constructor(params) {
|
2485 | super(params);
|
2486 | this.data.fieldValue = null;
|
2487 | }
|
2488 |
|
2489 | getFieldObject() {
|
2490 | return {
|
2491 | id: this.data.id,
|
2492 | value: null,
|
2493 | page: this.data.pageIndex,
|
2494 | type: "signature"
|
2495 | };
|
2496 | }
|
2497 |
|
2498 | }
|
2499 |
|
2500 | class TextAnnotation extends MarkupAnnotation {
|
2501 | constructor(parameters) {
|
2502 | const DEFAULT_ICON_SIZE = 22;
|
2503 | super(parameters);
|
2504 | const dict = parameters.dict;
|
2505 | this.data.annotationType = _util.AnnotationType.TEXT;
|
2506 |
|
2507 | if (this.data.hasAppearance) {
|
2508 | this.data.name = "NoIcon";
|
2509 | } else {
|
2510 | this.data.rect[1] = this.data.rect[3] - DEFAULT_ICON_SIZE;
|
2511 | this.data.rect[2] = this.data.rect[0] + DEFAULT_ICON_SIZE;
|
2512 | this.data.name = dict.has("Name") ? dict.get("Name").name : "Note";
|
2513 | }
|
2514 |
|
2515 | if (dict.has("State")) {
|
2516 | this.data.state = dict.get("State") || null;
|
2517 | this.data.stateModel = dict.get("StateModel") || null;
|
2518 | } else {
|
2519 | this.data.state = null;
|
2520 | this.data.stateModel = null;
|
2521 | }
|
2522 | }
|
2523 |
|
2524 | }
|
2525 |
|
2526 | class LinkAnnotation extends Annotation {
|
2527 | constructor(params) {
|
2528 | super(params);
|
2529 | this.data.annotationType = _util.AnnotationType.LINK;
|
2530 | const quadPoints = getQuadPoints(params.dict, this.rectangle);
|
2531 |
|
2532 | if (quadPoints) {
|
2533 | this.data.quadPoints = quadPoints;
|
2534 | }
|
2535 |
|
2536 | this.data.borderColor = this.data.borderColor || this.data.color;
|
2537 |
|
2538 | _catalog.Catalog.parseDestDictionary({
|
2539 | destDict: params.dict,
|
2540 | resultObj: this.data,
|
2541 | docBaseUrl: params.pdfManager.docBaseUrl
|
2542 | });
|
2543 | }
|
2544 |
|
2545 | }
|
2546 |
|
2547 | class PopupAnnotation extends Annotation {
|
2548 | constructor(parameters) {
|
2549 | super(parameters);
|
2550 | this.data.annotationType = _util.AnnotationType.POPUP;
|
2551 | let parentItem = parameters.dict.get("Parent");
|
2552 |
|
2553 | if (!parentItem) {
|
2554 | (0, _util.warn)("Popup annotation has a missing or invalid parent annotation.");
|
2555 | return;
|
2556 | }
|
2557 |
|
2558 | const parentSubtype = parentItem.get("Subtype");
|
2559 | this.data.parentType = parentSubtype instanceof _primitives.Name ? parentSubtype.name : null;
|
2560 | const rawParent = parameters.dict.getRaw("Parent");
|
2561 | this.data.parentId = rawParent instanceof _primitives.Ref ? rawParent.toString() : null;
|
2562 | const parentRect = parentItem.getArray("Rect");
|
2563 |
|
2564 | if (Array.isArray(parentRect) && parentRect.length === 4) {
|
2565 | this.data.parentRect = _util.Util.normalizeRect(parentRect);
|
2566 | } else {
|
2567 | this.data.parentRect = [0, 0, 0, 0];
|
2568 | }
|
2569 |
|
2570 | const rt = parentItem.get("RT");
|
2571 |
|
2572 | if ((0, _primitives.isName)(rt, _util.AnnotationReplyType.GROUP)) {
|
2573 | parentItem = parentItem.get("IRT");
|
2574 | }
|
2575 |
|
2576 | if (!parentItem.has("M")) {
|
2577 | this.data.modificationDate = null;
|
2578 | } else {
|
2579 | this.setModificationDate(parentItem.get("M"));
|
2580 | this.data.modificationDate = this.modificationDate;
|
2581 | }
|
2582 |
|
2583 | if (!parentItem.has("C")) {
|
2584 | this.data.color = null;
|
2585 | } else {
|
2586 | this.setColor(parentItem.getArray("C"));
|
2587 | this.data.color = this.color;
|
2588 | }
|
2589 |
|
2590 | if (!this.viewable) {
|
2591 | const parentFlags = parentItem.get("F");
|
2592 |
|
2593 | if (this._isViewable(parentFlags)) {
|
2594 | this.setFlags(parentFlags);
|
2595 | }
|
2596 | }
|
2597 |
|
2598 | this.setTitle(parentItem.get("T"));
|
2599 | this.data.titleObj = this._title;
|
2600 | this.setContents(parentItem.get("Contents"));
|
2601 | this.data.contentsObj = this._contents;
|
2602 |
|
2603 | if (parentItem.has("RC")) {
|
2604 | this.data.richText = _factory.XFAFactory.getRichTextAsHtml(parentItem.get("RC"));
|
2605 | }
|
2606 | }
|
2607 |
|
2608 | }
|
2609 |
|
2610 | class FreeTextAnnotation extends MarkupAnnotation {
|
2611 | constructor(parameters) {
|
2612 | super(parameters);
|
2613 | this.data.annotationType = _util.AnnotationType.FREETEXT;
|
2614 | }
|
2615 |
|
2616 | static createNewDict(annotation, xref, {
|
2617 | apRef,
|
2618 | ap
|
2619 | }) {
|
2620 | const {
|
2621 | color,
|
2622 | fontSize,
|
2623 | rect,
|
2624 | rotation,
|
2625 | user,
|
2626 | value
|
2627 | } = annotation;
|
2628 | const freetext = new _primitives.Dict(xref);
|
2629 | freetext.set("Type", _primitives.Name.get("Annot"));
|
2630 | freetext.set("Subtype", _primitives.Name.get("FreeText"));
|
2631 | freetext.set("CreationDate", `D:${(0, _util.getModificationDate)()}`);
|
2632 | freetext.set("Rect", rect);
|
2633 | const da = `/Helv ${fontSize} Tf ${(0, _default_appearance.getPdfColor)(color, true)}`;
|
2634 | freetext.set("DA", da);
|
2635 | freetext.set("Contents", value);
|
2636 | freetext.set("F", 4);
|
2637 | freetext.set("Border", [0, 0, 0]);
|
2638 | freetext.set("Rotate", rotation);
|
2639 |
|
2640 | if (user) {
|
2641 | freetext.set("T", (0, _util.stringToUTF8String)(user));
|
2642 | }
|
2643 |
|
2644 | const n = new _primitives.Dict(xref);
|
2645 | freetext.set("AP", n);
|
2646 |
|
2647 | if (apRef) {
|
2648 | n.set("N", apRef);
|
2649 | } else {
|
2650 | n.set("N", ap);
|
2651 | }
|
2652 |
|
2653 | return freetext;
|
2654 | }
|
2655 |
|
2656 | static async createNewAppearanceStream(annotation, xref, params) {
|
2657 | const {
|
2658 | baseFontRef,
|
2659 | evaluator,
|
2660 | task
|
2661 | } = params;
|
2662 | const {
|
2663 | color,
|
2664 | fontSize,
|
2665 | rect,
|
2666 | rotation,
|
2667 | value
|
2668 | } = annotation;
|
2669 | const resources = new _primitives.Dict(xref);
|
2670 | const font = new _primitives.Dict(xref);
|
2671 |
|
2672 | if (baseFontRef) {
|
2673 | font.set("Helv", baseFontRef);
|
2674 | } else {
|
2675 | const baseFont = new _primitives.Dict(xref);
|
2676 | baseFont.set("BaseFont", _primitives.Name.get("Helvetica"));
|
2677 | baseFont.set("Type", _primitives.Name.get("Font"));
|
2678 | baseFont.set("Subtype", _primitives.Name.get("Type1"));
|
2679 | baseFont.set("Encoding", _primitives.Name.get("WinAnsiEncoding"));
|
2680 | font.set("Helv", baseFont);
|
2681 | }
|
2682 |
|
2683 | resources.set("Font", font);
|
2684 | const helv = await WidgetAnnotation._getFontData(evaluator, task, {
|
2685 | fontName: "Helvetica",
|
2686 | fontSize
|
2687 | }, resources);
|
2688 | const [x1, y1, x2, y2] = rect;
|
2689 | let w = x2 - x1;
|
2690 | let h = y2 - y1;
|
2691 |
|
2692 | if (rotation % 180 !== 0) {
|
2693 | [w, h] = [h, w];
|
2694 | }
|
2695 |
|
2696 | const lines = value.split("\n");
|
2697 | const scale = fontSize / 1000;
|
2698 | let totalWidth = -Infinity;
|
2699 | const encodedLines = [];
|
2700 |
|
2701 | for (let line of lines) {
|
2702 | line = helv.encodeString(line).join("");
|
2703 | encodedLines.push(line);
|
2704 | let lineWidth = 0;
|
2705 | const glyphs = helv.charsToGlyphs(line);
|
2706 |
|
2707 | for (const glyph of glyphs) {
|
2708 | lineWidth += glyph.width * scale;
|
2709 | }
|
2710 |
|
2711 | totalWidth = Math.max(totalWidth, lineWidth);
|
2712 | }
|
2713 |
|
2714 | let hscale = 1;
|
2715 |
|
2716 | if (totalWidth > w) {
|
2717 | hscale = w / totalWidth;
|
2718 | }
|
2719 |
|
2720 | let vscale = 1;
|
2721 | const lineHeight = _util.LINE_FACTOR * fontSize;
|
2722 | const lineDescent = _util.LINE_DESCENT_FACTOR * fontSize;
|
2723 | const totalHeight = lineHeight * lines.length;
|
2724 |
|
2725 | if (totalHeight > h) {
|
2726 | vscale = h / totalHeight;
|
2727 | }
|
2728 |
|
2729 | const fscale = Math.min(hscale, vscale);
|
2730 | const newFontSize = fontSize * fscale;
|
2731 | const buffer = ["q", `0 0 ${(0, _core_utils.numberToString)(w)} ${(0, _core_utils.numberToString)(h)} re W n`, `BT`, `1 0 0 1 0 ${(0, _core_utils.numberToString)(h + lineDescent)} Tm 0 Tc ${(0, _default_appearance.getPdfColor)(color, true)}`, `/Helv ${(0, _core_utils.numberToString)(newFontSize)} Tf`];
|
2732 | const vShift = (0, _core_utils.numberToString)(lineHeight);
|
2733 |
|
2734 | for (const line of encodedLines) {
|
2735 | buffer.push(`0 -${vShift} Td (${(0, _util.escapeString)(line)}) Tj`);
|
2736 | }
|
2737 |
|
2738 | buffer.push("ET", "Q");
|
2739 | const appearance = buffer.join("\n");
|
2740 | const appearanceStreamDict = new _primitives.Dict(xref);
|
2741 | appearanceStreamDict.set("FormType", 1);
|
2742 | appearanceStreamDict.set("Subtype", _primitives.Name.get("Form"));
|
2743 | appearanceStreamDict.set("Type", _primitives.Name.get("XObject"));
|
2744 | appearanceStreamDict.set("BBox", [0, 0, w, h]);
|
2745 | appearanceStreamDict.set("Length", appearance.length);
|
2746 | appearanceStreamDict.set("Resources", resources);
|
2747 |
|
2748 | if (rotation) {
|
2749 | const matrix = WidgetAnnotation._getRotationMatrix(rotation, w, h);
|
2750 |
|
2751 | appearanceStreamDict.set("Matrix", matrix);
|
2752 | }
|
2753 |
|
2754 | const ap = new _stream.StringStream(appearance);
|
2755 | ap.dict = appearanceStreamDict;
|
2756 | return ap;
|
2757 | }
|
2758 |
|
2759 | }
|
2760 |
|
2761 | class LineAnnotation extends MarkupAnnotation {
|
2762 | constructor(parameters) {
|
2763 | super(parameters);
|
2764 | const {
|
2765 | dict
|
2766 | } = parameters;
|
2767 | this.data.annotationType = _util.AnnotationType.LINE;
|
2768 | const lineCoordinates = dict.getArray("L");
|
2769 | this.data.lineCoordinates = _util.Util.normalizeRect(lineCoordinates);
|
2770 | this.setLineEndings(dict.getArray("LE"));
|
2771 | this.data.lineEndings = this.lineEndings;
|
2772 |
|
2773 | if (!this.appearance) {
|
2774 | const strokeColor = this.color ? Array.from(this.color).map(c => c / 255) : [0, 0, 0];
|
2775 | const strokeAlpha = dict.get("CA");
|
2776 | let fillColor = null,
|
2777 | interiorColor = dict.getArray("IC");
|
2778 |
|
2779 | if (interiorColor) {
|
2780 | interiorColor = getRgbColor(interiorColor, null);
|
2781 | fillColor = interiorColor ? Array.from(interiorColor).map(c => c / 255) : null;
|
2782 | }
|
2783 |
|
2784 | const fillAlpha = fillColor ? strokeAlpha : null;
|
2785 | const borderWidth = this.borderStyle.width || 1,
|
2786 | borderAdjust = 2 * borderWidth;
|
2787 | const bbox = [this.data.lineCoordinates[0] - borderAdjust, this.data.lineCoordinates[1] - borderAdjust, this.data.lineCoordinates[2] + borderAdjust, this.data.lineCoordinates[3] + borderAdjust];
|
2788 |
|
2789 | if (!_util.Util.intersect(this.rectangle, bbox)) {
|
2790 | this.rectangle = bbox;
|
2791 | }
|
2792 |
|
2793 | this._setDefaultAppearance({
|
2794 | xref: parameters.xref,
|
2795 | extra: `${borderWidth} w`,
|
2796 | strokeColor,
|
2797 | fillColor,
|
2798 | strokeAlpha,
|
2799 | fillAlpha,
|
2800 | pointsCallback: (buffer, points) => {
|
2801 | buffer.push(`${lineCoordinates[0]} ${lineCoordinates[1]} m`, `${lineCoordinates[2]} ${lineCoordinates[3]} l`, "S");
|
2802 | return [points[0].x - borderWidth, points[1].x + borderWidth, points[3].y - borderWidth, points[1].y + borderWidth];
|
2803 | }
|
2804 | });
|
2805 | }
|
2806 | }
|
2807 |
|
2808 | }
|
2809 |
|
2810 | class SquareAnnotation extends MarkupAnnotation {
|
2811 | constructor(parameters) {
|
2812 | super(parameters);
|
2813 | this.data.annotationType = _util.AnnotationType.SQUARE;
|
2814 |
|
2815 | if (!this.appearance) {
|
2816 | const strokeColor = this.color ? Array.from(this.color).map(c => c / 255) : [0, 0, 0];
|
2817 | const strokeAlpha = parameters.dict.get("CA");
|
2818 | let fillColor = null,
|
2819 | interiorColor = parameters.dict.getArray("IC");
|
2820 |
|
2821 | if (interiorColor) {
|
2822 | interiorColor = getRgbColor(interiorColor, null);
|
2823 | fillColor = interiorColor ? Array.from(interiorColor).map(c => c / 255) : null;
|
2824 | }
|
2825 |
|
2826 | const fillAlpha = fillColor ? strokeAlpha : null;
|
2827 |
|
2828 | if (this.borderStyle.width === 0 && !fillColor) {
|
2829 | return;
|
2830 | }
|
2831 |
|
2832 | this._setDefaultAppearance({
|
2833 | xref: parameters.xref,
|
2834 | extra: `${this.borderStyle.width} w`,
|
2835 | strokeColor,
|
2836 | fillColor,
|
2837 | strokeAlpha,
|
2838 | fillAlpha,
|
2839 | pointsCallback: (buffer, points) => {
|
2840 | const x = points[2].x + this.borderStyle.width / 2;
|
2841 | const y = points[2].y + this.borderStyle.width / 2;
|
2842 | const width = points[3].x - points[2].x - this.borderStyle.width;
|
2843 | const height = points[1].y - points[3].y - this.borderStyle.width;
|
2844 | buffer.push(`${x} ${y} ${width} ${height} re`);
|
2845 |
|
2846 | if (fillColor) {
|
2847 | buffer.push("B");
|
2848 | } else {
|
2849 | buffer.push("S");
|
2850 | }
|
2851 |
|
2852 | return [points[0].x, points[1].x, points[3].y, points[1].y];
|
2853 | }
|
2854 | });
|
2855 | }
|
2856 | }
|
2857 |
|
2858 | }
|
2859 |
|
2860 | class CircleAnnotation extends MarkupAnnotation {
|
2861 | constructor(parameters) {
|
2862 | super(parameters);
|
2863 | this.data.annotationType = _util.AnnotationType.CIRCLE;
|
2864 |
|
2865 | if (!this.appearance) {
|
2866 | const strokeColor = this.color ? Array.from(this.color).map(c => c / 255) : [0, 0, 0];
|
2867 | const strokeAlpha = parameters.dict.get("CA");
|
2868 | let fillColor = null;
|
2869 | let interiorColor = parameters.dict.getArray("IC");
|
2870 |
|
2871 | if (interiorColor) {
|
2872 | interiorColor = getRgbColor(interiorColor, null);
|
2873 | fillColor = interiorColor ? Array.from(interiorColor).map(c => c / 255) : null;
|
2874 | }
|
2875 |
|
2876 | const fillAlpha = fillColor ? strokeAlpha : null;
|
2877 |
|
2878 | if (this.borderStyle.width === 0 && !fillColor) {
|
2879 | return;
|
2880 | }
|
2881 |
|
2882 | const controlPointsDistance = 4 / 3 * Math.tan(Math.PI / (2 * 4));
|
2883 |
|
2884 | this._setDefaultAppearance({
|
2885 | xref: parameters.xref,
|
2886 | extra: `${this.borderStyle.width} w`,
|
2887 | strokeColor,
|
2888 | fillColor,
|
2889 | strokeAlpha,
|
2890 | fillAlpha,
|
2891 | pointsCallback: (buffer, points) => {
|
2892 | const x0 = points[0].x + this.borderStyle.width / 2;
|
2893 | const y0 = points[0].y - this.borderStyle.width / 2;
|
2894 | const x1 = points[3].x - this.borderStyle.width / 2;
|
2895 | const y1 = points[3].y + this.borderStyle.width / 2;
|
2896 | const xMid = x0 + (x1 - x0) / 2;
|
2897 | const yMid = y0 + (y1 - y0) / 2;
|
2898 | const xOffset = (x1 - x0) / 2 * controlPointsDistance;
|
2899 | const yOffset = (y1 - y0) / 2 * controlPointsDistance;
|
2900 | buffer.push(`${xMid} ${y1} m`, `${xMid + xOffset} ${y1} ${x1} ${yMid + yOffset} ${x1} ${yMid} c`, `${x1} ${yMid - yOffset} ${xMid + xOffset} ${y0} ${xMid} ${y0} c`, `${xMid - xOffset} ${y0} ${x0} ${yMid - yOffset} ${x0} ${yMid} c`, `${x0} ${yMid + yOffset} ${xMid - xOffset} ${y1} ${xMid} ${y1} c`, "h");
|
2901 |
|
2902 | if (fillColor) {
|
2903 | buffer.push("B");
|
2904 | } else {
|
2905 | buffer.push("S");
|
2906 | }
|
2907 |
|
2908 | return [points[0].x, points[1].x, points[3].y, points[1].y];
|
2909 | }
|
2910 | });
|
2911 | }
|
2912 | }
|
2913 |
|
2914 | }
|
2915 |
|
2916 | class PolylineAnnotation extends MarkupAnnotation {
|
2917 | constructor(parameters) {
|
2918 | super(parameters);
|
2919 | const {
|
2920 | dict
|
2921 | } = parameters;
|
2922 | this.data.annotationType = _util.AnnotationType.POLYLINE;
|
2923 | this.data.vertices = [];
|
2924 |
|
2925 | if (!(this instanceof PolygonAnnotation)) {
|
2926 | this.setLineEndings(dict.getArray("LE"));
|
2927 | this.data.lineEndings = this.lineEndings;
|
2928 | }
|
2929 |
|
2930 | const rawVertices = dict.getArray("Vertices");
|
2931 |
|
2932 | if (!Array.isArray(rawVertices)) {
|
2933 | return;
|
2934 | }
|
2935 |
|
2936 | for (let i = 0, ii = rawVertices.length; i < ii; i += 2) {
|
2937 | this.data.vertices.push({
|
2938 | x: rawVertices[i],
|
2939 | y: rawVertices[i + 1]
|
2940 | });
|
2941 | }
|
2942 |
|
2943 | if (!this.appearance) {
|
2944 | const strokeColor = this.color ? Array.from(this.color).map(c => c / 255) : [0, 0, 0];
|
2945 | const strokeAlpha = dict.get("CA");
|
2946 | const borderWidth = this.borderStyle.width || 1,
|
2947 | borderAdjust = 2 * borderWidth;
|
2948 | const bbox = [Infinity, Infinity, -Infinity, -Infinity];
|
2949 |
|
2950 | for (const vertex of this.data.vertices) {
|
2951 | bbox[0] = Math.min(bbox[0], vertex.x - borderAdjust);
|
2952 | bbox[1] = Math.min(bbox[1], vertex.y - borderAdjust);
|
2953 | bbox[2] = Math.max(bbox[2], vertex.x + borderAdjust);
|
2954 | bbox[3] = Math.max(bbox[3], vertex.y + borderAdjust);
|
2955 | }
|
2956 |
|
2957 | if (!_util.Util.intersect(this.rectangle, bbox)) {
|
2958 | this.rectangle = bbox;
|
2959 | }
|
2960 |
|
2961 | this._setDefaultAppearance({
|
2962 | xref: parameters.xref,
|
2963 | extra: `${borderWidth} w`,
|
2964 | strokeColor,
|
2965 | strokeAlpha,
|
2966 | pointsCallback: (buffer, points) => {
|
2967 | const vertices = this.data.vertices;
|
2968 |
|
2969 | for (let i = 0, ii = vertices.length; i < ii; i++) {
|
2970 | buffer.push(`${vertices[i].x} ${vertices[i].y} ${i === 0 ? "m" : "l"}`);
|
2971 | }
|
2972 |
|
2973 | buffer.push("S");
|
2974 | return [points[0].x, points[1].x, points[3].y, points[1].y];
|
2975 | }
|
2976 | });
|
2977 | }
|
2978 | }
|
2979 |
|
2980 | }
|
2981 |
|
2982 | class PolygonAnnotation extends PolylineAnnotation {
|
2983 | constructor(parameters) {
|
2984 | super(parameters);
|
2985 | this.data.annotationType = _util.AnnotationType.POLYGON;
|
2986 | }
|
2987 |
|
2988 | }
|
2989 |
|
2990 | class CaretAnnotation extends MarkupAnnotation {
|
2991 | constructor(parameters) {
|
2992 | super(parameters);
|
2993 | this.data.annotationType = _util.AnnotationType.CARET;
|
2994 | }
|
2995 |
|
2996 | }
|
2997 |
|
2998 | class InkAnnotation extends MarkupAnnotation {
|
2999 | constructor(parameters) {
|
3000 | super(parameters);
|
3001 | this.data.annotationType = _util.AnnotationType.INK;
|
3002 | this.data.inkLists = [];
|
3003 | const rawInkLists = parameters.dict.getArray("InkList");
|
3004 |
|
3005 | if (!Array.isArray(rawInkLists)) {
|
3006 | return;
|
3007 | }
|
3008 |
|
3009 | const xref = parameters.xref;
|
3010 |
|
3011 | for (let i = 0, ii = rawInkLists.length; i < ii; ++i) {
|
3012 | this.data.inkLists.push([]);
|
3013 |
|
3014 | for (let j = 0, jj = rawInkLists[i].length; j < jj; j += 2) {
|
3015 | this.data.inkLists[i].push({
|
3016 | x: xref.fetchIfRef(rawInkLists[i][j]),
|
3017 | y: xref.fetchIfRef(rawInkLists[i][j + 1])
|
3018 | });
|
3019 | }
|
3020 | }
|
3021 |
|
3022 | if (!this.appearance) {
|
3023 | const strokeColor = this.color ? Array.from(this.color).map(c => c / 255) : [0, 0, 0];
|
3024 | const strokeAlpha = parameters.dict.get("CA");
|
3025 | const borderWidth = this.borderStyle.width || 1,
|
3026 | borderAdjust = 2 * borderWidth;
|
3027 | const bbox = [Infinity, Infinity, -Infinity, -Infinity];
|
3028 |
|
3029 | for (const inkLists of this.data.inkLists) {
|
3030 | for (const vertex of inkLists) {
|
3031 | bbox[0] = Math.min(bbox[0], vertex.x - borderAdjust);
|
3032 | bbox[1] = Math.min(bbox[1], vertex.y - borderAdjust);
|
3033 | bbox[2] = Math.max(bbox[2], vertex.x + borderAdjust);
|
3034 | bbox[3] = Math.max(bbox[3], vertex.y + borderAdjust);
|
3035 | }
|
3036 | }
|
3037 |
|
3038 | if (!_util.Util.intersect(this.rectangle, bbox)) {
|
3039 | this.rectangle = bbox;
|
3040 | }
|
3041 |
|
3042 | this._setDefaultAppearance({
|
3043 | xref: parameters.xref,
|
3044 | extra: `${borderWidth} w`,
|
3045 | strokeColor,
|
3046 | strokeAlpha,
|
3047 | pointsCallback: (buffer, points) => {
|
3048 | for (const inkList of this.data.inkLists) {
|
3049 | for (let i = 0, ii = inkList.length; i < ii; i++) {
|
3050 | buffer.push(`${inkList[i].x} ${inkList[i].y} ${i === 0 ? "m" : "l"}`);
|
3051 | }
|
3052 |
|
3053 | buffer.push("S");
|
3054 | }
|
3055 |
|
3056 | return [points[0].x, points[1].x, points[3].y, points[1].y];
|
3057 | }
|
3058 | });
|
3059 | }
|
3060 | }
|
3061 |
|
3062 | static createNewDict(annotation, xref, {
|
3063 | apRef,
|
3064 | ap
|
3065 | }) {
|
3066 | const {
|
3067 | paths,
|
3068 | rect,
|
3069 | rotation
|
3070 | } = annotation;
|
3071 | const ink = new _primitives.Dict(xref);
|
3072 | ink.set("Type", _primitives.Name.get("Annot"));
|
3073 | ink.set("Subtype", _primitives.Name.get("Ink"));
|
3074 | ink.set("CreationDate", `D:${(0, _util.getModificationDate)()}`);
|
3075 | ink.set("Rect", rect);
|
3076 | ink.set("InkList", paths.map(p => p.points));
|
3077 | ink.set("F", 4);
|
3078 | ink.set("Border", [0, 0, 0]);
|
3079 | ink.set("Rotate", rotation);
|
3080 | const n = new _primitives.Dict(xref);
|
3081 | ink.set("AP", n);
|
3082 |
|
3083 | if (apRef) {
|
3084 | n.set("N", apRef);
|
3085 | } else {
|
3086 | n.set("N", ap);
|
3087 | }
|
3088 |
|
3089 | return ink;
|
3090 | }
|
3091 |
|
3092 | static async createNewAppearanceStream(annotation, xref, params) {
|
3093 | const {
|
3094 | color,
|
3095 | rect,
|
3096 | rotation,
|
3097 | paths,
|
3098 | thickness,
|
3099 | opacity
|
3100 | } = annotation;
|
3101 | const [x1, y1, x2, y2] = rect;
|
3102 | let w = x2 - x1;
|
3103 | let h = y2 - y1;
|
3104 |
|
3105 | if (rotation % 180 !== 0) {
|
3106 | [w, h] = [h, w];
|
3107 | }
|
3108 |
|
3109 | const appearanceBuffer = [`${thickness} w 1 J 1 j`, `${(0, _default_appearance.getPdfColor)(color, false)}`];
|
3110 |
|
3111 | if (opacity !== 1) {
|
3112 | appearanceBuffer.push("/R0 gs");
|
3113 | }
|
3114 |
|
3115 | const buffer = [];
|
3116 |
|
3117 | for (const {
|
3118 | bezier
|
3119 | } of paths) {
|
3120 | buffer.length = 0;
|
3121 | buffer.push(`${(0, _core_utils.numberToString)(bezier[0])} ${(0, _core_utils.numberToString)(bezier[1])} m`);
|
3122 |
|
3123 | for (let i = 2, ii = bezier.length; i < ii; i += 6) {
|
3124 | const curve = bezier.slice(i, i + 6).map(_core_utils.numberToString).join(" ");
|
3125 | buffer.push(`${curve} c`);
|
3126 | }
|
3127 |
|
3128 | buffer.push("S");
|
3129 | appearanceBuffer.push(buffer.join("\n"));
|
3130 | }
|
3131 |
|
3132 | const appearance = appearanceBuffer.join("\n");
|
3133 | const appearanceStreamDict = new _primitives.Dict(xref);
|
3134 | appearanceStreamDict.set("FormType", 1);
|
3135 | appearanceStreamDict.set("Subtype", _primitives.Name.get("Form"));
|
3136 | appearanceStreamDict.set("Type", _primitives.Name.get("XObject"));
|
3137 | appearanceStreamDict.set("BBox", [0, 0, w, h]);
|
3138 | appearanceStreamDict.set("Length", appearance.length);
|
3139 |
|
3140 | if (rotation) {
|
3141 | const matrix = WidgetAnnotation._getRotationMatrix(rotation, w, h);
|
3142 |
|
3143 | appearanceStreamDict.set("Matrix", matrix);
|
3144 | }
|
3145 |
|
3146 | if (opacity !== 1) {
|
3147 | const resources = new _primitives.Dict(xref);
|
3148 | const extGState = new _primitives.Dict(xref);
|
3149 | const r0 = new _primitives.Dict(xref);
|
3150 | r0.set("CA", opacity);
|
3151 | r0.set("Type", _primitives.Name.get("ExtGState"));
|
3152 | extGState.set("R0", r0);
|
3153 | resources.set("ExtGState", extGState);
|
3154 | appearanceStreamDict.set("Resources", resources);
|
3155 | }
|
3156 |
|
3157 | const ap = new _stream.StringStream(appearance);
|
3158 | ap.dict = appearanceStreamDict;
|
3159 | return ap;
|
3160 | }
|
3161 |
|
3162 | }
|
3163 |
|
3164 | class HighlightAnnotation extends MarkupAnnotation {
|
3165 | constructor(parameters) {
|
3166 | super(parameters);
|
3167 | this.data.annotationType = _util.AnnotationType.HIGHLIGHT;
|
3168 | const quadPoints = this.data.quadPoints = getQuadPoints(parameters.dict, null);
|
3169 |
|
3170 | if (quadPoints) {
|
3171 | const resources = this.appearance && this.appearance.dict.get("Resources");
|
3172 |
|
3173 | if (!this.appearance || !(resources && resources.has("ExtGState"))) {
|
3174 | if (this.appearance) {
|
3175 | (0, _util.warn)("HighlightAnnotation - ignoring built-in appearance stream.");
|
3176 | }
|
3177 |
|
3178 | const fillColor = this.color ? Array.from(this.color).map(c => c / 255) : [1, 1, 0];
|
3179 | const fillAlpha = parameters.dict.get("CA");
|
3180 |
|
3181 | this._setDefaultAppearance({
|
3182 | xref: parameters.xref,
|
3183 | fillColor,
|
3184 | blendMode: "Multiply",
|
3185 | fillAlpha,
|
3186 | pointsCallback: (buffer, points) => {
|
3187 | buffer.push(`${points[0].x} ${points[0].y} m`, `${points[1].x} ${points[1].y} l`, `${points[3].x} ${points[3].y} l`, `${points[2].x} ${points[2].y} l`, "f");
|
3188 | return [points[0].x, points[1].x, points[3].y, points[1].y];
|
3189 | }
|
3190 | });
|
3191 | }
|
3192 | } else {
|
3193 | this.data.hasPopup = false;
|
3194 | }
|
3195 | }
|
3196 |
|
3197 | }
|
3198 |
|
3199 | class UnderlineAnnotation extends MarkupAnnotation {
|
3200 | constructor(parameters) {
|
3201 | super(parameters);
|
3202 | this.data.annotationType = _util.AnnotationType.UNDERLINE;
|
3203 | const quadPoints = this.data.quadPoints = getQuadPoints(parameters.dict, null);
|
3204 |
|
3205 | if (quadPoints) {
|
3206 | if (!this.appearance) {
|
3207 | const strokeColor = this.color ? Array.from(this.color).map(c => c / 255) : [0, 0, 0];
|
3208 | const strokeAlpha = parameters.dict.get("CA");
|
3209 |
|
3210 | this._setDefaultAppearance({
|
3211 | xref: parameters.xref,
|
3212 | extra: "[] 0 d 1 w",
|
3213 | strokeColor,
|
3214 | strokeAlpha,
|
3215 | pointsCallback: (buffer, points) => {
|
3216 | buffer.push(`${points[2].x} ${points[2].y} m`, `${points[3].x} ${points[3].y} l`, "S");
|
3217 | return [points[0].x, points[1].x, points[3].y, points[1].y];
|
3218 | }
|
3219 | });
|
3220 | }
|
3221 | } else {
|
3222 | this.data.hasPopup = false;
|
3223 | }
|
3224 | }
|
3225 |
|
3226 | }
|
3227 |
|
3228 | class SquigglyAnnotation extends MarkupAnnotation {
|
3229 | constructor(parameters) {
|
3230 | super(parameters);
|
3231 | this.data.annotationType = _util.AnnotationType.SQUIGGLY;
|
3232 | const quadPoints = this.data.quadPoints = getQuadPoints(parameters.dict, null);
|
3233 |
|
3234 | if (quadPoints) {
|
3235 | if (!this.appearance) {
|
3236 | const strokeColor = this.color ? Array.from(this.color).map(c => c / 255) : [0, 0, 0];
|
3237 | const strokeAlpha = parameters.dict.get("CA");
|
3238 |
|
3239 | this._setDefaultAppearance({
|
3240 | xref: parameters.xref,
|
3241 | extra: "[] 0 d 1 w",
|
3242 | strokeColor,
|
3243 | strokeAlpha,
|
3244 | pointsCallback: (buffer, points) => {
|
3245 | const dy = (points[0].y - points[2].y) / 6;
|
3246 | let shift = dy;
|
3247 | let x = points[2].x;
|
3248 | const y = points[2].y;
|
3249 | const xEnd = points[3].x;
|
3250 | buffer.push(`${x} ${y + shift} m`);
|
3251 |
|
3252 | do {
|
3253 | x += 2;
|
3254 | shift = shift === 0 ? dy : 0;
|
3255 | buffer.push(`${x} ${y + shift} l`);
|
3256 | } while (x < xEnd);
|
3257 |
|
3258 | buffer.push("S");
|
3259 | return [points[2].x, xEnd, y - 2 * dy, y + 2 * dy];
|
3260 | }
|
3261 | });
|
3262 | }
|
3263 | } else {
|
3264 | this.data.hasPopup = false;
|
3265 | }
|
3266 | }
|
3267 |
|
3268 | }
|
3269 |
|
3270 | class StrikeOutAnnotation extends MarkupAnnotation {
|
3271 | constructor(parameters) {
|
3272 | super(parameters);
|
3273 | this.data.annotationType = _util.AnnotationType.STRIKEOUT;
|
3274 | const quadPoints = this.data.quadPoints = getQuadPoints(parameters.dict, null);
|
3275 |
|
3276 | if (quadPoints) {
|
3277 | if (!this.appearance) {
|
3278 | const strokeColor = this.color ? Array.from(this.color).map(c => c / 255) : [0, 0, 0];
|
3279 | const strokeAlpha = parameters.dict.get("CA");
|
3280 |
|
3281 | this._setDefaultAppearance({
|
3282 | xref: parameters.xref,
|
3283 | extra: "[] 0 d 1 w",
|
3284 | strokeColor,
|
3285 | strokeAlpha,
|
3286 | pointsCallback: (buffer, points) => {
|
3287 | buffer.push(`${(points[0].x + points[2].x) / 2} ` + `${(points[0].y + points[2].y) / 2} m`, `${(points[1].x + points[3].x) / 2} ` + `${(points[1].y + points[3].y) / 2} l`, "S");
|
3288 | return [points[0].x, points[1].x, points[3].y, points[1].y];
|
3289 | }
|
3290 | });
|
3291 | }
|
3292 | } else {
|
3293 | this.data.hasPopup = false;
|
3294 | }
|
3295 | }
|
3296 |
|
3297 | }
|
3298 |
|
3299 | class StampAnnotation extends MarkupAnnotation {
|
3300 | constructor(parameters) {
|
3301 | super(parameters);
|
3302 | this.data.annotationType = _util.AnnotationType.STAMP;
|
3303 | }
|
3304 |
|
3305 | }
|
3306 |
|
3307 | class FileAttachmentAnnotation extends MarkupAnnotation {
|
3308 | constructor(parameters) {
|
3309 | super(parameters);
|
3310 | const file = new _file_spec.FileSpec(parameters.dict.get("FS"), parameters.xref);
|
3311 | this.data.annotationType = _util.AnnotationType.FILEATTACHMENT;
|
3312 | this.data.file = file.serializable;
|
3313 | }
|
3314 |
|
3315 | } |
\ | No newline at end of file |