UNPKG

@syncfusion/ej2-pdf

Version:

Feature-rich JavaScript PDF library with built-in support for loading and manipulating PDF document.

1,053 lines (1,052 loc) 44.4 kB
import { _PdfDictionary, _PdfReference } from './../pdf-primitives'; import { _checkReview, _isNullOrUndefined } from './../utils'; import { PdfLineAnnotation, PdfCircleAnnotation, PdfEllipseAnnotation, PdfAngleMeasurementAnnotation, PdfRectangleAnnotation, PdfSquareAnnotation, PdfPolyLineAnnotation, PdfPolygonAnnotation, PdfInkAnnotation, PdfPopupAnnotation, PdfAttachmentAnnotation, Pdf3DAnnotation, PdfFileLinkAnnotation, PdfWatermarkAnnotation, PdfRubberStampAnnotation, PdfSoundAnnotation, PdfFreeTextAnnotation, PdfRedactionAnnotation, PdfRichMediaAnnotation, PdfTextMarkupAnnotation, PdfDocumentLinkAnnotation, PdfTextWebLinkAnnotation, PdfUriAnnotation, PdfComment } from './annotation'; import { PdfAnnotationFlag } from './../enumerator'; import { initializeTelemetryFeature } from '@syncfusion/ej2-base'; /** * The class provides methods and properties to handle the collection of `PdfAnnotation`. * ```typescript * // Load an existing PDF document * let document: PdfDocument = new PdfDocument(data); * // Access annotation coolection from first page * let annotations: PdfAnnotationCollection = document.getPage(0).annotations; * // Save the document * document.save('output.pdf'); * // Destroy the document * document.destroy(); * ``` */ var PdfAnnotationCollection = /** @class */ (function () { /** * Represents a annotation collection. * * @private * @param {Array<_PdfReference>} array Annotation references. * @param {_PdfCrossReference} xref Cross reference object. * @param {PdfPage} page PDF page object. */ function PdfAnnotationCollection(array, xref, page) { /** * Indicates whether the collection is being used for export operations. * * @private */ this._isExport = false; if (_isNullOrUndefined(array)) { this._annotations = array; } else { this._annotations = []; } this._page = page; this._crossReference = xref; this._parsedAnnotations = new Map(); this._comments = []; } Object.defineProperty(PdfAnnotationCollection.prototype, "count", { /** * Gets the annotation count (Read only). * * @returns {number} Number of annotations. * * ```typescript * // Load an existing PDF document * let document: PdfDocument = new PdfDocument(data, password); * // Access first page * let page: PdfPage = document.getPage(0); * // Gets the annotation count * let count: number = page.annotations.count; * // Destroy the document * document.destroy(); * ``` */ get: function () { return this._annotations.length; }, enumerable: true, configurable: true }); /** * Gets the `PdfAnnotation` at the specified index. * * ```typescript * // Load an existing PDF document * let document: PdfDocument = new PdfDocument(data, password); * // Access first page * let page: PdfPage = document.getPage(0); * // Access the annotation at index 0 * let annotation: PdfAnnotation = page.annotations.at(0); * // Save the document * document.save('output.pdf'); * // Destroy the document * document.destroy(); * ``` * * @param {number} index Field index. * @returns {PdfAnnotation} Annotation at the specified index */ PdfAnnotationCollection.prototype.at = function (index) { if (index < 0 || index >= this._annotations.length) { throw Error('Index out of range.'); } if (!this._parsedAnnotations.has(index)) { var dictionary = this._annotations[index]; if (dictionary && dictionary instanceof _PdfReference) { dictionary = this._crossReference._fetch(dictionary); } if (dictionary && dictionary instanceof _PdfDictionary) { var annotation = this._parseAnnotation(dictionary, index); if (annotation) { annotation._ref = this._annotations[index]; this._parsedAnnotations.set(index, annotation); } } } return this._parsedAnnotations.get(index); }; /** * Add a new `PdfAnnotation` into the collection. * * ```typescript * // Load an existing PDF document * let document: PdfDocument = new PdfDocument(data, password); * // Access first page * let page: PdfPage = document.getPage(0); * // Add a new annotation into the collection * page.annotations.add(annotation); * // Save the document * document.save('output.pdf'); * // Destroy the document * document.destroy(); * ``` * * @param {PdfAnnotation} annotation Annotation to add. * @returns {number} Annotation index. */ PdfAnnotationCollection.prototype.add = function (annotation) { var _this = this; initializeTelemetryFeature('Annotation', 'PDFLibrary'); if (typeof annotation === 'undefined' || annotation === null) { throw Error('annotation cannot be null or undefined'); } if (annotation instanceof PdfPopupAnnotation && (annotation._isReview || annotation._isComment)) { if (annotation.bounds) { annotation.bounds.y = -annotation.bounds.y; annotation.bounds.height = -annotation.bounds.height; } } if (annotation._isLoaded) { throw Error('cannot add an existing annotation'); } annotation._initialize(this._page); var reference; if (typeof annotation._ref !== 'undefined' && annotation._ref._isNew) { reference = annotation._ref; } else { reference = this._crossReference._getNextReference(); this._crossReference._cacheMap.set(reference, annotation._dictionary); annotation._ref = reference; } var index = this._annotations.length; this._annotations.push(reference); this._parsedAnnotations.set(index, annotation); var isAdded = false; if (this._page && this._page._pageDictionary.has('Annots')) { var collection = this._page._pageDictionary.get('Annots'); if (collection !== null && typeof collection !== 'undefined' && collection.indexOf(reference) === -1) { collection.push(reference); this._page._pageDictionary.set('Annots', collection); isAdded = true; } } if (!isAdded) { this._page._pageDictionary.set('Annots', this._annotations); } this._page._pageDictionary._updated = true; if (annotation && annotation instanceof PdfComment) { this._addCommentsAndReview(annotation, annotation._dictionary.get('F')); } this._updateCustomAppearanceResource(annotation); if (annotation._customTemplate && annotation._customTemplate.size > 0) { annotation._customTemplate.forEach(function (template, key) { template._updatePendingResource(_this._crossReference); }); } return index; }; /** * Remove an annotation from the collection. * * ```typescript * // Load an existing PDF document * let document: PdfDocument = new PdfDocument(data); * // Access first page * let page: PdfPage = document.getPage(0); * // Access first annotation from the PDF page * let annotation: PdfAnnotation = page.annotations.at(0); * // Remove an annotation from the collection * page.annotations.remove(annotation); * // Save the document * document.save('output.pdf'); * // Destroy the document * document.destroy(); * ``` * * @param {PdfAnnotation} annotation Annotation to remove. * @returns {void} Nothing. */ PdfAnnotationCollection.prototype.remove = function (annotation) { if (annotation && annotation._ref) { var index = this._annotations.lastIndexOf(annotation._ref); if (index > -1) { this.removeAt(index); } } }; /** * Remove an annotation from the collection at the specified index. * * ```typescript * // Load an existing PDF document * let document: PdfDocument = new PdfDocument(data); * // Access first page * let page: PdfPage = document.getPage(0); * // Remove an annotation from the collection * page.annotations.removeAt(0); * // Save the document * document.save('output.pdf'); * // Destroy the document * document.destroy(); * ``` * * @param {number} index Annotation index. * @returns {void} Nothing. */ PdfAnnotationCollection.prototype.removeAt = function (index) { if (index < 0 || index >= this._annotations.length) { throw Error('Index out of range.'); } var reference = this._annotations[index]; if (reference && this._page) { var array = this._page._getProperty('Annots'); var parsedAnnotation = void 0; if (this._parsedAnnotations.has(index)) { parsedAnnotation = this._parsedAnnotations.get(index); } else { var annotationDictionary = this._crossReference._fetch(reference); parsedAnnotation = this._parseAnnotation(annotationDictionary); parsedAnnotation._ref = reference; } if (parsedAnnotation) { var comments = parsedAnnotation.comments; var reviewHistory = parsedAnnotation.reviewHistory; this._processAnnotations(comments, array); this._processAnnotations(reviewHistory, array); if (parsedAnnotation._dictionary && parsedAnnotation._dictionary.has('Popup')) { var popupRef = parsedAnnotation._dictionary.getRaw('Popup'); var popupIndex = (popupRef && popupRef instanceof _PdfReference) ? array.indexOf(popupRef) : -1; if (popupIndex > -1) { array.splice(popupIndex, 1); } } } var actualIndex = array.indexOf(reference); if (actualIndex > -1) { array.splice(actualIndex, 1); } this._page._pageDictionary.set('Annots', array); this._page._pageDictionary._updated = true; if (this._annotations.indexOf(reference) > -1) { this._annotations.splice(index, 1); } if (this._parsedAnnotations.has(index)) { this._parsedAnnotations.delete(index); this._reorderParsedAnnotations(index); } var crossReference = this._page._crossReference; if (crossReference && crossReference._cacheMap.has(reference)) { crossReference._cacheMap.delete(reference); } } }; /** * Processes and prunes matching object references from the provided arrays, * synchronizing internal annotation lists, parsed indices, and cross-reference cache. * * @private * @param {_PdfReference[]} references The references to remove. * @param {_PdfReference[]} array The target reference array to prune from. * @returns {void} No return value. */ PdfAnnotationCollection.prototype._processReferences = function (references, array) { var _this = this; references.forEach(function (ref) { if (ref && array.indexOf(ref) !== -1) { var index = array.indexOf(ref); array.splice(index, 1); var annotationsIndex = _this._annotations.indexOf(ref); if (annotationsIndex > -1) { _this._annotations.splice(annotationsIndex, 1); } if (_this._parsedAnnotations.has(index)) { _this._parsedAnnotations.delete(index); _this._reorderParsedAnnotations(index); } var crossReference = _this._page._crossReference; if (crossReference && crossReference._cacheMap.has(ref)) { crossReference._cacheMap.delete(ref); } } }); }; /** * Iterates popup annotations and removes their references from the provided reference array, * keeping internal state in sync. * * @private * @param {PdfPopupAnnotationCollection} annotationCollection The popup annotation collection to scan. * @param {_PdfReference[]} array The reference array to remove entries from. * @returns {void} No return value. */ PdfAnnotationCollection.prototype._processAnnotations = function (annotationCollection, array) { var _this = this; if (annotationCollection && annotationCollection._collection.length > 0) { annotationCollection._collection.forEach(function (annotation) { var annotationReferences = [annotation._ref]; if (annotation.reviewHistory && annotation.reviewHistory._collection.length > 0) { annotationReferences.push.apply(annotationReferences, annotation.reviewHistory._collection.map(function (review) { return review._ref; })); } _this._processReferences(annotationReferences, array); }); } }; /** * Reindexes parsed annotation entries after a removal, shifting keys above the given index down by one. * * @private * @param {number} index The removed index that subsequent keys should shift below. * @returns {void} No return value. */ PdfAnnotationCollection.prototype._reorderParsedAnnotations = function (index) { var result = new Map(); this._parsedAnnotations.forEach(function (value, key) { if (key > index) { result.set(key - 1, value); } else { result.set(key, value); } }); this._parsedAnnotations = result; }; /** * Updates the appearance resources of a rubber stamp annotation by processing * its normal appearance graphics with the associated cross-reference. * * @private * @param {PdfAnnotation} annotation The annotation whose appearance resources will be updated. * @returns {void} No return value. */ PdfAnnotationCollection.prototype._updateCustomAppearanceResource = function (annotation) { if (annotation && annotation instanceof PdfRubberStampAnnotation && typeof annotation._appearance !== 'undefined') { annotation._appearance.normal.graphics._processResources(annotation._crossReference); } }; /** * Updates comment and review-history child references for the given annotation * by applying the specified processing flag to both collections. * * @private * @param {PdfComment} annotation The parent annotation. * @param {number} flag The processing flag applied to children. * @returns {void} No return value. */ PdfAnnotationCollection.prototype._addCommentsAndReview = function (annotation, flag) { this._updateChildReference(annotation, annotation.comments, flag); this._updateChildReference(annotation, annotation.reviewHistory, flag); }; /** * Updates child popup-annotation references for comments or review history, * assigning appropriate IRT links and flags, and adds each processed child * to the annotation structure unless the operation is restricted. * * @private * @param {PdfComment} annotation The parent annotation to reference from. * @param {PdfPopupAnnotationCollection} collection The child popup collection to update. * @param {number} flag The processing flag governing add/deny behavior. * @returns {void} No return value. */ PdfAnnotationCollection.prototype._updateChildReference = function (annotation, collection, flag) { var _this = this; if (collection && collection.count > 0) { if (flag !== 30) { collection._collection.forEach(function (childAnnotation, i) { if (childAnnotation && !childAnnotation._dictionary.has('IRT')) { if (i === 0 || !collection._isReview) { childAnnotation._dictionary.update('IRT', annotation._ref); } else { childAnnotation._dictionary.update('IRT', collection._collection[i - 1]._ref); } if (collection._isReview) { childAnnotation._isReview = true; } else { childAnnotation._isComment = true; } _this.add(childAnnotation); } }); } else { throw new Error('Could not add comments/reviews to the review'); } } }; /** * Parses and caches page annotations when not already initialized, resolving references, * handling popups with external parents, and storing parsed annotations by their index. * * @private * @returns {void} No return value. */ PdfAnnotationCollection.prototype._getAnnotations = function () { if (this._parsedAnnotations.size === 0) { for (var i = 0; i < this._annotations.length; i++) { var dictionary = this._annotations[i]; if (dictionary && dictionary instanceof _PdfReference) { dictionary = this._crossReference._fetch(dictionary); } if (dictionary && dictionary instanceof _PdfDictionary) { var isPopupWithExternalParent = this._isPopupWithExternalParent(dictionary); var annotation = this._parseAnnotation(dictionary, i); if (annotation) { annotation._ref = this._annotations[i]; this._parsedAnnotations.set(i, annotation); } else if (isPopupWithExternalParent) { i--; } } } } }; /** * Determines whether the given dictionary represents a popup annotation * that has an external parent entry, indicating it should not be parsed * as a standalone annotation. * * @private * @param {_PdfDictionary} dictionary The dictionary to inspect. * @returns {boolean} True if the popup has an external parent; otherwise, false. */ PdfAnnotationCollection.prototype._isPopupWithExternalParent = function (dictionary) { if (dictionary && dictionary.has('Subtype')) { var key = dictionary.get('Subtype'); if (key && key.name === 'Popup' && dictionary.has('Parent')) { return true; } } return false; }; /** * Parses a raw annotation dictionary into a strongly-typed annotation instance * based on its subtype and context, handling special cases like popups with * external parents, geometric variants, and link-action types. * * @private * @param {_PdfDictionary} dictionary The raw annotation dictionary to parse. * @param {number} [index] Optional index of the annotation in the page array. * @returns {PdfAnnotation} The parsed annotation instance, or undefined when not applicable. */ PdfAnnotationCollection.prototype._parseAnnotation = function (dictionary, index) { var annot; var hasParent = false; if (dictionary && dictionary.has('Subtype') && this._page !== null && typeof this._page !== 'undefined') { var key = dictionary.get('Subtype'); var size = dictionary.get('Rect'); if (key) { var link = void 0; switch (key.name) { case 'Line': annot = PdfLineAnnotation._load(this._page, dictionary); break; case 'Circle': if (dictionary.has('Measure')) { annot = PdfCircleAnnotation._load(this._page, dictionary); } else { var width = size[2] - size[0]; var height = size[3] - size[1]; if (width === height) { annot = PdfCircleAnnotation._load(this._page, dictionary); } else { annot = PdfEllipseAnnotation._load(this._page, dictionary); } } break; case 'Square': if (size && size.length >= 4 && size[2] === size[3]) { annot = PdfSquareAnnotation._load(this._page, dictionary); } else { annot = PdfRectangleAnnotation._load(this._page, dictionary); } break; case 'Polygon': annot = PdfPolygonAnnotation._load(this._page, dictionary); break; case 'PolyLine': if (dictionary.has('Measure') && dictionary.has('IT')) { var type = dictionary.get('IT'); if (type && type.name === 'PolyLineAngle') { annot = PdfAngleMeasurementAnnotation._load(this._page, dictionary); } } if (!annot) { annot = PdfPolyLineAnnotation._load(this._page, dictionary); } break; case 'Ink': annot = PdfInkAnnotation._load(this._page, dictionary); break; case 'Popup': hasParent = this._isPopupWithExternalParent(dictionary); if (typeof index === 'number' && hasParent) { this._annotations.splice(index, 1); } else { annot = PdfPopupAnnotation._load(this._page, dictionary); } break; case 'Text': annot = PdfPopupAnnotation._load(this._page, dictionary); break; case 'Link': if (dictionary.has('A')) { link = dictionary.get('A'); } if (link && link.has('S')) { var type = link.get('S').name; if (type) { var isTextWebLink = this._hasValidBorder(dictionary.getArray('Border')); if (type === 'URI') { annot = isTextWebLink ? PdfTextWebLinkAnnotation._load(this._page, dictionary) : this._getLinkAnnotation(dictionary); } else if (type === 'Launch') { annot = PdfFileLinkAnnotation._load(this._page, dictionary); } else if (type === 'GoToR') { annot = this._getLinkAnnotation(dictionary); } else if (type === 'GoTo') { annot = PdfDocumentLinkAnnotation._load(this._page, dictionary); } } } else if (key.name === 'Link') { annot = PdfDocumentLinkAnnotation._load(this._page, dictionary); } break; case 'FileAttachment': annot = PdfAttachmentAnnotation._load(this._page, dictionary); break; case '3D': annot = Pdf3DAnnotation._load(this._page, dictionary); break; case 'FreeText': annot = PdfFreeTextAnnotation._load(this._page, dictionary); break; case 'Redact': annot = PdfRedactionAnnotation._load(this._page, dictionary); break; case 'RichMedia': annot = PdfRichMediaAnnotation._load(this._page, dictionary); break; case 'Watermark': annot = PdfWatermarkAnnotation._load(this._page, dictionary); break; case 'Stamp': annot = PdfRubberStampAnnotation._load(this._page, dictionary); break; case 'Sound': annot = PdfSoundAnnotation._load(this._page, dictionary); break; case 'Caret': case 'Highlight': case 'Squiggly': case 'StrikeOut': case 'Underline': annot = PdfTextMarkupAnnotation._load(this._page, dictionary); break; } } } return annot; }; /** * Creates a file or URI link annotation from the given dictionary by inspecting * the action subtype and target, defaulting to a URI link when unspecified. * * @private * @param {_PdfDictionary} dictionary The link annotation dictionary to analyze. * @returns {PdfFileLinkAnnotation|PdfUriAnnotation} The constructed link annotation. */ PdfAnnotationCollection.prototype._getLinkAnnotation = function (dictionary) { var annot; if (this._page) { if (dictionary && dictionary.has('A')) { var remote = dictionary.get('A'); if (remote && remote.has('S')) { var link = remote.get('S'); if (link && link.name === 'GoToR' && remote.has('F')) { annot = PdfFileLinkAnnotation._load(this._page, dictionary); } else if (link && link.name === 'URI') { annot = PdfUriAnnotation._load(this._page, dictionary); } } } else { annot = PdfUriAnnotation._load(this._page, dictionary); } } return annot; }; /** * Determines whether the border array represents a valid textweb link border, * ensuring all values are defined and nonpositive, as required for link detection. * * @private * @param {number[]} border The border array to validate. * @returns {boolean} True if the border represents a valid text web link; otherwise, false. */ PdfAnnotationCollection.prototype._hasValidBorder = function (border) { if (typeof border === 'undefined' || border === null) { return false; } var isValid = !border.some(function (value) { if (typeof value === 'undefined' || value === null) { return false; } return value > 0; }); return isValid; }; /** * Determines whether the border array represents a valid textweb link border, * ensuring all values are defined and nonpositive, as required for link detection. * * @private * @param {number[]} isFlatten The border array to validate. * @returns {void} nothing. */ PdfAnnotationCollection.prototype._doPostProcess = function (isFlatten) { var index = 0; while (index < this.count) { var annotation = this.at(index); if (annotation) { var flattenValue = annotation.flatten || isFlatten; if (flattenValue && !annotation.flatten) { annotation.flatten = flattenValue; } annotation._isExport = this._isExport; if (flattenValue && this._annotations.lastIndexOf(annotation._ref) === -1) { index++; } annotation._doPostProcess(flattenValue); if (!flattenValue) { index++; } } else { index++; } } }; /** * Reorders the annotations array by swapping a candidate entry into the specified tab index * when the parent reference or the item itself matches the provided reference. * * @private * @param {_PdfReference} ref The reference used to match the target item to move. * @param {number} tabIndex The desired position to place the matched item. * @param {number} index The current index of the candidate item in the annotation array. * @returns {_PdfReference[]} The updated annotations reference array. */ PdfAnnotationCollection.prototype._reArrange = function (ref, tabIndex, index) { if (this._annotations) { if (tabIndex > this._annotations.length) { tabIndex = 0; } if (index >= this._annotations.length) { index = this._annotations.indexOf(ref); } var annotationDictionary = this._crossReference. _fetch(this._annotations[index]); if (annotationDictionary && annotationDictionary.has('Parent')) { var parentReference = annotationDictionary.getRaw('Parent'); if ((parentReference && parentReference === ref) || ref === this._annotations[index]) { var temp = this._annotations[index]; this._annotations[index] = this._annotations[tabIndex]; this._annotations[tabIndex] = temp; } } } return this._annotations; }; /** * Clears all annotation data by resetting raw references, parsed annotations, * and cached comment collections to their initial empty state. * * @private * @returns {void} No return value. */ PdfAnnotationCollection.prototype._clear = function () { this._annotations = []; this._parsedAnnotations = new Map(); this._comments = []; }; return PdfAnnotationCollection; }()); export { PdfAnnotationCollection }; /** * Represents the collection of `PdfPopupAnnotation` * ```typescript * // Load an existing PDF document * let document: PdfDocument = new PdfDocument(data); * // Access annotation collection from first page * let annotations: PdfRectangleAnnotation = document.getPage(0).annotations; * // Gets the comments of annotation * let comments: PdfPopupAnnotationCollection = annotation.comments; * // Save the document * document.save('output.pdf'); * // Destroy the document * document.destroy(); * ``` */ var PdfPopupAnnotationCollection = /** @class */ (function () { /** * Initializes a new instance of the `PdfPopupAnnotationCollection` class * * @private * @param {PdfAnnotation} annotation Annotation reference * @param {boolean} isReview Boolean flag to set review */ function PdfPopupAnnotationCollection(annotation, isReview) { /** * Maintains the list of popup annotations linked to the parent annotation. * * @private */ this._collection = []; if (annotation) { this._annotation = annotation; } this._isReview = isReview; if (annotation && this._annotation._isLoaded || annotation._page) { this._page = annotation._page; this._parentDictionary = annotation._dictionary; if (this._annotation._isLoaded) { this._parseCommentsOrReview(); } } } Object.defineProperty(PdfPopupAnnotationCollection.prototype, "count", { /** * Gets the annotation count (Read only). * * @private * @returns {number} Number of annotations * * ```typescript * // Load an existing PDF document * let document: PdfDocument = new PdfDocument(data); * // Access annotation collection from first page * let annotations: PdfRectangleAnnotation = document.getPage(0).annotations; * // Gets the comments of annotation * let comments: PdfPopupAnnotationCollection = annotation.comments; * // Gets the count of comments * let count: number = comments.count; * // Save the document * document.save('output.pdf'); * // Destroy the document * document.destroy(); * ``` */ get: function () { return this._collection.length; }, enumerable: true, configurable: true }); /** * Gets the popup annotation at the specified index. * * ```typescript * // Load an existing PDF document * let document: PdfDocument = new PdfDocument(data); * // Access annotation collection from first page * let annotations: PdfRectangleAnnotation = document.getPage(0).annotations; * // Gets the comments of annotation * let comments: PdfPopupAnnotationCollection = annotation.comments; * // Gets the first comment * let comment: PdfPopupAnnotation = comments.at(0); * // Save the document * document.save('output.pdf'); * // Destroy the document * document.destroy(); * ``` * * @private * @param {number} index Index of the annotation * @returns {number} Annotation at the specified index */ PdfPopupAnnotationCollection.prototype.at = function (index) { if (index < 0 || index >= this._collection.length) { throw Error('Index out of range.'); } return this._collection[index]; }; /** * Add a new popup annotation into the collection * * ```typescript * // Load an existing PDF document * let document: PdfDocument = new PdfDocument(data, password); * // Access first page * let page: PdfPage = document.getPage(0); * // Create a new popup annotation * const popupAnnotation: PdfPopupAnnotation = new PdfPopupAnnotation('Test popup annotation', 10, 40, 30, 30); * popupAnnotation.author = 'Syncfusion'; * // Add a new popup annotation into the collection * annotation.comments.add(popupAnnotation); * // Save the document * document.save('output.pdf'); * // Destroy the document * document.destroy(); * ``` * * @param {PdfPopupAnnotation} annotation Annotation to add * @returns {void} Nothing */ PdfPopupAnnotationCollection.prototype.add = function (annotation) { if (this._annotation._dictionary.get('F') === 30) { throw new Error('Could not add comments/reviews to the review'); } annotation._dictionary.update('F', ((this._annotation.flags === PdfAnnotationFlag.locked) ? 128 : (this._isReview ? 30 : 28))); if (this._annotation && (this._annotation._isLoaded || (this._page && this._annotation._ref))) { this._page.annotations.add(annotation); var length_1 = this._collection.length; if (length_1 === 0 || !this._isReview) { annotation._dictionary.update('IRT', this._annotation._ref); } else { annotation._dictionary.update('IRT', this._collection[(length_1 - 1)]._ref); } if (this._isReview) { annotation._isReview = true; } else { annotation._isComment = true; } } this._collection.push(annotation); }; /** * Remove an annotation from the collection * * ```typescript * // Load an existing PDF document * let document: PdfDocument = new PdfDocument(data); * // Access annotation collection from first page * let annotations: PdfRectangleAnnotation = document.getPage(0).annotations; * // Gets the comments of annotation * let comments: PdfPopupAnnotationCollection = annotation.comments; * // Gets the first comment * let comment: PdfPopupAnnotation = comments.at(0); * // Remove the comment * comments.remove(comment); * // Save the document * document.save('output.pdf'); * // Destroy the document * document.destroy(); * ``` * * @param {PdfPopupAnnotation} annotation Annotation to remove * @returns {void} Nothing */ PdfPopupAnnotationCollection.prototype.remove = function (annotation) { var index = this._collection.indexOf(annotation); if (index > -1) { this.removeAt(index); } }; /** * Remove an annotation from the collection at the specified index * * ```typescript * // Load an existing PDF document * let document: PdfDocument = new PdfDocument(data); * // Access annotation collection from first page * let annotations: PdfRectangleAnnotation = document.getPage(0).annotations; * // Gets the comments of annotation * let comments: PdfPopupAnnotationCollection = annotation.comments; * // Remove the first comment * comments.removeAt(0); * // Save the document * document.save('output.pdf'); * // Destroy the document * document.destroy(); * ``` * * @param {number} index Annotation index to remove * @returns {void} Nothing */ PdfPopupAnnotationCollection.prototype.removeAt = function (index) { if (index > -1 && index < this._collection.length) { var annotation = this._collection[index]; if (this._isReview && index < this._collection.length - 1) { var nextAnnotation = this._collection[(index + 1)]; var previous = annotation._dictionary._get('IRT'); nextAnnotation._dictionary.set('IRT', previous); nextAnnotation._dictionary._updated = true; } this._collection.splice(index, 1); this._page.annotations.remove(annotation); } else { throw new Error('Index out of range.'); } }; /** * Parses either review data or regular comment data based on the current parsing mode. * * @private * @returns {void} No return value. */ PdfPopupAnnotationCollection.prototype._parseCommentsOrReview = function () { if (this._isReview) { this._parseReview(); } else { this._parseComments(); } }; /** * Parses and aggregates review-thread popup annotations linked to the current annotation, * attaching matching replies to the collection and deferring unmatched items to the comments cache. * * @private * @returns {void} No return value. */ PdfPopupAnnotationCollection.prototype._parseReview = function () { var _this = this; var collection; if (this._page) { collection = this._page.annotations; } var map = new Map(); map.set(this._annotation._ref, this._annotation); if (collection && collection._comments && collection._comments.length > 0) { var remaining_1 = []; collection._comments.forEach(function (annotation) { var reference = annotation._dictionary._get('IRT'); if (annotation._isReview && reference && map.has(reference)) { _this._collection.push(annotation); map.set(annotation._ref, annotation); } else { remaining_1.push(annotation); } }); if (remaining_1.length > 0) { collection._comments = remaining_1; } else { collection._comments = []; } } else if (collection) { var count = collection.count; for (var i = 0; i < count; i++) { var annotation = collection.at(i); if (annotation && annotation instanceof PdfPopupAnnotation) { var dictionary = annotation._dictionary; if (annotation._dictionary.has('IRT')) { var reference = dictionary._get('IRT'); if (annotation._isReview && reference && map.has(reference)) { this._collection.push(annotation); map.set(annotation._ref, annotation); } else { collection._comments.push(annotation); } } } } } map.clear(); }; /** * Parses non-review comment-thread popup annotations linked to the current annotation, * collecting direct comment replies and preserving unrelated items in the comments cache. * * @private * @returns {void} No return value. */ PdfPopupAnnotationCollection.prototype._parseComments = function () { var _this = this; var collection; if (this._page) { collection = this._page.annotations; } if (collection && collection._comments && collection._comments.length > 0) { var remaining_2 = []; collection._comments.forEach(function (annotation) { var dictionary = annotation._dictionary; var isReview = _checkReview(dictionary); var reference = dictionary._get('IRT'); if (reference && reference === _this._annotation._ref && !isReview) { _this._collection.push(annotation); } else { remaining_2.push(annotation); } }); if (remaining_2.length > 0) { collection._comments = remaining_2; } else { collection._comments = []; } } else if (collection) { var count = collection.count; for (var i = 0; i < count; i++) { var annotation = collection.at(i); if (annotation && annotation instanceof PdfPopupAnnotation) { var dictionary = annotation._dictionary; if (annotation._dictionary.has('IRT')) { var isReview = _checkReview(dictionary); var reference = dictionary._get('IRT'); if (reference && reference === this._annotation._ref && !isReview) { this._collection.push(annotation); } else { collection._comments.push(annotation); } } } } } }; return PdfPopupAnnotationCollection; }()); export { PdfPopupAnnotationCollection };