@syncfusion/ej2-pdf
Version:
Feature-rich JavaScript PDF library with built-in support for loading and manipulating PDF document.
1,709 lines • 83.7 kB
JavaScript
import { PdfWidgetAnnotation } from './annotations/annotation';
import { PdfPageOrientation } from './enumerator';
import { PdfFontFamily, PdfFontStyle, PdfStandardFont } from './fonts/pdf-standard-font';
import { PdfButtonField, PdfCheckBoxField, PdfComboBoxField, PdfListField, PdfRadioButtonListField, PdfSignatureField, PdfTextBoxField } from './form/field';
import { PdfPageSettings } from './pdf-document';
import { PdfNamedDestination } from './pdf-outline';
import { PdfDestination } from './pdf-page';
import { PdfPageImportOptions } from './pdf-page-import-options';
import { _PdfDictionary, _PdfName, _PdfReference } from './pdf-primitives';
import { _getItemValue } from './utils';
import { _PdfBaseStream, _PdfContentStream, _PdfStream } from './base-stream';
/**
* Helper that merges/imports pages, annotations, form fields, layers, and bookmarks between PDF documents.
*
* @private
*/
var _PdfMergeHelper = /** @class */ (function () {
function _PdfMergeHelper(crossReference, destination, source, pageReference, options) {
/**
* Accumulator for named destinations to be written to the Names tree.
*
* @private
*/
this._namedDestinations = []; // eslint-disable-line
/**
* Accumulates bookmark nodes discovered during import.
*
* @private
*/
this._bookmarks = []; // eslint-disable-line
/**
* Temporary storage for imported form fields.
*
* @private
*/
this._fields = []; // eslint-disable-line
/**
* Mapping of source page dictionaries to destination page objects.
*
* @private
*/
this._pageReference = new Map();
/**
* Mapping of source page references to destination page indexes for bookmark link fix-ups.
*
* @private
*/
this._bookmarksPageLinkReference = new Map();
/**
* Collected destination arrays from annotations to be fixed after import.
*
* @private
*/
this._destination = []; // eslint-disable-line
/**
* Lookup of oldtonew references created during copy to reconcile layer references.
*
* @private
*/
this._newList = new Map();
/**
* Mapping of annotation index to its associated layer reference.
*
* @private
*/
this._annotationLayer = new Map();
/**
* Indicates if optional content are present during import.
*
* @private
*/
this._isLayersPresent = false;
/**
* Tracks field names already present in destination to avoid duplicates.
*
* @private
*/
this._fieldNames = [];
/**
* Options that control how pages and related resources are imported.
*
* @private
*/
this._options = new PdfPageImportOptions();
/**
* Temporary storage for widget/field kid references encountered during processing.
*
* @private
*/
this._kidsReference = []; // eslint-disable-line
/**
* Mapping of source field index to newly created parent field reference in the destination.
*
* @private
*/
this._formFieldsCollection = new Map();
/**
* Collected field references that will be assigned to the destination AcroForm.
*
* @private
*/
this._formFields = [];
/**
* Indicates whether the current operation duplicates an existing page within the same document.
*
* @private
*/
this._isDuplicatePage = false;
/**
* Running count used when appending newly parsed fields into the destination form.
*
* @private
*/
this._fieldCount = 0;
this._crossReference = crossReference;
this._destinationDocument = destination;
this._sourceDocument = source;
this._pageReference = pageReference;
if (typeof options !== 'undefined') {
this._options = options;
}
this._copier = new _PdfCopier(this._crossReference, this._sourceDocument._crossReference);
}
/**
* Imports a page from the source document into the destination document, handling resources, annotations, form fields, and layers.
*
* @private
* @param {PdfPage} page The source page to import.
* @param {number} index The index at which the page should be inserted in the destination document.
* @param {boolean} layers Indicates whether optional content should be merged.
* @param {boolean} isCopiedPage Specifies whether the operation is duplicating an existing page.
* @param {PdfPageImportOptions} [options] Optional import settings including rotation and optimization.
* @param {boolean} [isSplitDocument] Indicates whether the operation is part of splitting a document.
* @returns {void}
*/
_PdfMergeHelper.prototype._importPages = function (page, index, layers, isCopiedPage, options, isSplitDocument) {
var _this = this;
var _a;
var template;
var newPage;
var pageDictionary = page._pageDictionary;
this._isDuplicatePage = isCopiedPage;
if (!options) {
this._options.rotation = page.rotation;
}
else {
this._options.rotation = options.rotation;
}
if (typeof index === 'number') {
newPage = this._insertNewPage(page, index);
}
else if (this._isDuplicatePage) {
newPage = this._insertNewPage(page, page._pageIndex + 1);
}
else {
newPage = this._insertNewPage(page);
}
if ((isCopiedPage || isSplitDocument) && this._options.optimizeResources) {
var newContents_1 = []; // eslint-disable-line
pageDictionary.forEach(function (key, value) {
if (key === 'Contents' && newContents_1.length === 0) {
var contents = value; // eslint-disable-line
if (contents instanceof _PdfReference) {
var pageContent = isSplitDocument ? _this._copier._copy(contents) : contents; // eslint-disable-line
newPage._pageDictionary.update(key, pageContent);
}
else if (contents instanceof Array) {
contents.forEach(function (content) {
var newContent = isSplitDocument ? _this._copier._copy(content) : content; // eslint-disable-line
newContents_1.push(newContent);
});
newPage._pageDictionary.update(key, newContents_1);
}
}
else if (key === 'Resources' && value) {
var resourceValue = isSplitDocument ? _this._copier._copy(value) : value; // eslint-disable-line
if (resourceValue) {
newPage._pageDictionary.update(key, resourceValue);
}
}
else if (key !== 'Resources' && key !== 'MediaBox' && key !== 'CropBox' && key !== 'Parent' && key !== 'Annots'
&& key !== 'Contents' && key !== 'Rotate') {
newPage._pageDictionary.update(key, value);
}
});
}
else {
template = page._contentTemplate;
newPage.graphics.drawTemplate(template, { x: 0, y: 0, width: template._size.width, height: template._size.height });
template._content.dictionary.update('Resources', this._copier._copy(pageDictionary.getRaw('Resources')));
this._pageReference.set(pageDictionary, newPage);
if (!isCopiedPage) {
this._bookmarksPageLinkReference.set(page._ref, newPage._pageIndex);
}
}
if (pageDictionary.has('Annots')) {
this._importAnnotation(page, newPage);
if (typeof this._options !== 'undefined' && this._options.groupFormFields && this._sourceDocument._catalog._catalogDictionary.has('AcroForm')
&& this._destinationDocument.form.count > 0) {
this._formFieldsGroupingSupport(this._sourceDocument.form, page, newPage);
}
else if (this._sourceDocument._catalog._catalogDictionary.has('AcroForm')) {
this._importFormField(page, this._sourceDocument.form, newPage);
}
}
if (!isCopiedPage) {
var bookMarkMap = this._sourceDocument._parseBookmarkDestination();
if (bookMarkMap && bookMarkMap.has(page)) {
var bookmarks = bookMarkMap.get(page);
(_a = this._bookmarks).push.apply(_a, bookmarks);
}
}
if ((!isCopiedPage && layers) || !this._options.optimizeResources) {
this._mergeLayer(newPage._pageDictionary, pageDictionary, this._sourceDocument._crossReference);
}
newPage._pageDictionary._updated = true;
};
/**
* Imports annotations from a source page into a destination page, preserving destinations and optional content references.
*
* @private
* @param {PdfPage} page The source page containing annotations.
* @param {PdfPage} newPage The destination page to receive the copied annotations.
* @returns {void}
*/
_PdfMergeHelper.prototype._importAnnotation = function (page, newPage) {
var oldCollection = page.annotations;
var annotations = oldCollection._annotations;
if (!annotations || annotations.length === 0) {
return;
}
var dstXref = this._crossReference;
var srcXref = this._sourceDocument._crossReference;
var result = [];
var count = annotations.length;
for (var i = 0; i < count; i++) {
var annotationReference = annotations[i];
if (!annotationReference) {
continue;
}
var annotationDictionary = srcXref._fetch(annotationReference);
if (!annotationDictionary) {
continue;
}
var dest = void 0; // eslint-disable-line
if (annotationDictionary.has('Dest')) {
var destinationArray = annotationDictionary.get('Dest'); // eslint-disable-line
var destination = annotationDictionary._get('Dest'); // eslint-disable-line
if (Array.isArray(destinationArray)) {
dest = destinationArray.slice();
}
else if (destination instanceof _PdfReference) {
dest = [destination];
}
}
if (dest && dest.length > 0) {
this._destination.push(dest);
}
if (annotationDictionary.has('OC')) {
var reference = annotationDictionary.getRaw('OC'); // eslint-disable-line
if (reference instanceof _PdfReference) {
this._annotationLayer.set(i, reference);
}
}
var copiedAnnotationReference = this._copier._copy(annotationReference);
var copiedAnnotationDictionary = dstXref._fetch(copiedAnnotationReference);
if (dest && dest.length > 0) {
copiedAnnotationDictionary.update('Dest', dest);
}
copiedAnnotationDictionary.update('P', newPage._ref);
result.push(copiedAnnotationReference);
}
if (result.length > 0) {
newPage._pageDictionary.update('Annots', result);
}
};
/**
* Groups and merges form fields for the imported page, aligning kids arrays and regenerating appearances when required.
*
* @private
* @param {PdfForm} form The source form collection to analyze.
* @param {PdfPage} oldPage The original page where the widgets reside.
* @param {PdfPage} newPage The destination page where widgets will be grouped.
* @returns {void}
*/
_PdfMergeHelper.prototype._formFieldsGroupingSupport = function (form, oldPage, newPage) {
var array = [];
var fieldNames = [];
var kidsArray = [];
var formFields;
var drEntry = form._dictionary.get('DR');
if (form._dictionary.has('DR')) {
drEntry = form._dictionary.get('DR');
}
if (newPage._pageDictionary.has('Annots')) {
array = newPage._pageDictionary.get('Annots');
}
if (oldPage._pageDictionary.has('Annots')) {
kidsArray = oldPage._pageDictionary.get('Annots');
}
if (!this._isDuplicatePage) {
formFields = this._destinationDocument.form;
this._fieldCount = formFields.count;
for (var k = 0; k < this._fieldCount; k++) {
fieldNames.push(formFields.fieldAt(k).name);
}
}
for (var i = 0; i < form.count; i++) {
var field = form.fieldAt(i);
var formField = void 0;
var destinationKids = [];
var sourceKids = field._dictionary.get('Kids');
if (fieldNames.indexOf(field.name) !== -1 || this._isDuplicatePage) {
if (!this._isDuplicatePage) {
formField = formFields.fieldAt(fieldNames.indexOf(field.name));
if (formField._dictionary.get('Kids')) {
destinationKids = formField._dictionary.get('Kids');
}
}
else {
formField = field;
destinationKids = sourceKids;
}
field._isDuplicatePage = true;
if ((field instanceof PdfSignatureField && formField instanceof PdfSignatureField) || !(field instanceof
PdfSignatureField)) {
if (sourceKids !== undefined && sourceKids.length > 0) {
for (var j = 0; j < sourceKids.length; j++) {
var fieldItem = field.itemAt(j); // eslint-disable-line
if (fieldItem.page === oldPage) {
formField._page = newPage;
array = this._groupFormFieldsKids(formField, field, kidsArray, destinationKids, sourceKids, newPage._ref, array, j, i, drEntry, fieldItem);
}
}
}
else {
array = this._groupFormFieldsKids(formField, field, kidsArray, destinationKids, sourceKids, newPage._ref, array, 0, i, drEntry);
}
}
}
else {
array = this._insertFormFields(i, field, form, newPage._ref, array, kidsArray);
}
}
if (array.length > 0) {
newPage._pageDictionary.update('Annots', array);
}
};
/**
* Groups kids between source and destination fields, creating or updating widget dictionaries and appearances.
*
* @private
* @param {PdfField} destinationField The destination field to receive kids.
* @param {PdfField} field The source field providing kids.
* @param {_PdfReference[]} kidsArray The source page annotations array.
* @param {_PdfReference[]} destKids The kids array of the destination field to be updated.
* @param {_PdfReference[]} oldKids The original kids from the source field.
* @param {_PdfReference} ref The destination page reference to assign to widgets.
* @param {_PdfReference[]} array The destination page annotations array to append to.
* @param {number} [index] Optional index of the kid in the source field.
* @param {number} [fieldIndex] Optional field index used for mapping.
* @param {_PdfDictionary} [drEntry] Optional default resources dictionary for appearance generation.
* @param {any} [widget] Optional widget information used for certain field types. // eslint-disable-line
* @returns {_PdfReference[]} The updated annotations array with any new widget references.
*/
_PdfMergeHelper.prototype._groupFormFieldsKids = function (destinationField, field, kidsArray, destKids, oldKids, ref, array, index, fieldIndex, drEntry, widget) {
if (field._dictionary.has('Kids') && destinationField._dictionary.has('Kids')) {
if (index !== null && typeof index !== 'undefined' && index >= 0 && oldKids.length > index) {
var oldKid = oldKids[index];
if (oldKid && kidsArray.indexOf(oldKid) !== -1) {
var oldDictionary = field._crossReference._fetch(oldKid);
var dictionary = this._copier._copyDictionary(oldDictionary, !this._isDuplicatePage);
dictionary.update('P', ref);
var reference = this._crossReference._getNextReference();
this._crossReference._cacheMap.set(reference, dictionary);
array.push(reference);
dictionary.update('Parent', destinationField._ref);
destKids.push(reference);
dictionary._updated = true;
destinationField._dictionary._updated = true;
if (!this._isDuplicatePage) {
if ((destinationField instanceof PdfTextBoxField ||
destinationField instanceof PdfButtonField ||
destinationField instanceof PdfComboBoxField) &&
dictionary.has('AS')) {
delete dictionary._map.AS;
}
this._createAppearance(destinationField, field, oldDictionary, dictionary, drEntry, widget);
}
}
}
}
else if (field._dictionary.has('Kids') && !destinationField._dictionary.has('Kids') || this._isDuplicatePage) {
var fieldDictionary = this._copier._copyDictionary(destinationField._dictionary, !this._isDuplicatePage);
this._updateFieldsWithKids(destinationField, field, fieldDictionary, index, fieldIndex, ref, oldKids, array, drEntry, destinationField._dictionary);
}
else if ((!field._dictionary.has('Kids') && destinationField._dictionary.has('Kids'))) {
var fieldDict = this._copier._copyDictionary(field._dictionary);
this._updateFieldDictionary(fieldDict, ref, destinationField._ref);
var reference = this._crossReference._getNextReference();
this._crossReference._cacheMap.set(reference, fieldDict);
destKids.push(reference);
array.push(reference);
destinationField._dictionary._updated = true;
this._createAppearance(destinationField, field, field._dictionary, fieldDict, drEntry, widget);
}
else if (!field._dictionary.has('Kids') && !destinationField._dictionary.has('Kids')) {
var fieldDictionary = this._copier._copyDictionary(destinationField._dictionary);
var formFieldDict = this._copier._copyDictionary(field._dictionary, !this._isDuplicatePage);
this._removeFieldDictionary(formFieldDict, ['Parent', 'FT', 'T', 'Ff']);
formFieldDict.update('P', ref);
this._updateFieldsWithKids(destinationField, field, fieldDictionary, index, fieldIndex, ref, oldKids, array, drEntry, formFieldDict);
}
return array;
};
/**
* Creates or updates a destination parent field with kids and appends the appropriate widget dictionaries and references.
*
* @private
* @param {PdfField} destinationField The destination field to update.
* @param {PdfField} field The source field used to derive structure and widget data.
* @param {_PdfDictionary} fieldDictionary The field dictionary used to build a new parent field.
* @param {number} index The source kid index, or `null/undefined` when using a provided dictionary.
* @param {number} fieldIndex The index of the form field in the global collection.
* @param {_PdfReference} ref The destination page reference for widget placement.
* @param {_PdfReference[]} oldKids The original kids from the source field.
* @param {_PdfReference[]} array The annotations array to append new widget references to.
* @param {_PdfDictionary} drEntry The default resources dictionary, for fonts and appearance resources.
* @param {_PdfDictionary} [formFieldDictionary] Optional field dictionary when no kid index is selected.
* @returns {void}
*/
_PdfMergeHelper.prototype._updateFieldsWithKids = function (destinationField, field, fieldDictionary, index, fieldIndex, ref, oldKids, array, drEntry, formFieldDictionary) {
var newFieldReference = this._crossReference._getNextReference();
var newFieldDict = this._createNewFieldDictionary(fieldDictionary, destinationField._dictionary);
newFieldDict.objId = newFieldReference.toString();
this._crossReference._cacheMap.set(newFieldReference, newFieldDict);
var newField = this._destinationDocument.form._parseFields(newFieldDict, newFieldReference);
destinationField._dictionary.update('Parent', newFieldReference);
newField._dictionary._updated = true;
this._updateFieldDictionary(fieldDictionary, ref, newFieldReference);
this._destinationDocument.form._dictionary._updated = true;
var oldDictionary;
if (oldKids !== undefined && oldKids.length > 0 && typeof index !== 'undefined' && index !== null && oldKids.length > index && index >= 0) {
oldDictionary = field._crossReference._fetch(oldKids[index]);
}
else {
oldDictionary = formFieldDictionary;
}
var dictionary = this._copier._copyDictionary(oldDictionary, !this._isDuplicatePage);
if ((destinationField instanceof PdfTextBoxField || destinationField instanceof PdfButtonField || destinationField instanceof PdfComboBoxField) && dictionary.has('AS')) {
delete dictionary._map.AS;
}
var reference = this._crossReference._getNextReference();
this._crossReference._cacheMap.set(reference, dictionary);
dictionary.update('P', ref);
array.push(reference);
dictionary.update('Parent', newField._ref);
var kidsElement = [];
kidsElement.push(destinationField._ref);
kidsElement.push(reference);
dictionary._updated = true;
destinationField._dictionary._updated = true;
newFieldDict.update('Kids', kidsElement);
newField._kids = kidsElement;
this._formFieldsCollection.set(fieldIndex, newFieldReference);
this._destinationDocument.form._parsedFields.set(fieldIndex, newField);
if (!this._isDuplicatePage) {
this._createAppearance(newField, field, oldDictionary, dictionary, drEntry);
}
newFieldDict._updated = true;
};
/**
* Removes the specified keys from a dictionary and returns the updated dictionary.
*
* @private
* @param {_PdfDictionary} dictionary The dictionary to modify.
* @param {string[]} keys The keys to remove from the dictionary.
* @returns {_PdfDictionary} The updated dictionary without the specified keys.
*/
_PdfMergeHelper.prototype._removeFieldDictionary = function (dictionary, keys) {
keys.forEach(function (key) {
if (dictionary.has(key)) {
delete dictionary._map[key]; // eslint-disable-line
}
});
return dictionary;
};
/**
* Updates a field or widget dictionary with page and parent references and marks it as updated.
*
* @private
* @param {_PdfDictionary} dictionary The dictionary to update.
* @param {_PdfReference} pageRef The page reference where the widget resides.
* @param {_PdfReference} parentRef The parent field reference to assign.
* @returns {void}
*/
_PdfMergeHelper.prototype._updateFieldDictionary = function (dictionary, pageRef, parentRef) {
dictionary = this._removeFieldDictionary(dictionary, ['Parent', 'FT', 'T', 'Ff']);
dictionary.update('P', pageRef);
dictionary.update('Parent', parentRef);
dictionary._updated = true;
};
/**
* Creates a new field dictionary by copying selected entries from an existing dictionary and removing them from the originals.
*
* @private
* @param {_PdfDictionary} fieldDictionary The source field dictionary to copy from.
* @param {_PdfDictionary} destDictionary The destination dictionary from which keys will also be removed.
* @returns {_PdfDictionary} A new field dictionary to act as a parent.
*/
_PdfMergeHelper.prototype._createNewFieldDictionary = function (fieldDictionary, destDictionary) {
var newFieldDict = new _PdfDictionary(this._crossReference);
['Parent', 'FT', 'T', 'V', 'Ff', 'TU', 'Opt', 'I'].forEach(function (key) {
if (fieldDictionary.has(key)) {
newFieldDict.update(key, fieldDictionary.get(key));
delete fieldDictionary._map[key]; // eslint-disable-line
delete destDictionary._map[key]; // eslint-disable-line
}
});
return newFieldDict;
};
/**
* Determines the style glyph or state used for checkbox/radio appearances based on MK dictionary or field type.
*
* @private
* @param {any} item The widget item to assign style information to. // eslint-disable-line
* @param {PdfField} field The associated field to infer default style when MK is not present.
* @returns {void}
*/
_PdfMergeHelper.prototype._getItemStyle = function (item, field) {
var mkDictionary = item._dictionary.get('MK');
if (mkDictionary && mkDictionary.has('CA')) {
item._styleText = mkDictionary.get('CA').charAt(0);
}
else {
item._styleText = (field instanceof PdfRadioButtonListField) ? 'l' : '4';
}
};
/**
* Creates appearance streams and templates for the destination field and its widgets using the provided DR resources.
*
* @private
* @param {PdfField} destinationField The destination field to render appearance for.
* @param {PdfField} field The source field guiding appearance characteristics.
* @param {_PdfDictionary} oldDictionary The source widget dictionary.
* @param {_PdfDictionary} dictionary The destination widget dictionary.
* @param {_PdfDictionary} drEntry The default resources dictionary for font resolution.
* @param {any} [widget] Optional widget context for signatures or list items. // eslint-disable-line
* @returns {void}
*/
_PdfMergeHelper.prototype._createAppearance = function (destinationField, field, oldDictionary, dictionary, drEntry, widget) {
var previousIndex = destinationField._kidsCount - 1;
var itemValue;
if (destinationField instanceof PdfCheckBoxField) {
var item = destinationField.itemAt(previousIndex);
item._enableGrouping = true;
this._getItemStyle(item, destinationField);
if (field instanceof PdfRadioButtonListField) {
item._dictionary.update('AS', _PdfName.get('Off'));
itemValue = _getItemValue(oldDictionary);
}
else {
item._postProcess(destinationField.checked ? 'Yes' : 'Off');
}
destinationField._drawAppearance(item, itemValue);
}
else if (destinationField instanceof PdfRadioButtonListField) {
var item = destinationField.itemAt(previousIndex);
this._getItemStyle(item, destinationField);
if (item._dictionary.has('AS')) {
item._postProcess(item._dictionary.get('AS').name);
}
else {
item._postProcess('Off');
}
item._enableGrouping = true;
destinationField._enableGrouping = true;
destinationField._drawAppearance(item);
}
else if (destinationField instanceof PdfListField) {
var item = destinationField.itemAt(previousIndex);
if (typeof widget !== 'undefined') {
item.rotationAngle = widget.rotationAngle;
}
if (item && !destinationField._checkFieldFlag(item._dictionary)) {
item._enableGrouping = true;
var template = destinationField._createAppearance(item);
destinationField._addAppearance(item._dictionary, template, 'N');
item._dictionary._updated = true;
}
}
else if (destinationField instanceof PdfTextBoxField || destinationField instanceof PdfButtonField || destinationField instanceof
PdfSignatureField) {
var widgetAnnotation = PdfWidgetAnnotation._load(dictionary, this._crossReference);
if (typeof widget !== 'undefined' && widget !== null && destinationField instanceof PdfSignatureField) {
destinationField._createAppearance(widget, false);
}
else {
widgetAnnotation.setAppearance(true);
widgetAnnotation._enableGrouping = true;
var pdfFont = void 0;
if (typeof widget !== 'undefined' && widget !== null) {
pdfFont = this._obtainFont(widget._dictionary, drEntry);
}
else {
pdfFont = this._obtainFont(dictionary, drEntry);
}
widgetAnnotation._pdfFont = pdfFont;
if (destinationField instanceof PdfSignatureField) {
destinationField._createAppearance(widgetAnnotation, false);
}
else {
destinationField._postProcess(false, widgetAnnotation);
}
}
}
};
/**
* Resolves a PDF font for widget appearance from DS/DA entries and the form default resources dictionary.
*
* @private
* @param {_PdfDictionary} item The annotation or widget dictionary that may contain DS/DA.
* @param {_PdfDictionary} formDictionary The form default resources dictionary (DR) used to resolve fonts.
* @returns {PdfFont} The resolved PDF font.
*/
_PdfMergeHelper.prototype._obtainFont = function (item, formDictionary) {
var fontFamily = '';
var fontSize = 8;
var pdfFont;
if (item && (item.has('DS') || item.has('DA'))) {
if (item.has('DS')) {
var collection = item.get('DS').split(';');
collection.forEach(function (item) {
var entry = item.split(':');
if (item.indexOf('font-family') !== -1) {
fontFamily = entry[1];
}
else if (item.indexOf('font-style') === -1 && item.indexOf('font') !== -1) {
var name_1 = entry[1];
var split = name_1.split(' ');
split.forEach(function (part) {
if (part !== '' && !part.endsWith('pt')) {
fontFamily += part + ' ';
}
});
while (fontFamily !== ' ' && fontFamily.endsWith(' ')) {
fontFamily = fontFamily.substring(0, fontFamily.length - 2);
}
if (fontFamily.indexOf(',') !== -1) {
fontFamily = fontFamily.split(',')[0];
}
}
});
}
else {
var value = item.get('DA');
if (value && value !== '' && value.indexOf('Tf') !== -1) {
var textCollection_1 = value.split(' ');
textCollection_1.forEach(function (text, index) {
if (text.indexOf('Tf') !== -1) {
fontFamily = textCollection_1[index - 2];
while (fontFamily !== '' && fontFamily.length > 1 && fontFamily[0] === '/') {
fontFamily = fontFamily.substring(1);
}
fontSize = Number.parseFloat(textCollection_1[index - 1]);
}
});
if (fontSize === 0) {
fontSize = 8;
}
}
}
}
fontFamily = fontFamily.trim();
var fontStyle = PdfFontStyle.regular;
var baseFontName;
if (typeof formDictionary != 'undefined' && formDictionary.has('Font')) {
var dictionary = formDictionary.get('Font').get(fontFamily);
if (typeof dictionary !== 'undefined') {
baseFontName = dictionary.get('BaseFont').name;
fontStyle = this._getFontStyle(baseFontName);
}
}
switch (fontFamily) {
case 'Helv':
pdfFont = new PdfStandardFont(PdfFontFamily.helvetica, fontSize, fontStyle);
break;
case 'Courier':
case 'Cour':
pdfFont = new PdfStandardFont(PdfFontFamily.courier, fontSize, fontStyle);
break;
case 'Symb':
pdfFont = new PdfStandardFont(PdfFontFamily.symbol, fontSize, fontStyle);
break;
case 'TiRo':
case 'TiIt':
pdfFont = new PdfStandardFont(PdfFontFamily.timesRoman, fontSize, fontStyle);
break;
case 'ZaDb':
pdfFont = new PdfStandardFont(PdfFontFamily.zapfDingbats, fontSize, fontStyle);
break;
default:
pdfFont = new PdfStandardFont(PdfFontFamily.helvetica, fontSize, fontStyle);
break;
}
return pdfFont;
};
/**
* Resolves the font style (bold/italic/regular) from a base font name.
*
* @private
* @param {string} fontStyle The base font name.
* @returns {PdfFontStyle} The resolved style.
*/
_PdfMergeHelper.prototype._getFontStyle = function (fontStyle) {
var style = PdfFontStyle.regular;
if (fontStyle.includes('Bold')) {
style = PdfFontStyle.bold;
}
else if (fontStyle.includes('Italic')) {
style = PdfFontStyle.italic;
}
return style;
};
/**
* Imports form fields for a given page, creating widgets in the destination and merging form DR resources.
*
* @private
* @param {PdfPage} page The source page that contains the fields.
* @param {PdfForm} pdfForm The source form collection to read from.
* @param {PdfPage} newPage The destination page to place the widgets on.
* @returns {void}
*/
_PdfMergeHelper.prototype._importFormField = function (page, pdfForm, newPage) {
var form = this._destinationDocument.form;
var array = [];
if (newPage && newPage._pageDictionary && newPage._pageDictionary.has('Annots')) {
array = newPage._pageDictionary.get('Annots');
}
var kidsArray = [];
var widgetArray = [];
if (this._destinationDocument.form._dictionary.has('Fields')) {
var formFields = this._destinationDocument.form;
this._fieldCount = formFields.count;
for (var k = 0; k < this._fieldCount; k++) {
var name_2 = formFields.fieldAt(k).name;
this._fieldNames.push(name_2);
}
}
if (page._pageDictionary.has('Annots')) {
widgetArray = page._pageDictionary.get('Annots');
}
var count = pdfForm.count;
for (var i = 0; i < count; ++i) {
var pdfField = pdfForm.fieldAt(i);
if (pdfField._dictionary.has('Kids')) {
kidsArray = pdfField._dictionary.get('Kids');
if (kidsArray.length > 1) {
for (var j = 0; j < kidsArray.length; j++) {
var fieldItem = pdfField.itemAt(j); // eslint-disable-line
if (fieldItem.page === page) {
array = this._insertFormFields(i, pdfField, form, newPage._ref, array, widgetArray);
break;
}
}
}
else if (kidsArray.length === 1) {
if (pdfField.page === page) {
array = this._insertFormFields(i, pdfField, form, newPage._ref, array, widgetArray);
}
}
}
else {
if (pdfField.page === page) {
array = this._insertFormFields(i, pdfField, form, newPage._ref, array, widgetArray);
}
}
}
if (pdfForm._dictionary.has('DR')) {
var dr = pdfForm._dictionary.get('DR');
var drDictionary = this._copier._copyDictionary(dr); // eslint-disable-line
var font = void 0; // eslint-disable-line
if (drDictionary.has('Font')) {
font = drDictionary.get('Font');
}
if (this._destinationDocument.form._dictionary.has('DR')) {
var curreneDR = this._destinationDocument.form._dictionary.get('DR');
if (curreneDR.has('Font')) {
var currentFont_1 = curreneDR.get('Font'); // eslint-disable-line
if (font) {
font.forEach(function (key, value) {
currentFont_1.set(key, value);
});
}
currentFont_1._updated = true;
}
}
else {
this._destinationDocument.form._dictionary.update('DR', drDictionary);
}
}
if (array.length > 0) {
newPage._pageDictionary.update('Annots', array);
}
};
/**
* Inserts form fields and widgets for the given source field into the destination form and page annotations.
*
* @private
* @param {number} index The index of the source field within the form.
* @param {PdfField} pdfField The source field to insert.
* @param {PdfForm} form The destination form collection.
* @param {_PdfReference} ref The destination page reference to assign to widgets.
* @param {_PdfReference[]} array The destination page annotations array to append to.
* @param {_PdfReference[]} kidsArray The list of source widget references on the page for filtering.
* @returns {_PdfReference[]} The updated annotations array with newly added widget references.
*/
_PdfMergeHelper.prototype._insertFormFields = function (index, pdfField, form, ref, array, kidsArray) {
var _this = this;
var dictionary = new _PdfDictionary();
if (pdfField._dictionary.has('Kids')) {
pdfField._dictionary.forEach(function (key, value) {
if (key !== 'Kids') {
dictionary.update(key, value);
}
});
}
else {
dictionary = this._copier._copyDictionary(pdfField._dictionary);
}
var newReference = this._crossReference._getNextReference();
dictionary.objId = newReference.toString();
var field = form._parseFields(dictionary, ref);
field._ref = newReference;
this._crossReference._cacheMap.set(newReference, field._dictionary);
if (pdfField._dictionary.has('Kids')) {
var oldKids = pdfField._dictionary.get('Kids');
var kids_1 = [];
oldKids.forEach(function (kid) {
if (kidsArray.indexOf(kid) !== -1) {
var oldDictionary = pdfField._crossReference._fetch(kid);
var dict = _this._copier._copyDictionary(oldDictionary);
dict.update('P', ref);
dict.update('Parent', newReference);
dict._updated = true;
var reference = _this._crossReference._getNextReference();
_this._crossReference._cacheMap.set(reference, dict);
array.push(reference);
kids_1.push(reference);
}
});
dictionary.update('Kids', kids_1);
field._kids = kids_1;
}
else {
field._dictionary.update('P', ref);
array.push(newReference);
}
field._dictionary._updated = true;
var i = 0;
var fieldName = field.name;
var modified = false;
while (this._fieldNames.indexOf(fieldName) !== -1) {
fieldName = field.name + i;
modified = true;
++i;
}
if (modified) {
field._dictionary.update('T', fieldName);
field._name = fieldName;
}
field._dictionary._updated = true;
if (this._fieldCount > 0) {
this._destinationDocument.form._parsedFields.set(this._fieldCount, field);
field._annotationIndex = this._fieldCount;
this._fieldCount++;
}
else {
this._destinationDocument.form._parsedFields.set(index, field);
field._annotationIndex = index;
}
this._destinationDocument.form._fields.push(newReference);
return array;
};
/**
* Merges the updated form fields collection into the destination document's AcroForm dictionary.
*
* @private
* @returns {void}
*/
_PdfMergeHelper.prototype._mergeFormFieldsWithDocument = function () {
var pdfFields = [];
if (this._formFieldsCollection.size > 0) {
var formDictionary = this._destinationDocument.form._dictionary;
if (formDictionary && formDictionary.has('Fields')) {
pdfFields = formDictionary.get('Fields');
}
this._formFieldsCollection.forEach(function (value, key) {
pdfFields[key] = value;
});
}
else {
pdfFields = this._destinationDocument.form._fields;
}
if (this._destinationDocument.form._dictionary.get('NeedAppearances')) {
this._destinationDocument.form._dictionary.set('NeedAppearances', false);
}
this._destinationDocument.form._dictionary.set('Fields', pdfFields);
this._destinationDocument.form._fields = pdfFields;
this._destinationDocument.form._dictionary._updated = true;
};
/**
* Imports optional content (layers) properties into the destination document and merges default view settings.
*
* @private
* @param {_PdfDictionary} ocProperties The source catalog dictionary that contains OCProperties.
* @param {boolean} layers Indicates whether layers are present and should be merged.
* @returns {void}
*/
_PdfMergeHelper.prototype._importLayers = function (ocProperties, layers) {
this._isLayersPresent = layers;
if (this._isLayersPresent && this._destinationDocument._catalog._catalogDictionary.has('OCProperties')) {
var destinationOCProperties = this._destinationDocument._catalog._catalogDictionary.get('OCProperties');
var currentOCProperties = ocProperties.get('OCProperties');
if (destinationOCProperties.has('OCGs')) {
var ocgs = destinationOCProperties.get('OCGs'); // eslint-disable-line
var Cocgs = currentOCProperties.get('OCGs'); // eslint-disable-line
if (ocgs.length > 0) {
ocgs.push.apply(ocgs, Cocgs);
}
}
destinationOCProperties._updated = true;
if (destinationOCProperties.has('D') && currentOCProperties.has('D')) {
var curreneDefaultView = destinationOCProperties.get('D');
var existingDefaultView = currentOCProperties.get('D');
if (curreneDefaultView && existingDefaultView) {
if (curreneDefaultView.has('Order') && existingDefaultView.has('Order')) {
var order = curreneDefaultView.get('Order'); // eslint-disable-line
var existingOrder = existingDefaultView.get('Order'); // eslint-disable-line
if (order.length > 0 && existingOrder.length > 0) {
order.push.apply(order, existingOrder);
}
}
else if (existingDefaultView.has('Order')) {
curreneDefaultView.set('Order', existingDefaultView.get('Order'));
}
if (curreneDefaultView.has('RBGroups') && existingDefaultView.has('RBGroups')) {
var groups = curreneDefaultView.get('RBGroups'); // eslint-disable-line
var existingRBGroups = existingDefaultView.get('RBGroups'); // eslint-disable-line
if (groups.length > 0 && existingRBGroups.length > 0) {
groups.push.apply(groups, existingRBGroups);
}
}
else if (existingDefaultView.has('RBGroups')) {
curreneDefaultView.set('RBGroups', existingDefaultView.get('RBGroups'));
curreneDefaultView._updated = true;
}
if (curreneDefaultView.has('ON') && existingDefaultView.has('ON')) {
var on = curreneDefaultView.get('ON'); // eslint-disable-line
var existingON = existingDefaultView.get('ON'); // eslint-disable-line
if (on.length > 0 && existingON.length > 0) {
on.push.apply(on, existingON);
}
}
else if (existingDefaultView.has('ON')) {
curreneDefaultView.set('ON', existingDefaultView.get('ON'));
}
if (curreneDefaultView.has('AS') && existingDefaultView.has('AS')) {
var elements = curreneDefaultView.get('AS'); // eslint-disable-line
var existingElements = existingDefaultView.get('AS'); // eslint-disable-line
if (elements.length > 0 && existingElements.length > 0) {
var asDictionary = existingElements[0];
var currentASDictionary = elements[0];
if (asDictionary instanceof _PdfReference && currentASDictionary instanceof _PdfReference) {
asDictionary = this._crossReference._fetch(asDictionary);
currentASDictionary = this._crossReference._fetch(currentASDictionary);
}
if (asDictionary.has('OCGs') && currentASDictionary.has('OCGs')) {
var usageGroup = asDictionary.get('OCGs'); // eslint-disable-line
var currentUsageGroup = currentASDictionary.get('OCGs'); // eslint-disable-line
if (usageGroup.length > 0 && currentUsageGroup.length > 0) {
currentUsageGroup.push.apply(currentUsageGroup, usageGroup);
}
}
elements.push.apply(elements, existingElements);
}
}
else if (existingDefaultView.has('AS')) {
curreneDefaultView.set('AS', existingDefaultView.get('AS'));
}
if (curreneDefaultView.has('OFF') && existingDefaultView.has('OFF')) {
var off = curreneDefaultView.get('OFF'); // eslint-disable-line
var existingOff = existingDefaultView.get('OFF'); // eslint-disable-line
if (off.length > 0 && existingOff.length > 0) {
off.push.apply(off, existingOff);
}
}
else if (existingDefaultView.has('OFF')) {
curreneDefaultView.set('OFF', existingDefaultView.get('OFF'));
}
}
if (curreneDefaultView.has('Locked') && existingDefaultView.has('Locked')) {
var locked = curreneDefaultView.get('Locked'); // eslint-disable-line
var existingLocked = existingDefaultView.get('Locked'); // eslint-disable-line
if (locked.length > 0 && existingLocked.length > 0) {
locked.push.apply(locked, existingLocked);
}
}
else if (existingDefaultView.has('Locked')) {
curreneDefaultView.set('Locked', existingDefaultView.get('Locked'));
}
}
else if (currentOCProperties.has('D')) {
destinationOCProperties.set('D', currentOCProperties.get('D'));
}
destinationOCProperties._updated = true;
this._destinationDocument._catalog._catalogDictionary._updated = true;
this._crossReference._allowCatalog = true;
}
else if (this._isLayersPresent) {
this._destinationDocument._catalog._catalogDictionary.update('OCProperties', ocProperties.get('OCProperties'));
this._destinationDocument._catalog._catalogDictionary._updated = true;
this._crossReference._allowCatalog = true;
}
};
/**
* Merges layer properties from the source page into the destination page including Properties, XObject, and annotations.
*
* @private
* @param {_PdfDictionary} newPageDictionary The destination page dictionary.
* @param {_PdfDictionary} oldPageDictionary The source page dictionary.
* @param {_PdfCrossReference} crossReference The cross-reference used to dereference objects.
* @returns {void}
*/
_PdfMergeHelper.prototype._mergeLayer = function (newPageDictionary, oldPageDictionary, crossReference) {
var _this = this;
var res = newPageDictionary.get('Resources');
var xobject = res.get('XObject');
var xobjdict; // eslint-disable-line
if (xobject) {
xobject.forEach(function (key, value) {
xobjdict = _this._crossReference._fetch(value);
});
}
var resource;
if (xobjdict) {
resource = xobjdict.dictionary.get('Resources');
}
var XObject; // eslint-disable-line
var oldPageList = new Map();
var oldPageResource = oldPageDictionary.get('Resources');
var layerDictionary; // eslint-disable-line
var dict; // eslint-disable-line
if (oldPageResource.has('Properties')) {
layerDictionary = oldPageResource.get('Properties');
layerDictionary.forEach(function (key, value) {
oldPageList.set(key, value);
});
var properties_1 = new _PdfDictionary(this._crossReference);
oldPageList.forEach(function (value, key) {
_this._newList.forEach(function (layerValue, layerkey) {
if (value === layerkey) {
properties_1.set(key, layerValue);
}
});
});
resource.set('Properties', properties_1);
resource._updated = true;
properties_1._updated = true;
}
else if (oldPageResource.has('XObject')) {
XObject = resource.get('XObject');
layerDictionary = oldPageResource.get('XObject');
layerDictionary.forEach(function (key, value) {
if (value instanceof _PdfReference) {
dict = crossReference._fetch(value);
dict.dictionary.forEach(function (annotationKey, annotationValue) {
if (annotationKey === 'OC') {
_this._newList.forEach(function (layerValue, layerKey) {
if (layerKey === annotationValue) {
if (XObject.has(key)) {
var xobjDictionary = XObject.get(key); // eslint-disable-line
xobjDictionary.dictionary.set(annotationKey, layerValue);
xobjDictionary._updated = true;
}
}
});
}
});
}
});
}
if (this._annotationLayer.size > 0) {
var annotations_1 = newPageDictionary._get('Annots'); // eslint-disable-line
this._annotationLayer.forEach(function (reference, index) {
var pdfAnnotation = annotations_1[index]; // eslint-disable-line
var annotDictionary = _this._crossReference._fetch(pdfAnnotation);
_this._newList.forEach(function (value, oldReference) {
if (reference === oldReference) {
annotDictionary.set('OC', value);
}
});
});
}
};
/**
* Exports collected bookmarks to the destination document, fixing page destinations and named destinations.
*
* @private
* @param {PdfDocument} document The destination document to write bookmarks to.
* @param {number} pageCount The number of pages considered during export.
* @returns {void}
*/
_PdfMergeHelper.prototype._exportBookmarks = function (document, pageCount) {
var _this = this;
if (this._bookmarks.length > 0) {
var bookmark = this._bookmarks;
var currentBase = this._destinationDocument.bookmarks;
var current = document.bookmarks;
var bkCollection = void 0; // eslint-disable-line
if (current) {
var stack = [];
var nodeInformation = { index: 0, base: currentBase, kids: current._bookMarkList };
if (document.pageCount !== pageCount) {
nodeInformation = { index: 0, base: currentBase, kids: bookmark };
bkCollection = [];
}
do {
var _loop_1 = function () {
current = nodeInformation.kids[nodeInformation.index];
if (bookmark.indexOf(current) !== -1 && typeof bkCollection !== 'undefined' && bkCollection.indexOf(current.title) === -1) {
var bm = current;
var newBm = currentBase.add(bm.title);
var dest = bm.destination;
newBm.color = bm.color;
newBm.textStyle = bm.textStyle;
var newDest = null;
var newPage_1 = null;
var page_1 = null;
var nDest = bm.namedDestination;
if (nDest) {
if (nDest.destination) {
page_1 = nDest.destination.page;
this_1._bookmarksPageLinkReference.forEach(function (value, key) {
if (page_1._ref === key) {
newPage_1 = _this._destinationDocument.getPage(value);
}
});
if (newPage_1) {
var newNameddest = this_1._getNamedDestination(nDest, newPage_1);
newBm.namedDestination = newNameddest;
delete newBm._dictionary._map.C;
this_1._namedDestinations.push(newNameddest._title);
var reference_1 = this_1._crossReference._getNextReference();
this_1._crossReference._cacheMap.set(reference_1, newNameddest._dictionary);
this_1._namedDestinations.push(reference_1);
}
}
}
else if (dest) {
page_1 = dest.page;
this_1._bookmarksPageLinkReference.forEach(function (value, key) {
if (page_1._ref === key) {
newPage_1 = _this._destinationDocument.getPage(value);
}
});
if (newPage_1) {
newDest = new PdfDestination(newPage_1, dest.location);
newDest.mode = dest.mode;
newDest.zoom = dest.zoom;
newDest.location = dest.location;
newBm.destination = newDest;
}
}
currentBase = newBm;
bkCollection.push(newBm.title);
}
else if (typeof bkCollection === 'undefined' || (typeof bkCollection !== 'undefined' && bkCollection.indexOf(current.title) === -1)) {
var bm = current;
var dest = bm.destination;
var newDest = null;
var newpage_1 = null;
var page_2 = null;
var nDest = bm.namedDestination;
if (document.pageCount === pageCount) {
var newBm = currentBase.add(bm.title);
if (bm._dictionary.has('A')) {
newBm._dictionary.update('A', bm._dictionary.get('A'));
}
newBm.textStyle = bm.textStyle;
newBm.color = bm.color;
if (nDest) {
if (nDest._destination) {
page_2 = nDest.destination.page;
this_1._bookmarksPageLinkReference.forEach(function (value, key) {
if (page_2._ref === key) {
newpage_1 = _this._destinationDocument.getPage(value);
}
});
if (newpage_1) {
var newNameddest = this_1._getNamedDestination(nDest, newpage_1);
newBm.namedDestination = newNameddest;
delete newBm._dictionary._map.C;
this_1._namedDestinations.push(newNameddest._title);
var reference_2 = this_1._crossReference._getNextReference();
this_1._crossReference._cacheMap.set(reference_2, newNameddest._dictionary);
this_1._namedDestinations.push(reference_2);
}
}
}
else if (dest) {
page_2 = dest.page;
this_1._bookmarksPageLinkReference.forEach(function (value, key) {
if (page_2._ref === key) {
newpage_1 = _this._destinationDocument.getPage(value);
}
});
if (newpage_1) {
newDest = new PdfDestination(newpage_1, dest.location);
newDest.mode = dest.mode;
newDest.zoom = dest.zoom;
newDest.location = dest.location;
newBm.destination = newDest;
}
}
currentBase = newBm;
}
}
nodeInformation.index += 1;
if (current.count > 0) {
stack.push(nodeInformation);
nodeInformation = { index: 0, base: currentBase, kids: current._bookMarkList };
}
else {
currentBase = nodeInformation.base;
}
};
var this_1 = this;
for (; nodeInformation.index < nodeInformation.kids.length;) {
_loop_1();
}
if (stack.length > 0) {
nodeInformation = stack.pop();
while ((nodeInformation.index === nodeInformation.kids.length) && (stack.length > 0)) {
nodeInformation = stack.pop();
}
currentBase = nodeInformation.base;
}
} while (nodeInformation.index < nodeInformation.kids.length);
}
var reference = void 0;
if (this._namedDestinations.length > 0) {
var dictionary = new _PdfDictionary(this._crossReference);
dictionary.update('Names', this._namedDestinations);
reference = this._crossReference._getNextReference();
this._crossReference._cacheMap.set(reference, dictionary);
dictionary = new _PdfDictionary(this._crossReference);
dictionary.update('Dests', reference);
reference = this._crossReference._getNextReference();
this._crossReference._cacheMap.set(reference, dictionary);
this._destinationDocument._catalog._catalogDictionary.set('Names', reference);
}
this._destinationDocument._catalog._catalogDictionary._updated = true;
this._destinationDocument._catalog._catalogDictionary.isCatalog = true;
this._crossReference._allowCatalog = true;
}
};
/**
* Creates a new named destination mapped to a new page based on an existing named destination.
*
* @private
* @param {PdfNamedDestination} nDest The source named destination.
* @param {PdfPage} page The destination page to associate with.
* @returns {PdfNamedDestination} The cloned named destination with updated page reference.
*/
_PdfMergeHelper.prototype._getNamedDestination = function (nDest, page) {
var newNamedDest = new PdfNamedDestination(nDest.title); // eslint-disable-line
newNamedDest.destination = this._getDestination(page, nDest.destination);
return newNamedDest;
};
/**
* Clones a destination for a different page while preserving mode, zoom, and location.
*
* @private
* @param {PdfPage} page The new page for the destination.
* @param {PdfDestination} dest The original destination to copy.
* @returns {PdfDestination} The new destination that targets the given page.
*/
_PdfMergeHelper.prototype._getDestination = function (page, dest) {
var newDest = new PdfDestination(page, dest.location);
newDest._location = dest._location;
newDest.mode = dest.mode;
newDest.zoom = dest.zoom;
newDest.location = dest.location;
return newDest;
};
/**
* Serializes a PDF object (primitive, array, dictionary, or reference) into a target container.
*
* @private
* @param {PdfDocument} document The document being written to.
* @param {_PdfDictionary} [table] The destination dictionary when writing key/value pairs.
* @param {any} [value] The value to serialize. // eslint-disable-line
* @param {_PdfDictionary} [dictionary] The current context dictionary used for dereferencing.
* @param {string} [key] The key under which to store the value in the table.
* @param {any[]} [array] The destination array when writing list entries. // eslint-disable-line
* @param {_PdfReference} [ref] Optional reference handle for object mapping.
* @returns {void}
*/
_PdfMergeHelper.prototype._writeObject = function (document, table, value, dictionary, key, array, ref) {
if (value instanceof _PdfName || typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
this._writeDictionary(value, table, key, array, ref, null);
}
else if (Array.isArray(value)) {
var list = []; // eslint-disable-line
this._writeArray(document, list, value, dictionary);
this._writeDictionary(null, table, key, array, ref, list);
}
else if (value instanceof _PdfDictionary) {
var subTable = new _PdfDictionary(this._crossReference);
this._writePropertiesDictionary(document, subTable, value);
this._writeDictionary(null, table, key, array, ref, subTable);
}
else if (value instanceof _PdfReference && this._crossReference) {
this._writeObject(document, table, document._crossReference._fetch(value), dictionary, key, array, value);
}
else if (value === null || typeof value === 'undefined') {
this._writeDictionary('null', table, key, array, ref, null);
}
};
/**
* Writes a key/value or list into a dictionary or array, managing reference remapping for layers.
*
* @private
* @param {any} value The primitive value to write, if any. // eslint-disable-line
* @param {_PdfDictionary} table The destination dictionary for key/value pairs.
* @param {string} key The key name for dictionary insertion.
* @param {any[]} array The destination array when writing list entries. // eslint-disable-line
* @param {_PdfReference} ref The reference used to map or replace objects.
* @param {any[]|_PdfDictionary} list The serialized list or sub-dictionary being written. // eslint-disable-line
* @returns {void}
*/
_PdfMergeHelper.prototype._writeDictionary = function (value, table, key, array, ref, list) {
if (key && value) {
table.set(key, value);
}
else if (key && list) {
table.set(key, list);
}
else if (list && !ref) {
array.push(list);
}
else if (value) {
array.push(value);
}
else if (ref) {
var reference_3;
if (this._newList && this._newList.size > 0) {
this._newList.forEach(function (value, key) {
if (key === ref) {
reference_3 = value;
}
});
}
if (reference_3) {
array.push(reference_3);
}
else {
var layerList = list;
reference_3 = this._crossReference._getNextReference();
this._crossReference._cacheMap.set(reference_3, layerList);
layerList._updated = true;
array.push(reference_3);
this._newList.set(ref, reference_3);
}
}
};
/**
* Serializes an array of PDF objects into a destination list.
*
* @private
* @param {PdfDocument} document The document being written to.
* @param {any[]} array The destination list to receive serialized items. // eslint-disable-line
* @param {any[]} value The source array to serialize. // eslint-disable-line
* @param {_PdfDictionary} dictionary The context dictionary used for dereferencing.
* @returns {void}
*/
_PdfMergeHelper.prototype._writeArray = function (document, array, value, dictionary) {
for (var i = 0, len = value.length; i < len; i++) {
this._writeObject(document, null, value[i], dictionary, null, array);
}
};
/**
* Writes all properties from a source dictionary into a destination dictionary, dereferencing references when needed.
*
* @private
* @param {PdfDocument} document The document being written to.
* @param {_PdfDictionary} table The destination dictionary to populate.
* @param {_PdfDictionary} dictionary The source dictionary whose entries will be serialized.
* @returns {void}
*/
_PdfMergeHelper.prototype._writePropertiesDictionary = function (document, table, dictionary) {
var _this = this;
if (dictionary && dictionary.size > 0) {
dictionary.forEach(function (key, value) {
_this._writeObject(document, table, ((value instanceof _PdfReference) ? dictionary.get(key) : value), dictionary, key);
});
}
};
/**
* Fixes stored destinations to point to the newly created page references after import.
*
* @private
* @param {PdfDocument} document The destination document to resolve references against.
* @returns {void}
*/
_PdfMergeHelper.prototype._fixDestinations = function (document) {
var pageLinkReference = this._pageReference;
if (this._destination.length > 0) {
this._destination.forEach(function (dest) {
if (dest instanceof Array) {
var destination = dest; // eslint-disable-line
if (destination.length > 0 && destination[0] && destination[0] instanceof _PdfReference) {
var ref = document._crossReference._fetch(destination[0]); // eslint-disable-line
var index = pageLinkReference.get(ref);
if (ref && pageLinkReference.has(ref) && index !== null) {
destination[0] = index._ref;
}
if (ref && pageLinkReference.has(ref) && index === null) {
destination[0] = null;
}
}
}
});
}
};
/**
* Inserts a new page in the destination document mirroring size, boxes, margins, orientation, and rotation from the source.
*
* @private
* @param {PdfPage} page The source page to mirror.
* @param {number} [index] Optional insertion index.
* @returns {PdfPage} The newly created destination page.
*/
_PdfMergeHelper.prototype._insertNewPage = function (page, index) {
var newPage;
var pagesettings = new PdfPageSettings();
pagesettings.size = page.size;
pagesettings.margins.left = 0;
pagesettings.margins.top = 0;
pagesettings.margins.right = 0;
pagesettings.margins.bottom = 0;
if (typeof this._options !== 'undefined' && typeof this._options.rotation !== 'undefined') {
pagesettings.rotation = this._options.rotation;
}
else {
pagesettings.rotation = page.rotation;
}
pagesettings.orientation = (page.size.width > page.size.height) ? PdfPageOrientation.landscape : PdfPageOrientation.portrait;
if (typeof index !== 'undefined') {
newPage = this._destinationDocument.addPage(index, pagesettings);
}
else {
newPage = this._destinationDocument.addPage(pagesettings);
}
var pageDictionary = page._pageDictionary;
if (pageDictionary._get('MediaBox')) {
var mBox = pageDictionary._get('MediaBox'); // eslint-disable-line
newPage._pageDictionary.update('MediaBox', mBox);
}
if (pageDictionary._get('CropBox')) {
var cBox = pageDictionary._get('CropBox'); // eslint-disable-line
newPage._pageDictionary.update('CropBox', cBox);
}
if (typeof this._options.rotation !== 'undefined' || page._pageDictionary.has('Rotate')) {
var rotate = void 0;
if (typeof this._options.rotation !== 'undefined') {
rotate = Math.floor(this._options.rotation) * 90;
}
else {
rotate = Math.floor(page.rotation) * 90;
}
rotate = rotate >= 360 ? rotate % 360 : rotate;
newPage._pageDictionary.update('Rotate', rotate);
}
return newPage;
};
/**
* Disposes internal state and temporary collections used during import/merge operations.
*
* @private
* @returns {void}
*/
_PdfMergeHelper.prototype._objectDispose = function () {
this._bookmarkHashTable = new Map();
this._namedDestinations = [];
this._bookmarks = [];
this._pageReference = new Map();
this._bookmarksPageLinkReference.clear();
this._destination = [];
this._newList = new Map();
this._annotationLayer = new Map();
this._fieldNames = [];
if (this._destinationDocument && this._destinationDocument._form && this._destinationDocument._form._widgetReferences) {
this._destinationDocument._form._widgetReferences = [];
}
};
return _PdfMergeHelper;
}());
export { _PdfMergeHelper };
/**
* Provides low-level object copying helpers for PDF structures, including dictionaries, arrays, streams, and references.
*
* @private
*/
var _PdfCopier = /** @class */ (function () {
/**
* Initializes a new copier with target and source cross reference tables.
*
* @private
* @param {_PdfCrossReference} targetCrossReference The destination cross-reference table.
* @param {_PdfCrossReference} sourceCrossReference The source cross-reference table.
*/
function _PdfCopier(targetCrossReference, sourceCrossReference) {
/**
* Tracks source-to-destination reference mappings to avoid duplicate cloning.
*
* @private
*/
this._traversedObjects = new Map();
/**
* Indicates whether grouping support is enabled during copy operations.
*
* @private
*/
this._isGroupingSupport = false;
this._targetCrossReference = targetCrossReference;
this._sourceCrossReference = sourceCrossReference;
}
/**
* Copies a PDF object depending on its type, returning a copied value or mapped reference.
*
* @private
* @param {any} object The object to copy.
* @returns {any} The copied object or target reference.
*/
_PdfCopier.prototype._copy = function (object) {
var clonedObject; // eslint-disable-line
if (object instanceof _PdfDictionary) {
clonedObject = this._copyDictionary(object);
}
else if (Array.isArray(object)) {
clonedObject = this._copyArray(object);
}
else if (object instanceof _PdfBaseStream) {
clonedObject = this._copyStream(object);
}
else if (object instanceof _PdfReference) {
clonedObject = this._copyReference(object);
}
else if (object instanceof _PdfName || typeof object === 'number' ||
typeof object === 'string' || typeof object === 'boolean') {
clonedObject = object;
}
return clonedObject;
};
/**
* Copies a dictionary and its entries, with optional handling for appearance dictionaries when copying pages.
*
* @private
* @param {_PdfDictionary} element The dictionary to copy from the source cross reference.
* @param {boolean} [copiedPage] Indicates whether the dictionary belongs to a page copy.
* @returns {_PdfDictionary} The cloned dictionary in the target context.
*/
_PdfCopier.prototype._copyDictionary = function (element, copiedPage) {
var _this = this;
var clonedDictionary = new _PdfDictionary(this._targetCrossReference);
if (element && element.size > 0) {
element.forEach(function (key, value) {
if (key === 'OC' && value instanceof Array || (key !== 'P' && key !== 'Parent' && key !== 'Dest' && key !== 'OC' && !(key === 'AP' && copiedPage))) {
var copiedValue = _this._copy(value); // eslint-disable-line
if (copiedValue !== null && typeof copiedValue !== 'undefined') {
clonedDictionary.update(key, copiedValue);
}
}
});
}
clonedDictionary._updated = true;
return clonedDictionary;
};
/**
* Deep-copies an array by copying each element into the target context.
*
* @private
* @param {any[]} originalArray The array to copy.
* @returns {any[]} The copied array.
*/
_PdfCopier.prototype._copyArray = function (originalArray) {
var newArray = []; // eslint-disable-line
for (var i = 0, len = originalArray.length; i < len; i++) {
newArray.push(this._copy(originalArray[i]));
}
return newArray;
};
/**
* Copies a base stream or content stream, preserving bytes and cloning its dictionary.
*
* @private
* @param {_PdfBaseStream} originalStream The source stream to copy.
* @returns {_PdfBaseStream} The cloned content stream in the target context.
*/
_PdfCopier.prototype._copyStream = function (originalStream) {
var bytes;
var imageStream = false;
var baseStream = originalStream; // eslint-disable-line
if (originalStream.dictionary.has('Subtype') && originalStream.dictionary.get('Subtype').name === 'Image') {
imageStream = true;
if (originalStream instanceof _PdfStream) {
bytes = originalStream.getByteRange(originalStream.offset, originalStream.end);
}
else if (originalStream && baseStream.stream && baseStream.stream instanceof _PdfStream) {
if (typeof baseStream._initialized === 'boolean' && baseStream._cipher) {
var streamLength = baseStream.stream.end - baseStream.stream.start;
baseStream.getBytes(streamLength);
bytes = baseStream.buffer.subarray(0, baseStream.bufferLength);
}
else {
var stream = baseStream.stream;
bytes = stream.getByteRange(stream.start, stream.end);
}
}
else if (baseStream.stream && baseStream.stream.stream) {
var flateStream = baseStream.stream; // eslint-disable-line
if (flateStream.stream instanceof _PdfStream && typeof flateStream._initialized === 'boolean' && flateStream._cipher) {
var streamLength = flateStream.stream.end - flateStream.stream.start;
flateStream.getBytes(streamLength);
bytes = flateStream.buffer.subarray(0, flateStream.bufferLength);
}
else if (flateStream.stream && flateStream.stream instanceof _PdfStream) {
var stream = flateStream.stream;
bytes = stream.getByteRange(stream.start, stream.end);
}
else {
bytes = [];
}
}
else {
bytes = originalStream.getBytes();
if ((!bytes || bytes.length === 0) && originalStream instanceof _PdfContentStream) {
bytes = originalStream._bytes;
}
}
}
else {
bytes = originalStream.getBytes();
if ((!bytes || bytes.length === 0) && originalStream instanceof _PdfContentStream) {
bytes = originalStream._bytes;
}
}
var content = (bytes instanceof Array) ? new _PdfContentStream(bytes)
: new _PdfContentStream(Array.from(bytes));
content._isImage = imageStream;
content.dictionary = this._copyDictionary(originalStream.dictionary);
content.dictionary._updated = true;
return content;
};
/**
* Copies or reuses a reference, ensuring a consistent mapping from source to target references.
*
* @private
* @param {_PdfReference} element The source reference to copy.
* @returns {any} The new reference or copied value for non-container objects. // eslint-disable-line
*/
_PdfCopier.prototype._copyReference = function (element) {
if (this._traversedObjects.has(element)) {
return this._traversedObjects.get(element);
}
else {
this._traversedObjects.set(element, null);
var dereferencedValue = this._sourceCrossReference._fetch(element); // eslint-disable-line
var copyValue = this._copy(dereferencedValue); // eslint-disable-line
if (copyValue instanceof _PdfDictionary || copyValue instanceof _PdfBaseStream) {
var newRef = this._addToDestination(copyValue);
this._traversedObjects.set(element, newRef);
return newRef;
}
else {
this._traversedObjects.set(element, copyValue);
return copyValue;
}
}
};
/**
* Adds a copied object to the target cross reference and returns its newly created reference.
*
* @private
* @param {any} element The dictionary or stream to add. // eslint-disable-line
* @returns {_PdfReference} The new reference pointing to the added object.
*/
_PdfCopier.prototype._addToDestination = function (element) {
var newRef = this._targetCrossReference._getNextReference();
this._targetCrossReference._cacheMap.set(newRef, element);
element.objId = newRef.objectNumber + " " + newRef.generationNumber;
return newRef;
};
return _PdfCopier;
}());
export { _PdfCopier };