@syncfusion/ej2-pdf
Version:
Feature-rich JavaScript PDF library with built-in support for loading and manipulating PDF document.
6,035 lines • 195 kB
JavaScript
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
import { _PdfDictionary, _PdfName, _PdfReference } from './pdf-primitives';
import { PdfFormFieldVisibility, PdfAnnotationFlag, PdfCheckBoxStyle, PdfHighlightMode, PdfBorderStyle, PdfBorderEffectStyle, PdfLineEndingStyle, _PdfCheckFieldState, PdfMeasurementUnit, _PdfGraphicsUnit, PdfTextMarkupAnnotationType, PdfRotationAngle, PdfAnnotationState, PdfAnnotationStateModel, PdfPopupIcon, PdfRubberStampAnnotationIcon, PdfAttachmentIcon, PdfAnnotationIntent, PdfBlendMode, _PdfAnnotationType, PdfNumberStyle, PdfDashStyle } from './enumerator';
import { _TagClassType, _ConstructionType, _UniversalType } from './security/digital-signature/asn1/enumerator';
import { _PdfTransformationMatrix } from './graphics/pdf-graphics';
import { _PdfBaseStream, _PdfStream } from './base-stream';
import { PdfAnnotation, PdfLineAnnotation, PdfRedactionAnnotation, PdfRubberStampAnnotation } from './annotations/annotation';
import { PdfTemplate } from './graphics/pdf-template';
import { PdfField, PdfTextBoxField, PdfComboBoxField } from './form/field';
import { PdfCjkFontFamily, PdfCjkStandardFont, PdfFontFamily, PdfFontStyle, PdfStandardFont, PdfTrueTypeFont } from './fonts/pdf-standard-font';
import { _JpegDecoder } from './graphics/images/jpeg-decoder';
import { _PngDecoder } from './graphics/images/png-decoder';
import { CompressedStreamWriter } from '@syncfusion/ej2-compression';
import { _PdfFontMetrics, _StandardWidthTable } from './fonts/pdf-font-metrics';
/**
* Gets the unsigned value.
*
* @private
* @param {number} value input value.
* @param {number} bits bits to process.
* @returns {number} unsigned value.
*/
export function _toUnsigned(value, bits) {
return (value & ((Math.pow(2, bits)) - 1));
}
/**
* Gets the signed 16 bit value.
*
* @private
* @param {number} value input value.
* @returns {number} unsigned value.
*/
export function _toSigned16(value) {
return (value << 16) >> 16;
}
/**
* Copy values from one array to another.
*
* @private
* @param {number[]} target destination array.
* @param {number} at target index.
* @param {number[]} source source array.
* @param {number} start start index.
* @param {number} end end index.
* @returns {void} Returns nothing.
*/
export function _copyRange(target, at, source, start, end) {
if (start === void 0) { start = 0; }
if (end === void 0) { end = source.length; }
start = Math.max(0, Math.min(source.length, start));
end = Math.max(0, Math.min(source.length, end));
var length = end - start;
target.length = Math.max(target.length, at + length);
for (var i = 0; i < length; i++) {
target[at + i] = source[start + i];
}
}
/**
* Checks the type of the image using header bytes.
*
* @private
* @param {Uint8Array} imageData image data.
* @param {number[]} header header bytes.
* @returns {boolean} Header matched or not.
*/
export function _checkType(imageData, header) {
return header.every(function (value, index) { return value === imageData[index]; });
}
/**
* Gets the image decoder.
*
* @private
* @param {Uint8Array} imageData image data.
* @returns {_ImageDecoder} Image decoder.
*/
export function _getDecoder(imageData) {
var decoder;
if (_checkType(imageData, [255, 216])) {
decoder = new _JpegDecoder(imageData);
}
else if (_checkType(imageData, [137, 80, 78, 71, 13, 10, 26, 10])) {
decoder = new _PngDecoder(imageData);
}
else {
throw new Error('Unsupported image format');
}
return decoder;
}
/**
* Gets the page rotation.
*
* @private
* @param {PdfPage} page Page.
* @param {number} height Height.
* @param {number} left Left.
* @returns {number} Page rotation.
*/
export function _checkRotation(page, height, left) {
var topValue = 0;
left = (typeof left === 'undefined' || left === null) ? 0 : left;
if (page.rotation === PdfRotationAngle.angle90) {
topValue = (typeof height === 'undefined' || height === null) ? 0 : left;
}
else if (page.rotation === PdfRotationAngle.angle180) {
topValue = (typeof height === 'undefined' || height === null) ? 0 : height;
}
else if (page.rotation === PdfRotationAngle.angle270) {
var size = page.size;
topValue = (typeof height === 'undefined' || height === null) ? 0 : size.width - left;
}
return topValue;
}
/**
* Gets the page index.
*
* @private
* @param {PdfDocument} loadedDocument Loaded document.
* @param {_PdfDictionary} pageDictionary Page dictionary.
* @returns {number} Page index.
*/
export function _getPageIndex(loadedDocument, pageDictionary) {
var index = -1;
if (pageDictionary && pageDictionary instanceof _PdfDictionary) {
for (var i = 0; i < loadedDocument.pageCount; i++) {
var page = loadedDocument.getPage(i);
if (page && page._pageDictionary && (page._pageDictionary === pageDictionary ||
page._pageDictionary.objId === pageDictionary.objId)) {
index = i;
break;
}
}
}
return index;
}
/**
* Convert string value from annotation flag
*
* @private
* @param {PdfAnnotationFlag} flag Annotation flag.
* @returns {string} Valid string to write into XML.
*/
export function _annotationFlagsToString(flag) {
var values = [];
if ((flag & PdfAnnotationFlag.hidden) !== 0) {
values.push('hidden');
}
if ((flag & PdfAnnotationFlag.invisible) !== 0) {
values.push('invisible');
}
if ((flag & PdfAnnotationFlag.locked) !== 0) {
values.push('locked');
}
if ((flag & PdfAnnotationFlag.noRotate) !== 0) {
values.push('norotate');
}
if ((flag & PdfAnnotationFlag.noView) !== 0) {
values.push('noview');
}
if ((flag & PdfAnnotationFlag.noZoom) !== 0) {
values.push('nozoom');
}
if ((flag & PdfAnnotationFlag.print) !== 0) {
values.push('print');
}
if ((flag & PdfAnnotationFlag.readOnly) !== 0) {
values.push('readonly');
}
if ((flag & PdfAnnotationFlag.toggleNoView) !== 0) {
values.push('togglenoview');
}
if ((flag & PdfAnnotationFlag.default) !== 0) {
values.push('default');
}
return values.join(',');
}
/**
* Convert string value to annotation flag
*
* @private
* @param {string} flag String value to map
* @returns {PdfAnnotationFlag} Annotation flag
*/
export function _stringToAnnotationFlags(flag) {
switch (flag) {
case 'hidden':
return PdfAnnotationFlag.hidden;
case 'invisible':
return PdfAnnotationFlag.invisible;
case 'locked':
return PdfAnnotationFlag.locked;
case 'norotate':
return PdfAnnotationFlag.noRotate;
case 'noview':
return PdfAnnotationFlag.noView;
case 'nozoom':
return PdfAnnotationFlag.noZoom;
case 'print':
return PdfAnnotationFlag.print;
case 'readonly':
return PdfAnnotationFlag.readOnly;
case 'togglenoview':
return PdfAnnotationFlag.toggleNoView;
default:
return PdfAnnotationFlag.default;
}
}
/**
* Convert string value to byte array
*
* @private
* @param {string} value string value.
* @returns {string} Valid string to write into PDF.
*/
export function _stringToPdfString(value) {
if (typeof value === 'string' && value.length > 0 && value.charCodeAt(0) >= '\xEF'.charCodeAt(0)) {
var encoding = void 0;
if (value[0] === '\xEF' && value[1] === '\xBB' && value[2] === '\xBF') {
encoding = 'utf-8';
}
else if (value[0] === '\xFF' && value[1] === '\xFE') {
encoding = 'utf-16le';
}
else if (value[0] === '\xFE' && value[1] === '\xFF') {
encoding = 'utf-16be';
}
if (encoding) {
try {
return (new TextDecoder(encoding, { fatal: true })).decode(_stringToBytes(value));
}
catch (e) { } // eslint-disable-line
}
}
var buffer = [];
var translateTable = [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x2d8,
0x2c7, 0x2c6, 0x2d9, 0x2dd, 0x2db, 0x2da, 0x2dc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0x2022, 0x2020, 0x2021, 0x2026, 0x2014, 0x2013, 0x192,
0x2044, 0x2039, 0x203a, 0x2212, 0x2030, 0x201e, 0x201c, 0x201d, 0x2018,
0x2019, 0x201a, 0x2122, 0xfb01, 0xfb02, 0x141, 0x152, 0x160, 0x178, 0x17d,
0x131, 0x142, 0x153, 0x161, 0x17e, 0, 0x20ac
];
for (var i = 0; i < value.length; i++) {
var code = translateTable[value.charCodeAt(i)];
buffer.push(code ? String.fromCharCode(code) : value.charAt(i));
}
return buffer.join('');
}
/**
* Convert string value to byte array
*
* @private
* @param {string} value string value.
* @param {boolean} isDirect Whether to return a number[] or Uint8Array.
* @param {boolean} isPassword Whether the string is a password.
* @param {number[]} destination Destination array.
* @returns {number[] | Uint8Array} Byte array
*/
export function _stringToBytes(value, isDirect, isPassword, destination) {
if (isDirect === void 0) { isDirect = false; }
if (isPassword === void 0) { isPassword = false; }
if (isPassword) {
var len = value.length;
if (destination) {
for (var i = 0; i < len; i++) {
destination.push(value.charCodeAt(i));
}
return destination;
}
var out = new Uint8Array(len);
for (var i = 0; i < len; i++) {
out[i] = value.charCodeAt(i);
}
return isDirect ? Array.from(out) : out;
}
var byteLength = 0;
for (var i = 0; i < value.length; i++) {
var c = value.charCodeAt(i);
if (c < 0x80) {
byteLength += 1;
}
else if (c < 0x800) {
byteLength += 2;
}
else if (c < 0xD800 || c >= 0xE000) {
byteLength += 3;
}
else {
i++;
byteLength += 4;
}
}
var buffer = new Uint8Array(byteLength);
var offset = 0;
for (var i = 0; i < value.length; i++) {
var c = value.charCodeAt(i);
if (c < 0x80) {
buffer[offset++] = c;
}
else if (c < 0x800) {
buffer[offset++] = (c >> 6) | 0xC0;
buffer[offset++] = (c & 0x3F) | 0x80;
}
else if (c < 0xD800 || c >= 0xE000) {
buffer[offset++] = (c >> 12) | 0xE0;
buffer[offset++] = ((c >> 6) & 0x3F) | 0x80;
buffer[offset++] = (c & 0x3F) | 0x80;
}
else {
i++;
c = 0x10000 + (((c & 0x3FF) << 10) | (value.charCodeAt(i) & 0x3FF));
buffer[offset++] = (c >> 18) | 0xF0;
buffer[offset++] = ((c >> 12) & 0x3F) | 0x80;
buffer[offset++] = ((c >> 6) & 0x3F) | 0x80;
buffer[offset++] = (c & 0x3F) | 0x80;
}
}
if (destination) {
for (var i = 0; i < buffer.length; i++) {
destination.push(buffer[i]);
}
return destination;
}
return isDirect ? Array.from(buffer) : buffer;
}
/**
* Check equal or not.
*
* @private
* @param {Uint8Array | number[]} first byte array.
* @param {Uint8Array | number[]} second byte array.
* @returns {boolean} Equal or not
*/
export function _areArrayEqual(first, second) {
return first.length === second.length && first.every(function (val, i) { return val === second[i]; });
}
/**
* Check whether entries in points are equal or not.
*
* @private
* @param {Point[]} a first point array.
* @param {Point[]} b second point array.
* @returns {boolean} Return true if for each elements are equal in both point array.
*/
export function _arePointsEqual(a, b) {
if (a.length !== b.length) {
return false;
}
return a.every(function (p, i) { return p.x === b[i].x && p.y === b[i].y; });
}
/**
* Convert number to string as round value with fixed decimal points 2.
*
* @private
* @param {number} value number value.
* @returns {boolean} Equal string.
*/
export function _numberToString(value) {
if (Number.isInteger(value)) {
return value.toString();
}
return value.toFixed(7);
}
/**
* Check whether entries in two array are equal or not.
*
* @private
* @param {number[]} value first array.
* @param {number[]} current second array.
* @returns {boolean} Return true if for each elements are equal in both array.
*/
export function _areNotEqual(value, current) {
var result = false;
if (value.length !== current.length) {
return true;
}
for (var i = 0; i < value.length; i++) {
if (value[i] !== current[i]) { // eslint-disable-line
result = true;
break;
}
}
return result;
}
/**
* Check whether entries in points are equal or not.
*
* @private
* @param {Point[]} value first point array.
* @param {Point[]} current second point array.
* @returns {boolean} Return true if for each elements are equal in both point array.
*/
export function _arePointsNotEqual(value, current) {
if (value.length !== current.length) {
return true;
}
for (var i = 0; i < value.length; i++) {
if (value[i].x !== current[i].x || value[i].y !== current[i].y) {
return true;
}
}
return false;
}
/**
* Process bytes and convert as string.
*
* @private
* @param {Uint8Array} bytes Input data.
* @param {boolean} isJson Whether is json or xfdf.
* @returns {string} String value processed from input bytes.
*/
export function _bytesToString(bytes, isJson) {
if (isJson === void 0) { isJson = false; }
if (!bytes || bytes.length === 0) {
return '';
}
if (isJson) {
return _decodeUnicodeBytes(bytes);
}
var chunk = 8192;
var result = '';
for (var i = 0; i < bytes.length; i += chunk) {
var end = i + chunk < bytes.length ? i + chunk : bytes.length;
result += String.fromCharCode.apply(null, bytes.subarray(i, end));
}
return result;
}
/**
* Decodes encoded name values by converting hexadecimal Unicode escape sequences into corresponding characters.
*
* @private
* @param {string} name Encoded name string.
* @returns {string} Decoded string.
*/
export function _decodeName(name) {
if (!name || name.length === 0) {
return name;
}
var pattern = /_[Xx]([0-9A-Fa-f]{4}|[0-9A-Fa-f]{8})_/g;
return name.replace(pattern, function (_match, hex) {
var codePoint = parseInt(hex, 16);
if (isNaN(codePoint)) {
return _match;
}
if (codePoint <= 0xFFFF) {
return String.fromCharCode(codePoint);
}
var code = codePoint - 0x10000;
var high = 0xd800 + (code >> 10);
var low = 0xdc00 + (code & 0x3ff);
return String.fromCharCode(high, low);
});
}
/**
* Decode unicode string.
*
* @private
* @param {Uint8Array} bytes Input data.
* @returns {string} String value processed from input bytes.
*/
export function _decodeUnicodeBytes(bytes) {
var len = bytes.length;
if (len === 0) {
return '';
}
var chunk = 4096;
var result = '';
var codeUnits = new Uint16Array(chunk);
var i = 0;
var cuIndex = 0;
while (i < len) {
var byte1 = bytes[i++];
if (byte1 < 0x80) {
codeUnits[cuIndex++] = byte1;
}
else if (byte1 < 0xE0) {
codeUnits[cuIndex++] =
((byte1 & 0x1F) << 6) |
(bytes[i++] & 0x3F);
}
else if (byte1 < 0xF0) {
codeUnits[cuIndex++] =
((byte1 & 0x0F) << 12) |
((bytes[i++] & 0x3F) << 6) |
(bytes[i++] & 0x3F);
}
else {
var codePoint = ((byte1 & 0x07) << 18) |
((bytes[i++] & 0x3F) << 12) |
((bytes[i++] & 0x3F) << 6) |
(bytes[i++] & 0x3F) -
0x10000;
codeUnits[cuIndex++] = (codePoint >> 10) + 0xD800;
codeUnits[cuIndex++] = (codePoint & 0x03FF) + 0xDC00;
}
if (cuIndex >= chunk - 2) {
result += String.fromCharCode.apply(null, codeUnits.subarray(0, cuIndex));
cuIndex = 0;
}
}
if (cuIndex > 0) {
result += String.fromCharCode.apply(null, codeUnits.subarray(0, cuIndex));
}
return result;
}
/**
* Convert string to unicode array.
*
* @private
* @param {string} value string value.
* @returns {Uint8Array} unicode array
*/
export function _stringToUnicodeArray(value) {
var output = [];
if (value !== null && typeof value !== 'undefined') {
for (var i = 0; i < value.length; i++) {
var code = value.charCodeAt(i);
output.push(code / 256 >>> 0);
output.push(code & 0xff);
}
}
var unicodeArray = new Uint8Array(output);
return unicodeArray;
}
/**
* Convert byte array to hex string.
*
* @private
* @param {Uint8Array} byteArray Byte array.
* @returns {string} Hex string.
*/
export function _byteArrayToHexString(byteArray) {
var hexArray = new Array(256); // eslint-disable-line
for (var i = 0; i < 256; i++) {
var h = i.toString(16).toUpperCase();
hexArray[i] = h.length === 1 ? '0' + h : h;
}
var len = byteArray.length;
if (len === 0) {
return '';
}
var parts = new Array(len);
for (var i = 0; i < len; i++) {
parts[i] = hexArray[byteArray[i]];
}
return parts.join('');
}
/**
* Convert hex string to byte array.
*
* @private
* @param {string} hexString Hex string.
* @param {boolean} isDirect Whether to return object or number[]. Default is false.
* @returns {Uint8Array | number[]} Byte array.
*/
export function _hexStringToByteArray(hexString, isDirect) {
if (isDirect === void 0) { isDirect = false; }
var hexTable = new Int16Array(256).fill(-1);
for (var i = 0; i < 10; i++) {
hexTable[48 + i] = i;
}
for (var i = 0; i < 6; i++) {
hexTable[65 + i] = 10 + i;
hexTable[97 + i] = 10 + i;
}
if (!hexString) {
return isDirect ? [] : new Uint8Array(0);
}
var len = hexString.length >> 1;
var out = new Uint8Array(len);
var j = 0;
for (var i = 0; i < len; i++) {
var high = hexTable[hexString.charCodeAt(j++)];
var low = hexTable[hexString.charCodeAt(j++)];
out[i] = (high << 4) | low;
}
return isDirect ? Array.from(out) : out;
}
/**
* Convert hex string to normal string.
*
* @private
* @param {string} hexString Hex string.
* @returns {string} Normal string.
*/
export function _hexStringToString(hexString) {
var result = '';
if (hexString && hexString[0] === '#') {
hexString = hexString.substring(1);
for (var i = 0; i < hexString.length; i += 2) {
result += String.fromCharCode(parseInt(hexString.substring(i, i + 2), 16));
}
return result;
}
return hexString;
}
/**
* Check whether the character code is white space.
*
* @private
* @param {number} ch The character code to check.
* @returns {boolean} True if the character is space, otherwise false.
*/
export function _isWhiteSpace(ch) {
return ch === 0x20 || ch === 0x09 || ch === 0x0d || ch === 0x0a;
}
/**
* Decode a chunk of base64 string into Uint8Array.
*
* @private
* @param {string} input The base64 string to decode.
* @returns {Uint8Array} Decoded bytes as Uint8Array.
*/
function _decodeChunk(input) {
var key = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
var chr1;
var chr2;
var chr3;
var enc1;
var enc2;
var enc3;
var enc4;
var i = 0;
var resultIndex = 0;
input = input.replace(/[^A-Za-z0-9\+\/\=]/g, ''); // eslint-disable-line
var totalLength = input.length * 3 / 4;
if (input.charAt(input.length - 1) === key.charAt(64)) {
totalLength--;
}
var output = new Array(totalLength | 0);
while (i < input.length) {
enc1 = key.indexOf(input.charAt(i++));
enc2 = key.indexOf(input.charAt(i++));
enc3 = key.indexOf(input.charAt(i++));
enc4 = key.indexOf(input.charAt(i++));
chr1 = (enc1 << 2) | (enc2 >> 4);
chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
chr3 = ((enc3 & 3) << 6) | enc4;
if (resultIndex < totalLength) {
output[resultIndex++] = chr1;
}
if (resultIndex < totalLength) {
output[resultIndex++] = chr2;
}
if (resultIndex < totalLength) {
output[resultIndex++] = chr3;
}
}
return new Uint8Array(output);
}
/**
* Decode bytes from base64 string.
*
* @private
* @param {string} input The base64 string to decode.
* @param {boolean} isDirect Whether to return object or number[]. Default is false.
* @returns {Uint8Array | number[]} Decoded bytes.
*/
export function _decode(input, isDirect) {
if (isDirect === void 0) { isDirect = false; }
var chunkSize = 3000000;
if (input.length >= chunkSize) {
input = input.replace(/[^A-Za-z0-9+/=]/g, '');
var outputChunks = [];
var totalLength = 0;
for (var i = 0; i < input.length; i += chunkSize) {
var chunk = input.substring(i, i + chunkSize);
var decodedChunk = _decodeChunk(chunk);
outputChunks.push(decodedChunk);
totalLength += decodedChunk.length;
}
var output = new Uint8Array(totalLength);
var offset = 0;
for (var _i = 0, outputChunks_1 = outputChunks; _i < outputChunks_1.length; _i++) {
var chunk = outputChunks_1[_i];
output.set(chunk, offset);
offset += chunk.length;
}
return isDirect ? Array.from(output) : output;
}
else {
var key = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
var chr1 = void 0;
var chr2 = void 0;
var chr3 = void 0;
var enc1 = void 0;
var enc2 = void 0;
var enc3 = void 0;
var enc4 = void 0;
var i = 0;
var resultIndex = 0;
input = input.replace(/[^A-Za-z0-9\+\/\=]/g, ''); // eslint-disable-line
var totalLength = input.length * 3 / 4;
if (input.charAt(input.length - 1) === key.charAt(64)) {
totalLength--;
}
var output = new Array(totalLength | 0);
while (i < input.length) {
enc1 = key.indexOf(input.charAt(i++));
enc2 = key.indexOf(input.charAt(i++));
enc3 = key.indexOf(input.charAt(i++));
enc4 = key.indexOf(input.charAt(i++));
chr1 = (enc1 << 2) | (enc2 >> 4);
chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
chr3 = ((enc3 & 3) << 6) | enc4;
if (resultIndex < totalLength) {
output[resultIndex++] = chr1;
}
if (resultIndex < totalLength) {
output[resultIndex++] = chr2;
}
if (resultIndex < totalLength) {
output[resultIndex++] = chr3;
}
}
return isDirect ? output : new Uint8Array(output);
}
}
/**
* Encode a chunk of bytes to base64 string.
*
* @private
* @param {Uint8Array} bytes Bytes to encode.
* @param {boolean} isLastChunk Defines a last chunk of bytes.
* @returns {string} Decoded string.
*/
function _encodeChunk(bytes, isLastChunk) {
if (isLastChunk === void 0) { isLastChunk = false; }
var key = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
var output = [];
var length = bytes.length;
var i = 0;
while (i < length) {
var byte1 = bytes[i++];
var byte2 = i < length ? bytes[i++] : 0;
var byte3 = i < length ? bytes[i++] : 0;
output.push(key[byte1 >> 2], key[((byte1 & 3) << 4) | (byte2 >> 4)], i - 1 > length ? '=' : key[((byte2 & 15) << 2) | (byte3 >> 6)], i > length ? '=' : key[byte3 & 63]);
}
if (isLastChunk) {
if (length % 3 === 1) {
output[output.length - 1] = '=';
output[output.length - 2] = '=';
}
else if (length % 3 === 2) {
output[output.length - 1] = '=';
}
}
return output.join('');
}
/**
* Encode bytes to base64 string.
*
* @private
* @param {Uint8Array} bytes Bytes to encode.
* @returns {string} Decoded string.
*/
export function _encode(bytes) {
var chunkSize = 3000000;
var key = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
var length = bytes.length;
if (length >= chunkSize) {
var output = [];
if (length > chunkSize) {
for (var start = 0; start < length; start += chunkSize) {
var chunk = bytes.subarray(start, Math.min(start + chunkSize, length));
if ((start + chunkSize) >= length) {
output.push(_encodeChunk(chunk, true));
}
else {
output.push(_encodeChunk(chunk));
}
}
}
else {
output.push(_encodeChunk(bytes, true));
}
return output.join('');
}
else {
var output = '';
var currentChar = 0;
for (var i = 0; i < bytes.length; i++) {
if (i % 3 === 0) {
currentChar = (bytes[i] >> 2);
output += key[currentChar];
currentChar = (bytes[i] << 4) & 63;
}
else if (i % 3 === 1) {
currentChar += (bytes[i] >> 4);
output += key[currentChar];
currentChar = (bytes[i] << 2) & 63;
}
else if (i % 3 === 2) {
currentChar += (bytes[i] >> 6);
output += key[currentChar];
currentChar = bytes[i] & 63;
output += key[currentChar];
}
}
if (bytes.length % 3 === 1) {
output += key[currentChar] + "==";
}
if (bytes.length % 3 === 2) {
output += key[currentChar] + "=";
}
return output;
}
}
/**
* Get property value in inheritable mode.
*
* @private
* @param {_PdfDictionary} dictionary Input dictionary.
* @param {string} key Input dictionary.
* @param {boolean} isArray Search array.
* @param {boolean} stopWhenFound Stop when found.
* @param {string[]} parentKey Key string for parent node.
* @returns {any} Property value.
*/
export function _getInheritableProperty(dictionary, key, isArray, stopWhenFound) {
if (isArray === void 0) { isArray = false; }
if (stopWhenFound === void 0) { stopWhenFound = true; }
var parentKey = [];
for (var _i = 4; _i < arguments.length; _i++) {
parentKey[_i - 4] = arguments[_i];
}
var values; // eslint-disable-line
var refSet = new Set(); // eslint-disable-line
while (dictionary instanceof _PdfDictionary && dictionary.objId && !refSet.has(dictionary.objId)) {
if (dictionary.objId) {
refSet.add(dictionary.objId);
}
var value = isArray ? dictionary.getArray(key) : dictionary.get(key); // eslint-disable-line
if (value !== undefined) {
if (stopWhenFound) {
return value;
}
if (!values) {
values = [];
}
values.push(value);
}
var index = 0;
var hasParent = false;
while (index < parentKey.length) {
var element = parentKey[index]; // eslint-disable-line
if (dictionary.has(element)) {
dictionary = dictionary.get(element);
hasParent = true;
break;
}
index++;
}
if (!hasParent) {
break;
}
}
return values;
}
/**
* Calculate bounds of annotation or field.
*
* @private
* @param {_PdfDictionary} dictionary Input dictionary.
* @param {boolean} isWidget Input page.
* @returns {any} Bounds value.
*/
export function _parseRectangle(dictionary, isWidget) {
var rectangle = { x: 0, y: 0, width: 0, height: 0 };
var elements = dictionary.getArray('Rect');
if (elements && Array.isArray(elements)) {
var x1 = elements[0];
var y1 = elements[1];
var x2 = elements[2];
var y2 = elements[3];
if (typeof x1 !== 'undefined' && typeof y1 !== 'undefined' && typeof x2 !== 'undefined' && typeof y2 !== 'undefined') {
rectangle.x = Math.min(x1, x2);
rectangle.y = Math.min(y1, y2);
rectangle.width = Math.max(x1, x2) - rectangle.x;
rectangle.height = Math.max(y1, y2) - rectangle.y;
if (isWidget) {
rectangle.height = parseFloat(rectangle.height.toFixed(3));
if (elements[1] < 0) {
rectangle.y = elements[1];
if (elements[1] > elements[3]) {
rectangle.y -= rectangle.height;
}
}
}
}
}
return rectangle;
}
/**
* Calculate bounds of annotation or field.
*
* @private
* @param {_PdfDictionary} dictionary Input dictionary.
* @param {string} page Input page.
* @returns {any} Bounds value.
*/
export function _calculateBounds(dictionary, page) {
var rect;
if (dictionary.has('Rect')) {
rect = _parseRectangle(dictionary);
if (page) {
var size = page.size;
var mBox = page.mediaBox;
var cropBox = page.cropBox;
if (cropBox && Array.isArray(cropBox) && cropBox.length === 4 && page._pageDictionary.has('CropBox')) {
if ((cropBox[0] !== 0 || cropBox[1] !== 0 || size.width === cropBox[2] ||
size.height === cropBox[3]) && (rect.x !== cropBox[0])) {
rect.x -= cropBox[0];
rect.y = cropBox[3] - (rect.y + rect.height);
}
else {
rect.y = size.height - (rect.y + rect.height);
}
}
else if (mBox && Array.isArray(mBox) && mBox.length === 4 && page._pageDictionary.has('MediaBox')) {
if (mBox[0] > 0 || mBox[1] > 0 || size.width === mBox[2] || size.height === mBox[3]) {
rect.x -= mBox[0];
rect.y = mBox[3] - (rect.y + rect.height);
}
else {
rect.y = size.height - (rect.y + rect.height);
}
}
else {
rect.y = size.height - (rect.y + rect.height);
}
}
else {
rect.y = rect.y + rect.height;
}
}
return rect;
}
/**
* Calculate bounds of annotation or field.
*
* @private
* @param {number[]} value array value.
* @returns {any} Rectangle value.
*/
export function _toRectangle(value) {
return {
x: Math.min(value[0], value[2]),
y: Math.min(value[1], value[3]),
width: Math.abs(value[0] - value[2]),
height: Math.abs(value[1] - value[3])
};
}
/**
* Calculate bounds of annotation or field.
*
* @private
* @param {any} value Rectangle value.
* @param {any} value.x X value.
* @param {any} value.y Y value.
* @param {any} value.width Width value.
* @param {any} value.height Height value.
* @returns {number[]} Bounds value.
*/
export function _fromRectangle(value) {
return [value.x, value.y, value.x + value.width, value.y + value.height];
}
/**
* Calculate bounds of annotation or field.
*
* @private
* @param {number[]} value Input dictionary.
* @param {string} page Input page.
* @returns {number[]} Bounds value.
*/
export function _getUpdatedBounds(value, page) {
var x = value[0];
var y = value[1];
var width = value[2];
var height = value[3];
if (page) {
var size = page.size;
var pageWidth = size.width;
var pageHeight = size.height;
var mBox = page.mediaBox;
var cropBox = page.cropBox;
if (cropBox && Array.isArray(cropBox) && cropBox.length === 4) {
if (cropBox[0] !== 0 || cropBox[1] !== 0 || pageWidth === cropBox[2] || pageHeight === cropBox[3]) {
x += cropBox[0];
y = cropBox[3] - (y + height);
}
else {
y = pageHeight - (y + height);
}
}
else if (mBox && Array.isArray(mBox) && mBox.length === 4) {
if (mBox[0] > 0 || mBox[1] > 0 || pageWidth === mBox[2] || pageHeight === mBox[3]) {
x -= mBox[0];
y = mBox[3] - (y + height);
}
else {
y = pageHeight - (y + height);
}
}
else {
y = pageHeight - (y + height);
}
}
return [x, y, x + width, y + height];
}
/**
* Parse RGB color.
*
* @private
* @param {string} colorString Color value in string format.
* @returns {PdfColor | undefined} RGB color value.
*/
export function _convertToColor(colorString) {
var color = _getColorValue(colorString);
if (!color) {
var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(colorString);
if (result) {
color = [parseInt(result[1], 16), parseInt(result[2], 16), parseInt(result[3], 16)];
}
}
return color ? { r: color[0], g: color[1], b: color[2] } : undefined;
}
/**
* Checks if the given value is an array of Point objects.
*
* @private
* @param {any} value - Value to check.
* @returns {boolean} True if value is Point[].
*/
export function _isPointArray(value) {
return Array.isArray(value) &&
value.every(function (item) {
return item &&
typeof item.x === 'number' &&
typeof item.y === 'number';
});
}
/**
* Converts a flat number array into an array of Point objects.
*
* @private
* @param {number[]} arr - Array of numbers [x1, y1, x2, y2, ...].
* @returns {Point[]} Array of Point objects.
*/
export function _convertToPoints(arr) {
var points = [];
for (var i = 0; i < arr.length; i += 2) {
points.push({ x: arr[i], y: arr[i + 1] });
}
return points;
}
/**
* Converts a number array into an array of Point arrays.
*
* @private
* @param {Array<number[]>} data - Array of arrays containing numeric coordinates.
* @returns {Array<Point[]>} Array of Point arrays.
*/
export function _convertNumberToPointArrays(data) {
return data.map(function (innerArray) {
var points = [];
for (var i = 0; i < innerArray.length; i += 2) {
points.push({ x: innerArray[i], y: innerArray[i + 1] });
}
return points;
});
}
/**
* Converts a number array into a flat array of Point objects.
*
* @private
* @param {Array<number[]>} data - Array of arrays containing numeric coordinates.
* @returns {Point[]} Flattened array of Point objects.
*/
export function _convertNumberArraysToPoints(data) {
var points = [];
for (var _i = 0, data_1 = data; _i < data_1.length; _i++) {
var innerArray = data_1[_i];
for (var i = 0; i < innerArray.length; i += 2) {
points.push({ x: innerArray[i], y: innerArray[i + 1] });
}
}
return points;
}
/**
* Converts an array of Point arrays into a number array.
*
* @private
* @param {Array<Point[]>} data - Array of Point arrays.
* @returns {Array<number[]>} Array of arrays containing numeric coordinates.
*/
export function _convertPointsToNumberArrays(data) {
return data.map(function (innerArray) {
var numbers = [];
for (var _i = 0, innerArray_1 = innerArray; _i < innerArray_1.length; _i++) {
var point = innerArray_1[_i];
numbers.push(point.x, point.y);
}
return numbers;
});
}
/**
* Converts an array of Point objects into a flat number array.
*
* @private
* @param {Point[]} data - Array of Point objects.
* @returns {number[]} Array of numbers [x1, y1, x2, y2, ...].
*/
export function _convertPointToNumberArray(data) {
var numbers = [];
for (var i = 0; i < data.length; i++) {
var point = data[i];
numbers.push(point.x, point.y);
}
return numbers;
}
/**
* Parse RGB color.
*
* @private
* @param {number[]} array Color array in dictionary.
* @returns {PdfColor} RGB color value.
*/
export function _parseColor(array) {
var color;
if (array) {
if (array.length === 1) {
var entry = array[0];
if (typeof entry !== 'undefined') {
var round = Math.round(entry * 255);
color = { r: round, g: round, b: round };
}
}
else if (array.length === 3) {
var r = array[0];
var g = array[1];
var b = array[2];
if (typeof r !== 'undefined' && typeof g !== 'undefined' && typeof b !== 'undefined') {
color = { r: Math.round(r * 255), g: Math.round(g * 255), b: Math.round(b * 255) };
}
}
else if (array.length === 4) {
var c = array[0];
var m = array[1];
var y = array[2];
var k = array[3];
if (typeof c !== 'undefined' && typeof m !== 'undefined' && typeof y !== 'undefined' && typeof k !== 'undefined') {
var fBlack = k * 255;
color = { r: Math.round(255 - Math.min(255, ((c * (255 - fBlack)) + fBlack))),
g: Math.round(255 - Math.min(255, ((m * (255 - fBlack)) + fBlack))),
b: Math.round(255 - Math.min(255, ((y * (255 - fBlack)) + fBlack))) };
}
}
}
return color;
}
/**
* Get the border style in _PdfName.
*
* @private
* @param {PdfBorderStyle} style border style in enum.
* @returns {_PdfName} border style in _PdfName.
*/
export function _mapBorderStyle(style) {
var token = 'S';
switch (style) {
case PdfBorderStyle.dot:
case PdfBorderStyle.dashed:
token = 'D';
break;
case PdfBorderStyle.beveled:
token = 'B';
break;
case PdfBorderStyle.inset:
token = 'I';
break;
case PdfBorderStyle.underline:
token = 'U';
break;
}
return _PdfName.get(token);
}
/**
* Get the border effect style in _PdfName.
*
* @private
* @param {string} style border effect style as string.
* @returns {PdfBorderEffectStyle} border effect style.
*/
export function _mapBorderEffectStyle(style) {
var value = PdfBorderEffectStyle.solid;
switch (style) {
case 'C':
value = PdfBorderEffectStyle.cloudy;
break;
}
return value;
}
/**
* Get the string value for line ending style.
*
* @private
* @param {PdfLineEndingStyle} style style in enum.
* @returns {string} value default None.
*/
export function _reverseMapEndingStyle(style) {
var value = 'None';
if (typeof style !== 'undefined') {
switch (style) {
case PdfLineEndingStyle.openArrow:
value = 'OpenArrow';
break;
case PdfLineEndingStyle.closedArrow:
value = 'ClosedArrow';
break;
case PdfLineEndingStyle.rOpenArrow:
value = 'ROpenArrow';
break;
case PdfLineEndingStyle.rClosedArrow:
value = 'RClosedArrow';
break;
case PdfLineEndingStyle.butt:
value = 'Butt';
break;
case PdfLineEndingStyle.diamond:
value = 'Diamond';
break;
case PdfLineEndingStyle.circle:
value = 'Circle';
break;
case PdfLineEndingStyle.square:
value = 'Square';
break;
case PdfLineEndingStyle.slash:
value = 'Slash';
break;
}
}
return value;
}
/**
* Get the enum value for line ending style.
*
* @private
* @param {string} style Style value in string.
* @param {PdfLineEndingStyle} defaultValue Default style value to return.
* @returns {PdfLineEndingStyle} enum value default 0.
*/
export function _mapLineEndingStyle(style, defaultValue) {
var value;
switch (style.toLowerCase()) {
case 'openarrow':
value = PdfLineEndingStyle.openArrow;
break;
case 'closedarrow':
value = PdfLineEndingStyle.closedArrow;
break;
case 'ropenarrow':
value = PdfLineEndingStyle.rOpenArrow;
break;
case 'rclosedarrow':
value = PdfLineEndingStyle.rClosedArrow;
break;
case 'butt':
value = PdfLineEndingStyle.butt;
break;
case 'diamond':
value = PdfLineEndingStyle.diamond;
break;
case 'circle':
value = PdfLineEndingStyle.circle;
break;
case 'square':
value = PdfLineEndingStyle.square;
break;
case 'slash':
value = PdfLineEndingStyle.slash;
break;
default:
value = PdfLineEndingStyle.none;
break;
}
return value;
}
/**
* Get highlight mode.
*
* @private
* @param {string} mode Mode entry in dictionary.
* @returns {PdfHighlightMode} Highlight mode.
*/
export function _mapHighlightMode(mode) {
switch (mode) {
case 'P':
return PdfHighlightMode.push;
case 'N':
return PdfHighlightMode.noHighlighting;
case 'O':
return PdfHighlightMode.outline;
default:
return PdfHighlightMode.invert;
}
}
/**
* Get highlight mode as string.
*
* @private
* @param {PdfHighlightMode} mode Mode entry.
* @returns {_PdfName} Highlight mode as PDF name.
*/
export function _reverseMapHighlightMode(mode) {
switch (mode) {
case PdfHighlightMode.push:
return _PdfName.get('P');
case PdfHighlightMode.noHighlighting:
return _PdfName.get('N');
case PdfHighlightMode.outline:
return _PdfName.get('O');
default:
return _PdfName.get('I');
}
}
/**
* Reverse map blend mode.
*
* @private
* @param {PdfBlendMode} mode Mode entry.
* @returns {_PdfName} Blend mode as name.
*/
export function _reverseMapBlendMode(mode) {
var token = 'Normal';
switch (mode) {
case PdfBlendMode.multiply:
token = 'Multiply';
break;
case PdfBlendMode.screen:
token = 'Screen';
break;
case PdfBlendMode.overlay:
token = 'Overlay';
break;
case PdfBlendMode.darken:
token = 'Darken';
break;
case PdfBlendMode.lighten:
token = 'Lighten';
break;
case PdfBlendMode.colorDodge:
token = 'ColorDodge';
break;
case PdfBlendMode.colorBurn:
token = 'ColorBurn';
break;
case PdfBlendMode.hardLight:
token = 'HardLight';
break;
case PdfBlendMode.softLight:
token = 'SoftLight';
break;
case PdfBlendMode.difference:
token = 'Difference';
break;
case PdfBlendMode.exclusion:
token = 'Exclusion';
break;
case PdfBlendMode.hue:
token = 'Hue';
break;
case PdfBlendMode.saturation:
token = 'Saturation';
break;
case PdfBlendMode.color:
token = 'Color';
break;
case PdfBlendMode.luminosity:
token = 'Luminosity';
break;
default:
token = 'Normal';
break;
}
return _PdfName.get(token);
}
/**
* Map blend mode.
*
* @private
* @param {_PdfName} token Blend mode as name.
* @returns {PdfBlendMode} Mode value;
*/
export function _mapBlendMode(token) {
var style = PdfBlendMode.normal;
switch (token.name) {
case 'Multiply':
style = PdfBlendMode.multiply;
break;
case 'Screen':
style = PdfBlendMode.screen;
break;
case 'Overlay':
style = PdfBlendMode.overlay;
break;
case 'Darken':
style = PdfBlendMode.darken;
break;
case 'Lighten':
style = PdfBlendMode.lighten;
break;
case 'ColorDodge':
style = PdfBlendMode.colorDodge;
break;
case 'ColorBurn':
style = PdfBlendMode.colorBurn;
break;
case 'HardLight':
style = PdfBlendMode.hardLight;
break;
case 'SoftLight':
style = PdfBlendMode.softLight;
break;
case 'Difference':
style = PdfBlendMode.difference;
break;
case 'Exclusion':
style = PdfBlendMode.exclusion;
break;
case 'Hue':
style = PdfBlendMode.hue;
break;
case 'Saturation':
style = PdfBlendMode.saturation;
break;
case 'Color':
style = PdfBlendMode.color;
break;
case 'Luminosity':
style = PdfBlendMode.luminosity;
break;
default:
style = PdfBlendMode.normal;
break;
}
return style;
}
/**
* Convert float to string.
*
* @private
* @param {number} value number value.
* @returns {string} equal fixed length string value;
*/
export function _floatToString(value) {
var returnString = value.toFixed(2);
if (returnString === '0.00') {
returnString = '.00';
}
return returnString;
}
/**
* Check and add proc set value.
*
* @private
* @param {string} value entry.
* @param {_PdfDictionary} dictionary source dictionary.
* @returns {void} Nothing;
*/
export function _addProcSet(value, dictionary) {
var name = _PdfName.get(value);
if (dictionary.has('ProcSet')) {
var procset = dictionary.getArray('ProcSet');
if (procset && procset.indexOf(name) === -1) {
procset.push(name);
dictionary.update('ProcSet', procset);
}
}
else {
dictionary.update('ProcSet', [name]);
}
}
/**
* Get new GUID string.
*
* @private
* @returns {string} A new GUID string;
*/
export function _getNewGuidString() {
return 'aaaaaaaa-aaaa-4aaa-baaa-aaaaaaaaaaaa'.replace(/[ab]/g, function (c) {
var random = Math.random() * 16 | 0;
var result = c === 'a' ? random : (random & 0x3 | 0x8);
return result.toString(16);
});
}
/**
* Escape PDF name.
*
* @private
* @param {string} value name value.
* @returns {string} equal and processed name value;
*/
export function _escapePdfName(value) {
if (!value || value.length === 0) {
return value;
}
var out = [];
var i = 0;
while (i < value.length) {
var ch = value[i];
var code = value.charCodeAt(i);
if (ch === '#' && i + 2 < value.length) {
var c1 = value[i + 1];
var c2 = value[i + 2];
if (_isHexDigit(c1) && _isHexDigit(c2)) {
out.push('#', c1.toUpperCase(), c2.toUpperCase());
i += 3;
continue;
}
}
var isVisible = (code >= 0x21 && code <= 0x7E);
var isDelimiter = ch === '(' || ch === ')' ||
ch === '<' || ch === '>' ||
ch === '[' || ch === ']' ||
ch === '{' || ch === '}' ||
ch === '/' || ch === '%' ||
ch === '#';
if (isVisible && !isDelimiter) {
out.push(ch);
i++;
continue;
}
if (code <= 0x7F) {
out.push('#', _toHex2(code));
i += 1;
continue;
}
var codePoint = void 0;
if (code >= 0xD800 && code <= 0xDBFF) {
if (i + 1 < value.length) {
var low = value.charCodeAt(i + 1);
if (low >= 0xDC00 && low <= 0xDFFF) {
codePoint = ((code - 0xD800) << 10) + (low - 0xDC00) + 0x10000;
i += 2;
}
else {
codePoint = 0xFFFD;
i += 1;
}
}
else {
codePoint = 0xFFFD;
i += 1;
}
}
else if (code >= 0xDC00 && code <= 0xDFFF) {
codePoint = 0xFFFD;
i += 1;
}
else {
codePoint = code;
i += 1;
}
var bytes = _encodeCodePointToUtf8(codePoint);
for (var k = 0; k < bytes.length; k++) {
out.push('#', _toHex2(bytes[k]));
}
}
return out.join('');
}
/**
* Encodes a single Unicode code point (U+0000 to U+10FFFF) into UTF-8 bytes.
*
* @param {number} codePoint - The Unicode code point to encode.
* @returns {number[]} An array of UTF-8 byte values (0 to 255).
*/
export function _encodeCodePointToUtf8(codePoint) {
if (codePoint <= 0x7F) {
return [codePoint];
}
if (codePoint <= 0x7FF) {
return [
0xC0 | (codePoint >> 6),
0x80 | (codePoint & 0x3F)
];
}
if (codePoint <= 0xFFFF) {
return [
0xE0 | (codePoint >> 12),
0x80 | ((codePoint >> 6) & 0x3F),
0x80 | (codePoint & 0x3F)
];
}
return [
0xF0 | (codePoint >> 18),
0x80 | ((codePoint >> 12) & 0x3F),
0x80 | ((codePoint >> 6) & 0x3F),
0x80 | (codePoint & 0x3F)
];
}
/**
* Converts a number to a two-character uppercase hexadecimal string.
*
* @param {number} n - The number to convert (0 to 255 recommended).
* @returns {string} A two-character uppercase hexadecimal string.
*/
export function _toHex2(n) {
var h = n.toString(16).toUpperCase();
return h.length === 1 ? '0' + h : h;
}
/**
* Checks whether a given character is a valid hexadecimal digit.
*
* @param {string} ch - The character to check.
* @returns {boolean} True if the character is a hex digit; otherwise, false.
*/
export function _isHexDigit(ch) {
var cc = ch.charCodeAt(0);
return ((cc >= 0x30 && cc <= 0x39) ||
(cc >= 0x41 && cc <= 0x46) ||
(cc >= 0x61 && cc <= 0x66));
}
/**
* Calculate bezier arc points.
*
* @private
* @param {number} x1 value.
* @param {number} y1 value.
* @param {number} x2 value.
* @param {number} y2 value.
* @param {number} start value.
* @param {number} extent value.
* @returns {number[]} bezier arc points;
*/
export function _getBezierArc(x1, y1, x2, y2, start, extent) {
if (x1 > x2) {
var swap = x1;
x1 = x2;
x2 = swap;
}
if (y2 > y1) {
var swap = y1;
y1 = y2;
y2 = swap;
}
var angle;
var count;
if (Math.abs(extent) <= 90) {
angle = extent;
count = 1;
}
else {
count = Math.ceil(Math.abs(extent) / 90);
angle = extent / count;
}
var first = ((x1 + x2) / 2);
var second = ((y1 + y2) / 2);
var firstAngle = ((x2 - x1) / 2);
var secondAngle = ((y2 - y1) / 2);
var half = (angle * (Math.PI / 360));
var value = (Math.abs(4.0 / 3.0 * (1.0 - Math.cos(half)) / Math.sin(half)));
var points = [];
for (var i = 0; (i < count); i++) {
var zero = (((start + (i * angle)) * (Math.PI / 180)));
var one = (((start + ((i + 1) * angle)) * (Math.PI / 180)));
var cosZero = (Math.cos(zero));
var cosOne = (Math.cos(one));
var sinZero = (Math.sin(zero));
var sinOne = (Math.sin(one));
if ((angle > 0)) {
points.push(first + (firstAngle * cosZero));
points.push(second - (secondAngle * sinZero));
points.push(first + (firstAngle * (cosZero - (value * sinZero))));
points.push(second - (secondAngle * (sinZero + (value * cosZero))));
points.push(first + (firstAngle * (cosOne + (value * sinOne))));
points.push(second - (secondAngle * (sinOne - (value * cosOne))));
points.push(first + (firstAngle * cosOne));
points.push(second - (secondAngle * sinOne));
}
else {
points.push(first + (firstAngle * cosZero));
points.push(second - (secondAngle * sinZero));
points.push(first + (firstAngle * (cosZero + (value * sinZero))));
points.push(second - (secondAngle * (sinZero - (value * cosZero))));
points.push(first + (firstAngle * (cosOne - (value * sinOne))));
points.push(second - (secondAngle * (sinOne + (value * cosOne))));
points.push(first + (firstAngle * cosOne));
points.push(second - (secondAngle * sinOne));
}
}
return points;
}
/**
* Find page of the annotation.
*
* @private
* @param {PdfDocument} document PDF document.
* @param {_PdfReference} reference Annotation reference.
* @returns {PdfPage} Page of the annotation;
*/
export function _findPage(document, reference) {
var page;
for (var i = 0; i < document.pageCount && typeof page === 'undefined'; i++) {
var entry = document.getPage(i);
if (entry && entry._pageDictionary.has('Annots')) {
var annots = entry._pageDictionary.get('Annots');
if (Array.isArray(annots) &&
typeof page === 'undefined' &&
annots.some(function (ref) { return ref instanceof _PdfReference && ref === reference; })) {
page = entry;
}
}
}
return page;
}
/**
* Check the field is checked or not.
*
* @private
* @param {_PdfDictionary} dictionary PDF dictionary.
* @returns {boolean} True if the field is checked, otherwise false;
*/
export function _checkField(dictionary) {
var check = false;
if (dictionary.has('AS')) {
var state = dictionary.get('AS');
if (state) {
check = state.name !== 'Off';
}
else {
var actual = dictionary.get('V');
if (actual) {
check = actual.name === _getItemValue(dictionary);
}
}
}
return check;
}
/**
* Get item value from state item field.
*
* @private
* @param {_PdfDictionary} itemDictionary PDF document.
* @returns {string} value of item;
*/
export function _getItemValue(itemDictionary) {
var itemValue = '';
var name;
if (itemDictionary && itemDictionary instanceof _PdfDictionary) {
if (itemDictionary.has('AS')) {
name = itemDictionary.get('AS');
if (name !== null && name.name !== 'Off') {
itemValue = name.name;
}
}
else if (itemDictionary.has('V')) {
name = itemDictionary.get('V');
if (name !== null && name.name !== 'Off') {
itemValue = name.name;
}
}
if (itemValue === '' && itemDictionary && itemDictionary.has('AP')) {
var dictionary = itemDictionary.get('AP');
if (dictionary && dictionary.has('N')) {
var appearance = dictionary.get('N');
if (appearance instanceof _PdfBaseStream) {
appearance = appearance.dictionary;
}
if (appearance && appearance instanceof _PdfDictionary) {
var hasKey_1 = false;
appearance.forEach(function (key, value) {
if (!hasKey_1 && key !== 'Off') {
itemValue = key;
hasKey_1 = true;
}
});
}
}
}
}
return itemValue;
}
/**
* Get state item template.
*
* @private
* @param {_PdfCheckFieldState} state Check field state.
* @param {PdfStateItem | PdfField} item source to check.
* @returns {PdfTemplate} Appearance template;
*/
export function _getStateTemplate(state, item) {
var value = state === _PdfCheckFieldState.checked ? _getItemValue(item._dictionary) : 'Off';
var template;
if (item._dictionary.has('AP')) {
var dictionary = item._dictionary.get('AP');
if (dictionary && dictionary.has('N')) {
var appearance = dictionary.get('N');
if (appearance && appearance instanceof _PdfBaseStream) {
appearance = appearance.dictionary;
}
if (appearance && appearance instanceof _PdfDictionary && (value && value !== '' && appearance.has(value))) {
var stream = appearance.get(value);
var reference = appearance.getRaw(value);
if (reference) {
stream.reference = reference;
}
if (stream) {
template = new PdfTemplate(stream, item._crossReference);
}
}
}
}
return template;
}
/**
* Get color value
*
* @private
* @param {string} colorName name of the color.
* @returns {number[]} return color value as number array.
*/
export function _getColorValue(colorName) {
var color;
switch (colorName) {
case 'transparent':
color = [255, 255, 255];
break;
case 'aliceblue':
color = [240, 248, 255];
break;
case 'antiquewhite':
color = [250, 235, 215];
break;
case 'aqua':
color = [0, 255, 255];
break;
case 'aquamarine':
color = [127, 255, 212];
break;
case 'azure':
color = [240, 255, 255];
break;
case 'beige':
color = [245, 245, 220];
break;
case 'bisque':
color = [255, 228, 196];
break;
case 'black':
color = [0, 0, 0];
break;
case 'blanchedalmond':
color = [255, 235, 205];
break;
case 'blue':
color = [0, 0, 255];
break;
case 'blueviolet':
color = [138, 43, 226];
break;
case 'brown':
color = [165, 42, 42];
break;
case 'burlywood':
color = [222, 184, 135];
break;
case 'cadetBlue':
color = [95, 158, 160];
break;
case 'chartreuse':
color = [127, 255, 0];
break;
case 'chocolate':
color = [210, 105, 30];
break;
case 'coral':
color = [255, 127, 80];
break;
case 'cornflowerblue':
color = [100, 149, 237];
break;
case 'cornsilk':
color = [255, 248, 220];
break;
case 'crimson':
color = [220, 20, 60];
break;
case 'cyan':
color = [0, 255, 255];
break;
case 'darkblue':
color = [0, 0, 139];
break;
case 'darkcyan':
color = [0, 139, 139];
break;
case 'darkgoldenrod':
color = [184, 134, 11];
break;
case 'darkgray':
color = [169, 169, 169];
break;
case 'darkgreen':
color = [0, 100, 0];
break;
case 'darkkhaki':
color = [189, 183, 107];
break;
case 'darkmagenta':
color = [139, 0, 139];
break;
case 'darkolivegreen':
color = [85, 107, 47];
break;
case 'darkorange':
color = [255, 140, 0];
break;
case 'darkorchid':
color = [153, 50, 204];
break;
case 'darkred':
color = [139, 0, 0];
break;
case 'darksalmon':
color = [233, 150, 122];
break;
case 'darkseagreen':
color = [143, 188, 139];
break;
case 'darkslateblue':
color = [72, 61, 139];
break;
case 'darkslategray':
color = [47, 79, 79];
break;
case 'darkturquoise':
color = [0, 206, 209];
break;
case 'darkviolet':
color = [148, 0, 211];
break;
case 'deeppink':
color = [255, 20, 147];
break;
case 'deepskyblue':
color = [0, 191, 255];
break;
case 'dimgray':
color = [105, 105, 105];
break;
case 'dodgerblue':
color = [30, 144, 255];
break;
case 'firebrick':
color = [178, 34, 34];
break;
case 'floralwhite':
color = [255, 250, 240];
break;
case 'forestgreen':
color = [34, 139, 34];
break;
case 'fuchsia':
color = [255, 0, 255];
break;
case 'gainsboro':
color = [220, 220, 220];
break;
case 'ghostwhite':
color = [248, 248, 255];
break;
case 'gold':
color = [255, 215, 0];
break;
case 'goldenrod':
color = [218, 165, 32];
break;
case 'gray':
color = [128, 128, 128];
break;
case 'green':
color = [0, 128, 0];
break;
case 'greenyellow':
color = [173, 255, 47];
break;
case 'honeydew':
color = [240, 255, 240];
break;
case 'hotpink':
color = [255, 105, 180];
break;
case 'indianred':
color = [205, 92, 92];
break;
case 'indigo':
color = [75, 0, 130];
break;
case 'ivory':
color = [255, 255, 240];
break;
case 'khaki':
color = [240, 230, 140];
break;
case 'lavender':
color = [230, 230, 250];
break;
case 'lavenderblush':
color = [255, 240, 245];
break;
case 'lawngreen':
color = [124, 252, 0];
break;
case 'lemonchiffon':
color = [255, 250, 205];
break;
case 'lightblue':
color = [173, 216, 230];
break;
case 'lightcoral':
color = [240, 128, 128];
break;
case 'lightcyan':
color = [224, 255, 255];
break;
case 'lightgoldenrodyellow':
color = [250, 250, 210];
break;
case 'lightgreen':
color = [144, 238, 144];
break;
case 'lightgray':
color = [211, 211, 211];
break;
case 'LightPink':
color = [255, 182, 193];
break;
case 'lightsalmon':
color = [255, 160, 122];
break;
case 'lightseagreen':
color = [32, 178, 170];
break;
case 'lightskyblue':
color = [135, 206, 250];
break;
case 'lightslategray':
color = [119, 136, 153];
break;
case 'lightsteelblue':
color = [176, 196, 222];
break;
case 'lightyellow':
color = [255, 255, 224];
break;
case 'lime':
color = [0, 255, 0];
break;
case 'limeGreen':
color = [50, 205, 50];
break;
case 'linen':
color = [250, 240, 230];
break;
case 'magenta':
color = [255, 0, 255];
break;
case 'maroon':
color = [128, 0, 0];
break;
case 'mediumaquamarine':
color = [102, 205, 170];
break;
case 'mediumblue':
color = [0, 0, 205];
break;
case 'mediumorchid':
color = [186, 85, 211];
break;
case 'mediumpurple':
color = [147, 112, 219];
break;
case 'mediumseagreen':
color = [60, 179, 113];
break;
case 'mediumslateblue':
color = [123, 104, 238];
break;
case 'mediumspringgreen':
color = [0, 250, 154];
break;
case 'mediumturquoise':
color = [72, 209, 204];
break;
case 'mediumvioletred':
color = [199, 21, 133];
break;
case 'midnightblue':
color = [25, 25, 112];
break;
case 'mintcream':
color = [245, 255, 250];
break;
case 'mistyrose':
color = [255, 228, 225];
break;
case 'moccasin':
color = [255, 228, 181];
break;
case 'navajowhite':
color = [255, 222, 173];
break;
case 'navy':
color = [0, 0, 128];
break;
case 'oldLace':
color = [253, 245, 230];
break;
case 'olive':
color = [128, 128, 0];
break;
case 'olivedrab':
color = [107, 142, 35];
break;
case 'orange':
color = [255, 165, 0];
break;
case 'orangered':
color = [255, 69, 0];
break;
case 'orchid':
color = [218, 112, 214];
break;
case 'palegoldenrod':
color = [238, 232, 170];
break;
case 'palegreen':
color = [152, 251, 152];
break;
case 'paleturquoise':
color = [175, 238, 238];
break;
case 'palebioletred':
color = [219, 112, 147];
break;
case 'papayawhip':
color = [255, 239, 213];
break;
case 'peachpuff':
color = [255, 218, 185];
break;
case 'peru':
color = [205, 133, 63];
break;
case 'pink':
color = [255, 192, 203];
break;
case 'plum':
color = [221, 160, 221];
break;
case 'powderblue':
color = [176, 224, 230];
break;
case 'purple':
color = [128, 0, 128];
break;
case 'red':
color = [255, 0, 0];
break;
case 'rosybrown':
color = [188, 143, 143];
break;
case 'royalblue':
color = [65, 105, 225];
break;
case 'saddlebrown':
color = [139, 69, 19];
break;
case 'salmon':
color = [250, 128, 114];
break;
case 'sandybrown':
color = [244, 164, 96];
break;
case 'seagreen':
color = [46, 139, 87];
break;
case 'seashell':
color = [255, 245, 238];
break;
case 'sienna':
color = [160, 82, 45];
break;
case 'silver':
color = [192, 192, 192];
break;
case 'skyblue':
color = [135, 206, 235];
break;
case 'slateblue':
color = [106, 90, 205];
break;
case 'slategray':
color = [112, 128, 144];
break;
case 'snow':
color = [255, 250, 250];
break;
case 'springgreen':
color = [0, 255, 127];
break;
case 'steelblue':
color = [70, 130, 180];
break;
case 'tan':
color = [210, 180, 140];
break;
case 'teal':
color = [0, 128, 128];
break;
case 'thistle':
color = [216, 191, 216];
break;
case 'tomato':
color = [255, 99, 71];
break;
case 'turquoise':
color = [64, 224, 208];
break;
case 'violet':
color = [238, 130, 238];
break;
case 'wheat':
color = [245, 222, 179];
break;
case 'white':
color = [255, 255, 255];
break;
case 'whitesmoke':
color = [245, 245, 245];
break;
case 'yellow':
color = [255, 255, 0];
break;
case 'yellowgreen':
color = [154, 205, 50];
break;
}
return color;
}
/**
* Update box value in template bounds.
*
* @private
* @param {PdfTemplate} template Template object.
* @param {number} angle Angle value.
* @param {PdfAnnotation} annotation annotation instance.
* @returns {void} Nothing.
*/
export function _setMatrix(template, angle, annotation) {
var box = template._content.dictionary.getArray('BBox');
var centerX = 0.1;
var centerY = 0.1;
if (box && typeof angle !== 'undefined' && angle !== null) {
if (angle === 0) {
template._content.dictionary.set('Matrix', [1, 0, 0, 1, -box[0], -box[1]]);
}
else {
var matrix = new _PdfTransformationMatrix();
if (angle === 90) {
matrix._translate(box[3], -box[0]);
}
else if (angle === 180) {
matrix._translate(box[2], box[3]);
}
else if (angle === 270) {
if (annotation) {
matrix._translate(-box[1], box[2]);
}
else {
matrix._translate(-box[1], box[3]);
}
}
if (angle % 90 !== 0 && annotation && annotation instanceof PdfRubberStampAnnotation) {
var box0 = void 0;
var box1 = void 0;
if (box && Array.isArray(box) && box.length > 1) {
box0 = box[0];
box1 = box[1];
}
var w = annotation.bounds.width;
var h = annotation.bounds.height;
if (typeof box0 === 'number' && typeof box1 === 'number' && box0 !== 0 && box1 !== 0) {
var width = _getCenterX(angle, box, centerX, annotation);
var height = _getCenterY(angle, box, centerY, annotation);
if (width > 0) {
if (w > width) {
while (Math.round(w * 10) / 10 !== Math.round(_getCenterX(angle, box, centerX, annotation) * 10) / 10 &&
Math.round(w * 10) / 10 > Math.round(_getCenterX(angle, box, centerX, annotation) * 10) / 10) {
centerX += 0.1;
}
}
else {
while (Math.round(w * 10) / 10 !== Math.round(_getCenterX(angle, box, centerX, annotation) * 10) / 10 &&
Math.round(w * 10) / 10 < Math.round(_getCenterX(angle, box, centerX, annotation) * 10) / 10) {
centerX -= 0.1;
}
}
}
else {
while (Math.round(w * 10) / 10 !== Math.round(_getCenterX(angle, box, centerX, annotation) * 10) / 10 &&
Math.round(w * 10) / 10 > Math.round(_getCenterX(angle, box, centerX, annotation) * 10) / 10) {
centerX += 0.1;
}
}
if (height > 0) {
if (h > height) {
while (Math.round(h * 10) / 10 !== Math.round(_getCenterY(angle, box, centerY, annotation) * 10) / 10 &&
Math.round(h * 10) / 10 > Math.round(_getCenterY(angle, box, centerY, annotation) * 10) / 10) {
centerY += 0.1;
}
}
else {
while (Math.round(h * 10) / 10 !== Math.round(_getCenterY(angle, box, centerY, annotation) * 10) / 10 &&
Math.round(h * 10) / 10 < Math.round(_getCenterY(angle, box, centerY, annotation) * 10) / 10) {
centerY -= 0.1;
}
}
}
else {
while (Math.round(h * 10) / 10 !== Math.round(_getCenterY(angle, box, centerY, annotation) * 10) / 10 &&
Math.round(h * 10) / 10 > Math.round(_getCenterY(angle, box, centerY, annotation) * 10) / 10) {
centerY += 0.1;
}
}
matrix._translate(centerX, centerY);
}
else {
var targetCenterX = Math.abs(annotation.bounds.width -
Math.round(_getCenterX(angle, box, centerX, annotation)));
var targetCenterY = Math.abs(annotation.bounds.height -
Math.round(_getCenterY(angle, box, centerY, annotation)));
if (Math.round(annotation.bounds.width) > centerX) {
centerX = Math.round(targetCenterX / centerX) * centerX;
}
if (Math.round(annotation.bounds.width) > centerY) {
centerY = Math.round(targetCenterY / centerY) * centerY;
}
matrix._translate(centerX, centerY);
}
}
matrix._rotate(angle);
template._content.dictionary.set('Matrix', matrix._matrix._elements);
}
}
}
/**
* Computes the center X-coordinate after transforming the bounding box by a rotation matrix.
*
* @private
* @param {number} angle The rotation angle in degrees.
* @param {number[]} bbox The bounding box represented as an array of four numbers [x, y, width, height].
* @param {number} x The original center X-coordinate.
* @param {PdfRubberStampAnnotation} annotation The annotation to be transformed.
* @returns {number} The transformed center X-coordinate.
*/
export function _getCenterX(angle, bbox, x, annotation) {
var matrix = new _PdfTransformationMatrix();
matrix._translate(x, x);
matrix._rotate(angle);
var rectangleF = annotation._transformBBox({ x: bbox[0], y: bbox[1], width: bbox[2], height: bbox[3] }, matrix._matrix._elements);
return rectangleF[2];
}
/**
* Computes the center Y-coordinate after transforming the bounding box by a rotation matrix.
*
* @private
* @param {number} angle The rotation angle in degrees.
* @param {number[]} bbox The bounding box represented as an array of four numbers [x, y, width, height].
* @param {number} y The original center Y-coordinate.
* @param {PdfRubberStampAnnotation} annotation The annotation to be transformed.
* @returns {number} The transformed center Y-coordinate.
*/
export function _getCenterY(angle, bbox, y, annotation) {
var matrix = new _PdfTransformationMatrix();
matrix._translate(y, y);
matrix._rotate(angle);
var rectangleF = annotation._transformBBox({ x: bbox[0], y: bbox[1], width: bbox[2], height: bbox[3] }, matrix._matrix._elements);
return rectangleF[3];
}
/**
* Get the state item style to string
*
* @private
* @param {PdfCheckBoxStyle} style State item style.
* @returns {string} return as string value.
*/
export function _styleToString(style) {
var value = '4';
switch (style) {
case PdfCheckBoxStyle.circle:
value = 'l';
break;
case PdfCheckBoxStyle.cross:
value = '8';
break;
case PdfCheckBoxStyle.diamond:
value = 'u';
break;
case PdfCheckBoxStyle.square:
value = 'n';
break;
case PdfCheckBoxStyle.star:
value = 'H';
break;
}
return value;
}
/**
* Get the string to state item style
*
* @private
* @param {string} style State item style as string.
* @returns {PdfCheckBoxStyle} return as state item style.
*/
export function _stringToStyle(style) {
var value = PdfCheckBoxStyle.check;
switch (style) {
case 'l':
value = PdfCheckBoxStyle.circle;
break;
case '8':
value = PdfCheckBoxStyle.cross;
break;
case 'u':
value = PdfCheckBoxStyle.diamond;
break;
case 'n':
value = PdfCheckBoxStyle.square;
break;
case 'H':
value = PdfCheckBoxStyle.star;
break;
}
return value;
}
/**
* Map measurement unit type.
*
* @private
* @param {string} unitString measurement unit as string.
* @returns {PdfMeasurementUnit} measurement unit.
*/
export function _mapMeasurementUnit(unitString) {
var unit;
switch (unitString) {
case 'cm':
unit = PdfMeasurementUnit.centimeter;
break;
case 'in':
unit = PdfMeasurementUnit.inch;
break;
case 'mm':
unit = PdfMeasurementUnit.millimeter;
break;
case 'p':
unit = PdfMeasurementUnit.pica;
break;
case 'pt':
unit = PdfMeasurementUnit.point;
break;
default:
unit = PdfMeasurementUnit.centimeter;
break;
}
return unit;
}
/**
* Map markup annotation type.
*
* @private
* @param {string} text markup type as string.
* @returns {PdfTextMarkupAnnotationType} markup type as name.
*/
export function _mapMarkupAnnotationType(text) {
var type;
switch (text) {
case 'Highlight':
type = PdfTextMarkupAnnotationType.highlight;
break;
case 'Squiggly':
type = PdfTextMarkupAnnotationType.squiggly;
break;
case 'StrikeOut':
type = PdfTextMarkupAnnotationType.strikeOut;
break;
case 'Underline':
type = PdfTextMarkupAnnotationType.underline;
break;
default:
type = PdfTextMarkupAnnotationType.highlight;
break;
}
return type;
}
/**
* Reverse text markup annotation type.
*
* @private
* @param {PdfTextMarkupAnnotationType} type markup type.
* @returns {string} markup type as name.
*/
export function _reverseMarkupAnnotationType(type) {
var token = 'Highlight';
switch (type) {
case PdfTextMarkupAnnotationType.highlight:
token = 'Highlight';
break;
case PdfTextMarkupAnnotationType.squiggly:
token = 'Squiggly';
break;
case PdfTextMarkupAnnotationType.strikeOut:
token = 'StrikeOut';
break;
case PdfTextMarkupAnnotationType.underline:
token = 'Underline';
break;
default:
token = 'Highlight';
break;
}
return token;
}
/**
* Map graphics unit.
*
* @private
* @param {string} unitString String value.
* @returns {_PdfGraphicsUnit} PDF graphics unit.
*/
export function _mapGraphicsUnit(unitString) {
var unit;
switch (unitString) {
case 'cm':
unit = _PdfGraphicsUnit.centimeter;
break;
case 'in':
unit = _PdfGraphicsUnit.inch;
break;
case 'mm':
unit = _PdfGraphicsUnit.millimeter;
break;
case 'p':
unit = _PdfGraphicsUnit.pica;
break;
case 'pt':
unit = _PdfGraphicsUnit.point;
break;
default:
unit = _PdfGraphicsUnit.centimeter;
break;
}
return unit;
}
/**
* Map rubber stamp icon.
*
* @private
* @param {string} iconString String value.
* @returns {PdfRubberStampAnnotationIcon} Rubber stamp icon.
*/
export function _mapRubberStampIcon(iconString) {
if (iconString.includes('23')) {
iconString = iconString.replace(/\s+/g, '').replace(/23/g, '');
}
var icon;
switch (iconString) {
case '#Approved':
case 'SBApproved':
icon = PdfRubberStampAnnotationIcon.approved;
break;
case '#AsIs':
case 'SBAsIs':
icon = PdfRubberStampAnnotationIcon.asIs;
break;
case '#Completed':
case 'SBCompleted':
icon = PdfRubberStampAnnotationIcon.completed;
break;
case '#Confidential':
case 'SBConfidential':
icon = PdfRubberStampAnnotationIcon.confidential;
break;
case '#Departmental':
case 'SBDepartmental':
icon = PdfRubberStampAnnotationIcon.departmental;
break;
case '#Draft':
case 'SBDraft':
icon = PdfRubberStampAnnotationIcon.draft;
break;
case '#Experimental':
case 'SBExperimental':
icon = PdfRubberStampAnnotationIcon.experimental;
break;
case '#Expired':
case 'SBExpired':
icon = PdfRubberStampAnnotationIcon.expired;
break;
case '#Final':
case 'SBFinal':
icon = PdfRubberStampAnnotationIcon.final;
break;
case '#ForComment':
case 'SBForComment':
icon = PdfRubberStampAnnotationIcon.forComment;
break;
case '#ForPublicRelease':
case 'SBForPublicRelease':
icon = PdfRubberStampAnnotationIcon.forPublicRelease;
break;
case '#InformationOnly':
case 'SBInformationOnly':
icon = PdfRubberStampAnnotationIcon.informationOnly;
break;
case '#NotApproved':
case 'SBNotApproved':
icon = PdfRubberStampAnnotationIcon.notApproved;
break;
case '#NotForPublicRelease':
case 'SBNotForPublicRelease':
icon = PdfRubberStampAnnotationIcon.notForPublicRelease;
break;
case '#PreliminaryResults':
case 'SBPreliminaryResults':
icon = PdfRubberStampAnnotationIcon.preliminaryResults;
break;
case '#Sold':
case 'SBSold':
icon = PdfRubberStampAnnotationIcon.sold;
break;
case '#TopSecret':
case 'SBTopSecret':
icon = PdfRubberStampAnnotationIcon.topSecret;
break;
case '#Void':
case 'SBVoid':
icon = PdfRubberStampAnnotationIcon.void;
break;
default:
icon = PdfRubberStampAnnotationIcon.draft;
break;
}
return icon;
}
/**
* Map popup icon.
*
* @private
* @param {string} iconString String value.
* @returns {PdfRubberStampAnnotationIcon} Popup icon.
*/
export function _mapPopupIcon(iconString) {
var icon;
switch (iconString) {
case 'Note':
icon = PdfPopupIcon.note;
break;
case 'Comment':
icon = PdfPopupIcon.comment;
break;
case 'Help':
icon = PdfPopupIcon.help;
break;
case 'Insert':
icon = PdfPopupIcon.insert;
break;
case 'Key':
icon = PdfPopupIcon.key;
break;
case 'NewParagraph':
icon = PdfPopupIcon.newParagraph;
break;
case 'Paragraph':
icon = PdfPopupIcon.paragraph;
break;
default:
icon = PdfPopupIcon.note;
break;
}
return icon;
}
/**
* Convert annotation state to string value.
*
* @private
* @param {PdfAnnotationState} type Annotation state.
* @returns {string} String value.
*/
export function _reverseMapAnnotationState(type) {
var token = 'None';
switch (type) {
case PdfAnnotationState.none:
token = 'None';
break;
case PdfAnnotationState.accepted:
token = 'Accepted';
break;
case PdfAnnotationState.rejected:
token = 'Rejected';
break;
case PdfAnnotationState.cancel:
token = 'Cancelled';
break;
case PdfAnnotationState.completed:
token = 'Completed';
break;
case PdfAnnotationState.marked:
token = 'Marked';
break;
case PdfAnnotationState.unmarked:
token = 'Unmarked';
break;
case PdfAnnotationState.unknown:
token = 'Unknown';
break;
default:
token = 'None';
break;
}
return token;
}
/**
* Convert string value to annotation state.
*
* @private
* @param {string} type String value.
* @returns {PdfAnnotationState} Annotation state.
*/
export function _mapAnnotationState(type) {
var token = PdfAnnotationState.none;
switch (type) {
case 'None':
token = PdfAnnotationState.none;
break;
case 'Accepted':
token = PdfAnnotationState.accepted;
break;
case 'Rejected':
token = PdfAnnotationState.rejected;
break;
case 'Cancelled':
token = PdfAnnotationState.cancel;
break;
case 'Completed':
token = PdfAnnotationState.completed;
break;
case 'Marked':
token = PdfAnnotationState.marked;
break;
case 'Unmarked':
token = PdfAnnotationState.unmarked;
break;
case 'Unknown':
token = PdfAnnotationState.unknown;
break;
}
return token;
}
/**
* Convert annotation state model to string value.
*
* @private
* @param {PdfAnnotationStateModel} type Annotation state model.
* @returns {string} String value.
*/
export function _reverseMapAnnotationStateModel(type) {
var token = 'None';
switch (type) {
case PdfAnnotationStateModel.none:
token = 'None';
break;
case PdfAnnotationStateModel.marked:
token = 'Marked';
break;
case PdfAnnotationStateModel.review:
token = 'Review';
break;
default:
token = 'None';
break;
}
return token;
}
/**
* Convert string value to annotation state model.
*
* @private
* @param {string} type String value.
* @returns {PdfAnnotationStateModel} Annotation state model.
*/
export function _mapAnnotationStateModel(type) {
var token = PdfAnnotationStateModel.none;
switch (type) {
case 'None':
token = PdfAnnotationStateModel.none;
break;
case 'Marked':
token = PdfAnnotationStateModel.marked;
break;
case 'Review':
token = PdfAnnotationStateModel.review;
break;
}
return token;
}
/**
* Map attachment icon.
*
* @private
* @param {string} iconString String value.
* @returns {PdfAttachmentIcon} Icon.
*/
export function _mapAttachmentIcon(iconString) {
var icon;
switch (iconString) {
case 'PushPin':
icon = PdfAttachmentIcon.pushPin;
break;
case 'Tag':
icon = PdfAttachmentIcon.tag;
break;
case 'Graph':
icon = PdfAttachmentIcon.graph;
break;
case 'Paperclip':
icon = PdfAttachmentIcon.paperClip;
break;
default:
icon = PdfAttachmentIcon.pushPin;
break;
}
return icon;
}
/**
* Map attachment intent.
*
* @private
* @param {string} intentString String value.
* @returns {PdfAnnotationIntent} intent.
*/
export function _mapAnnotationIntent(intentString) {
var intent;
switch (intentString) {
case 'None':
intent = PdfAnnotationIntent.none;
break;
case 'FreeTextCallout':
intent = PdfAnnotationIntent.freeTextCallout;
break;
case 'FreeTextTypeWriter':
intent = PdfAnnotationIntent.freeTextTypeWriter;
break;
default:
intent = PdfAnnotationIntent.none;
break;
}
return intent;
}
/**
* Convert PDF font style to string value.
*
* @private
* @param {PdfFontStyle} style Font style.
* @returns {string} String value.
*/
export function _reverseMapPdfFontStyle(style) {
var value = [];
if ((style & PdfFontStyle.bold) > 0) {
value.push('Bold');
}
if ((style & PdfFontStyle.italic) > 0) {
value.push('Italic');
}
if ((style & PdfFontStyle.underline) > 0) {
value.push('Underline');
}
if ((style & PdfFontStyle.strikeout) > 0) {
value.push('Strikeout');
}
if (value.length === 0) {
return 'Regular';
}
return value.join(', ');
}
/**
* Get special character.
*
* @private
* @param {string} input Input string.
* @returns {string} String value.
*/
export function _getSpecialCharacter(input) {
var result;
switch (input) {
case 'head2right':
result = '\u27A2';
break;
case 'aacute':
result = 'a\u0301';
break;
case 'eacute':
result = 'e\u0301';
break;
case 'iacute':
result = 'i\u0301';
break;
case 'oacute':
result = 'o\u0301';
break;
case 'uacute':
result = 'u\u0301';
break;
case 'circleright':
result = '\u27B2';
break;
case 'bleft':
result = '\u21E6';
break;
case 'bright':
result = '\u21E8';
break;
case 'bup':
result = '\u21E7';
break;
case 'bdown':
result = '\u21E9';
break;
case 'barb4right':
result = '\u2794';
break;
case 'bleftright':
result = '\u2B04';
break;
case 'bupdown':
result = '\u21F3';
break;
case 'bnw':
result = '\u2B00';
break;
case 'bne':
result = '\u2B01';
break;
case 'bsw':
result = '\u2B03';
break;
case 'bse':
result = '\u2B02';
break;
case 'bdash1':
result = '\u25AD';
break;
case 'bdash2':
result = '\u25AB';
break;
case 'xmarkbld':
result = '\u2717';
break;
case 'checkbld':
result = '\u2713';
break;
case 'boxxmarkbld':
result = '\u2612';
break;
case 'boxcheckbld':
result = '\u2611';
break;
case 'space':
result = '\u0020';
break;
case 'pencil':
result = '\u270F';
break;
case 'scissors':
result = '\u2702';
break;
case 'scissorscutting':
result = '\u2701';
break;
case 'readingglasses':
result = '\u2701';
break;
case 'bell':
result = '\u2701';
break;
case 'book':
result = '\u2701';
break;
case 'telephonesolid':
result = '\u2701';
break;
case 'telhandsetcirc':
result = '\u2701';
break;
case 'envelopeback':
result = '\u2701';
break;
case 'hourglass':
result = '\u231B';
break;
case 'keyboard':
result = '\u2328';
break;
case 'tapereel':
result = '\u2707';
break;
case 'handwrite':
result = '\u270D';
break;
case 'handv':
result = '\u270C';
break;
case 'handptleft':
result = '\u261C';
break;
case 'handptright':
result = '\u261E';
break;
case 'handptup':
result = '\u261D';
break;
case 'handptdown':
result = '\u261F';
break;
case 'smileface':
result = '\u263A';
break;
case 'frownface':
result = '\u2639';
break;
case 'skullcrossbones':
result = '\u2620';
break;
case 'flag':
result = '\u2690';
break;
case 'pennant':
result = '\u1F6A9';
break;
case 'airplane':
result = '\u2708';
break;
case 'sunshine':
result = '\u263C';
break;
case 'droplet':
result = '\u1F4A7';
break;
case 'snowflake':
result = '\u2744';
break;
case 'crossshadow':
result = '\u271E';
break;
case 'crossmaltese':
result = '\u2720';
break;
case 'starofdavid':
result = '\u2721';
break;
case 'crescentstar':
result = '\u262A';
break;
case 'yinyang':
result = '\u262F';
break;
case 'om':
result = '\u0950';
break;
case 'wheel':
result = '\u2638';
break;
case 'aries':
result = '\u2648';
break;
case 'taurus':
result = '\u2649';
break;
case 'gemini':
result = '\u264A';
break;
case 'cancer':
result = '\u264B';
break;
case 'leo':
result = '\u264C';
break;
case 'virgo':
result = '\u264D';
break;
case 'libra':
result = '\u264E';
break;
case 'scorpio':
result = '\u264F';
break;
case 'saggitarius':
result = '\u2650';
break;
case 'capricorn':
result = '\u2651';
break;
case 'aquarius':
result = '\u2652';
break;
case 'pisces':
result = '\u2653';
break;
case 'ampersanditlc':
result = '\u0026';
break;
case 'ampersandit':
result = '\u0026';
break;
case 'circle6':
result = '\u25CF';
break;
case 'circleshadowdwn':
result = '\u274D';
break;
case 'square6':
result = '\u25A0';
break;
case 'box3':
result = '\u25A1';
break;
case 'boxshadowdwn':
result = '\u2751';
break;
case 'boxshadowup':
result = '\u2752';
break;
case 'lozenge4':
result = '\u2B27';
break;
case 'lozenge6':
result = '\u29EB';
break;
case 'rhombus6':
result = '\u25C6';
break;
case 'xrhombus':
result = '\u2756';
break;
case 'rhombus4':
result = '\u2B25';
break;
case 'clear':
result = '\u2327';
break;
case 'escape':
result = '\u2353';
break;
case 'command':
result = '\u2318';
break;
case 'rosette':
result = '\u2740';
break;
case 'rosettesolid':
result = '\u273F';
break;
case 'quotedbllftbld':
result = '\u275D';
break;
case 'quotedblrtbld':
result = '\u275E';
break;
case '.notdef':
result = '\u25AF';
break;
case 'zerosans':
result = '\u24EA';
break;
case 'onesans':
result = '\u2460';
break;
case 'twosans':
result = '\u2461';
break;
case 'threesans':
result = '\u2462';
break;
case 'foursans':
result = '\u2463';
break;
case 'fivesans':
result = '\u2464';
break;
case 'sixsans':
result = '\u2465';
break;
case 'sevensans':
result = '\u2466';
break;
case 'eightsans':
result = '\u2467';
break;
case 'ninesans':
result = '\u2468';
break;
case 'tensans':
result = '\u2469';
break;
case 'zerosansinv':
result = '\u24FF';
break;
case 'onesansinv':
result = '\u2776';
break;
case 'twosansinv':
result = '\u2777';
break;
case 'threesansinv':
result = '\u2778';
break;
case 'foursansinv':
result = '\u2779';
break;
case 'circle2':
result = '\u00B7';
break;
case 'circle4':
result = '\u2022';
break;
case 'square2':
result = '\u25AA';
break;
case 'ring2':
result = '\u25CB';
break;
case 'ringbutton2':
result = '\u25C9';
break;
case 'target':
result = '\u25CE';
break;
case 'square4':
result = '\u25AA';
break;
case 'box2':
result = '\u25FB';
break;
case 'crosstar2':
result = '\u2726';
break;
case 'pentastar2':
result = '\u2605';
break;
case 'hexstar2':
result = '\u2736';
break;
case 'octastar2':
result = '\u2734';
break;
case 'dodecastar3':
result = '\u2739';
break;
case 'octastar4':
result = '\u2735';
break;
case 'registercircle':
result = '\u2316';
break;
case 'cuspopen':
result = '\u27E1';
break;
case 'cuspopen1':
result = '\u2311';
break;
case 'circlestar':
result = '\u2605';
break;
case 'starshadow':
result = '\u2730';
break;
case 'deleteleft':
result = '\u232B';
break;
case 'deleteright':
result = '\u2326';
break;
case 'scissorsoutline':
result = '\u2704';
break;
case 'telephone':
result = '\u260F';
break;
case 'telhandset':
result = '\u1F4DE';
break;
case 'handptlft1':
result = '\u261C';
break;
case 'handptrt1':
result = '\u261E';
break;
case 'handptlftsld1':
result = '\u261A';
break;
case 'handptrtsld1':
result = '\u261B';
break;
case 'handptup1':
result = '\u261D';
break;
case 'handptdwn1':
result = '\u261F';
break;
case 'xmark':
result = '\u2717';
break;
case 'check':
result = '\u2713';
break;
case 'boxcheck':
result = '\u2611';
break;
case 'boxx':
result = '\u2612';
break;
case 'boxxbld':
result = '\u2612';
break;
case 'circlex':
result = '=\u2314';
break;
case 'circlexbld':
result = '\u2314';
break;
case 'prohibit':
case 'prohibitbld':
result = '\u29B8';
break;
case 'ampersanditaldm':
case 'ampersandbld':
case 'ampersandsans':
case 'ampersandsandm':
result = '\u0026';
break;
case 'interrobang':
case 'interrobangdm':
case 'interrobangsans':
case 'interrobngsandm':
result = '\u203D';
break;
case 'sacute':
result = 'ś';
break;
case 'Sacute':
result = 'Ś';
break;
case 'eogonek':
result = 'ę';
break;
case 'cacute':
result = 'ć';
break;
case 'aogonek':
result = 'ą';
break;
default:
result = input;
break;
}
return result;
}
/**
* Get latin character.
*
* @private
* @param {string} input Input string.
* @returns {string} String value.
*/
export function _getLatinCharacter(input) {
var result;
switch (input) {
case 'zero':
result = '0';
break;
case 'one':
result = '1';
break;
case 'two':
result = '2';
break;
case 'three':
result = '3';
break;
case 'four':
result = '4';
break;
case 'five':
result = '5';
break;
case 'six':
result = '6';
break;
case 'seven':
result = '7';
break;
case 'eight':
result = '8';
break;
case 'nine':
result = '9';
break;
case 'aacute':
result = 'á';
break;
case 'asciicircum':
result = '^';
break;
case 'asciitilde':
result = '~';
break;
case 'asterisk':
result = '*';
break;
case 'at':
result = '@';
break;
case 'atilde':
result = 'ã';
break;
case 'backslash':
result = '\\';
break;
case 'bar':
result = '|';
break;
case 'braceleft':
result = '{';
break;
case 'braceright':
result = '}';
break;
case 'bracketleft':
result = '[';
break;
case 'bracketright':
result = ']';
break;
case 'breve':
result = '˘';
break;
case 'brokenbar':
result = '|';
break;
case 'bullet3':
result = '•';
break;
case 'bullet':
result = '•';
break;
case 'caron':
result = 'ˇ';
break;
case 'ccedilla':
result = 'ç';
break;
case 'cedilla':
result = '¸';
break;
case 'cent':
result = '¢';
break;
case 'circumflex':
result = 'ˆ';
break;
case 'colon':
result = ':';
break;
case 'comma':
result = ',';
break;
case 'copyright':
result = '©';
break;
case 'currency1':
result = '¤';
break;
case 'dagger':
result = '†';
break;
case 'daggerdbl':
result = '‡';
break;
case 'degree':
result = '°';
break;
case 'dieresis':
result = '¨';
break;
case 'divide':
result = '÷';
break;
case 'dollar':
result = '$';
break;
case 'dotaccent':
result = '˙';
break;
case 'dotlessi':
result = 'ı';
break;
case 'eacute':
result = 'é';
break;
case 'middot':
result = '˙';
break;
case 'edieresis':
result = 'ë';
break;
case 'egrave':
result = 'è';
break;
case 'ellipsis':
result = '...';
break;
case 'emdash':
result = '—';
break;
case 'endash':
result = '–';
break;
case 'equal':
result = '=';
break;
case 'eth':
result = 'ð';
break;
case 'exclam':
result = '!';
break;
case 'exclamdown':
result = '¡';
break;
case 'florin':
result = 'ƒ';
break;
case 'fraction':
result = '⁄';
break;
case 'germandbls':
result = 'ß';
break;
case 'grave':
result = '`';
break;
case 'greater':
result = '>';
break;
case 'guillemotleft4':
result = '«';
break;
case 'guillemotright4':
result = '»';
break;
case 'guilsinglleft':
result = '‹';
break;
case 'guilsinglright':
result = '›';
break;
case 'hungarumlaut':
result = '˝';
break;
case 'hyphen5':
result = '-';
break;
case 'iacute':
result = 'í';
break;
case 'icircumflex':
result = 'î';
break;
case 'idieresis':
result = 'ï';
break;
case 'igrave':
result = 'ì';
break;
case 'less':
result = '<';
break;
case 'logicalnot':
result = '¬';
break;
case 'lslash':
result = 'ł';
break;
case 'Lslash':
result = 'Ł';
break;
case 'macron':
result = '¯';
break;
case 'minus':
result = '−';
break;
case 'mu':
result = 'μ';
break;
case 'multiply':
result = '×';
break;
case 'ntilde':
result = 'ñ';
break;
case 'numbersign':
result = '#';
break;
case 'oacute':
result = 'ó';
break;
case 'ocircumflex':
result = 'ô';
break;
case 'odieresis':
result = 'ö';
break;
case 'oe':
result = 'oe';
break;
case 'ogonek':
result = '˛';
break;
case 'ograve':
result = 'ò';
break;
case 'onehalf':
result = '1/2';
break;
case 'onequarter':
result = '1/4';
break;
case 'onesuperior':
result = '¹';
break;
case 'ordfeminine':
result = 'ª';
break;
case 'ordmasculine':
result = 'º';
break;
case 'otilde':
result = 'õ';
break;
case 'paragraph':
result = '¶';
break;
case 'parenleft':
result = '(';
break;
case 'parenright':
result = ')';
break;
case 'percent':
result = '%';
break;
case 'period':
result = '.';
break;
case 'periodcentered':
result = '·';
break;
case 'perthousand':
result = '‰';
break;
case 'plus':
result = '+';
break;
case 'plusminus':
result = '±';
break;
case 'question':
result = '?';
break;
case 'questiondown':
result = '¿';
break;
case 'quotedbl':
result = '\'';
break;
case 'quotedblbase':
result = '„';
break;
case 'quotedblleft':
result = '“';
break;
case 'quotedblright':
result = '”';
break;
case 'quoteleft':
result = '‘';
break;
case 'quoteright':
result = '’';
break;
case 'quotesinglbase':
result = '‚';
break;
case 'quotesingle':
result = '\'';
break;
case 'registered':
result = '®';
break;
case 'ring':
result = '˚';
break;
case 'scaron':
result = 'š';
break;
case 'section':
result = '§';
break;
case 'semicolon':
result = ';';
break;
case 'slash':
result = '/';
break;
case 'space6':
result = ' ';
break;
case 'space':
result = ' ';
break;
case 'udieresis':
result = 'ü';
break;
case 'uacute':
result = 'ú';
break;
case 'Ecircumflex':
result = 'Ê';
break;
case 'hyphen':
result = '-';
break;
case 'underscore':
result = '_';
break;
case 'adieresis':
result = 'ä';
break;
case 'ampersand':
result = '&';
break;
case 'Adieresis':
result = 'Ä';
break;
case 'Udieresis':
result = 'Ü';
break;
case 'ccaron':
result = 'č';
break;
case 'Scaron':
result = 'Š';
break;
case 'zcaron':
result = 'ž';
break;
case 'sterling':
result = '£';
break;
case 'agrave':
result = 'à';
break;
case 'ecircumflex':
result = 'ê';
break;
case 'acircumflex':
result = 'â';
break;
case 'Oacute':
result = 'Ó';
break;
default:
result = input;
break;
}
return result;
}
/**
* Encode value to string.
*
* @private
* @param {string} value Input string.
* @returns {string} result.
*/
export function _encodeValue(value) {
var name = '';
for (var i = 0; i < value.length; i++) {
var code = value.charCodeAt(i) & 0xff;
var entry = String.fromCharCode(code);
var hex = '';
switch (entry) {
case ' ':
case '%':
case '(':
case ')':
case '<':
case '>':
case '[':
case ']':
case '{':
case '}':
case '/':
case '#':
name += '#';
hex = code.toString(16).toUpperCase();
name += (hex.length === 1 ? ('0' + hex) : hex);
break;
default:
if (code > 126 || code < 37) {
name += '#';
hex = code.toString(16).toUpperCase();
name += (hex.length === 1 ? ('0' + hex) : hex);
}
else {
name += entry;
}
break;
}
}
return name;
}
/**
* Parse and retrieve comments and review history from the annotation.
*
* @private
* @param {PdfComment} annotation Input annotation.
* @param {boolean} isReview Input is review or not.
* @returns {PdfPopupAnnotationCollection} result.
*/
export function _getCommentsOrReview(annotation, isReview) {
if (isReview) {
return annotation.reviewHistory;
}
else {
return annotation.comments;
}
}
/**
* Returns true if input dictionary is belongs to the review history.
*
* @private
* @param {_PdfDictionary} dictionary Input dictionary.
* @returns {boolean} Input is review or not.
*/
export function _checkReview(dictionary) {
var flag = dictionary.get('F');
return ((dictionary.has('State') || dictionary.has('StateModel')) && (flag === 30 || flag === 128));
}
/**
* Returns true if input dictionary is belongs to the comments.
*
* @private
* @param {_PdfDictionary} dictionary Input dictionary.
* @returns {boolean} Input is comments or not.
*/
export function _checkComment(dictionary) {
var flag = dictionary.get('F');
return (!(dictionary.has('State') || dictionary.has('StateModel')) && (flag === 28 || flag === 128));
}
/**
* Update visibility.
*
* @private
* @param {_PdfDictionary} dictionary Input dictionary.
* @param {PdfFormFieldVisibility} value Visibility.
* @returns {void} Nothing.
*/
export function _updateVisibility(dictionary, value) {
if (dictionary.has('F')) {
delete dictionary._map.F;
dictionary._updated = true;
}
switch (value) {
case PdfFormFieldVisibility.hidden:
dictionary.update('F', PdfAnnotationFlag.hidden);
break;
case PdfFormFieldVisibility.hiddenPrintable:
dictionary.update('F', (PdfAnnotationFlag.noView | PdfAnnotationFlag.print));
break;
case PdfFormFieldVisibility.visible:
if (dictionary.has('DV')) {
delete dictionary._map.DV;
dictionary._updated = true;
}
if (dictionary.has('MK')) {
var mkDict = dictionary.get('MK');
if (mkDict && mkDict.has('BG')) {
delete mkDict._map.BG;
mkDict._updated = true;
}
}
break;
}
}
/**
* Remove duplicate reference.
*
* @private
* @param {_PdfDictionary} dictionary Input dictionary.
* @param {_PdfCrossReference} crossTable Cross reference table.
* @param {string} key Key string for appearance type.
* @returns {void} Nothing.
*/
export function _removeDuplicateReference(dictionary, crossTable, key) {
if (dictionary && dictionary.has(key)) {
var oldAppearance = dictionary.getRaw(key);
if (oldAppearance && oldAppearance instanceof _PdfReference && oldAppearance._isNew) {
var appearance = dictionary.get(key); // eslint-disable-line
if (appearance) {
if (appearance instanceof _PdfReference) {
appearance = crossTable._fetch(appearance);
}
var appearanceDictionary = void 0;
if (appearance instanceof _PdfDictionary) {
appearanceDictionary = appearance;
}
else if (appearance instanceof _PdfBaseStream) {
appearanceDictionary = appearance.dictionary;
}
if (appearanceDictionary && appearanceDictionary.has('Resources')) {
_removeDuplicateFromResources(appearanceDictionary.get('Resources'), crossTable);
}
}
crossTable._cacheMap.delete(oldAppearance);
}
}
}
/**
* Remove duplicate reference from resources.
*
* @private
* @param {_PdfDictionary} resources Input resources.
* @param {_PdfCrossReference} crossTable Cross reference table.
* @returns {void} Nothing.
*/
export function _removeDuplicateFromResources(resources, crossTable) {
if (resources && resources.size > 0) {
resources.forEach(function (key, value) {
if (typeof key !== 'undefined' && typeof value !== 'undefined') {
if (value instanceof _PdfReference) {
var reference = value;
if (reference._isNew) {
var dictionary = resources.get(key);
if (dictionary && dictionary instanceof _PdfDictionary) {
if (key === 'XObject' && dictionary.has('Resources')) {
_removeDuplicateFromResources(dictionary.get('Resources'), crossTable);
}
crossTable._cacheMap.delete(reference);
}
}
}
else if (value instanceof _PdfDictionary) {
if (value.has('Resources')) {
_removeDuplicateFromResources(value.get('Resources'), crossTable);
}
if (key === 'Font' || key === 'XObject' || key === 'ExtGState') {
_removeDuplicateFromResources(value, crossTable);
}
}
}
});
}
}
/**
* Remove duplicate reference.
*
* @private
* @param {any} normal Input.
* @param {_PdfCrossReference} crossReference Cross reference table.
* @param {string} firstKey Key string for appearance type.
* @param {string} secondKey Key string for appearance type.
* @returns {void} Nothing.
*/
export function _removeReferences(normal, crossReference, firstKey, secondKey) {
var normalElement;
if (normal) {
if (normal instanceof _PdfDictionary) {
normalElement = normal;
}
else if (normal instanceof _PdfStream) {
normalElement = normal.dictionary;
}
}
if (normalElement) {
_removeDuplicateReference(normalElement, crossReference, firstKey);
_removeDuplicateReference(normalElement, crossReference, secondKey);
}
}
/**
* Represents the base class for all custom exceptions.
* Provides a message and a name for the exception.
*/
var BaseException = /** @class */ (function () {
/**
* Creates a new BaseException instance.
*
* @private
* @param {string} message - The error message.
* @param {string} name - The name of the exception.
*/
function BaseException(message, name) {
this.message = message;
this.name = name;
}
return BaseException;
}());
export { BaseException };
/**
* Represents an error related to invalid format.
* Extends BaseException.
*/
var FormatError = /** @class */ (function (_super) {
__extends(FormatError, _super);
/**
* Creates a new FormatError instance.
*
* @param {string} message - The error message describing the format issue.
*/
function FormatError(message) {
return _super.call(this, message, 'FormatError') || this;
}
return FormatError;
}(BaseException));
export { FormatError };
/**
* Represents an error thrown when the parser reaches the end of the file unexpectedly.
* Extends BaseException.
*/
var ParserEndOfFileException = /** @class */ (function (_super) {
__extends(ParserEndOfFileException, _super);
/**
* Creates a new ParserEndOfFileException instance.
*
* @param {string} message - The error message describing the EOF condition.
*/
function ParserEndOfFileException(message) {
return _super.call(this, message, 'ParserEndOfFileException') || this;
}
return ParserEndOfFileException;
}(BaseException));
export { ParserEndOfFileException };
/**
* Gets the default string.
*
* @private
* @param {string} item Input string.
* @returns {string} result.
*/
export function _defaultToString(item) {
if (Object.prototype.toString.call(item) === '[object String]') {
return '$s' + item;
}
else {
return '$o' + item.toString();
}
}
/**
* Gets the form field font.
*
* @private
* @param {PdfForm} form form.
* @param {PdfWidgetAnnotation} widget widget annotation.
* @param {PdfField} field field.
* @returns {PdfFont} font.
*/
export function _obtainFontDetails(form, widget, field) {
var fontFamily = '';
var fontSize;
var font;
var defaultAppearance; // eslint-disable-line
var cacheKey;
var hasValidFontCache = true;
if (widget && widget._dictionary.has('DA') || field._dictionary.has('DA')) {
if (widget && widget._dictionary.has('DA')) {
defaultAppearance = widget._dictionary.get('DA');
}
else {
defaultAppearance = field._dictionary.get('DA');
}
}
if (defaultAppearance instanceof _PdfName) {
defaultAppearance = defaultAppearance.name;
}
if (defaultAppearance && defaultAppearance.includes('Tf')) {
var parts = defaultAppearance.trim().split(/\s+/);
var index = parts.indexOf('Tf');
if (index >= 2) {
fontFamily = parts[index - 2];
if (fontFamily.startsWith('/')) {
fontFamily = fontFamily.slice(1);
}
if (fontFamily) {
fontFamily = _decodeFontFamily(fontFamily);
}
fontSize = parseFloat(parts[index - 1]);
}
}
if (fontFamily) {
fontFamily = fontFamily.trim();
}
if (form && form._dictionary.has('DR')) {
var resources = form._dictionary.get('DR');
if (resources.has('Font')) {
var fonts = resources.get('Font');
if (fonts.has(fontFamily)) {
var fontDictionary = fonts.get(fontFamily);
if (fontDictionary && fontFamily && fontDictionary.has('BaseFont')) {
var baseFont = fontDictionary.get('BaseFont');
var textFontStyle = PdfFontStyle.regular;
var family = PdfFontFamily.helvetica;
if (fontFamily !== null && typeof fontFamily !== 'undefined' && fontFamily !== '') {
family = _getFontFamily(fontFamily);
}
if (fontSize === 0) {
fontSize = _getFontSize(field, family);
}
if (field && field._dictionary.has('AP')) {
hasValidFontCache = _hasSharedFontResource(field);
}
if (hasValidFontCache) {
cacheKey = fontFamily + "_" + fontSize + "_" + textFontStyle;
}
if (baseFont) {
defaultAppearance = baseFont.name;
if (baseFont.name === 'Helvetica') {
baseFont.name = 'Helv';
}
textFontStyle = _getFontStyle(baseFont.name);
if (form && form._fontCache && form._fontCache.has(cacheKey) && fontSize !== 0) {
font = form._fontCache.get(cacheKey);
if (field && field._dictionary && field._dictionary.has('V') && font instanceof PdfTrueTypeFont) {
font._isUnicode = _checkUnicodeString(field._dictionary);
}
}
if (!font) {
if (defaultAppearance.includes('-')) {
defaultAppearance = defaultAppearance.substring(0, defaultAppearance.indexOf('-'));
}
if (widget && widget._dictionary.has('DA')) {
if (widget._dictionary.has('AP')) {
font = _mapFont(defaultAppearance, fontSize, textFontStyle, widget);
}
else {
font = _mapFont(defaultAppearance, fontSize, textFontStyle, widget, fontDictionary);
}
}
else if (field && field._dictionary.has('DA')) {
if (field._dictionary.has('AP')) {
font = _mapFont(defaultAppearance, fontSize, textFontStyle, field);
}
else {
font = _mapFont(defaultAppearance, fontSize, textFontStyle, field, fontDictionary);
}
}
}
}
if (!hasValidFontCache && font instanceof PdfStandardFont && field instanceof PdfTextBoxField &&
!field._isTextChanged && fontDictionary) {
var widthTable = font._metrics._widthTable;
var metrics = _createFontMetrics(fontDictionary, font.height, baseFont.name, font);
if (metrics) {
font._metrics = metrics;
}
font._metrics._widthTable = widthTable;
}
}
}
}
if (font && font._dictionary && font._dictionary.has('BaseFont')) {
var fontName = font._dictionary.get('BaseFont').name;
if (fontName && fontName !== fontFamily) {
var fonts = resources.get('Font');
if (fonts && fonts.has(fontFamily)) {
var fontDictionary = fonts.get(fontFamily);
var fontSubtType = fontDictionary.get('Subtype').name; // eslint-disable-line
if (fontDictionary && fontFamily && fontDictionary.has('BaseFont')) {
var baseFont = fontDictionary.get('BaseFont');
var textFontStyle = baseFont ? _getFontStyle(baseFont.name) : PdfFontStyle.regular;
if (fontSubtType === 'TrueType') {
var fontData = _createFontStream(form, fontDictionary);
if (fontData && fontData.length > 0) {
var base64String = _encode(fontData);
if (base64String && base64String.length > 0) {
var isUnicode = true;
if (widget || field) {
var dictionary = widget ? widget._dictionary : field._dictionary;
if (dictionary && dictionary.has('V')) {
var text = dictionary.get('V');
if (text !== null && typeof text !== 'undefined') {
isUnicode = _isUnicode(text);
if (dictionary.has('FT')) {
var type = dictionary.get('FT');
if (type.name === 'Ch' && dictionary.has('Opt')) {
var options = dictionary.get('Opt');
if (options && options.length > 0) {
for (var _i = 0, _a = options.filter(function (innerArray) { return innerArray.length > 1; }); _i < _a.length; _i++) {
var _b = _a[_i], itemsKey = _b[0], itemsValue = _b[1];
if (itemsKey === text) {
isUnicode = _isUnicode(itemsValue);
break;
}
}
}
}
}
}
}
}
font = new PdfTrueTypeFont(base64String, fontSize, textFontStyle);
font._isUnicode = isUnicode;
}
}
}
}
}
}
}
}
if ((font === null || typeof font === 'undefined') && typeof fontSize !== 'undefined') {
var family = PdfFontFamily.helvetica;
if (fontFamily !== null && typeof fontFamily !== 'undefined' && fontFamily !== '') {
family = _getFontFamily(fontFamily);
}
if (fontSize === 0) {
fontSize = _getFontSize(field, family);
}
font = new PdfStandardFont(family, fontSize, PdfFontStyle.regular);
}
if ((font === null || typeof font === 'undefined') || (font && font.size === 1)) {
if (widget && !(widget._field instanceof PdfComboBoxField)) {
font = widget._circleCaptionFont;
}
else if (field) {
font = field._circleCaptionFont;
}
}
if (form && form._fontCache && fontSize !== 0 && font && typeof cacheKey === 'string' && !form._fontCache.has(cacheKey)) {
form._fontCache.set(cacheKey, font);
}
return font;
}
/**
* Gets the form field font metrics.
*
* @private
* @param {_PdfDictionary} fontDictionary Form field.
* @param {number} height Font family.
* @param {string} baseFontName Font name.
* @param {PdfStandardFont} font The font.
* @returns {_PdfFontMetrics} Font metrics.
*/
export function _createFontMetrics(fontDictionary, height, baseFontName, font) {
var fontMetrics;
if (fontDictionary.has('FontDescriptor')) {
fontMetrics = new _PdfFontMetrics();
var fontDescriptor = fontDictionary.get('FontDescriptor');
if (fontDescriptor) {
font._ascent = fontDescriptor.get('Ascent');
font._descent = fontDescriptor.get('Descent');
font._ascent = fontDescriptor.get('Ascent');
font._height = font._ascent - font._descent;
fontMetrics._postScriptName = baseFontName;
}
}
if (fontMetrics && fontDictionary.has('Widths')) {
var widths = fontDictionary.getArray('Widths');
fontMetrics._widthTable = new _StandardWidthTable(widths);
}
if (fontMetrics) {
fontMetrics._name = baseFontName;
}
return fontMetrics;
}
/**
* Gets the form field font size.
*
* @private
* @param {PdfField} field Form field.
* @param {PdfFontFamily} family Font family.
* @returns {number} Font size.
*/
export function _getFontSize(field, family) {
var selectedValue;
var measureValue = [];
var s = 0;
try {
if (field instanceof PdfComboBoxField) {
var boundsWidth = field.bounds.width;
var boundsHeight = field.bounds.height;
var itemFont = new PdfStandardFont(family, 12);
if (typeof field.selectedIndex === 'number') {
var item = field.itemAt(field.selectedIndex);
if (item && typeof item.text === 'string') {
selectedValue = item.text;
measureValue.push(itemFont.measureString(selectedValue));
}
}
else if (Array.isArray(field.selectedIndex)) {
for (var i = 0; i < field.selectedIndex.length; i++) {
selectedValue = field.itemAt(field.selectedIndex[i]).text;
measureValue.push(itemFont.measureString(selectedValue));
}
}
var offset = [0, 0];
var borderWidth = field.border.width;
var doubleBorderWidth = 2 * borderWidth;
var defaultPadding = 2;
var padding = (field.border.style === PdfBorderStyle.inset || field.border.style === PdfBorderStyle.beveled);
if (padding) {
offset[0] = 2 * doubleBorderWidth;
offset[1] = 2 * borderWidth;
}
else {
offset[0] = doubleBorderWidth + defaultPadding;
offset[1] = 1 * borderWidth + (defaultPadding - 1);
}
var rect = [0, 0, boundsWidth, boundsHeight];
var width = rect[2] - doubleBorderWidth;
var rectangle = rect;
if (padding) {
rectangle[3] -= doubleBorderWidth;
}
else {
rectangle[3] -= borderWidth;
}
if (field.rotationAngle === 0 && padding) {
width -= doubleBorderWidth;
}
if (measureValue.length > 0) {
var maxWidthSize = (12 * (width - offset[0])) / measureValue[measureValue.length - 1].width;
var maxHeightSize = (12 * (rect[3] - offset[1])) / measureValue[measureValue.length - 1].height;
s = Math.min(maxWidthSize, maxHeightSize);
}
else {
s = 12;
}
if (field._obtainSelectedValue().length !== 0) {
var fonts = new PdfStandardFont(family, s);
var text = field._dictionary.get('V');
var textSize = void 0;
if (typeof text !== 'undefined') {
if (Array.isArray(text) && text.length >= 1) {
textSize = fonts.measureString(text[0]);
}
else {
textSize = fonts.measureString(text);
}
}
if (typeof textSize !== 'undefined') {
if (textSize.width > boundsWidth || textSize.height > boundsHeight) {
var width_1 = boundsWidth - 4 * field.border.width;
var heightLimit = boundsHeight - 4 * field.border.width;
var minimumFontSize = 0.248;
var fontSize = s;
for (var i = 1; i <= boundsHeight; i++) {
fonts = new PdfStandardFont(family, i);
fonts._size = i;
var textSize_1 = void 0;
if (typeof text !== 'undefined') {
if (Array.isArray(text) && text.length >= 1) {
textSize_1 = fonts.measureString(text[0]);
}
else {
textSize_1 = fonts.measureString(text);
}
}
if (textSize_1.width > boundsWidth || textSize_1.height > heightLimit) {
fontSize = i;
do {
fontSize -= 0.001;
if (fontSize < minimumFontSize) {
fonts._size = minimumFontSize;
break;
}
fonts = new PdfStandardFont(family, fontSize);
fonts._size = fontSize;
var stringFormat = field._getStringFormat();
if (Array.isArray(text) && text.length >= 1) {
text = text[0];
}
var textWidth = fonts.getLineWidth(text, stringFormat);
var newSize = fonts.measureString(text, stringFormat);
if (textWidth < width_1 && newSize.height < heightLimit) {
fonts._size = fontSize;
break;
}
} while (fontSize > minimumFontSize);
s = fontSize;
break;
}
}
}
}
}
else if (s > 12) {
s = 12;
}
}
else if (field instanceof PdfTextBoxField) {
var boundsWidth = field.bounds.width;
var boundsHeight = field.bounds.height;
var text = field.text || '';
var offset = [0, 0];
var borderWidth = field.border.width;
var doubleBorderWidth = 2 * borderWidth;
var defaultPadding = 2;
var hasPadding = (field.border.style === PdfBorderStyle.inset || field.border.style === PdfBorderStyle.beveled);
if (hasPadding) {
offset[0] = 2 * doubleBorderWidth;
offset[1] = 2 * borderWidth;
}
else {
offset[0] = doubleBorderWidth + defaultPadding;
offset[1] = borderWidth + defaultPadding - 1;
}
var availableWidth = boundsWidth - offset[0];
var availableHeight = boundsHeight - offset[1];
var refFontSize = 12;
var refFont = new PdfStandardFont(family, refFontSize);
if (!field.multiLine) {
var refSize = refFont.measureString(text);
if (refSize.width > 0 && refSize.height > 0) {
var sizeBasedOnWidth = (refFontSize * availableWidth) / refSize.width;
var sizeBasedOnHeight = (refFontSize * availableHeight) / refSize.height;
s = Math.min(sizeBasedOnWidth, sizeBasedOnHeight);
}
else {
s = 8;
}
}
else {
s = 12.5;
}
}
}
catch (e) {
if (field instanceof PdfTextBoxField) {
if (field.multiLine) {
s = 12.5;
}
else {
s = 8;
}
}
else {
s = 12;
}
}
return s === 0 ? 12 : s;
}
/**
* Gets the form field font family.
*
* @private
* @param {string} name Font name.
* @returns {PdfFontFamily} Font family.
*/
export function _getFontFamily(name) {
var fontFamily = name ? name : '';
if (fontFamily.includes('-')) {
fontFamily = fontFamily.substring(0, fontFamily.indexOf('-'));
}
switch (fontFamily) {
case 'Helv':
case 'Helvetica':
return PdfFontFamily.helvetica;
case 'Cour':
case 'Courier':
return PdfFontFamily.courier;
case 'Symb':
case 'Symbol':
return PdfFontFamily.symbol;
case 'Times':
case 'TiRo':
case 'TimesRoman':
return PdfFontFamily.timesRoman;
case 'ZaDb':
case 'ZapfDingbats':
return PdfFontFamily.zapfDingbats;
}
return PdfFontFamily.helvetica;
}
/**
* Gets the font style.
*
* @private
* @param {string} fontFamilyString Font family string.
* @returns {PdfFontStyle} result.
*/
export function _getFontStyle(fontFamilyString) {
var position = fontFamilyString.indexOf('-');
if (position < 0) {
position = fontFamilyString.indexOf(',');
}
var style = PdfFontStyle.regular;
if (position >= 0) {
var standardName = fontFamilyString.substring(position + 1, fontFamilyString.length);
switch (standardName) {
case 'Bold':
case 'BoldMT':
style = PdfFontStyle.bold;
break;
case 'Italic':
case 'ItalicMT':
case 'Oblique':
case 'It':
style = PdfFontStyle.italic;
break;
case 'BoldItalic':
case 'BoldItalicMT':
case 'BoldOblique':
style = PdfFontStyle.bold | PdfFontStyle.italic;
break;
}
}
return style;
}
/**
* Map the font.
*
* @private
* @param {string} name Font name.
* @param {number} size Font size.
* @param {PdfFontStyle} style Font style.
* @param {PdfAnnotation} annotation Annotation or Field.
* @param {_PdfDictionary} fontDictionary Font dictionary.
* @returns {PdfFont} result.
*/
export function _mapFont(name, size, style, annotation, fontDictionary) {
var font;
var fontData;
var fontFamily = name ? name : '';
if (fontFamily.includes('-')) {
fontFamily = fontFamily.substring(0, fontFamily.indexOf('-'));
}
if (typeof size === 'undefined' && annotation instanceof PdfLineAnnotation && annotation._isLoaded) {
size = 10;
}
var fontSize = typeof size !== 'undefined' ? size : 1;
if (annotation._dictionary.has('DS') || annotation._dictionary.has('DA') || annotation instanceof PdfRedactionAnnotation
&& annotation._dictionary.has('AP')) {
switch (fontFamily) {
case 'Helv':
case 'Helvetica':
font = new PdfStandardFont(PdfFontFamily.helvetica, fontSize, style);
break;
case 'Cour':
case 'Courier':
font = new PdfStandardFont(PdfFontFamily.courier, fontSize, style);
break;
case 'Symb':
case 'Symbol':
font = new PdfStandardFont(PdfFontFamily.symbol, fontSize, style);
break;
case 'Times':
case 'TiRo':
case 'TimesRoman':
font = new PdfStandardFont(PdfFontFamily.timesRoman, fontSize, style);
break;
case 'ZaDb':
case 'ZapfDingbats':
font = new PdfStandardFont(PdfFontFamily.zapfDingbats, fontSize, style);
break;
case 'MonotypeSungLight':
font = new PdfCjkStandardFont(PdfCjkFontFamily.monotypeSungLight, fontSize, style);
break;
case 'SinoTypeSongLight':
font = new PdfCjkStandardFont(PdfCjkFontFamily.sinoTypeSongLight, fontSize, style);
break;
case 'MonotypeHeiMedium':
font = new PdfCjkStandardFont(PdfCjkFontFamily.monotypeHeiMedium, fontSize, style);
break;
case 'HanyangSystemsGothicMedium':
font = new PdfCjkStandardFont(PdfCjkFontFamily.hanyangSystemsGothicMedium, fontSize, style);
break;
case 'HanyangSystemsShinMyeongJoMedium':
font = new PdfCjkStandardFont(PdfCjkFontFamily.hanyangSystemsShinMyeongJoMedium, fontSize, style);
break;
case 'HeiseiKakuGothicW5':
font = new PdfCjkStandardFont(PdfCjkFontFamily.heiseiKakuGothicW5, fontSize, style);
break;
case 'HeiseiMinchoW3':
font = new PdfCjkStandardFont(PdfCjkFontFamily.heiseiMinchoW3, fontSize, style);
break;
default:
if (annotation._dictionary.has('AP')) {
fontData = _tryParseFontStream(annotation._crossReference, annotation, name);
}
else if (fontDictionary) {
fontData = _getFontFromDescriptor(fontDictionary);
}
if (fontData && fontData.length > 0) {
var ttf = new PdfTrueTypeFont(fontData, fontSize, style);
if (annotation._dictionary && annotation._dictionary.has('V')) {
ttf._isUnicode = _checkUnicodeString(annotation._dictionary);
}
font = ttf;
}
break;
}
}
if (font === null || typeof font === 'undefined') {
var isAnnotation = annotation instanceof PdfAnnotation;
var isField = annotation instanceof PdfField;
if ((isAnnotation && !(annotation instanceof PdfRedactionAnnotation)) || isField) {
var annotationType = annotation._type;
var hasCircleFont = annotation._circleCaptionFont && fontSize > annotation._circleCaptionFont.size;
var isWidget = isAnnotation && annotationType !== _PdfAnnotationType.widgetAnnotation;
var isLargerTextBox = annotation instanceof PdfTextBoxField && hasCircleFont;
var isLargerComboBox = annotation instanceof PdfComboBoxField && hasCircleFont;
if (isWidget || isLargerTextBox || isLargerComboBox) {
font = new PdfStandardFont(PdfFontFamily.helvetica, fontSize, style);
}
else {
font = annotation._circleCaptionFont;
}
if (annotationType === _PdfAnnotationType.widgetAnnotation && hasCircleFont) {
font = new PdfStandardFont(PdfFontFamily.helvetica, fontSize, style);
}
}
}
return font;
}
/**
* Checks whether the value of a form field is a Unicode string.
*
* @private
* @param {_PdfDictionary} dictionary - The dictionary representing the form field.
* @returns {boolean} `true` if the value or corresponding display value is Unicode; otherwise, `false`..
*/
function _checkUnicodeString(dictionary) {
var isUnicode = true;
var text = dictionary.get('V');
if (text !== null && typeof text !== 'undefined') {
isUnicode = _isUnicode(text);
if (dictionary.has('FT')) {
var type = dictionary.get('FT');
if (type.name === 'Ch' && dictionary.has('Opt')) {
var options = dictionary.get('Opt');
if (options && options.length > 0) {
for (var i = 0; i < options.length; i++) {
var innerArray = options[i];
if (innerArray && innerArray.length > 1) {
var itemsKey = innerArray[0];
var itemsValue = innerArray[1];
if (itemsKey && itemsValue) {
if (itemsKey === text && itemsValue) {
isUnicode = _isUnicode(itemsValue);
break;
}
}
}
}
}
}
}
}
return isUnicode;
}
/**
* Retrieves the font resources dictionary from a widget's appearance stream.
*
* @private
* @param {PdfWidgetAnnotation | PdfField} annotation The annotation or field containing the appearance stream.
* @returns {_PdfDictionary} The font resources dictionary, or undefined if not found.
*/
function _getAppearanceFontResources(annotation) {
var fontResources;
var widgetDictionary = annotation._dictionary;
if (widgetDictionary && widgetDictionary.has('AP')) {
var appearance = widgetDictionary.get('AP');
if (appearance && appearance instanceof _PdfDictionary && appearance.has('N')) {
var baseStream = appearance.get('N'); // eslint-disable-line
var normal = void 0;
if (baseStream) {
if (baseStream instanceof _PdfStream) {
normal = baseStream;
}
else if (baseStream.stream && baseStream.stream instanceof _PdfStream) {
normal = baseStream.stream;
}
}
if (normal && normal.dictionary && normal.dictionary.has('Resources')) {
var resourcesDictionary = normal.dictionary.get('Resources');
if (resourcesDictionary && resourcesDictionary instanceof _PdfDictionary && resourcesDictionary.has('Font')) {
var fontDictionary = resourcesDictionary.get('Font');
if (fontDictionary instanceof _PdfDictionary) {
fontResources = fontDictionary;
}
}
}
}
}
return fontResources;
}
/**
* Checks if a font resource from the field's appearance stream is also defined in the form's default resources.
*
* @private
* @param {PdfAnnotation | PdfField} annotation The annotation or field object.
* @returns {boolean} Returns `true` if the form field appearance font has a form object font resource.
*/
export function _hasSharedFontResource(annotation) {
var hasFontResources = false;
var fontDictionary = _getAppearanceFontResources(annotation);
if (fontDictionary && annotation instanceof PdfField) {
var form = annotation.form;
if (form && form._dictionary.has('DR')) {
var resources = form._dictionary.get('DR');
if (resources.has('Font')) {
if (!form._fontResources) {
form._fontResources = resources.get('Font');
}
var fonts_1 = form._fontResources;
if (fonts_1) {
fontDictionary.forEach(function (key, value) {
if (fonts_1.has(key)) {
hasFontResources = true;
}
});
}
}
}
}
return hasFontResources;
}
/**
* Gets the font stream.
*
* @private
* @param {_PdfCrossReference} crossReference Cross reference.
* @param {PdfAnnotation} annotation Annotation.
* @param {string} fontResourceName Font resource name.
* @returns {Uint8Array} result.
*/
export function _tryParseFontStream(crossReference, annotation, fontResourceName) {
var fontData;
var appearanceFonts = _getAppearanceFontResources(annotation);
if (appearanceFonts) {
appearanceFonts.forEach(function (key, value) {
if (!fontData && value instanceof _PdfReference) {
var dictionary = crossReference._fetch(value);
fontData = _getFontFromDescriptor(dictionary);
}
});
}
if (!fontData && annotation instanceof PdfField && fontResourceName) {
var form = annotation.form;
if (form && form._dictionary.has('DR')) {
var resources = form._dictionary.get('DR');
if (resources && resources.has('Font')) {
var fonts = resources.get('Font');
if (fonts && fonts.has(fontResourceName)) {
var fontDictionary = fonts.get(fontResourceName);
if (fontDictionary) {
fontData = _getFontFromDescriptor(fontDictionary);
}
}
}
}
}
return fontData;
}
/**
* Gets the font data.
*
* @private
* @param {_PdfDictionary} dictionary font dictionary.
* @returns {Uint8Array} result.
*/
export function _getFontFromDescriptor(dictionary) {
var fontData;
var fontDescriptor;
if (dictionary && dictionary.has('DescendantFonts')) {
var descendant = dictionary.getArray('DescendantFonts'); // eslint-disable-line
if (descendant && descendant.length > 0) {
descendant.forEach(function (descendantFont) {
if (descendantFont && descendantFont instanceof _PdfDictionary && descendantFont.has('FontDescriptor')) {
fontDescriptor = descendantFont.get('FontDescriptor');
}
});
}
}
else if (dictionary && dictionary.has('FontDescriptor')) {
fontDescriptor = dictionary.get('FontDescriptor');
}
if (fontDescriptor && fontDescriptor.has('FontFile2')) {
var fontFile = fontDescriptor.get('FontFile2'); // eslint-disable-line
if (fontFile instanceof _PdfStream && fontFile.length > 0) {
fontData = fontFile.getByteRange(fontFile.start, fontFile.end);
}
else if (fontFile.stream && fontFile.dictionary &&
(fontFile.dictionary.has('Length1') || fontFile.dictionary.has('Length'))) {
var streamLength = fontFile.dictionary.get(fontFile.dictionary.has('Length1') ? 'Length1' : 'Length');
fontFile.getBytes(streamLength);
fontData = fontFile.buffer.subarray(0, streamLength);
}
}
return fontData;
}
/**
* Gets the boolean if two arrays are equal.
*
* @private
* @param {Array<number[]>} inkPointsCollection Ink points collection.
* @param {Array<number[]>} previousCollection Previous collection.
* @returns {boolean} result.
*/
export function _checkInkPoints(inkPointsCollection, previousCollection) {
if (inkPointsCollection.length !== previousCollection.length) {
return false;
}
return inkPointsCollection.every(function (point, index) {
return _arePointsEqual(point, previousCollection[index]);
});
}
/**
* Update the annotation bounds.
*
* @private
* @param {PdfAnnotation} annotation annotation.
* @param {number[]} bounds annotation bounds.
* @returns {number[]} bounds.
*/
export function _updateBounds(annotation, bounds) {
if (bounds) {
annotation._bounds = { x: bounds[0], y: bounds[1], width: bounds[2], height: bounds[3] };
}
var rect;
if (annotation._page && annotation.bounds) {
rect = [annotation.bounds.x, annotation.bounds.y + annotation.bounds.height,
annotation.bounds.width, annotation.bounds.height];
if (annotation._page._isNew && annotation._page._pageSettings) {
var pageSettings = annotation._page._pageSettings;
var pageBounds = [pageSettings.margins.left, pageSettings.margins.top, pageSettings.size.width -
(pageSettings.margins.left + pageSettings.margins.right),
pageSettings.size.height - (pageSettings.margins.top + pageSettings.margins.bottom)];
rect[0] += pageBounds[0];
rect[1] = pageSettings.size.height - (pageBounds[1] + rect[1]);
}
else {
var size = annotation._page.size;
rect[1] = size.height - (annotation.bounds.y + annotation.bounds.height);
var cropBoxOrMediaBox = annotation._getCropOrMediaBox();
if (cropBoxOrMediaBox && cropBoxOrMediaBox.length > 2 && (cropBoxOrMediaBox[0] !== 0 || cropBoxOrMediaBox[1] !== 0)) {
rect[0] += cropBoxOrMediaBox[0];
rect[1] += cropBoxOrMediaBox[1];
}
}
if (annotation._page && typeof annotation._page._getTemplateReservedSpace === 'function') {
var reserved = annotation._page._getTemplateReservedSpace();
if (reserved && reserved.length >= 4) {
rect[0] += reserved[3];
rect[1] -= reserved[0];
}
}
return [rect[0], rect[1], rect[0] + rect[2], rect[1] + rect[3]];
}
return rect;
}
/**
* Trim a specific trailing substring from the end of a string, if it matches exactly.
*
* @private
* @param {string} s - The input string.
* @param {string} tail - The exact tail to remove.
* @returns {string} The trimmed or original string.
*/
export function _trimTailIfMatches(s, tail) {
if (!s || !tail) {
return s;
}
if (s.length < tail.length) {
return s;
}
var start = s.length - tail.length;
for (var i = 0; i < tail.length; i++) {
if (s.charCodeAt(start + i) !== tail.charCodeAt(i)) {
return s;
}
}
return s.substring(0, start);
}
/**
* Decode text.
*
* @private
* @param {string} text Text to decode.
* @param {boolean} isColorSpace Color space or not
* @param {boolean} isPassword Password or not
* @returns {string} Decoded text.
*/
export function _decodeText(text, isColorSpace, isPassword) {
if (!text || typeof text !== 'string' || isColorSpace || isPassword) {
return text;
}
if (text.length < 2) {
return text;
}
var b0 = text.charCodeAt(0) & 0xFF;
var b1 = text.charCodeAt(1) & 0xFF;
var isBE = (b0 === 0xFE && b1 === 0xFF);
var isLE = (b0 === 0xFF && b1 === 0xFE);
if (!isBE && !isLE) {
return text;
}
var body = text.substring(2);
if (isBE) {
body = _trimTailIfMatches(body, '\u00FF\u00FD');
}
else {
body = _trimTailIfMatches(body, '\u00FD\u00FF');
}
if (body.length > 0 && ((body.charCodeAt(body.length - 1) & 0xFF) === 0x00)) {
body = body.substring(0, body.length - 1);
}
var n = body.length;
if (n === 0) {
return '';
}
var bytes = new Uint8Array(n);
for (var i = 0; i < n; i++) {
bytes[i] = body.charCodeAt(i) & 0xFF;
}
if ((bytes.length & 1) !== 0) {
var fixed = new Uint8Array(bytes.length + 1);
if (isLE) {
fixed.set(bytes, 0);
fixed[bytes.length] = 0x00;
}
else {
fixed[0] = 0x00;
fixed.set(bytes, 1);
}
return _decodeUtf16Bytes(fixed, isBE);
}
return _decodeUtf16Bytes(bytes, isBE);
}
/**
* Decodes a UTF 16 byte array (big-endian or little-endian) into a string.
*
* @private
* @param {Uint8Array} bytes - Even-length UTF 16 byte sequence.
* @param {boolean} isBE - Whether the byte order is big-endian (`true` for UTF 16BE, `false` for UTF 16LE).
* @returns {string} The decoded string.
*/
export function _decodeUtf16Bytes(bytes, isBE) {
var len = bytes.length;
var unitsLen = len / 2;
var codeUnits = new Array(unitsLen);
if (isBE) {
for (var bi = 0, ui = 0; bi < len; bi += 2, ui++) {
codeUnits[ui] = (bytes[bi] << 8) | bytes[bi + 1];
}
}
else {
for (var bi = 0, ui = 0; bi < len; bi += 2, ui++) {
codeUnits[ui] = (bytes[bi + 1] << 8) | bytes[bi];
}
}
return String.fromCharCode.apply(null, codeUnits);
}
/**
* Number of bytes required to save the number.
*
* @private
* @param {number} input number.
* @returns {number} number of bytes.
*/
export function _getSize(input) {
var size = 0;
var uintMaxValue = 0xFFFFFFFF;
var ushortMaxValue = 0xFFFF;
var byteMaxValue = 0xFF;
if (input <= uintMaxValue) {
if (input <= ushortMaxValue) {
if (input <= byteMaxValue) {
size = 1;
}
else {
size = 2;
}
}
else {
if (input <= (ushortMaxValue | (ushortMaxValue << 8))) {
size = 3;
}
else {
size = 4;
}
}
}
else {
size = 8;
}
return size;
}
/**
* Convert the string to big endian bytes.
*
* @private
* @param {string} input string.
* @returns {number[]} bytes.
*/
export function _stringToBigEndianBytes(input) {
var bytes = [];
for (var i = 0; i < input.length; i++) {
var charCode = input.charCodeAt(i);
if (charCode <= 0xFFFF) {
bytes.push((charCode >> 8) & 0xFF);
bytes.push(charCode & 0xFF);
}
}
return bytes;
}
/**
* Convert number respect to ordered list number style.
*
* @private
* @param {number} intArabic Input value.
* @param {PdfNumberStyle} numberStyle Number style.
* @returns {string} String value.
*/
export function _convertNumber(intArabic, numberStyle) {
switch (numberStyle) {
case PdfNumberStyle.none:
return '';
case PdfNumberStyle.numeric:
return intArabic.toString();
case PdfNumberStyle.lowerLatin:
return _arabicToLetter(intArabic).toLowerCase();
case PdfNumberStyle.lowerRoman:
return _arabicToRoman(intArabic).toLowerCase();
case PdfNumberStyle.upperLatin:
return _arabicToLetter(intArabic);
case PdfNumberStyle.upperRoman:
return _arabicToRoman(intArabic);
}
}
/**
* Convert arabic numbers to roman style.
*
* @private
* @param {number} intArabic Input value.
* @returns {string} String value.
*/
export function _arabicToRoman(intArabic) {
var retval = '';
var romanNumerals = [
[1000, 'M'], [900, 'CM'], [500, 'D'], [400, 'CD'],
[100, 'C'], [90, 'XC'], [50, 'L'], [40, 'XL'],
[10, 'X'], [9, 'IX'], [5, 'V'], [4, 'IV'], [1, 'I']
];
for (var _i = 0, romanNumerals_1 = romanNumerals; _i < romanNumerals_1.length; _i++) {
var _a = romanNumerals_1[_i], value = _a[0], numeral = _a[1];
while (intArabic >= value) {
retval += numeral;
intArabic -= value;
}
}
return retval;
}
/**
* Convert arabic numbers to alphabet.
*
* @private
* @param {number} arabic Input value.
* @returns {string} String value.
*/
export function _arabicToLetter(arabic) {
var result = '';
while (arabic > 0) {
var remainder = arabic % 26;
arabic = Math.floor(arabic / 26);
if (remainder === 0) {
arabic--;
remainder = 26;
}
result = _appendChar(remainder) + result;
}
return result;
}
/**
* Convert character code to string.
*
* @private
* @param {number} value Input value.
* @returns {string} String value.
*/
export function _appendChar(value) {
if (value <= 0 || value > 26) {
throw new Error('Value can not be less 0 and greater 26');
}
return String.fromCharCode(64 + value);
}
/**
* Check whether the value is null or undefined.
*
* @private
* @param {any} value Input value.
* @returns {boolean} Return true if the value is null or undefined; otherwise, return false
*/
export function _isNullOrUndefined(value) {
if (value !== null && typeof value !== 'undefined') {
return true;
}
return false;
}
/**
* Defines a property on an object with specific attributes.
*
* @piq
* @param {Object} obj - The target object on which the property will be defined.
* @param {string} prop - The name of the property to define.
* @param {any} value - The value to assign to the property.
* @param {boolean} [serializable = false] - If true, the property will not be enumerable.
* @returns {any} The value of the property that was defined.
*
*/
export function _defineProperty(obj, prop, value, serializable) {
if (serializable === void 0) { serializable = false; }
Object.defineProperty(obj, prop, {
value: value,
enumerable: !serializable,
configurable: true,
writable: false
});
return value;
}
/**
* Compresses the content of a PDFBaseStream
*
* @private
* @param {_PdfBaseStream} stream - Base stream to compress.
* @param {boolean} isExport - Denotes compress the stream as a hex-encoded string.
* @returns {boolean} compressed string.
*/
export function _compressStream(stream, isExport) {
if (isExport === void 0) { isExport = false; }
var dataArray;
if (stream instanceof _PdfStream && stream.bytes && stream.isImageStream) {
dataArray = stream.bytes;
}
else {
var value_1 = stream.getString();
var byteArray = [];
for (var i = 0; i < value_1.length; i++) {
byteArray.push(value_1.charCodeAt(i));
}
dataArray = new Uint8Array(byteArray);
}
var sw = new CompressedStreamWriter();
sw.write(dataArray, 0, dataArray.length);
sw.close();
var value = sw.getCompressedString;
stream.dictionary.update('Filter', _PdfName.get('FlateDecode'));
if (isExport) {
var buffer = [];
for (var i = 0; i < value.length; i++) {
buffer.push(value.charCodeAt(i) & 0xff);
}
return _byteArrayToHexString(new Uint8Array(buffer));
}
return value;
}
/**
* Check whether the input string contains any right-to-left (RTL) characters.
*
* @private
* @param {string} input The input string.
* @returns {boolean} Returns true if the string contains any RTL characters; otherwise, returns false.
*/
export function _isRightToLeftCharacters(input) {
// Unicode range for RTL characters
var rtlRegex = /[\u0590-\u08FF\uFB1D-\uFDFF\uFE70-\uFEFF]/;
return rtlRegex.test(input);
}
/**
* Updates the page count value in the dictionary
*
* @private
* @param {_PdfDictionary} dictionary - Dictionary to update page count.
* @param {number} valueToIncrement - Page count.
* @returns {void} Nothing.
*/
export function _updatePageCount(dictionary, valueToIncrement) {
dictionary.update('Count', dictionary.get('Count') + valueToIncrement);
if (dictionary.has('Parent')) {
var parentDictionary = dictionary.get('Parent');
if (parentDictionary && parentDictionary.get('Type').name === 'Pages') {
_updatePageCount(parentDictionary, valueToIncrement);
}
}
}
/**
* Updates the page settings in the dictionary
*
* @private
* @param {_PdfDictionary} dictionary - Dictionary to update page settings.
* @param {PdfPageSettings} settings - PDF page settings.
* @returns {void} Nothing.
*/
export function _updatePageSettings(dictionary, settings) {
var bounds = [0, 0, settings.size.width, settings.size.height];
dictionary.update('MediaBox', bounds);
dictionary.update('CropBox', bounds);
var rotate = Math.floor(settings.rotation) * 90;
if (rotate >= 360) {
rotate = rotate % 360;
}
dictionary.update('Rotate', rotate);
}
/**
* Checks if the given string contains any Unicode (non-ASCII) characters.
*
* @private
* @param {string} value - The string to check for Unicode characters.
* @returns {boolean} `true` if the string contains at least one Unicode character; otherwise, `false`.
*/
export function _hasUnicodeCharacters(value) {
var unicodeRegex = /[^\x00-\x7F]/; // eslint-disable-line
return value.split('').some(function (char) { return unicodeRegex.exec(char) !== null; }); // eslint-disable-line
}
/**
* Creates a font stream for the given font and form, extracting the font data from font descriptors.
*
* @private
* @param {PdfForm} form - The target PDF form containing cross-references to the font data.
* @param {_PdfDictionary} font - The dictionary that defines the font, containing references to font descriptors.
* @returns {Uint8Array} The font data extracted from the font file.
*/
export function _createFontStream(form, font) {
var fontData;
if (font) {
font.forEach(function (key, value) {
if (value && value.objectNumber) {
var dictionary_1 = form._crossReference._fetch(value);
if (dictionary_1 && dictionary_1 instanceof _PdfDictionary) {
dictionary_1.forEach(function (key, value) {
if (value && value instanceof _PdfName && value.name === 'FontDescriptor') {
var fontFile = void 0; // eslint-disable-line
if (dictionary_1 && dictionary_1.has('FontFile2')) {
fontFile = dictionary_1.get('FontFile2');
if (fontFile && fontFile instanceof _PdfBaseStream) {
fontData = fontFile.getBytes();
}
}
else if (dictionary_1 && dictionary_1.has('FontFile3')) {
fontFile = dictionary_1.get('FontFile3');
if (fontFile && fontFile instanceof _PdfBaseStream) {
fontData = fontFile.getBytes();
}
}
}
});
}
}
});
}
return fontData;
}
/**
* Determines whether a given string contains Unicode characters.
*
* @private
* @param {string} value - The string to be checked.
* @returns {boolean} True if the string contains Unicode characters; otherwise, false.
* @throws {Error} If the input value is null or undefined.
*/
export function _isUnicode(value) {
if (value === null || typeof value === 'undefined') {
throw new Error('ArgumentNullException: value');
}
for (var i = 0; i < value.length; i++) {
if (value.charCodeAt(i) > 127) {
return true;
}
}
return false;
}
/**
* Converts a single hexadecimal character to its numeric value.
*
* @private
* @param {string} char - A single character string representing a hexadecimal digit ('0'-'9', 'A'-'F', 'a'-'f').
* @returns {number} The numeric value corresponding to the hexadecimal character.
* @throws {Error} Throws an error if the input character is not a valid hexadecimal character.
*/
export function _convertToHex(char) {
if (char >= '0' && char <= '9') {
return char.charCodeAt(0) - '0'.charCodeAt(0);
}
else if (char >= 'A' && char <= 'F') {
return char.charCodeAt(0) - 'A'.charCodeAt(0) + 10;
}
else if (char >= 'a' && char <= 'f') {
return char.charCodeAt(0) - 'a'.charCodeAt(0) + 10;
}
else {
throw new Error("Invalid hex character: " + char);
}
}
/**
* Decodes a font family string that contains hexadecimal encoded characters.
*
* @private
* @param {string} fontFamily - The font family string to be decoded. May contain hex encoded characters prefixed by '#'.
* @returns {string} The decoded font family string with hex characters replaced by their ASCII equivalents.
* @throws {Error} Throws an error if the input contains invalid hexadecimal sequences.
*/
export function _decodeFontFamily(fontFamily) {
var builder = [];
var length = fontFamily.length;
for (var k = 0; k < length; ++k) {
var character = fontFamily[k];
if (character === '#') {
var hex1 = _convertToHex(fontFamily[k + 1]);
var hex2 = _convertToHex(fontFamily[k + 2]);
character = String.fromCharCode((hex1 << 4) + hex2);
k += 2;
}
builder.push(character);
}
return builder.join('');
}
/**
* Updates the border style to dashed pattern if the border style is set to dashed.
*
* @private
* @param {PdfInteractiveBorder} border - The interactive border object containing style information.
* @param {_PaintParameter} parameter - The paint parameter object that contains the border pen to be updated.
* @returns {void} Nothing.
*/
export function _updateDashedBorderStyle(border, parameter) {
if (border.style === PdfBorderStyle.dashed) {
parameter.borderPen._dashStyle = PdfDashStyle.dash;
parameter.borderPen._dashPattern = [3];
}
}
/**
* Reads a 16-bit unsigned integer from the specified offset in the given data array.
*
* @private
* @param {Uint8Array} data - The data array containing the bytes.
* @param {number} offset - The position in the data array to start reading.
* @returns {number} The 16-bit unsigned integer read from the data array.
*/
export function _readUnsignedInteger16(data, offset) {
return (data[offset] << 8) | data[offset + 1];
}
/**
* Sets the rotation angle for a PDF annotation if necessary.
* It ensures that the rotation is within the normalized range [0, 360) degrees.
*
* @private
* @param {number} rotateAngle - The rotation angle to be set for the annotation. Negative values are normalized.
* @param {PdfAnnotation} annot - The PDF annotation object which may have its rotation angle modified.
* @returns {void} Nothing.
*/
export function _setRotateAngle(rotateAngle, annot) {
if (annot && rotateAngle !== annot.rotate) {
if (rotateAngle < 0) {
rotateAngle = 360 + rotateAngle;
}
if (rotateAngle >= 360) {
rotateAngle = 360 - rotateAngle;
}
annot._dictionary.update('Rotate', rotateAngle);
}
}
/**
* Reads a 32-bit unsigned integer from the specified offset in the given data array.
*
* @private
* @param {Uint8Array} data - The data array containing the bytes.
* @param {number} offset - The position in the data array to start reading.
* @returns {number} The 32-bit unsigned integer read from the data array.
*/
export function _readUnsignedInteger32(data, offset) {
return (((data[offset] << 24) | (data[offset + 1] << 16) | (data[offset + 2] << 8) |
data[offset + 3]) >>> 0);
}
/**
* Reads a signed 8-bit integer from the specified offset in the given data array.
*
* @private
* @param {Uint8Array} data - The data array containing the bytes.
* @param {number} offset - The position in the data array to start reading.
* @returns {number} The 8-bit signed integer read from the data array.
*/
export function _readInteger8(data, offset) {
return (data[offset] << 24) >> 24;
}
/**
* Calculates the base-2 logarithm of a number and rounds it up to the nearest integer.
*
* @private
* @param {number} x - The number to calculate the logarithm for.
* @returns {number} The smallest integer greater than or equal to the logarithm of x to base 2; returns 0 if x is less than or equal to 0.
*/
export function _log2(x) {
return x > 0 ? Math.ceil(Math.log2(x)) : 0;
}
/**
* Defines a non-enumerable property on an object.
*
* @private
* @param {object} obj - The object on which to define the property.
* @param {string} prop - The name of the property to define.
* @param {*} value - The value of the property.
* @param {boolean} [nonSerializable=false] - Indicates whether the property should be enumerable.
* @returns {*} The value that was set for the property.
*/
export function _defineLazyProperty(obj, prop, value, nonSerializable) {
if (nonSerializable === void 0) { nonSerializable = false; }
Object.defineProperty(obj, prop, {
value: value,
enumerable: !nonSerializable,
configurable: true,
writable: false
});
return value;
}
/**
* Clamps a number between a minimum and maximum value.
*
* @private
* @param {number} v - The number to clamp.
* @param {number} min - The minimum value.
* @param {number} max - The maximum value.
* @returns {number} The clamped value.
*/
export function _mathClamp(v, min, max) {
return Math.min(Math.max(v, min), max);
}
/**
* Throws an error with the given message.
*
* @private
* @param {string} msg - The error message.
* @returns {void} This function does not return a value.
*/
export function _unreachable(msg) {
throw new Error(msg);
}
/**
* Converts a grayScale image data array to an RGBA image data array.
*
* @private
* @param {Uint8Array} src - The source grayScale data array.
* @param {Uint32Array} dest - The destination RGBA data array.
* @returns {void} This function does not return a value.
*/
export function _grayToRgba(src, dest) {
if (_isLittleEndian()) {
for (var i = 0, ii = src.length; i < ii; i++) {
dest[i] = (src[i] * 0x10101) | 0xff000000;
}
}
else {
for (var i = 0, ii = src.length; i < ii; i++) {
dest[i] = (src[i] * 0x1010100) | 0x000000ff;
}
}
}
/**
* Checks if the current environment is little-endian.
*
* @private
* @returns {boolean} True if the environment is little-endian, false otherwise.
*/
export function _isLittleEndian() {
var buffer8 = new Uint8Array(4);
buffer8[0] = 1;
var view32 = new Uint32Array(buffer8.buffer, 0, 1);
return view32[0] === 1;
}
/**
* Extracts the attributes element from a DER-encoded ASN1 collection.
*
* @private
* @param {_PdfUniqueEncodingElement} abstractSyntaxCollection - The ASN1 collection from which attributes are to be extracted.
* @returns {_PdfUniqueEncodingElement | undefined} The extracted attributes element if valid, otherwise undefined.
*/
export function _extractAttributes(abstractSyntaxCollection) {
var sequence = abstractSyntaxCollection._getSequence();
if (sequence.length === 3) {
var attributesElement = sequence[2];
if (attributesElement._tagClass === _TagClassType.universal &&
attributesElement._getTagNumber() === _UniversalType.abstractSyntaxSet &&
attributesElement._construction === _ConstructionType.constructed) {
return attributesElement;
}
}
return undefined;
}
/**
* Compares two Uint8Array instances for byte-wise equality.
*
* @private
* @param {Uint8Array} a - The first Uint8Array to compare.
* @param {Uint8Array} b - The second Uint8Array to compare.
* @returns {boolean} Returns true if both arrays are equal in length and content, otherwise false.
*/
export function _areUint8ArraysEqual(a, b) {
if (a.length !== b.length) {
return false;
}
for (var i = 0; i < a.length; i++) {
if (a[i] !== b[i]) {
return false;
}
}
return true;
}
/**
* Computes modular exponentiation: (base^exp) mod mod.
* Efficiently calculates large powers using the right-to-left binary method.
*
* @private
* @param {bigint} base - The base number.
* @param {bigint} exp - The exponent.
* @param {bigint} mod - The modulus.
* @returns {bigint} The result of (base^exp) % mod.
*/
export function _modPow(base, exp, mod) {
var bigInt = _getBigInt();
var res = bigInt(1);
base = base % mod;
while (exp > bigInt(0)) {
if (exp % bigInt(2) === bigInt(1)) {
res = (res * base) % mod;
}
exp = exp >> bigInt(1);
base = (base * base) % mod;
}
return res;
}
/**
* Computes the modular inverse of a number `a` modulo `m`.
* That is, finds `x` such that (a * x) % m === 1.
* Uses the Extended Euclidean Algorithm.
*
* @private
* @param {bigint} a - The number to find the inverse of.
* @param {bigint} m - The modulus.
* @returns {bigint} The modular inverse of `a` modulo `m`, or 0 if no inverse exists.
*/
export function _modInverse(a, m) {
var bigInt = _getBigInt();
var m0 = m;
var x0 = bigInt(0);
var x1 = bigInt(1);
if (m === bigInt(1)) {
return bigInt(0);
}
while (a > bigInt(1)) {
if (m === bigInt(0)) {
return bigInt(1);
}
var q = a / m;
var t = m;
m = a % m;
a = t;
t = x0;
x0 = x1 - q * x0;
x1 = t;
}
if (x1 < bigInt(0)) {
x1 += m0;
}
return x1;
}
/**
* Converts a Uint8Array to a BigInt by interpreting the bytes as a big-endian integer.
*
* @private
* @param {Uint8Array} bytes - The byte array to convert.
* @returns {bigint} The resulting BigInt value.
*/
export function _bytesToBigInt(bytes) {
var bigInt = _getBigInt();
var result = bigInt(0);
for (var i = 0; i < bytes.length; i++) {
result = (result << bigInt(8)) + bigInt(bytes[i]);
}
return result;
}
/**
* Converts a BigInt to a Uint8Array using big-endian byte order.
*
* @private
* @param {bigint} n - The BigInt value to convert.
* @returns {Uint8Array} The resulting byte array.
*/
export function _bigIntToBytes(n) {
var bigInt = _getBigInt();
if (n === bigInt(0)) {
return new Uint8Array([0]);
}
var hex = n.toString(16); // eslint-disable-line
if (hex.length % 2 !== 0) {
hex = '0' + hex;
}
var len = hex.length / 2;
var u8 = new Uint8Array(len);
for (var i = 0; i < len; i++) {
u8[i] = parseInt(hex.substr(i * 2, 2), 16);
}
return u8;
}
/**
* Generates a cryptographically insecure random BigInt of the specified bit length.
* The result is a non-negative BigInt with up to `bitLength` bits.
*
* @private
* @param {number} bitLength - The desired bit length of the random number.
* @returns {bigint} A randomly generated BigInt.
*/
export function _randomBigInt(bitLength) {
var byteLength = Math.ceil(bitLength / 8);
var randomBytes = new Uint8Array(byteLength);
for (var i = 0; i < byteLength; i++) {
randomBytes[i] = Math.floor(Math.random() * 256);
}
var mask = (1 << (bitLength % 8)) - 1;
if (mask > 0) {
randomBytes[0] &= mask;
}
return _bytesToBigInt(randomBytes);
}
/**
* Generates a random BigInt within the inclusive range [min, max].
* Uses rejection sampling to ensure uniform distribution.
* Falls back to a smaller random if no valid candidate is found after 1000 attempts.
*
* @private
* @param {bigint} min - The minimum value (inclusive).
* @param {bigint} max - The maximum value (inclusive).
* @returns {bigint} A random BigInt between min and max.
*/
export function _createRandomInRange(min, max) {
if (min >= max) {
return min;
}
var bitLength = max.toString(2).length; // eslint-disable-line
for (var i = 0; i < 1000; i++) {
var candidate = _randomBigInt(bitLength);
if (candidate >= min && candidate <= max) {
return candidate;
}
}
var fallback = _randomBigInt((max - min).toString(2).length - 1); // eslint-disable-line
return fallback + min;
}
/**
* Handle explicit conversion
*
* @private
* @param {Uint8Array} value - Input value.
* @returns {Uint8Array} Converted value.
*/
export function _handleExplicitConversion(value) {
var len = value.length;
if ((len === 0x4D || len === 0x6D || len === 0x5D || len === 0x41) && value[0] === 0x31) {
return value.slice(1);
}
else if ((len === 0x87 || len === 0xD4 || len === 0xB4) && value[0] === 0x31 && value[1] === 0x81) {
return value.slice(2);
}
else if (len === 0x77 && value[0] === 0x31) {
return value.slice(1);
}
return value;
}
/**
* Returns a function that converts a value to bigint.
*
* @private
* @returns {bigint} The bigInt
*/
export function _getBigInt() {
return (Function('return BigInt'))();
}
/**
* Pads a single-digit number with a leading zero to ensure two-digit formatting.
*
* @private
* @param {number} value - The number to pad.
* @returns {string} A string representing the number with at least two digits.
*/
export function _pad2(value) {
return value < 10 ? '0' + value : '' + value;
}
/**
* Converts a Date object to a string in the PDF date format 'D:YYYYMMDDHHMMSSOHH'MM'SS''.
*
* @private
* @param {Date} dateTime - The Date object to be converted to a string.
* @returns {string} A string representing the date and time in the PDF format.
*/
export function _convertDateToString(dateTime) {
var year = dateTime.getUTCFullYear();
var month = _pad2(dateTime.getUTCMonth() + 1);
var day = _pad2(dateTime.getUTCDate());
var hours = _pad2(dateTime.getUTCHours());
var minutes = _pad2(dateTime.getUTCMinutes());
var seconds = _pad2(dateTime.getUTCSeconds());
return "D:" + year + month + day + hours + minutes + seconds + "Z";
}
/**
* Converts a PDF date string into a JavaScript Date object.
*
* @private
* @param {string} date - The date string to convert.
* @returns {Date} A JavaScript Date object representing the converted date.
*/
export function _convertStringToDate(date) {
if (date.startsWith('D:')) {
var year = parseInt(date.substring(2, 6), 10);
var month = parseInt(date.substring(6, 8), 10) - 1;
var day = parseInt(date.substring(8, 10), 10);
var hour = parseInt(date.substring(10, 12), 10);
var minute = parseInt(date.substring(12, 14), 10);
var second = parseInt(date.substring(14, 16), 10);
var utcTime = Date.UTC(year, month, day, hour, minute, second);
if (date.length >= 17) {
var tz = date[16];
if (tz === 'Z') {
return new Date(utcTime);
}
if ((tz === '+' || tz === '-') && date.length >= 23) {
var tzHour = parseInt(date.substring(17, 19), 10);
var tzMinute = parseInt(date.substring(20, 22), 10);
var offset = (tzHour * 60 + tzMinute) * 60000;
utcTime -= tz === '+' ? offset : -offset;
return new Date(utcTime);
}
}
var istOffset = (5 * 60 + 30) * 60000;
utcTime -= istOffset;
return new Date(utcTime);
}
return new Date(date);
}
/**
* Returns the appropriate CJK font encoding name based on the specified `PdfCjkFontFamily`.
*
* @private
* @param {PdfCjkFontFamily} fontFamily The cjk font family.
* @returns {_PdfName} representing the encoding name suitable for the given font family.
*/
export function _getCjkEncoding(fontFamily) {
var encoding = 'Unknown';
switch (fontFamily) {
case PdfCjkFontFamily.hanyangSystemsGothicMedium:
case PdfCjkFontFamily.hanyangSystemsShinMyeongJoMedium:
encoding = 'UniKS-UCS2-H';
break;
case PdfCjkFontFamily.heiseiKakuGothicW5:
case PdfCjkFontFamily.heiseiMinchoW3:
encoding = 'UniJIS-UCS2-H';
break;
case PdfCjkFontFamily.monotypeHeiMedium:
case PdfCjkFontFamily.monotypeSungLight:
encoding = 'UniCNS-UCS2-H';
break;
case PdfCjkFontFamily.sinoTypeSongLight:
encoding = 'UniGB-UCS2-H';
break;
}
return new _PdfName(encoding);
}
/**
* Creates and returns a descendant CIDFont dictionary for a specified CJK font family.
*
* @private
* @param {PdfCjkFontFamily} family - The CJK font family to be used.
* @param {PdfFontStyle} style - The font style to apply.
* @param {_PdfFontMetrics} metrics - The font metrics containing width table, PostScript name, and other font-specific data.
* @returns {_PdfDictionary[]} An array containing a single `_PdfDictionary` that represents the descendant font definition.
*/
export function _getCjkDescendantFont(family, style, metrics) {
var dictionary = new _PdfDictionary();
dictionary._updated = true;
dictionary.set('Type', _PdfName.get('Font'));
dictionary.set('Subtype', _PdfName.get('CIDFontType2'));
dictionary.set('BaseFont', new _PdfName(metrics._postScriptName));
dictionary.set('DW', metrics._widthTable._defaultWidth);
dictionary.set('W', metrics._widthTable._toArray());
dictionary.set('CIDSystemInfo', _getCjkSystemInfo(family));
return [dictionary];
}
/**
* Returns the CIDSystemInfo dictionary for the specified CJK font family.
*
* @private
* @param {PdfCjkFontFamily} family - The CJK font family for which the system information is needed.
* @returns {_PdfDictionary} A `_PdfDictionary` containing the CIDSystemInfo entries.
*/
export function _getCjkSystemInfo(family) {
var systemInformation = new _PdfDictionary();
systemInformation._updated = true;
systemInformation.set('Registry', 'Adobe');
switch (family) {
case PdfCjkFontFamily.hanyangSystemsGothicMedium:
case PdfCjkFontFamily.hanyangSystemsShinMyeongJoMedium:
systemInformation.set('Ordering', 'Korea1');
systemInformation.set('Supplement', 1);
break;
case PdfCjkFontFamily.heiseiKakuGothicW5:
case PdfCjkFontFamily.heiseiMinchoW3:
systemInformation.set('Ordering', 'Japan1');
systemInformation.set('Supplement', 2);
break;
case PdfCjkFontFamily.monotypeHeiMedium:
case PdfCjkFontFamily.monotypeSungLight:
systemInformation.set('Ordering', 'CNS1');
systemInformation.set('Supplement', '0');
break;
case PdfCjkFontFamily.sinoTypeSongLight:
systemInformation.set('Ordering', 'GB1');
systemInformation.set('Supplement', 2);
break;
}
return systemInformation;
}
/**
* Resolves and returns the corresponding `PdfFontFamily` enum value based on the given PostScript font name.
*
* @private
* @param {string} postScriptName - The PostScript name of the font.
* @returns {PdfFontFamily} The resolved `PdfFontFamily` enum value corresponding to the font name.
*/
export function _resolveStandardFontFamily(postScriptName) {
if (postScriptName.includes('Helvetica')) {
return PdfFontFamily.helvetica;
}
if (postScriptName.includes('Courier')) {
return PdfFontFamily.courier;
}
if (postScriptName.includes('Times')) {
return PdfFontFamily.timesRoman;
}
if (postScriptName.includes('Symbol')) {
return PdfFontFamily.symbol;
}
if (postScriptName.includes('ZapfDingbats')) {
return PdfFontFamily.zapfDingbats;
}
return PdfFontFamily.helvetica;
}
/**
* Resolves and returns the corresponding `PdfCjkFontFamily` enum value based on the given PostScript font name.
*
* @private
* @param {string} postScriptName - The PostScript name of the CJK font.
* @returns {PdfCjkFontFamily} The resolved `PdfCjkFontFamily` enum value corresponding to the font name.
* @throws {Error} Error if the font name does not match any known CJK font family.
*/
export function _resolveCjkFontFamily(postScriptName) {
switch (postScriptName) {
case 'HeiseiKakuGo-W5':
case 'HeiseiKakuGo-W5,BoldItalic':
case 'HeiseiKakuGo-W5,Bold':
case 'HeiseiKakuGo-W5,Italic':
return PdfCjkFontFamily.heiseiKakuGothicW5;
case 'HeiseiMin-W3':
case 'HeiseiMin-W3,BoldItalic':
case 'HeiseiMin-W3,Bold':
case 'HeiseiMin-W3,Italic':
return PdfCjkFontFamily.heiseiMinchoW3;
case 'HYGoThic-Medium':
case 'HYGoThic-Medium,BoldItalic':
case 'HYGoThic-Medium,Bold':
case 'HYGoThic-Medium,Italic':
return PdfCjkFontFamily.hanyangSystemsGothicMedium;
case 'HYSMyeongJo-Medium':
case 'HYSMyeongJo-Medium,BoldItalic':
case 'HYSMyeongJo-Medium,Bold':
case 'HYSMyeongJo-Medium,Italic':
return PdfCjkFontFamily.hanyangSystemsShinMyeongJoMedium;
case 'MHei-Medium':
case 'MHei-Medium,BoldItalic':
case 'MHei-Medium,Bold':
case 'MHei-Medium,Italic':
return PdfCjkFontFamily.monotypeHeiMedium;
case 'MSung-Light':
case 'MSung-Light,BoldItalic':
case 'MSung-Light,Bold':
case 'MSung-Light,Italic':
return PdfCjkFontFamily.monotypeSungLight;
case 'STSong-Light':
case 'STSong-Light,BoldItalic':
case 'STSong-Light,Bold':
case 'STSong-Light,Italic':
return PdfCjkFontFamily.sinoTypeSongLight;
default:
throw new Error("Unknown CJK font family for: " + postScriptName);
}
}
/**
* Pads the current string with another string (multiple times, if needed)
*
* @private
* @param {string} str - The original string to be padded.
* @param {number} targetLength - The desired length
* @param {string} [padString='0'] - The string to pad the original string with.
* @returns {string} The padded string if the original string length is less than the target length. Returns the original string otherwise.
*/
export function _padStart(str, targetLength, padString) {
if (padString === void 0) { padString = '0'; }
targetLength = targetLength >> 0;
padString = String(padString || ' ');
if (str.length >= targetLength) {
return str;
}
else {
var remainingLength = targetLength - str.length;
if (remainingLength > padString.length) {
padString += padString.repeat(remainingLength / padString.length);
}
return padString.slice(0, remainingLength) + str;
}
}
/**
* Converts a Uint8Array to a hexadecimal string representation.
*
* @private
* @param {Uint8Array} buffer - The input byte array to convert.
* @returns {string} A hexadecimal string representation of the input.
*/
export function _bytesToHex(buffer) {
return Array.from(buffer)
.map(function (byte) { return _padStart(byte.toString(16), 2, '0'); })
.join('')
.toUpperCase();
}
/**
* Formats a number according to the current style.
*
* @private
* @param {number} value The numeric value.
* @param {PdfNumberStyle} numberStyle The numeric value.
* @returns {string} The formatted string.
*/
export function _formatNumber(value, numberStyle) {
switch (numberStyle) {
case PdfNumberStyle.numeric:
return value.toString();
case PdfNumberStyle.upperRoman:
return _toRoman(value).toUpperCase();
case PdfNumberStyle.lowerRoman:
return _toRoman(value).toLowerCase();
case PdfNumberStyle.upperLatin:
return _toAlpha(value).toUpperCase();
case PdfNumberStyle.lowerLatin:
return _toAlpha(value).toLowerCase();
default:
return value.toString();
}
}
/**
* Converts a number to Roman numerals.
*
* @private
* @param {number} num The number to convert.
* @returns {string} The Roman numeral representation.
*/
export function _toRoman(num) {
var values = [1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1];
var symbols = ['M', 'CM', 'D', 'CD', 'C', 'XC', 'L', 'XL', 'X', 'IX', 'V', 'IV', 'I'];
var result = '';
for (var i = 0; i < values.length; i++) {
while (num >= values[i]) {
result += symbols[i];
num -= values[i];
}
}
return result;
}
/**
* Converts a number to alphabetic representation.
*
* @private
* @param {number} num The number to convert.
* @returns {string} The alphabetic representation.
*/
export function _toAlpha(num) {
var result = '';
while (num > 0) {
num--;
result = String.fromCharCode(97 + (num % 26)) + result;
num = Math.floor(num / 26);
}
return result;
}