modern-pdf-lib 0.30.0 → 0.32.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -546,7 +546,7 @@ const NS_PDFAID = "http://www.aiim.org/pdfa/ns/id/";
546
546
  * Escape special characters for XML text content.
547
547
  * @internal
548
548
  */
549
- function escapeXml$4(str) {
549
+ function escapeXml$5(str) {
550
550
  const parts = [];
551
551
  for (let i = 0; i < str.length; i++) {
552
552
  const c = str.charCodeAt(i);
@@ -594,14 +594,14 @@ function buildXmpMetadata(meta) {
594
594
  if (meta.title !== void 0) {
595
595
  lines.push(" <dc:title>");
596
596
  lines.push(" <rdf:Alt>");
597
- lines.push(` <rdf:li xml:lang="x-default">${escapeXml$4(meta.title)}</rdf:li>`);
597
+ lines.push(` <rdf:li xml:lang="x-default">${escapeXml$5(meta.title)}</rdf:li>`);
598
598
  lines.push(" </rdf:Alt>");
599
599
  lines.push(" </dc:title>");
600
600
  }
601
601
  if (meta.author !== void 0) {
602
602
  lines.push(" <dc:creator>");
603
603
  lines.push(" <rdf:Seq>");
604
- lines.push(` <rdf:li>${escapeXml$4(meta.author)}</rdf:li>`);
604
+ lines.push(` <rdf:li>${escapeXml$5(meta.author)}</rdf:li>`);
605
605
  lines.push(" </rdf:Seq>");
606
606
  lines.push(" </dc:creator>");
607
607
  }
@@ -611,7 +611,7 @@ function buildXmpMetadata(meta) {
611
611
  lines.push(" <rdf:Bag>");
612
612
  for (const kw of keywords) {
613
613
  const trimmed = kw.trim();
614
- if (trimmed.length > 0) lines.push(` <rdf:li>${escapeXml$4(trimmed)}</rdf:li>`);
614
+ if (trimmed.length > 0) lines.push(` <rdf:li>${escapeXml$5(trimmed)}</rdf:li>`);
615
615
  }
616
616
  lines.push(" </rdf:Bag>");
617
617
  lines.push(" </dc:subject>");
@@ -619,15 +619,15 @@ function buildXmpMetadata(meta) {
619
619
  if (meta.subject !== void 0) {
620
620
  lines.push(" <dc:description>");
621
621
  lines.push(" <rdf:Alt>");
622
- lines.push(` <rdf:li xml:lang="x-default">${escapeXml$4(meta.subject)}</rdf:li>`);
622
+ lines.push(` <rdf:li xml:lang="x-default">${escapeXml$5(meta.subject)}</rdf:li>`);
623
623
  lines.push(" </rdf:Alt>");
624
624
  lines.push(" </dc:description>");
625
625
  }
626
- if (meta.creator !== void 0) lines.push(` <xmp:CreatorTool>${escapeXml$4(meta.creator)}</xmp:CreatorTool>`);
626
+ if (meta.creator !== void 0) lines.push(` <xmp:CreatorTool>${escapeXml$5(meta.creator)}</xmp:CreatorTool>`);
627
627
  if (meta.creationDate !== void 0) lines.push(` <xmp:CreateDate>${formatXmpDate(meta.creationDate)}</xmp:CreateDate>`);
628
628
  if (meta.modDate !== void 0) lines.push(` <xmp:ModifyDate>${formatXmpDate(meta.modDate)}</xmp:ModifyDate>`);
629
- if (meta.producer !== void 0) lines.push(` <pdf:Producer>${escapeXml$4(meta.producer)}</pdf:Producer>`);
630
- if (meta.keywords !== void 0) lines.push(` <pdf:Keywords>${escapeXml$4(meta.keywords)}</pdf:Keywords>`);
629
+ if (meta.producer !== void 0) lines.push(` <pdf:Producer>${escapeXml$5(meta.producer)}</pdf:Producer>`);
630
+ if (meta.keywords !== void 0) lines.push(` <pdf:Keywords>${escapeXml$5(meta.keywords)}</pdf:Keywords>`);
631
631
  lines.push("</rdf:Description>");
632
632
  lines.push("</rdf:RDF>");
633
633
  lines.push("</x:xmpmeta>");
@@ -7019,7 +7019,7 @@ function countMatches(text, regex) {
7019
7019
  //#region src/compliance/xmpGenerator.ts
7020
7020
  const encoder$2 = new TextEncoder();
7021
7021
  /** Escape XML special characters in a string. */
7022
- function escapeXml$3(str) {
7022
+ function escapeXml$4(str) {
7023
7023
  return str.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll("\"", "&quot;").replaceAll("'", "&apos;");
7024
7024
  }
7025
7025
  /**
@@ -7053,35 +7053,35 @@ function generatePdfAXmp(options) {
7053
7053
  if (options.title) {
7054
7054
  xmp += " <dc:title>\n";
7055
7055
  xmp += " <rdf:Alt>\n";
7056
- xmp += ` <rdf:li xml:lang="${lang}">${escapeXml$3(options.title)}</rdf:li>\n`;
7056
+ xmp += ` <rdf:li xml:lang="${lang}">${escapeXml$4(options.title)}</rdf:li>\n`;
7057
7057
  xmp += " </rdf:Alt>\n";
7058
7058
  xmp += " </dc:title>\n";
7059
7059
  }
7060
7060
  if (options.author) {
7061
7061
  xmp += " <dc:creator>\n";
7062
7062
  xmp += " <rdf:Seq>\n";
7063
- xmp += ` <rdf:li>${escapeXml$3(options.author)}</rdf:li>\n`;
7063
+ xmp += ` <rdf:li>${escapeXml$4(options.author)}</rdf:li>\n`;
7064
7064
  xmp += " </rdf:Seq>\n";
7065
7065
  xmp += " </dc:creator>\n";
7066
7066
  }
7067
7067
  if (options.subject) {
7068
7068
  xmp += " <dc:description>\n";
7069
7069
  xmp += " <rdf:Alt>\n";
7070
- xmp += ` <rdf:li xml:lang="${lang}">${escapeXml$3(options.subject)}</rdf:li>\n`;
7070
+ xmp += ` <rdf:li xml:lang="${lang}">${escapeXml$4(options.subject)}</rdf:li>\n`;
7071
7071
  xmp += " </rdf:Alt>\n";
7072
7072
  xmp += " </dc:description>\n";
7073
7073
  }
7074
7074
  xmp += " </rdf:Description>\n";
7075
7075
  xmp += " <rdf:Description rdf:about=\"\"\n";
7076
7076
  xmp += " xmlns:xmp=\"http://ns.adobe.com/xap/1.0/\">\n";
7077
- xmp += ` <xmp:CreatorTool>${escapeXml$3(creatorTool)}</xmp:CreatorTool>\n`;
7077
+ xmp += ` <xmp:CreatorTool>${escapeXml$4(creatorTool)}</xmp:CreatorTool>\n`;
7078
7078
  xmp += ` <xmp:CreateDate>${createDate}</xmp:CreateDate>\n`;
7079
7079
  xmp += ` <xmp:ModifyDate>${modifyDate}</xmp:ModifyDate>\n`;
7080
7080
  xmp += " </rdf:Description>\n";
7081
7081
  xmp += " <rdf:Description rdf:about=\"\"\n";
7082
7082
  xmp += " xmlns:pdf=\"http://ns.adobe.com/pdf/1.3/\">\n";
7083
- xmp += ` <pdf:Producer>${escapeXml$3(producer)}</pdf:Producer>\n`;
7084
- if (options.keywords) xmp += ` <pdf:Keywords>${escapeXml$3(options.keywords)}</pdf:Keywords>\n`;
7083
+ xmp += ` <pdf:Producer>${escapeXml$4(producer)}</pdf:Producer>\n`;
7084
+ if (options.keywords) xmp += ` <pdf:Keywords>${escapeXml$4(options.keywords)}</pdf:Keywords>\n`;
7085
7085
  xmp += " </rdf:Description>\n";
7086
7086
  xmp += " </rdf:RDF>\n";
7087
7087
  xmp += "</x:xmpmeta>\n";
@@ -17060,7 +17060,7 @@ const SECTION_TYPES = /* @__PURE__ */ new Set([
17060
17060
  "BlockQuote"
17061
17061
  ]);
17062
17062
  /** Illustration types that require alt text per PDF/UA. */
17063
- const ILLUSTRATION_TYPES = /* @__PURE__ */ new Set([
17063
+ const ILLUSTRATION_TYPES$1 = /* @__PURE__ */ new Set([
17064
17064
  "Figure",
17065
17065
  "Formula",
17066
17066
  "Form"
@@ -17403,7 +17403,7 @@ function findPreviousHeadingInSection(current, sectionHeadings) {
17403
17403
  */
17404
17404
  function checkAltText(elements, errors) {
17405
17405
  for (const elem of elements) {
17406
- if (!ILLUSTRATION_TYPES.has(elem.type)) continue;
17406
+ if (!ILLUSTRATION_TYPES$1.has(elem.type)) continue;
17407
17407
  if (elem.options.artifact) continue;
17408
17408
  if (elem.options.altText === void 0 && elem.options.actualText === void 0) errors.push({
17409
17409
  code: "UA-STRUCT-005",
@@ -20875,7 +20875,7 @@ const VAT_CATEGORY_STANDARD$1 = "S";
20875
20875
  /** Unit code C62 = "one" (unitless piece, UN/ECE Rec 20). */
20876
20876
  const UNIT_CODE_ONE$1 = "C62";
20877
20877
  /** Escape XML special characters in a text value. */
20878
- function escapeXml$2(str) {
20878
+ function escapeXml$3(str) {
20879
20879
  return str.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll("\"", "&quot;").replaceAll("'", "&apos;");
20880
20880
  }
20881
20881
  /** Format a numeric monetary/quantity value with two decimal places. */
@@ -20933,13 +20933,13 @@ function computeTotals$1(lines) {
20933
20933
  /** Render a single trade party block (Seller or Buyer). */
20934
20934
  function renderParty$1(party, indent) {
20935
20935
  const lines = [];
20936
- lines.push(`${indent}<ram:Name>${escapeXml$2(party.name)}</ram:Name>`);
20936
+ lines.push(`${indent}<ram:Name>${escapeXml$3(party.name)}</ram:Name>`);
20937
20937
  lines.push(`${indent}<ram:PostalTradeAddress>`);
20938
- lines.push(`${indent} <ram:CountryID>${escapeXml$2(party.countryCode)}</ram:CountryID>`);
20938
+ lines.push(`${indent} <ram:CountryID>${escapeXml$3(party.countryCode)}</ram:CountryID>`);
20939
20939
  lines.push(`${indent}</ram:PostalTradeAddress>`);
20940
20940
  if (party.vatId !== void 0 && party.vatId !== "") {
20941
20941
  lines.push(`${indent}<ram:SpecifiedTaxRegistration>`);
20942
- lines.push(`${indent} <ram:ID schemeID="VA">${escapeXml$2(party.vatId)}</ram:ID>`);
20942
+ lines.push(`${indent} <ram:ID schemeID="VA">${escapeXml$3(party.vatId)}</ram:ID>`);
20943
20943
  lines.push(`${indent}</ram:SpecifiedTaxRegistration>`);
20944
20944
  }
20945
20945
  return lines.join("\n");
@@ -20953,7 +20953,7 @@ function renderLine$2(line, index, currency) {
20953
20953
  out.push(` <ram:LineID>${index}</ram:LineID>`);
20954
20954
  out.push(" </ram:AssociatedDocumentLineDocument>");
20955
20955
  out.push(" <ram:SpecifiedTradeProduct>");
20956
- out.push(` <ram:Name>${escapeXml$2(line.description)}</ram:Name>`);
20956
+ out.push(` <ram:Name>${escapeXml$3(line.description)}</ram:Name>`);
20957
20957
  out.push(" </ram:SpecifiedTradeProduct>");
20958
20958
  out.push(" <ram:SpecifiedLineTradeAgreement>");
20959
20959
  out.push(" <ram:NetPriceProductTradePrice>");
@@ -20970,7 +20970,7 @@ function renderLine$2(line, index, currency) {
20970
20970
  out.push(` <ram:RateApplicablePercent>${formatPercent$1(line.taxPercent)}</ram:RateApplicablePercent>`);
20971
20971
  out.push(" </ram:ApplicableTradeTax>");
20972
20972
  out.push(" <ram:SpecifiedTradeSettlementLineMonetarySummation>");
20973
- out.push(` <ram:LineTotalAmount currencyID="${escapeXml$2(currency)}">${formatAmount$1(net)}</ram:LineTotalAmount>`);
20973
+ out.push(` <ram:LineTotalAmount currencyID="${escapeXml$3(currency)}">${formatAmount$1(net)}</ram:LineTotalAmount>`);
20974
20974
  out.push(" </ram:SpecifiedTradeSettlementLineMonetarySummation>");
20975
20975
  out.push(" </ram:SpecifiedLineTradeSettlement>");
20976
20976
  out.push(" </ram:IncludedSupplyChainTradeLineItem>");
@@ -20980,9 +20980,9 @@ function renderLine$2(line, index, currency) {
20980
20980
  function renderTaxGroup$1(group, currency) {
20981
20981
  const out = [];
20982
20982
  out.push(" <ram:ApplicableTradeTax>");
20983
- out.push(` <ram:CalculatedAmount currencyID="${escapeXml$2(currency)}">${formatAmount$1(group.taxAmount)}</ram:CalculatedAmount>`);
20983
+ out.push(` <ram:CalculatedAmount currencyID="${escapeXml$3(currency)}">${formatAmount$1(group.taxAmount)}</ram:CalculatedAmount>`);
20984
20984
  out.push(" <ram:TypeCode>VAT</ram:TypeCode>");
20985
- out.push(` <ram:BasisAmount currencyID="${escapeXml$2(currency)}">${formatAmount$1(group.basisAmount)}</ram:BasisAmount>`);
20985
+ out.push(` <ram:BasisAmount currencyID="${escapeXml$3(currency)}">${formatAmount$1(group.basisAmount)}</ram:BasisAmount>`);
20986
20986
  out.push(` <ram:CategoryCode>${VAT_CATEGORY_STANDARD$1}</ram:CategoryCode>`);
20987
20987
  out.push(` <ram:RateApplicablePercent>${formatPercent$1(group.taxPercent)}</ram:RateApplicablePercent>`);
20988
20988
  out.push(" </ram:ApplicableTradeTax>");
@@ -21010,11 +21010,11 @@ function generateCiiXml(invoice, profile = "EN16931") {
21010
21010
  out.push("<rsm:CrossIndustryInvoice xmlns:rsm=\"urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100\" xmlns:ram=\"urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100\" xmlns:udt=\"urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100\">");
21011
21011
  out.push(" <rsm:ExchangedDocumentContext>");
21012
21012
  out.push(" <ram:GuidelineSpecifiedDocumentContextParameter>");
21013
- out.push(` <ram:ID>${escapeXml$2(guidelineUrn)}</ram:ID>`);
21013
+ out.push(` <ram:ID>${escapeXml$3(guidelineUrn)}</ram:ID>`);
21014
21014
  out.push(" </ram:GuidelineSpecifiedDocumentContextParameter>");
21015
21015
  out.push(" </rsm:ExchangedDocumentContext>");
21016
21016
  out.push(" <rsm:ExchangedDocument>");
21017
- out.push(` <ram:ID>${escapeXml$2(invoice.invoiceNumber)}</ram:ID>`);
21017
+ out.push(` <ram:ID>${escapeXml$3(invoice.invoiceNumber)}</ram:ID>`);
21018
21018
  out.push(` <ram:TypeCode>${COMMERCIAL_INVOICE_TYPE_CODE$1}</ram:TypeCode>`);
21019
21019
  out.push(" <ram:IssueDateTime>");
21020
21020
  out.push(` <udt:DateTimeString format="102">${toDateString102$1(invoice.issueDate)}</udt:DateTimeString>`);
@@ -21032,14 +21032,14 @@ function generateCiiXml(invoice, profile = "EN16931") {
21032
21032
  out.push(" </ram:ApplicableHeaderTradeAgreement>");
21033
21033
  out.push(" <ram:ApplicableHeaderTradeDelivery/>");
21034
21034
  out.push(" <ram:ApplicableHeaderTradeSettlement>");
21035
- out.push(` <ram:InvoiceCurrencyCode>${escapeXml$2(currency)}</ram:InvoiceCurrencyCode>`);
21035
+ out.push(` <ram:InvoiceCurrencyCode>${escapeXml$3(currency)}</ram:InvoiceCurrencyCode>`);
21036
21036
  for (const group of totals.taxGroups) out.push(renderTaxGroup$1(group, currency));
21037
21037
  out.push(" <ram:SpecifiedTradeSettlementHeaderMonetarySummation>");
21038
- out.push(` <ram:LineTotalAmount currencyID="${escapeXml$2(currency)}">${formatAmount$1(totals.lineTotal)}</ram:LineTotalAmount>`);
21039
- out.push(` <ram:TaxBasisTotalAmount currencyID="${escapeXml$2(currency)}">${formatAmount$1(totals.lineTotal)}</ram:TaxBasisTotalAmount>`);
21040
- out.push(` <ram:TaxTotalAmount currencyID="${escapeXml$2(currency)}">${formatAmount$1(totals.taxTotal)}</ram:TaxTotalAmount>`);
21041
- out.push(` <ram:GrandTotalAmount currencyID="${escapeXml$2(currency)}">${formatAmount$1(totals.grandTotal)}</ram:GrandTotalAmount>`);
21042
- out.push(` <ram:DuePayableAmount currencyID="${escapeXml$2(currency)}">${formatAmount$1(totals.duePayable)}</ram:DuePayableAmount>`);
21038
+ out.push(` <ram:LineTotalAmount currencyID="${escapeXml$3(currency)}">${formatAmount$1(totals.lineTotal)}</ram:LineTotalAmount>`);
21039
+ out.push(` <ram:TaxBasisTotalAmount currencyID="${escapeXml$3(currency)}">${formatAmount$1(totals.lineTotal)}</ram:TaxBasisTotalAmount>`);
21040
+ out.push(` <ram:TaxTotalAmount currencyID="${escapeXml$3(currency)}">${formatAmount$1(totals.taxTotal)}</ram:TaxTotalAmount>`);
21041
+ out.push(` <ram:GrandTotalAmount currencyID="${escapeXml$3(currency)}">${formatAmount$1(totals.grandTotal)}</ram:GrandTotalAmount>`);
21042
+ out.push(` <ram:DuePayableAmount currencyID="${escapeXml$3(currency)}">${formatAmount$1(totals.duePayable)}</ram:DuePayableAmount>`);
21043
21043
  out.push(" </ram:SpecifiedTradeSettlementHeaderMonetarySummation>");
21044
21044
  out.push(" </ram:ApplicableHeaderTradeSettlement>");
21045
21045
  out.push(" </rsm:SupplyChainTradeTransaction>");
@@ -21261,7 +21261,7 @@ const PDFA4_PART = 4;
21261
21261
  /** PDF/A-4 revision year (`pdfaid:rev`). */
21262
21262
  const PDFA4_REV = "2020";
21263
21263
  /** Escape XML special characters in a string. */
21264
- function escapeXml$1(str) {
21264
+ function escapeXml$2(str) {
21265
21265
  return str.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll("\"", "&quot;").replaceAll("'", "&apos;");
21266
21266
  }
21267
21267
  /**
@@ -21279,17 +21279,17 @@ function conformanceFor(level) {
21279
21279
  function renderExtensionSchema(s) {
21280
21280
  let out = "";
21281
21281
  out += " <rdf:li rdf:parseType=\"Resource\">\n";
21282
- out += ` <pdfaSchema:schema>${escapeXml$1(s.schema)}</pdfaSchema:schema>\n`;
21283
- out += ` <pdfaSchema:namespaceURI>${escapeXml$1(s.namespaceUri)}</pdfaSchema:namespaceURI>\n`;
21284
- out += ` <pdfaSchema:prefix>${escapeXml$1(s.prefix)}</pdfaSchema:prefix>\n`;
21282
+ out += ` <pdfaSchema:schema>${escapeXml$2(s.schema)}</pdfaSchema:schema>\n`;
21283
+ out += ` <pdfaSchema:namespaceURI>${escapeXml$2(s.namespaceUri)}</pdfaSchema:namespaceURI>\n`;
21284
+ out += ` <pdfaSchema:prefix>${escapeXml$2(s.prefix)}</pdfaSchema:prefix>\n`;
21285
21285
  out += " <pdfaSchema:property>\n";
21286
21286
  out += " <rdf:Seq>\n";
21287
21287
  for (const p of s.properties) {
21288
21288
  out += " <rdf:li rdf:parseType=\"Resource\">\n";
21289
- out += ` <pdfaProperty:name>${escapeXml$1(p.name)}</pdfaProperty:name>\n`;
21290
- out += ` <pdfaProperty:valueType>${escapeXml$1(p.valueType)}</pdfaProperty:valueType>\n`;
21289
+ out += ` <pdfaProperty:name>${escapeXml$2(p.name)}</pdfaProperty:name>\n`;
21290
+ out += ` <pdfaProperty:valueType>${escapeXml$2(p.valueType)}</pdfaProperty:valueType>\n`;
21291
21291
  out += ` <pdfaProperty:category>${p.category}</pdfaProperty:category>\n`;
21292
- out += ` <pdfaProperty:description>${escapeXml$1(p.description)}</pdfaProperty:description>\n`;
21292
+ out += ` <pdfaProperty:description>${escapeXml$2(p.description)}</pdfaProperty:description>\n`;
21293
21293
  out += " </rdf:li>\n";
21294
21294
  }
21295
21295
  out += " </rdf:Seq>\n";
@@ -21326,7 +21326,7 @@ function buildPdfA4Xmp(options) {
21326
21326
  xmp += " xmlns:dc=\"http://purl.org/dc/elements/1.1/\">\n";
21327
21327
  xmp += " <dc:title>\n";
21328
21328
  xmp += " <rdf:Alt>\n";
21329
- xmp += ` <rdf:li xml:lang="x-default">${escapeXml$1(title)}</rdf:li>\n`;
21329
+ xmp += ` <rdf:li xml:lang="x-default">${escapeXml$2(title)}</rdf:li>\n`;
21330
21330
  xmp += " </rdf:Alt>\n";
21331
21331
  xmp += " </dc:title>\n";
21332
21332
  xmp += " </rdf:Description>\n";
@@ -21400,7 +21400,7 @@ const ORDER_X_TYPE_CODES = {
21400
21400
  OrderResponse: ORDER_RESPONSE_TYPE_CODE
21401
21401
  };
21402
21402
  /** Escape XML special characters in a text value. */
21403
- function escapeXml(str) {
21403
+ function escapeXml$1(str) {
21404
21404
  return str.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll("\"", "&quot;").replaceAll("'", "&apos;");
21405
21405
  }
21406
21406
  /** Format a numeric monetary/quantity value with two decimal places. */
@@ -21457,13 +21457,13 @@ function computeTotals(lines) {
21457
21457
  /** Render a single trade party block (Seller or Buyer). */
21458
21458
  function renderParty(party, indent) {
21459
21459
  const out = [];
21460
- out.push(`${indent}<ram:Name>${escapeXml(party.name)}</ram:Name>`);
21460
+ out.push(`${indent}<ram:Name>${escapeXml$1(party.name)}</ram:Name>`);
21461
21461
  out.push(`${indent}<ram:PostalTradeAddress>`);
21462
- out.push(`${indent} <ram:CountryID>${escapeXml(party.countryCode)}</ram:CountryID>`);
21462
+ out.push(`${indent} <ram:CountryID>${escapeXml$1(party.countryCode)}</ram:CountryID>`);
21463
21463
  out.push(`${indent}</ram:PostalTradeAddress>`);
21464
21464
  if (party.vatId !== void 0 && party.vatId !== "") {
21465
21465
  out.push(`${indent}<ram:SpecifiedTaxRegistration>`);
21466
- out.push(`${indent} <ram:ID schemeID="VA">${escapeXml(party.vatId)}</ram:ID>`);
21466
+ out.push(`${indent} <ram:ID schemeID="VA">${escapeXml$1(party.vatId)}</ram:ID>`);
21467
21467
  out.push(`${indent}</ram:SpecifiedTaxRegistration>`);
21468
21468
  }
21469
21469
  return out.join("\n");
@@ -21477,7 +21477,7 @@ function renderLine$1(line, index, currency) {
21477
21477
  out.push(` <ram:LineID>${index}</ram:LineID>`);
21478
21478
  out.push(" </ram:AssociatedDocumentLineDocument>");
21479
21479
  out.push(" <ram:SpecifiedTradeProduct>");
21480
- out.push(` <ram:Name>${escapeXml(line.description)}</ram:Name>`);
21480
+ out.push(` <ram:Name>${escapeXml$1(line.description)}</ram:Name>`);
21481
21481
  out.push(" </ram:SpecifiedTradeProduct>");
21482
21482
  out.push(" <ram:SpecifiedLineTradeAgreement>");
21483
21483
  out.push(" <ram:NetPriceProductTradePrice>");
@@ -21494,7 +21494,7 @@ function renderLine$1(line, index, currency) {
21494
21494
  out.push(` <ram:RateApplicablePercent>${formatPercent(line.taxPercent)}</ram:RateApplicablePercent>`);
21495
21495
  out.push(" </ram:ApplicableTradeTax>");
21496
21496
  out.push(" <ram:SpecifiedTradeSettlementLineMonetarySummation>");
21497
- out.push(` <ram:LineTotalAmount currencyID="${escapeXml(currency)}">${formatAmount(net)}</ram:LineTotalAmount>`);
21497
+ out.push(` <ram:LineTotalAmount currencyID="${escapeXml$1(currency)}">${formatAmount(net)}</ram:LineTotalAmount>`);
21498
21498
  out.push(" </ram:SpecifiedTradeSettlementLineMonetarySummation>");
21499
21499
  out.push(" </ram:SpecifiedLineTradeSettlement>");
21500
21500
  out.push(" </ram:IncludedSupplyChainTradeLineItem>");
@@ -21504,9 +21504,9 @@ function renderLine$1(line, index, currency) {
21504
21504
  function renderTaxGroup(group, currency) {
21505
21505
  const out = [];
21506
21506
  out.push(" <ram:ApplicableTradeTax>");
21507
- out.push(` <ram:CalculatedAmount currencyID="${escapeXml(currency)}">${formatAmount(group.taxAmount)}</ram:CalculatedAmount>`);
21507
+ out.push(` <ram:CalculatedAmount currencyID="${escapeXml$1(currency)}">${formatAmount(group.taxAmount)}</ram:CalculatedAmount>`);
21508
21508
  out.push(" <ram:TypeCode>VAT</ram:TypeCode>");
21509
- out.push(` <ram:BasisAmount currencyID="${escapeXml(currency)}">${formatAmount(group.basisAmount)}</ram:BasisAmount>`);
21509
+ out.push(` <ram:BasisAmount currencyID="${escapeXml$1(currency)}">${formatAmount(group.basisAmount)}</ram:BasisAmount>`);
21510
21510
  out.push(` <ram:CategoryCode>${VAT_CATEGORY_STANDARD}</ram:CategoryCode>`);
21511
21511
  out.push(` <ram:RateApplicablePercent>${formatPercent(group.taxPercent)}</ram:RateApplicablePercent>`);
21512
21512
  out.push(" </ram:ApplicableTradeTax>");
@@ -21516,11 +21516,11 @@ function renderTaxGroup(group, currency) {
21516
21516
  function renderMonetarySummation(totals, currency) {
21517
21517
  const out = [];
21518
21518
  out.push(" <ram:SpecifiedTradeSettlementHeaderMonetarySummation>");
21519
- out.push(` <ram:LineTotalAmount currencyID="${escapeXml(currency)}">${formatAmount(totals.lineTotal)}</ram:LineTotalAmount>`);
21520
- out.push(` <ram:TaxBasisTotalAmount currencyID="${escapeXml(currency)}">${formatAmount(totals.lineTotal)}</ram:TaxBasisTotalAmount>`);
21521
- out.push(` <ram:TaxTotalAmount currencyID="${escapeXml(currency)}">${formatAmount(totals.taxTotal)}</ram:TaxTotalAmount>`);
21522
- out.push(` <ram:GrandTotalAmount currencyID="${escapeXml(currency)}">${formatAmount(totals.grandTotal)}</ram:GrandTotalAmount>`);
21523
- out.push(` <ram:DuePayableAmount currencyID="${escapeXml(currency)}">${formatAmount(totals.duePayable)}</ram:DuePayableAmount>`);
21519
+ out.push(` <ram:LineTotalAmount currencyID="${escapeXml$1(currency)}">${formatAmount(totals.lineTotal)}</ram:LineTotalAmount>`);
21520
+ out.push(` <ram:TaxBasisTotalAmount currencyID="${escapeXml$1(currency)}">${formatAmount(totals.lineTotal)}</ram:TaxBasisTotalAmount>`);
21521
+ out.push(` <ram:TaxTotalAmount currencyID="${escapeXml$1(currency)}">${formatAmount(totals.taxTotal)}</ram:TaxTotalAmount>`);
21522
+ out.push(` <ram:GrandTotalAmount currencyID="${escapeXml$1(currency)}">${formatAmount(totals.grandTotal)}</ram:GrandTotalAmount>`);
21523
+ out.push(` <ram:DuePayableAmount currencyID="${escapeXml$1(currency)}">${formatAmount(totals.duePayable)}</ram:DuePayableAmount>`);
21524
21524
  out.push(" </ram:SpecifiedTradeSettlementHeaderMonetarySummation>");
21525
21525
  return out.join("\n");
21526
21526
  }
@@ -21544,11 +21544,11 @@ function generateXRechnungCii(invoice, options = {}) {
21544
21544
  out.push("<rsm:CrossIndustryInvoice xmlns:rsm=\"urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100\" xmlns:ram=\"urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100\" xmlns:udt=\"urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100\">");
21545
21545
  out.push(" <rsm:ExchangedDocumentContext>");
21546
21546
  out.push(" <ram:GuidelineSpecifiedDocumentContextParameter>");
21547
- out.push(` <ram:ID>${escapeXml(XRECHNUNG_GUIDELINE_URN)}</ram:ID>`);
21547
+ out.push(` <ram:ID>${escapeXml$1(XRECHNUNG_GUIDELINE_URN)}</ram:ID>`);
21548
21548
  out.push(" </ram:GuidelineSpecifiedDocumentContextParameter>");
21549
21549
  out.push(" </rsm:ExchangedDocumentContext>");
21550
21550
  out.push(" <rsm:ExchangedDocument>");
21551
- out.push(` <ram:ID>${escapeXml(invoice.invoiceNumber)}</ram:ID>`);
21551
+ out.push(` <ram:ID>${escapeXml$1(invoice.invoiceNumber)}</ram:ID>`);
21552
21552
  out.push(` <ram:TypeCode>${COMMERCIAL_INVOICE_TYPE_CODE}</ram:TypeCode>`);
21553
21553
  out.push(" <ram:IssueDateTime>");
21554
21554
  out.push(` <udt:DateTimeString format="102">${toDateString102(invoice.issueDate)}</udt:DateTimeString>`);
@@ -21557,7 +21557,7 @@ function generateXRechnungCii(invoice, options = {}) {
21557
21557
  out.push(" <rsm:SupplyChainTradeTransaction>");
21558
21558
  for (const [i, line] of invoice.lines.entries()) out.push(renderLine$1(line, i + 1, currency));
21559
21559
  out.push(" <ram:ApplicableHeaderTradeAgreement>");
21560
- if (buyerReference !== void 0 && buyerReference !== "") out.push(` <ram:BuyerReference>${escapeXml(buyerReference)}</ram:BuyerReference>`);
21560
+ if (buyerReference !== void 0 && buyerReference !== "") out.push(` <ram:BuyerReference>${escapeXml$1(buyerReference)}</ram:BuyerReference>`);
21561
21561
  out.push(" <ram:SellerTradeParty>");
21562
21562
  out.push(renderParty(invoice.seller, " "));
21563
21563
  out.push(" </ram:SellerTradeParty>");
@@ -21567,7 +21567,7 @@ function generateXRechnungCii(invoice, options = {}) {
21567
21567
  out.push(" </ram:ApplicableHeaderTradeAgreement>");
21568
21568
  out.push(" <ram:ApplicableHeaderTradeDelivery/>");
21569
21569
  out.push(" <ram:ApplicableHeaderTradeSettlement>");
21570
- out.push(` <ram:InvoiceCurrencyCode>${escapeXml(currency)}</ram:InvoiceCurrencyCode>`);
21570
+ out.push(` <ram:InvoiceCurrencyCode>${escapeXml$1(currency)}</ram:InvoiceCurrencyCode>`);
21571
21571
  for (const group of totals.taxGroups) out.push(renderTaxGroup(group, currency));
21572
21572
  out.push(renderMonetarySummation(totals, currency));
21573
21573
  out.push(" </ram:ApplicableHeaderTradeSettlement>");
@@ -21598,11 +21598,11 @@ function generateOrderX(invoice, orderType) {
21598
21598
  out.push("<rsm:SCRDMCCBDACIOMessageStructure xmlns:rsm=\"urn:un:unece:uncefact:data:standard:SCRDMCCBDACIOMessageStructure:100\" xmlns:ram=\"urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:128\" xmlns:udt=\"urn:un:unece:uncefact:data:standard:UnqualifiedDataType:128\">");
21599
21599
  out.push(" <rsm:ExchangedDocumentContext>");
21600
21600
  out.push(" <ram:GuidelineSpecifiedDocumentContextParameter>");
21601
- out.push(` <ram:ID>${escapeXml(ORDER_X_GUIDELINE_URN)}</ram:ID>`);
21601
+ out.push(` <ram:ID>${escapeXml$1(ORDER_X_GUIDELINE_URN)}</ram:ID>`);
21602
21602
  out.push(" </ram:GuidelineSpecifiedDocumentContextParameter>");
21603
21603
  out.push(" </rsm:ExchangedDocumentContext>");
21604
21604
  out.push(" <rsm:ExchangedDocument>");
21605
- out.push(` <ram:ID>${escapeXml(invoice.invoiceNumber)}</ram:ID>`);
21605
+ out.push(` <ram:ID>${escapeXml$1(invoice.invoiceNumber)}</ram:ID>`);
21606
21606
  out.push(` <ram:TypeCode>${typeCode}</ram:TypeCode>`);
21607
21607
  out.push(" <ram:IssueDateTime>");
21608
21608
  out.push(` <udt:DateTimeString format="102">${toDateString102(invoice.issueDate)}</udt:DateTimeString>`);
@@ -21620,7 +21620,7 @@ function generateOrderX(invoice, orderType) {
21620
21620
  out.push(" </ram:ApplicableHeaderTradeAgreement>");
21621
21621
  out.push(" <ram:ApplicableHeaderTradeDelivery/>");
21622
21622
  out.push(" <ram:ApplicableHeaderTradeSettlement>");
21623
- out.push(` <ram:OrderCurrencyCode>${escapeXml(currency)}</ram:OrderCurrencyCode>`);
21623
+ out.push(` <ram:OrderCurrencyCode>${escapeXml$1(currency)}</ram:OrderCurrencyCode>`);
21624
21624
  for (const group of totals.taxGroups) out.push(renderTaxGroup(group, currency));
21625
21625
  out.push(renderMonetarySummation(totals, currency));
21626
21626
  out.push(" </ram:ApplicableHeaderTradeSettlement>");
@@ -30416,6 +30416,823 @@ function buildBlackPointCompensationExtGState(mode) {
30416
30416
  return gs;
30417
30417
  }
30418
30418
  //#endregion
30419
+ //#region src/accessibility/taggingHelpers.ts
30420
+ /**
30421
+ * The property key under which {@link tagList} records the chosen
30422
+ * {@link ListNumbering} on a list element's `options` object.
30423
+ *
30424
+ * `StructureElementOptions` has no dedicated `listNumbering` field, so
30425
+ * the value is stored as an extra (string-keyed) property on the same
30426
+ * options object. When the structure tree is serialized this is the
30427
+ * value an attribute writer should emit as the list's `/ListNumbering`
30428
+ * entry inside an `/A` attribute dictionary whose owner is `/List`
30429
+ * (ISO 32000, Table 384):
30430
+ *
30431
+ * ```
30432
+ * /A << /O /List /ListNumbering /Decimal >>
30433
+ * ```
30434
+ *
30435
+ * Using a well-known string key (rather than a `Symbol`) keeps the
30436
+ * value plain-serializable and inspectable from tests.
30437
+ */
30438
+ const LIST_NUMBERING_KEY = "__listNumbering";
30439
+ /**
30440
+ * Heading level → structure-type mapping for {@link tagHeading}.
30441
+ *
30442
+ * Indexed by the numeric heading level (`1`..`6`); the result is the
30443
+ * corresponding standard heading structure type (`'H1'`..`'H6'`).
30444
+ */
30445
+ const HEADING_TYPE = {
30446
+ 1: "H1",
30447
+ 2: "H2",
30448
+ 3: "H3",
30449
+ 4: "H4",
30450
+ 5: "H5",
30451
+ 6: "H6"
30452
+ };
30453
+ /**
30454
+ * Tag a heading element of the given level.
30455
+ *
30456
+ * @param tree The structure tree to add the element to.
30457
+ * @param parent The parent element, or `null` to add under the root
30458
+ * `Document` element.
30459
+ * @param level The heading level (`1`..`6`); maps to `H1`..`H6`.
30460
+ * @param options Optional attributes (title, language, id, …).
30461
+ * @returns The newly created heading element (type `H1`..`H6`).
30462
+ *
30463
+ * @example
30464
+ * ```ts
30465
+ * const tree = doc.createStructureTree();
30466
+ * const h2 = tagHeading(tree, null, 2, { title: 'Background' });
30467
+ * // h2.type === 'H2'
30468
+ * ```
30469
+ */
30470
+ function tagHeading(tree, parent, level, options) {
30471
+ return tree.addElement(parent, HEADING_TYPE[level], options);
30472
+ }
30473
+ /**
30474
+ * Tag a paragraph (`P`) element.
30475
+ *
30476
+ * @param tree The structure tree to add the element to.
30477
+ * @param parent The parent element, or `null` for the root.
30478
+ * @param options Optional attributes.
30479
+ * @returns The newly created `P` element.
30480
+ */
30481
+ function tagParagraph(tree, parent, options) {
30482
+ return tree.addElement(parent, "P", options);
30483
+ }
30484
+ /**
30485
+ * Tag a figure (`Figure`) element with alternative text.
30486
+ *
30487
+ * The `altText` argument is required because PDF/UA mandates
30488
+ * alternative text for illustration elements. If the caller also
30489
+ * supplies `altText` in `options`, that explicit value takes
30490
+ * precedence over the positional argument.
30491
+ *
30492
+ * @param tree The structure tree to add the element to.
30493
+ * @param parent The parent element, or `null` for the root.
30494
+ * @param altText Alternative text describing the figure.
30495
+ * @param options Optional additional attributes.
30496
+ * @returns The newly created `Figure` element with `/Alt` set.
30497
+ */
30498
+ function tagFigure(tree, parent, altText, options) {
30499
+ const merged = {
30500
+ altText,
30501
+ ...options
30502
+ };
30503
+ return tree.addElement(parent, "Figure", merged);
30504
+ }
30505
+ /**
30506
+ * Tag a link (`Link`) element.
30507
+ *
30508
+ * @param tree The structure tree to add the element to.
30509
+ * @param parent The parent element, or `null` for the root.
30510
+ * @param options Optional attributes.
30511
+ * @returns The newly created `Link` element.
30512
+ */
30513
+ function tagLink(tree, parent, options) {
30514
+ return tree.addElement(parent, "Link", options);
30515
+ }
30516
+ /**
30517
+ * Tag a list (`L`) element and record its numbering style.
30518
+ *
30519
+ * The chosen {@link ListNumbering} is stored on the returned element's
30520
+ * `options` object under {@link LIST_NUMBERING_KEY} (since
30521
+ * `StructureElementOptions` has no dedicated field). A serializer can
30522
+ * emit it as the list's `/ListNumbering` attribute (ISO 32000,
30523
+ * Table 384) inside an `/A` dictionary owned by `/List`.
30524
+ *
30525
+ * @param tree The structure tree to add the element to.
30526
+ * @param parent The parent element, or `null` for the root.
30527
+ * @param numbering The list numbering style (default `'None'`).
30528
+ * @param options Optional additional attributes.
30529
+ * @returns The newly created `L` element.
30530
+ */
30531
+ function tagList(tree, parent, numbering = "None", options) {
30532
+ const list = tree.addElement(parent, "L", options);
30533
+ list.options[LIST_NUMBERING_KEY] = numbering;
30534
+ return list;
30535
+ }
30536
+ /**
30537
+ * Tag a list item under a list, building the conventional
30538
+ * `LI` → (`Lbl`, `LBody`) substructure.
30539
+ *
30540
+ * @param tree The structure tree to add the elements to.
30541
+ * @param list The parent `L` (list) element.
30542
+ * @param options Optional attributes for the `LI` element.
30543
+ * @returns The created `item` (`LI`), `label` (`Lbl`) and
30544
+ * `body` (`LBody`) elements.
30545
+ *
30546
+ * @example
30547
+ * ```ts
30548
+ * const list = tagList(tree, null, 'Decimal');
30549
+ * const { item, label, body } = tagListItem(tree, list);
30550
+ * // item.type === 'LI', label.type === 'Lbl', body.type === 'LBody'
30551
+ * ```
30552
+ */
30553
+ function tagListItem(tree, list, options) {
30554
+ const item = tree.addElement(list, "LI", options);
30555
+ return {
30556
+ item,
30557
+ label: tree.addElement(item, "Lbl"),
30558
+ body: tree.addElement(item, "LBody")
30559
+ };
30560
+ }
30561
+ /**
30562
+ * Tag a table (`Table`) element.
30563
+ *
30564
+ * @param tree The structure tree to add the element to.
30565
+ * @param parent The parent element, or `null` for the root.
30566
+ * @param options Optional attributes.
30567
+ * @returns The newly created `Table` element.
30568
+ */
30569
+ function tagTable(tree, parent, options) {
30570
+ return tree.addElement(parent, "Table", options);
30571
+ }
30572
+ /**
30573
+ * Tag a table row (`TR`) under a table.
30574
+ *
30575
+ * @param tree The structure tree to add the element to.
30576
+ * @param table The parent `Table` element.
30577
+ * @returns The newly created `TR` element.
30578
+ */
30579
+ function tagTableRow(tree, table) {
30580
+ return tree.addElement(table, "TR");
30581
+ }
30582
+ /**
30583
+ * Tag a table header cell (`TH`) under a row, recording its scope.
30584
+ *
30585
+ * The `scope` is stored in the element's options (`/Scope` attribute,
30586
+ * one of `Row`, `Column`, or `Both`) and is used by table-header
30587
+ * validation to associate header cells with the cells they describe.
30588
+ *
30589
+ * @param tree The structure tree to add the element to.
30590
+ * @param row The parent `TR` element.
30591
+ * @param scope The header scope (default `'Column'`).
30592
+ * @param options Optional additional attributes (e.g. colSpan/rowSpan).
30593
+ * @returns The newly created `TH` element with `scope` set.
30594
+ */
30595
+ function tagTableHeaderCell(tree, row, scope = "Column", options) {
30596
+ const merged = {
30597
+ ...options,
30598
+ scope
30599
+ };
30600
+ return tree.addElement(row, "TH", merged);
30601
+ }
30602
+ /**
30603
+ * Tag a table data cell (`TD`) under a row.
30604
+ *
30605
+ * @param tree The structure tree to add the element to.
30606
+ * @param row The parent `TR` element.
30607
+ * @param options Optional attributes (e.g. colSpan/rowSpan).
30608
+ * @returns The newly created `TD` element.
30609
+ */
30610
+ function tagTableDataCell(tree, row, options) {
30611
+ return tree.addElement(row, "TD", options);
30612
+ }
30613
+ //#endregion
30614
+ //#region src/accessibility/pdfUa2.ts
30615
+ /** The AIIM PDF/UA identification namespace URI (used in the XMP packet). */
30616
+ const PDFUA_ID_NS = "http://www.aiim.org/pdfua/ns/id/";
30617
+ /** The PDF/UA part identified by this module's XMP. */
30618
+ const PDFUA2_PART = 2;
30619
+ /**
30620
+ * The PDF/UA-2 revision year. ISO 14289-2 was published in 2024, which the
30621
+ * AIIM `pdfuaid:rev` field records as a four-digit year.
30622
+ */
30623
+ const PDFUA2_REV = 2024;
30624
+ /** Illustration types that require alternative text under PDF/UA-2. */
30625
+ const ILLUSTRATION_TYPES = /* @__PURE__ */ new Set([
30626
+ "Figure",
30627
+ "Formula",
30628
+ "Form"
30629
+ ]);
30630
+ /**
30631
+ * Validate a PDF document against PDF/UA-2 (ISO 14289-2) requirements.
30632
+ *
30633
+ * The check reuses {@link validatePdfUa} for the shared tagging, language,
30634
+ * MarkInfo, and metadata requirements, then layers the PDF 2.0 / UA-2
30635
+ * specific requirements on top:
30636
+ *
30637
+ * - **UA2-STRUCT-001** — a structure tree must exist (tagged PDF).
30638
+ * - **UA2-NS-001** — the structure tree must declare structure
30639
+ * `/Namespaces` (PDF/UA-2 builds on PDF 2.0 namespaces).
30640
+ * - **UA2-LANG-001** — the document must declare a natural language
30641
+ * (`/Lang`).
30642
+ * - **UA2-FIG-001** — every figure must carry alternative text.
30643
+ *
30644
+ * Each failure is mapped to an ISO 14289-2 clause string. The returned
30645
+ * result is `conformant` only when there are no issues.
30646
+ *
30647
+ * @param doc The PDF document to validate.
30648
+ * @returns A {@link PdfUa2Result} describing conformance and issues.
30649
+ *
30650
+ * @example
30651
+ * ```ts
30652
+ * import { createPdf } from 'modern-pdf-lib';
30653
+ * import { validatePdfUa2 } from 'modern-pdf-lib/accessibility';
30654
+ *
30655
+ * const doc = createPdf();
30656
+ * const result = validatePdfUa2(doc);
30657
+ * if (!result.conformant) {
30658
+ * for (const issue of result.issues) {
30659
+ * console.error(`[${issue.code}] ${issue.message} (§${issue.clause})`);
30660
+ * }
30661
+ * }
30662
+ * ```
30663
+ */
30664
+ function validatePdfUa2(doc) {
30665
+ const issues = [];
30666
+ const tree = doc.getStructureTree();
30667
+ if (!tree) issues.push({
30668
+ code: "UA2-STRUCT-001",
30669
+ message: "Document has no structure tree (/StructTreeRoot). PDF/UA-2 requires a fully tagged PDF 2.0 document with logical structure.",
30670
+ clause: "8.2"
30671
+ });
30672
+ if (!hasDeclaredNamespaces(tree)) issues.push({
30673
+ code: "UA2-NS-001",
30674
+ message: "Structure tree does not declare structure /Namespaces. PDF/UA-2 builds on PDF 2.0 structure namespaces (ISO 32000-2 §14.7.4); the StructTreeRoot must declare its namespaces.",
30675
+ clause: "8.2.2"
30676
+ });
30677
+ const lang = doc.getLanguage();
30678
+ if (lang === void 0 || lang.trim().length === 0) issues.push({
30679
+ code: "UA2-LANG-001",
30680
+ message: "Document has no natural language (/Lang). PDF/UA-2 requires the document catalog to specify a default natural language.",
30681
+ clause: "7.2"
30682
+ });
30683
+ if (tree) for (const elem of tree.getAllElements()) {
30684
+ if (!ILLUSTRATION_TYPES.has(elem.type)) continue;
30685
+ if (elem.options.artifact) continue;
30686
+ const alt = elem.options.altText;
30687
+ const actual = elem.options.actualText;
30688
+ const hasAlt = alt !== void 0 && alt.trim().length > 0;
30689
+ const hasActual = actual !== void 0 && actual.trim().length > 0;
30690
+ if (!hasAlt && !hasActual) issues.push({
30691
+ code: "UA2-FIG-001",
30692
+ message: `${elem.type} element has no /Alt or /ActualText. PDF/UA-2 requires alternative text for all non-decorative illustration elements.`,
30693
+ clause: "7.3"
30694
+ });
30695
+ }
30696
+ const ua1 = validatePdfUa(doc);
30697
+ for (const err of ua1.errors) {
30698
+ if (isCoveredByUa2(err.code)) continue;
30699
+ issues.push({
30700
+ code: `UA2-${err.code}`,
30701
+ message: err.message,
30702
+ clause: mapUa1Clause(err.clause)
30703
+ });
30704
+ }
30705
+ return {
30706
+ conformant: issues.length === 0,
30707
+ issues
30708
+ };
30709
+ }
30710
+ /**
30711
+ * Build an XMP packet (RDF/XML) that identifies a document as PDF/UA-2.
30712
+ *
30713
+ * The packet declares the AIIM PDF/UA identification schema
30714
+ * (`pdfuaid`, namespace `http://www.aiim.org/pdfua/ns/id/`) with:
30715
+ *
30716
+ * - `pdfuaid:part` = `2` — the PDF/UA part (ISO 14289-2);
30717
+ * - `pdfuaid:rev` = the revision year of the standard.
30718
+ *
30719
+ * The result is a serialized, packet-wrapped XMP string suitable for
30720
+ * embedding as the document's `/Metadata` stream.
30721
+ *
30722
+ * @returns The serialized PDF/UA-2 identification XMP packet.
30723
+ *
30724
+ * @example
30725
+ * ```ts
30726
+ * import { buildPdfUa2Xmp } from 'modern-pdf-lib/accessibility';
30727
+ *
30728
+ * doc.setXmpMetadata(buildPdfUa2Xmp());
30729
+ * ```
30730
+ */
30731
+ function buildPdfUa2Xmp() {
30732
+ return [
30733
+ "<?xpacket begin=\"\" id=\"W5M0MpCehiHzreSzNTczkc9d\"?>",
30734
+ "<x:xmpmeta xmlns:x=\"adobe:ns:meta/\">",
30735
+ " <rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\">",
30736
+ ` <rdf:Description rdf:about=""`,
30737
+ ` xmlns:pdfuaid="${PDFUA_ID_NS}">`,
30738
+ ` <pdfuaid:part>${PDFUA2_PART}</pdfuaid:part>`,
30739
+ ` <pdfuaid:rev>${PDFUA2_REV}</pdfuaid:rev>`,
30740
+ " </rdf:Description>",
30741
+ " </rdf:RDF>",
30742
+ "</x:xmpmeta>",
30743
+ "<?xpacket end=\"w\"?>"
30744
+ ].join("\n");
30745
+ }
30746
+ /**
30747
+ * Determine whether a structure tree declares one or more structure
30748
+ * namespaces.
30749
+ *
30750
+ * The in-memory {@link PdfStructureTree} model does not yet carry a
30751
+ * first-class namespaces field, so callers declare namespaces by attaching
30752
+ * a `namespaces` array (of namespace URI strings, or namespace descriptor
30753
+ * objects) to the tree. This helper reads that field defensively and also
30754
+ * recognizes a per-element `namespace` option as evidence of namespace use.
30755
+ *
30756
+ * @internal
30757
+ */
30758
+ function hasDeclaredNamespaces(tree) {
30759
+ if (!tree) return false;
30760
+ const declared = tree.namespaces;
30761
+ if (Array.isArray(declared) && declared.length > 0) return true;
30762
+ for (const elem of tree.getAllElements()) {
30763
+ const ns = elem.options.namespace;
30764
+ if (typeof ns === "string" && ns.length > 0) return true;
30765
+ }
30766
+ return false;
30767
+ }
30768
+ /**
30769
+ * Whether a PDF/UA-1 error code is already represented by a dedicated
30770
+ * UA-2 issue produced above (to avoid duplicate structure-tree / language
30771
+ * findings).
30772
+ *
30773
+ * @internal
30774
+ */
30775
+ function isCoveredByUa2(ua1Code) {
30776
+ return ua1Code === "UA-STRUCT-001" || ua1Code === "UA-STRUCT-002" || ua1Code === "UA-META-001" || ua1Code === "UA-META-002" || ua1Code === "UA-META-003";
30777
+ }
30778
+ /**
30779
+ * Map a PDF/UA-1 (ISO 14289-1) clause reference onto the corresponding
30780
+ * PDF/UA-2 (ISO 14289-2) clause. The two standards share most clause
30781
+ * numbering; when a UA-1 clause is absent we fall back to the general
30782
+ * UA-2 conformance clause.
30783
+ *
30784
+ * @internal
30785
+ */
30786
+ function mapUa1Clause(ua1Clause) {
30787
+ if (ua1Clause === void 0 || ua1Clause.length === 0) return "5";
30788
+ return ua1Clause;
30789
+ }
30790
+ //#endregion
30791
+ //#region src/accessibility/autoTag.ts
30792
+ /** Default heading-detection scale relative to body text size. */
30793
+ const DEFAULT_HEADING_SCALE = 1.2;
30794
+ /**
30795
+ * Maximum vertical gap (in page-space units, as a fraction of the run's
30796
+ * font size) within which two text runs are considered to belong to the
30797
+ * same visual line. Runs whose baselines are within this fraction of an
30798
+ * em are merged onto one line.
30799
+ */
30800
+ const SAME_LINE_FRACTION = .5;
30801
+ /** Highest heading level tag supported. */
30802
+ const MAX_HEADING_LEVEL = 6;
30803
+ /**
30804
+ * Infer a coarse logical structure for a single untagged page and add the
30805
+ * inferred `H1`..`H6` and `P` elements to the document's structure tree.
30806
+ *
30807
+ * The procedure:
30808
+ * 1. Interpret the page into positioned text runs.
30809
+ * 2. Group runs into visual lines by their baseline y-position.
30810
+ * 3. Determine the body font size as the median run font size.
30811
+ * 4. Order lines top-to-bottom (reading order on a y-up page).
30812
+ * 5. Classify each line as a heading (font size `>= headingScale × body`)
30813
+ * or body text; map distinct heading sizes to `H1`..`H6`
30814
+ * (largest → `H1`).
30815
+ * 6. Emit one heading element per heading line and one `P` element per
30816
+ * contiguous block of body lines.
30817
+ *
30818
+ * Never throws on an empty (or text-free) page — it returns all-zero
30819
+ * counts and leaves the structure tree untouched.
30820
+ *
30821
+ * @param doc The document containing the page.
30822
+ * @param pageIndex Zero-based index of the page to tag.
30823
+ * @param options Optional heuristic tuning ({@link AutoTagOptions}).
30824
+ * @returns Counts of the elements that were added.
30825
+ */
30826
+ function autoTagPage(doc, pageIndex, options) {
30827
+ const headingScale = options?.headingScale ?? DEFAULT_HEADING_SCALE;
30828
+ const textItems = collectTextItems(doc, pageIndex);
30829
+ if (textItems.length === 0) return {
30830
+ headings: 0,
30831
+ paragraphs: 0,
30832
+ elements: 0
30833
+ };
30834
+ const lines = groupIntoLines(textItems);
30835
+ if (lines.length === 0) return {
30836
+ headings: 0,
30837
+ paragraphs: 0,
30838
+ elements: 0
30839
+ };
30840
+ const bodySize = medianFontSize(textItems);
30841
+ const ordered = [...lines].sort((a, b) => b.y - a.y);
30842
+ const headingThreshold = bodySize * headingScale;
30843
+ const headingLevelForSize = buildHeadingLevelMap(ordered, headingThreshold);
30844
+ const tree = doc.createStructureTree();
30845
+ let headings = 0;
30846
+ let paragraphs = 0;
30847
+ let paragraphOpen = false;
30848
+ for (const line of ordered) if (line.fontSize >= headingThreshold) {
30849
+ paragraphOpen = false;
30850
+ const type = `H${headingLevelForSize.get(line.fontSize) ?? 1}`;
30851
+ tree.addElement(null, type, { title: line.text });
30852
+ headings++;
30853
+ } else if (!paragraphOpen) {
30854
+ tree.addElement(null, "P");
30855
+ paragraphs++;
30856
+ paragraphOpen = true;
30857
+ }
30858
+ return {
30859
+ headings,
30860
+ paragraphs,
30861
+ elements: headings + paragraphs
30862
+ };
30863
+ }
30864
+ /**
30865
+ * Interpret the page and return only its text runs. Returns an empty
30866
+ * array (never throws) if the page cannot be interpreted.
30867
+ *
30868
+ * @internal
30869
+ */
30870
+ function collectTextItems(doc, pageIndex) {
30871
+ const pageCount = doc.getPageCount();
30872
+ if (pageIndex < 0 || pageIndex >= pageCount) return [];
30873
+ let items = [];
30874
+ try {
30875
+ items = interpretPage(doc.getPage(pageIndex)).items.filter((it) => it.type === "text" && it.text.trim().length > 0);
30876
+ } catch {
30877
+ return [];
30878
+ }
30879
+ return [...items];
30880
+ }
30881
+ /**
30882
+ * Group text runs into visual lines by their baseline y-position.
30883
+ *
30884
+ * The baseline is taken from the run's text-space → page-space transform
30885
+ * (`transform[5]`, the `f` translation component). Runs whose baselines
30886
+ * fall within {@link SAME_LINE_FRACTION} of an em of an existing line are
30887
+ * merged onto that line; the line's font size is the maximum run size.
30888
+ *
30889
+ * @internal
30890
+ */
30891
+ function groupIntoLines(items) {
30892
+ const sorted = [...items].sort((a, b) => b.transform[5] - a.transform[5]);
30893
+ const lines = [];
30894
+ for (const item of sorted) {
30895
+ const y = item.transform[5];
30896
+ const size = item.fontSize > 0 ? item.fontSize : Math.abs(item.transform[3]) || 1;
30897
+ const last = lines[lines.length - 1];
30898
+ const tolerance = size * SAME_LINE_FRACTION;
30899
+ if (last && Math.abs(last.y - y) <= tolerance) {
30900
+ last.text = `${last.text} ${item.text}`.trim();
30901
+ if (size > last.fontSize) last.fontSize = size;
30902
+ } else lines.push({
30903
+ y,
30904
+ fontSize: size,
30905
+ text: item.text.trim()
30906
+ });
30907
+ }
30908
+ return lines.map((l) => ({
30909
+ y: l.y,
30910
+ fontSize: l.fontSize,
30911
+ text: l.text
30912
+ }));
30913
+ }
30914
+ /**
30915
+ * Compute the median font size across all text runs. The median is more
30916
+ * robust than the mean against a handful of oversized heading runs, so it
30917
+ * gives a reliable estimate of the body text size.
30918
+ *
30919
+ * @internal
30920
+ */
30921
+ function medianFontSize(items) {
30922
+ const sizes = items.map((it) => it.fontSize > 0 ? it.fontSize : Math.abs(it.transform[3])).filter((s) => s > 0).sort((a, b) => a - b);
30923
+ if (sizes.length === 0) return 1;
30924
+ const mid = sizes.length >> 1;
30925
+ if (sizes.length % 2 === 1) return sizes[mid];
30926
+ return (sizes[mid - 1] + sizes[mid]) / 2;
30927
+ }
30928
+ /**
30929
+ * Build a map from each distinct heading font size to a heading level.
30930
+ * The largest heading size becomes `H1`, the next-largest `H2`, and so on,
30931
+ * capped at {@link MAX_HEADING_LEVEL} (`H6`).
30932
+ *
30933
+ * @internal
30934
+ */
30935
+ function buildHeadingLevelMap(lines, headingThreshold) {
30936
+ const distinct = [...new Set(lines.filter((l) => l.fontSize >= headingThreshold).map((l) => l.fontSize))].sort((a, b) => b - a);
30937
+ const map = /* @__PURE__ */ new Map();
30938
+ distinct.forEach((size, index) => {
30939
+ map.set(size, Math.min(index + 1, MAX_HEADING_LEVEL));
30940
+ });
30941
+ return map;
30942
+ }
30943
+ //#endregion
30944
+ //#region src/compliance/profileConvert.ts
30945
+ /** Canonical PDF/A identification namespace URI (`pdfaid`). */
30946
+ const PDFAID_NS = "http://www.aiim.org/pdfa/ns/id/";
30947
+ /**
30948
+ * Run a synchronous, pre-save PDF/A preflight over an in-memory document.
30949
+ *
30950
+ * See the module documentation for the (intentional) scope and limitations of
30951
+ * this check relative to the byte-level `validatePdfA` validator.
30952
+ *
30953
+ * @param doc - The in-memory document to inspect. Never mutated.
30954
+ * @param level - Optional target level (e.g. `'2b'`, `'3u'`, `'PDF/A-4'`).
30955
+ * Only used to refine messages; all checks here are
30956
+ * level-agnostic prerequisites common to every PDF/A part.
30957
+ * @returns A (possibly empty) list of preflight issues. Never throws.
30958
+ */
30959
+ function preflightPdfA(doc, level) {
30960
+ const issues = [];
30961
+ const target = level !== void 0 && level.length > 0 ? ` (${level})` : "";
30962
+ let xmp;
30963
+ try {
30964
+ xmp = doc.getXmpMetadata();
30965
+ } catch {
30966
+ xmp = void 0;
30967
+ }
30968
+ if (xmp === void 0 || xmp.length === 0) issues.push({
30969
+ code: "PDFA-001",
30970
+ message: `XMP metadata stream is required but not set on the document${target}.`,
30971
+ severity: "error",
30972
+ fixable: true,
30973
+ clause: "ISO 19005 (XMP metadata)"
30974
+ });
30975
+ else if (!xmp.includes("pdfaid:part")) issues.push({
30976
+ code: "PDFA-002",
30977
+ message: "XMP metadata does not declare PDF/A identification (pdfaid:part).",
30978
+ severity: "error",
30979
+ fixable: true,
30980
+ clause: "ISO 19005 (PDF/A identification schema)"
30981
+ });
30982
+ if (!documentHasOutputIntent(doc)) issues.push({
30983
+ code: "PDFA-012",
30984
+ message: "A PDF/A output intent (/OutputIntents) with an ICC destination profile is required (none detected on the in-memory document).",
30985
+ severity: "error",
30986
+ fixable: true,
30987
+ clause: "ISO 19005 (OutputIntents)"
30988
+ });
30989
+ let lang;
30990
+ try {
30991
+ lang = doc.getLanguage();
30992
+ } catch {
30993
+ lang = void 0;
30994
+ }
30995
+ if (lang === void 0 || lang.length === 0) issues.push({
30996
+ code: "PDFA-011",
30997
+ message: "The document language (/Lang) is not set; PDF/A recommends a BCP 47 language tag.",
30998
+ severity: "warning",
30999
+ fixable: true,
31000
+ clause: "ISO 19005 (document language)"
31001
+ });
31002
+ let title;
31003
+ try {
31004
+ title = doc.getTitle();
31005
+ } catch {
31006
+ title = void 0;
31007
+ }
31008
+ if (title === void 0 || title.length === 0) issues.push({
31009
+ code: "PDFA-014",
31010
+ message: "The document title is not set; PDF/A requires a dc:title.",
31011
+ severity: "warning",
31012
+ fixable: true,
31013
+ clause: "ISO 19005 (descriptive metadata)"
31014
+ });
31015
+ let pageCount = 0;
31016
+ try {
31017
+ pageCount = doc.getPageCount();
31018
+ } catch {
31019
+ pageCount = 0;
31020
+ }
31021
+ if (pageCount === 0) issues.push({
31022
+ code: "PDFA-015",
31023
+ message: "The document has no pages; a PDF/A file must contain at least one page.",
31024
+ severity: "error",
31025
+ fixable: false,
31026
+ clause: "ISO 32000 (page tree)"
31027
+ });
31028
+ return issues;
31029
+ }
31030
+ /**
31031
+ * Best-effort, pre-save detection of an output intent on a document.
31032
+ *
31033
+ * The public {@link PdfDocument} surface exposes no output-intent accessor, so
31034
+ * this currently always returns `false` for an in-memory document. It is
31035
+ * factored out so a future output-intent API can be wired in without touching
31036
+ * the issue-mapping logic.
31037
+ */
31038
+ function documentHasOutputIntent(_doc) {
31039
+ return false;
31040
+ }
31041
+ /** Map a numeric part to its decimal string. */
31042
+ function partString(part) {
31043
+ return String(part);
31044
+ }
31045
+ /** Map a conformance letter to the upper-case form stored in XMP. */
31046
+ function conformanceString(conformance) {
31047
+ return conformance.toUpperCase();
31048
+ }
31049
+ /**
31050
+ * Remap the PDF/A identification (`pdfaid:part`, and optionally
31051
+ * `pdfaid:conformance`) inside an existing XMP packet.
31052
+ *
31053
+ * Both the **attribute** form (`pdfaid:part="3"`) and the **element** form
31054
+ * (`<pdfaid:part>3</pdfaid:part>`) are handled. When no `pdfaid:part` is
31055
+ * present, identification is injected into the first `rdf:Description` element
31056
+ * (declaring the `pdfaid` namespace on it if necessary). All other content of
31057
+ * the packet is preserved verbatim.
31058
+ *
31059
+ * This is a pure string transform; it does not parse or re-serialize the XML.
31060
+ *
31061
+ * @param xmp - The source XMP packet string.
31062
+ * @param toPart - Target PDF/A part (1, 2, 3 or 4).
31063
+ * @param toConformance - Optional target conformance level (`a`/`b`/`u`). When
31064
+ * omitted, any existing conformance is left untouched.
31065
+ * @returns The transformed XMP packet string.
31066
+ */
31067
+ function convertPdfAConformanceXmp(xmp, toPart, toConformance) {
31068
+ const partVal = partString(toPart);
31069
+ let result = xmp;
31070
+ const partAttr = /pdfaid:part\s*=\s*"[^"]*"/;
31071
+ const partElem = /<pdfaid:part>[^<]*<\/pdfaid:part>/;
31072
+ if (partAttr.test(result)) result = result.replace(partAttr, `pdfaid:part="${partVal}"`);
31073
+ else if (partElem.test(result)) result = result.replace(partElem, `<pdfaid:part>${partVal}</pdfaid:part>`);
31074
+ else {
31075
+ result = injectIdentification(result, partVal, toConformance);
31076
+ return result;
31077
+ }
31078
+ if (toConformance !== void 0) {
31079
+ const confVal = conformanceString(toConformance);
31080
+ const confAttr = /pdfaid:conformance\s*=\s*"[^"]*"/;
31081
+ const confElem = /<pdfaid:conformance>[^<]*<\/pdfaid:conformance>/;
31082
+ if (confAttr.test(result)) result = result.replace(confAttr, `pdfaid:conformance="${confVal}"`);
31083
+ else if (confElem.test(result)) result = result.replace(confElem, `<pdfaid:conformance>${confVal}</pdfaid:conformance>`);
31084
+ else result = addConformanceBesidePart(result, confVal);
31085
+ }
31086
+ return result;
31087
+ }
31088
+ /**
31089
+ * Inject a fresh `pdfaid` identification block into the first `rdf:Description`
31090
+ * element. Used when the source packet has no `pdfaid:part` at all.
31091
+ */
31092
+ function injectIdentification(xmp, partVal, toConformance) {
31093
+ const nsDecl = `xmlns:pdfaid="${PDFAID_NS}"`;
31094
+ const hasNs = xmp.includes(PDFAID_NS);
31095
+ let frag = `<pdfaid:part>${partVal}</pdfaid:part>`;
31096
+ if (toConformance !== void 0) frag += `<pdfaid:conformance>${conformanceString(toConformance)}</pdfaid:conformance>`;
31097
+ const selfClosing = /<rdf:Description\b([^>]*?)\/>/;
31098
+ const scMatch = selfClosing.exec(xmp);
31099
+ if (scMatch) {
31100
+ const replacement = `<rdf:Description${scMatch[1] ?? ""}${hasNs ? "" : ` ${nsDecl}`}>${frag}</rdf:Description>`;
31101
+ return xmp.replace(selfClosing, replacement);
31102
+ }
31103
+ const open = /<rdf:Description\b([^>]*)>/;
31104
+ const openMatch = open.exec(xmp);
31105
+ if (openMatch) {
31106
+ const replacement = `<rdf:Description${openMatch[1] ?? ""}${hasNs ? "" : ` ${nsDecl}`}>${frag}`;
31107
+ return xmp.replace(open, replacement);
31108
+ }
31109
+ return xmp;
31110
+ }
31111
+ /**
31112
+ * Add a `pdfaid:conformance` next to an already-present `pdfaid:part`,
31113
+ * mirroring the part's representation (attribute vs element form).
31114
+ */
31115
+ function addConformanceBesidePart(xmp, confVal) {
31116
+ const partElem = /(<pdfaid:part>[^<]*<\/pdfaid:part>)/;
31117
+ if (partElem.test(xmp)) return xmp.replace(partElem, `$1<pdfaid:conformance>${confVal}</pdfaid:conformance>`);
31118
+ const partAttr = /(pdfaid:part\s*=\s*"[^"]*")/;
31119
+ if (partAttr.test(xmp)) return xmp.replace(partAttr, `$1 pdfaid:conformance="${confVal}"`);
31120
+ return xmp;
31121
+ }
31122
+ //#endregion
31123
+ //#region src/compliance/rasterProfile.ts
31124
+ /**
31125
+ * VERIFIED: PDF Association "PDF Declarations" namespace URI / prefix.
31126
+ * (Some published examples use the `https://` scheme; the `http://` form
31127
+ * is the one most commonly cited and is used here for stability.)
31128
+ */
31129
+ const PDFD_NS = "http://pdfa.org/declarations/";
31130
+ /**
31131
+ * PROVISIONAL: WTPDF declaration target URIs, keyed by conformance level.
31132
+ * The fragment form follows the PDF Association's corrected pattern
31133
+ * (`…/declarations/wtpdf#<level>1.0`) but is acknowledged as unsettled
31134
+ * (pdf-issues #395). Treat as identification hint, not normative match.
31135
+ */
31136
+ const WTPDF_CONFORMS_TO_BASE = "http://pdfa.org/declarations/wtpdf#";
31137
+ /**
31138
+ * PROVISIONAL: PDF/R declaration target URI. ISO 23504 / PDF/Raster has
31139
+ * no published PDF Declarations URI; this follows the same pattern and is
31140
+ * non-normative.
31141
+ */
31142
+ const PDFR_CONFORMS_TO = "http://pdfa.org/declarations/pdfr#1.0";
31143
+ /** Escape XML special characters in a string. */
31144
+ function escapeXml(str) {
31145
+ return str.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll("\"", "&quot;").replaceAll("'", "&apos;");
31146
+ }
31147
+ /**
31148
+ * Build an XMP packet carrying a single PDF Declaration plus a plain
31149
+ * `part`/`conformance` identification block.
31150
+ *
31151
+ * The packet is intentionally minimal: it declares the verified `pdfd`
31152
+ * PDF Declarations namespace and structure, embeds the (provisional)
31153
+ * `conformsTo` target, and additionally renders the supplied `part` and
31154
+ * `conformance` values under a clearly-named, profile-local namespace so
31155
+ * that the identification facts are machine-readable even though no ISO
31156
+ * identification namespace exists for these profiles.
31157
+ */
31158
+ function buildIdentificationXmp(identity) {
31159
+ const { profileName, conformsTo, part, conformance } = identity;
31160
+ let xmp = "<?xpacket begin=\"\" id=\"W5M0MpCehiHzreSzNTczkc9d\"?>\n";
31161
+ xmp += "<x:xmpmeta xmlns:x=\"adobe:ns:meta/\">\n";
31162
+ xmp += ` <!-- ${escapeXml(profileName)} identification marker (non-normative). -->\n`;
31163
+ xmp += " <rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\">\n";
31164
+ xmp += " <rdf:Description rdf:about=\"\"\n";
31165
+ xmp += ` xmlns:pdfd="${PDFD_NS}">\n`;
31166
+ xmp += " <pdfd:declarations>\n";
31167
+ xmp += " <rdf:Bag>\n";
31168
+ xmp += " <rdf:li rdf:parseType=\"Resource\">\n";
31169
+ xmp += ` <pdfd:conformsTo>${escapeXml(conformsTo)}</pdfd:conformsTo>\n`;
31170
+ xmp += " </rdf:li>\n";
31171
+ xmp += " </rdf:Bag>\n";
31172
+ xmp += " </pdfd:declarations>\n";
31173
+ xmp += " </rdf:Description>\n";
31174
+ xmp += " <rdf:Description rdf:about=\"\"\n";
31175
+ xmp += " xmlns:pid=\"http://modern-pdf-lib/ns/profile-id/\">\n";
31176
+ xmp += ` <pid:part>${part}</pid:part>\n`;
31177
+ if (conformance !== void 0) xmp += ` <pid:conformance>${escapeXml(conformance)}</pid:conformance>\n`;
31178
+ xmp += " </rdf:Description>\n";
31179
+ xmp += " </rdf:RDF>\n";
31180
+ xmp += "</x:xmpmeta>\n";
31181
+ xmp += "<?xpacket end=\"w\"?>";
31182
+ return xmp;
31183
+ }
31184
+ /**
31185
+ * Build a WTPDF ("Well-Tagged PDF") identification XMP packet.
31186
+ *
31187
+ * WTPDF conformance is asserted through the PDF Association's PDF
31188
+ * Declarations mechanism (VERIFIED). The `conformsTo` target URI is
31189
+ * PROVISIONAL — see the module doc comment and pdf-issues #395 for the
31190
+ * acknowledged inconsistency in its exact form. This builder produces an
31191
+ * identification marker only and does not assert or validate WTPDF
31192
+ * conformance.
31193
+ *
31194
+ * @param options - Optional part (default `1`, i.e. WTPDF 1.0) and a
31195
+ * conformance level (WTPDF defines `'reuse'` and `'accessibility'`).
31196
+ * @returns A serialized XMP/RDF identification packet.
31197
+ */
31198
+ function buildWtpdfIdentificationXmp(options) {
31199
+ const part = options?.part ?? 1;
31200
+ const conformance = options?.conformance;
31201
+ let conformsTo = `${WTPDF_CONFORMS_TO_BASE}1.0`;
31202
+ if (conformance === "reuse" || conformance === "accessibility") conformsTo = `${WTPDF_CONFORMS_TO_BASE}${conformance}1.0`;
31203
+ return buildIdentificationXmp({
31204
+ profileName: "WTPDF (Well-Tagged PDF) 1.0",
31205
+ conformsTo,
31206
+ part,
31207
+ conformance
31208
+ });
31209
+ }
31210
+ /**
31211
+ * Build a PDF/R (ISO 23504 / PDF/Raster) identification XMP packet.
31212
+ *
31213
+ * IMPORTANT: PDF/R is normatively identified by a comment marker before
31214
+ * the final `startxref` in the file trailer, NOT by XMP. There is no
31215
+ * ISO-defined XMP identification namespace for PDF/R, so this XMP marker
31216
+ * is non-normative: the `pdfd:conformsTo` target is PROVISIONAL. Use this
31217
+ * only as a supplementary, machine-readable hint alongside the required
31218
+ * trailer comment marker; it does not assert or validate PDF/R
31219
+ * conformance.
31220
+ *
31221
+ * @param options - Optional part (default `1`, i.e. ISO 23504-1 / PDF/R-1)
31222
+ * and a conformance token.
31223
+ * @returns A serialized XMP/RDF identification packet.
31224
+ */
31225
+ function buildPdfRIdentificationXmp(options) {
31226
+ const part = options?.part ?? 1;
31227
+ const conformance = options?.conformance;
31228
+ return buildIdentificationXmp({
31229
+ profileName: "PDF/R (ISO 23504, raster image transport and storage)",
31230
+ conformsTo: PDFR_CONFORMS_TO,
31231
+ part,
31232
+ conformance
31233
+ });
31234
+ }
31235
+ //#endregion
30419
31236
  //#region src/index.ts
30420
31237
  /** Whether initWasm has already completed successfully. */
30421
31238
  let wasmInitialized = false;
@@ -30461,6 +31278,6 @@ async function initWasm(options) {
30461
31278
  wasmInitialized = true;
30462
31279
  }
30463
31280
  //#endregion
30464
- export { decodeTileRegion as $, ChangeTracker as $a, addCounterSignature as $i, InvalidColorError as $n, encodeCode128Values as $r, buildType5Halftone as $t, extractEmbeddedRevocationData as A, PdfSquareAnnotation as Aa, getSupportedLevels as Ai, timestampPlugin as An, readEan13 as Ar, h as At, layoutParagraph as B, generateLineAppearance as Ba, flattenTransparency as Bi, removeAllBookmarks as Bn, upcAToOperators as Br, sampleShadingColor as Bt, generateThumbnail as C, PdfRedactAnnotation as Ca, stripProhibitedFeatures as Ci, buildRequirements as Cn, borderedPreset as Cr, isWoff2 as Ct, renderPageToImage as D, PdfLineAnnotation as Da, parseXmpMetadata as Di, tableToJson as Dn, readBarcode as Dr, buildPdfVtDParts as Dt, rasterize as E, PdfCircleAnnotation as Ea, extractXmpMetadata as Ei, tableToCsv as En, stripedPreset as Er, createWorkerPool as Et, validateKeyUsage as F, PdfFreeTextAnnotation as Fa, getToUnicodeCmap as Fi, batchFlatten as Fn, pdf417ToOperators as Fr, generateOrderX as Ft, downscale16To8 as G, PdfLinkAnnotation as Ga, isLinearized as Gi, BatchProcessingError as Gn, encodeEan8 as Gr, buildBoxDict as Gt, buildPdfXOutputIntent as H, generateSquigglyAppearance as Ha, validatePdfA as Hi, flattenField as Hn, ean13ToOperators as Hr, levenshtein as Ht, buildCertificateChain as I, generateCircleAppearance as Ia, buildOutputIntent as Ii, batchMerge as In, dataMatrixToOperators as Ir, generateXRechnungCii as It, offsetSignedToUnsigned as J, createXmpStream as Ja, findChangedObjects as Ji, ExceededMaxLengthError as Jn, code39ToOperators as Jr, validateBoxGeometry as Jt, getComponentDepths as K, PdfTextAnnotation as Ka, linearizePdf as Ki, CombedTextLayoutError as Kn, encodeItf as Kr, buildGtsPdfxVersion as Kt, validateCertificateChain as L, generateFreeTextAppearance as La, SRGB_ICC_PROFILE as Li, processBatch as Ln, encodeDataMatrix as Lr, buildPdfA4Xmp as Lt, EKU_OIDS as M, PdfSquigglyAnnotation as Ma, generateSymbolToUnicodeCmap as Mi, PdfDocumentBuilder as Mn, calculateBarcodeDimensions as Mr, createRangeFetcher as Mt, validateCertificatePolicy as N, PdfStrikeOutAnnotation as Na, generateWinAnsiToUnicodeCmap as Ni, enforcePdfUa as Nn, renderStyledBarcode as Nr, resolveFallback as Nt, interpretContentStream as O, PdfPolyLineAnnotation as Oa, validateXmpMetadata as Oi, accessibilityPlugin as On, readCode128 as Or, buildVtDpm as Ot, validateExtendedKeyUsage as P, PdfUnderlineAnnotation as Pa, generateZapfDingbatsToUnicodeCmap as Pi, validatePdfUa as Pn, encodePdf417 as Pr, splitByScript as Pt, decodeTile as Q, buildSeparationColorSpace as Qa, hasLtvData as Qi, ForeignPageError as Qn, encodeCode128 as Qr, buildType1Halftone as Qt, findHyphenationPoints as R, generateHighlightAppearance as Ra, generateSrgbIccProfile as Ri, addBookmark as Rn, calculateUpcCheckDigit as Rr, pdfA4Rules as Rt, extractImages as S, PdfPopupAnnotation as Sa, countOccurrences as Si, buildRequirement as Sn, applyTablePreset as Sr, isWoff as St, renderPageToCanvas as T, PdfStampAnnotation as Ta, createAssociatedFile as Ti, extractTables as Tn, professionalPreset as Tr, signDeferred as Tt, enforcePdfX as U, generateStrikeOutAppearance as Ua, delinearizePdf as Ui, flattenFields as Un, ean8ToOperators as Ur, renderCodeFrame as Ut, layoutTextFlow as V, generateSquareAppearance as Va, enforcePdfA as Vi, removeBookmark as Vn, calculateEanCheckDigit as Vr, didYouMean as Vt, validatePdfX as W, generateUnderlineAppearance as Wa, getLinearizationInfo as Wi, flattenForm as Wn, encodeEan13 as Wr, generateCiiXml as Wt, upscale8To16 as X, PDFOperator as Xa, buildDssDictionary as Xi, FieldExistsAsNonTerminalError as Xn, encodeCode39 as Xr, buildSampledTransferFunction as Xt, summarizeBitDepth as Y, parseXmpMetadata$1 as Ya, optimizeIncrementalSave as Yi, FieldAlreadyExistsError as Yn, computeCode39CheckDigit as Yr, STANDARD_SPOT_FUNCTIONS as Yt, assembleTiles as Z, buildDeviceNColorSpace as Za, embedLtvData as Zi, FontNotEmbeddedError as Zn, code128ToOperators as Zr, buildThresholdHalftone as Zt, redactRegions as _, parseTimestampResponse as _a, recompressImage as _i, MATHML_NAMESPACE as _n, estimateTextWidth as _r, formatDate as _t, buildStencilMask as a, detectModifications as aa, recompressWebP as ai, reconstructLines as an, RemovePageFromEmptyDocumentError as ar, isCertificateRevoked as at, comparePages as b, PdfFileAttachmentAnnotation as ba, generatePdfAXmp as bi, buildNamespacesArray as bn, wrapText$2 as br, formatNumber$1 as bt, buildEncryptedPayload as c, getCertificationLevel as ca, convertTiffCmykToRgb as ci, buildDocTimeStampDict as cn, UnexpectedFieldTypeError as cr, createSandbox as ct, buildPageOutputIntent as d, appendIncrementalUpdate as da, extractJpegMetadata as di, buildLab as dn, formatDate$1 as dr, setFieldValue as dt, getCounterSignatures as ea, valuesToModules as ei, identityTransferFunction as en, saveDocumentIncremental as eo, InvalidFieldNamePartError as er, parseTileInfo as et, attachAssociatedFiles as f, findExistingSignatures as fa, injectJpegMetadata as fi, labToRgb as fn, replaceTemplateVariables as fr, addVisibilityAction as ft, renderPageTile as g, buildTimestampRequest as ga, optimizeImage as gi, toSarif as gn, ellipsisText as gr, AFDate_FormatEx as gt, computeTileGrid as h, validateByteRangeIntegrity as ha, estimateJpegQuality as hi, toJsonReport as hn, applyOverflow as hr, AFSpecial_Format as ht, buildImageSoftMask as i, getFieldLocks as ia, encodePngFromPixels as ii, buildCollection as in, PluginError as ir, extractCrlUrls as it, verifyOfflineRevocation as j, PdfHighlightAnnotation as ja, isValidLevel as ji, StreamingPdfParser as jn, readEan8 as jr, renderToPdf as jt, interpretPage as k, PdfPolygonAnnotation as ka, getProfile as ki, metadataPlugin as kn, readCode39 as kr, gtsPdfVtVersion as kt, buildUnencryptedWrapper as l, setCertificationLevel as la, embedTiffCmyk as li, buildCalGray as ln, applyHeaderFooter as lr, getFieldValue as lt, RenderCache as m, saveIncrementalWithSignaturePreservation as ma, downscaleImage as mi, SARIF_SCHEMA_URI as mn, toRoman as mr, validateFieldValue as mt, buildBlackPointCompensationExtGState as n, addFieldLock as na, canDirectEmbed as ni, evaluateFunction as nn, MissingOnValueCheckError as nr, TrustStore as nt, buildSoftMaskGroupExtGState as o, MdpPermission as oa, webpToJpeg as oi, reconstructParagraphs as on, RichTextFieldReadError as or, checkCertificateStatus as ot, registerEmbeddedFile as p, parseExistingTrailer as pa, analyzeJpegMarkers as pi, DEFAULT_SARIF_TOOL_NAME as pn, toAlpha as pr, setFieldVisibility as pt, normalizeComponentDepth as q, buildXmpMetadata as qa, computeObjectHash as qi, EncryptedPdfError as qn, itfToOperators as qr, buildPdfX6OutputIntent as qt, buildColorKeyMask as r, buildFieldLockDict as ra, embedTiffDirect as ri, markdownToPdf as rn, NoSuchFieldError as rr, downloadCrl as rt, buildSoftMaskNone as s, buildDocMdpReference as sa, webpToPng as si, DEFAULT_DOC_TIMESTAMP_CONTENTS_SIZE as sn, StreamingParseError as sr, extractOcspUrl as st, initWasm as t, diffSignedContent as ta, PdfWorker as ti, nameHalftone as tn, saveIncremental as to, InvalidPageSizeError as tr, verifySignatureDetailed as tt, attachOutputIntents as u, validateSignatureChain as ua, isCmykTiff as ui, buildCalRGB as un, applyHeaderFooterToPage as ur, resolveFieldReference as ut, applyOcr as v, requestTimestamp as va, applyRedaction as vi, PDF2_NAMESPACE as vn, shrinkFontSize as vr, parseAcrobatDate as vt, renderDisplayListToCanvas as w, PdfInkAnnotation as wa, buildAfArray as wi, buildDPartRoot as wn, minimalPreset as wr, readWoffHeader as wt, extractFonts as x, PdfCaretAnnotation as xa, generatePdfAXmpBytes as xi, buildPieceInfo as xn, applyPreset as xr, decodeWoff as xt, compareImages as y, searchTextItems as ya, enforcePdfAFull as yi, buildNamespace as yn, truncateText as yr, AFNumber_Format as yt, layoutColumns as z, generateInkAppearance as za, detectTransparency as zi, getBookmarks as zn, encodeUpcA as zr, buildFunctionShading as zt };
31281
+ export { validateKeyUsage as $, PdfFreeTextAnnotation as $a, getToUnicodeCmap as $i, batchFlatten as $n, pdf417ToOperators as $r, generateOrderX as $t, attachAssociatedFiles as A, findExistingSignatures as Aa, injectJpegMetadata as Ai, labToRgb as An, replaceTemplateVariables as Ar, addVisibilityAction as At, extractImages as B, PdfPopupAnnotation as Ba, countOccurrences as Bi, buildRequirement as Bn, applyTablePreset as Br, isWoff as Bt, buildStencilMask as C, detectModifications as Ca, recompressWebP as Ci, reconstructLines as Cn, RemovePageFromEmptyDocumentError as Cr, isCertificateRevoked as Ct, buildUnencryptedWrapper as D, setCertificationLevel as Da, embedTiffCmyk as Di, buildCalGray as Dn, applyHeaderFooter as Dr, getFieldValue as Dt, buildEncryptedPayload as E, getCertificationLevel as Ea, convertTiffCmykToRgb as Ei, buildDocTimeStampDict as En, UnexpectedFieldTypeError as Er, createSandbox as Et, redactRegions as F, parseTimestampResponse as Fa, recompressImage as Fi, MATHML_NAMESPACE as Fn, estimateTextWidth as Fr, formatDate as Ft, renderPageToImage as G, PdfLineAnnotation as Ga, parseXmpMetadata as Gi, tableToJson as Gn, readBarcode as Gr, buildPdfVtDParts as Gt, renderDisplayListToCanvas as H, PdfInkAnnotation as Ha, buildAfArray as Hi, buildDPartRoot as Hn, minimalPreset as Hr, readWoffHeader as Ht, applyOcr as I, requestTimestamp as Ia, applyRedaction as Ii, PDF2_NAMESPACE as In, shrinkFontSize as Ir, parseAcrobatDate as It, extractEmbeddedRevocationData as J, PdfSquareAnnotation as Ja, getSupportedLevels as Ji, timestampPlugin as Jn, readEan13 as Jr, h as Jt, interpretContentStream as K, PdfPolyLineAnnotation as Ka, validateXmpMetadata as Ki, accessibilityPlugin as Kn, readCode128 as Kr, buildVtDpm as Kt, compareImages as L, searchTextItems as La, enforcePdfAFull as Li, buildNamespace as Ln, truncateText as Lr, AFNumber_Format as Lt, RenderCache as M, saveIncrementalWithSignaturePreservation as Ma, downscaleImage as Mi, SARIF_SCHEMA_URI as Mn, toRoman as Mr, validateFieldValue as Mt, computeTileGrid as N, validateByteRangeIntegrity as Na, estimateJpegQuality as Ni, toJsonReport as Nn, applyOverflow as Nr, AFSpecial_Format as Nt, attachOutputIntents as O, validateSignatureChain as Oa, isCmykTiff as Oi, buildCalRGB as On, applyHeaderFooterToPage as Or, resolveFieldReference as Ot, renderPageTile as P, buildTimestampRequest as Pa, optimizeImage as Pi, toSarif as Pn, ellipsisText as Pr, AFDate_FormatEx as Pt, validateExtendedKeyUsage as Q, PdfUnderlineAnnotation as Qa, generateZapfDingbatsToUnicodeCmap as Qi, validatePdfUa as Qn, encodePdf417 as Qr, splitByScript as Qt, comparePages as R, PdfFileAttachmentAnnotation as Ra, generatePdfAXmp as Ri, buildNamespacesArray as Rn, wrapText$2 as Rr, formatNumber$1 as Rt, buildImageSoftMask as S, getFieldLocks as Sa, encodePngFromPixels as Si, buildCollection as Sn, PluginError as Sr, extractCrlUrls as St, buildSoftMaskNone as T, buildDocMdpReference as Ta, webpToPng as Ti, DEFAULT_DOC_TIMESTAMP_CONTENTS_SIZE as Tn, StreamingParseError as Tr, extractOcspUrl as Tt, renderPageToCanvas as U, PdfStampAnnotation as Ua, createAssociatedFile as Ui, extractTables as Un, professionalPreset as Ur, signDeferred as Ut, generateThumbnail as V, PdfRedactAnnotation as Va, stripProhibitedFeatures as Vi, buildRequirements as Vn, borderedPreset as Vr, isWoff2 as Vt, rasterize as W, PdfCircleAnnotation as Wa, extractXmpMetadata as Wi, tableToCsv as Wn, stripedPreset as Wr, createWorkerPool as Wt, EKU_OIDS as X, PdfSquigglyAnnotation as Xa, generateSymbolToUnicodeCmap as Xi, PdfDocumentBuilder as Xn, calculateBarcodeDimensions as Xr, createRangeFetcher as Xt, verifyOfflineRevocation as Y, PdfHighlightAnnotation as Ya, isValidLevel as Yi, StreamingPdfParser as Yn, readEan8 as Yr, renderToPdf as Yt, validateCertificatePolicy as Z, PdfStrikeOutAnnotation as Za, generateWinAnsiToUnicodeCmap as Zi, enforcePdfUa as Zn, renderStyledBarcode as Zr, resolveFallback as Zt, tagTableDataCell as _, addCounterSignature as _a, encodeCode128Values as _i, buildType5Halftone as _n, ChangeTracker as _o, InvalidColorError as _r, decodeTileRegion as _t, preflightPdfA as a, enforcePdfA as aa, calculateEanCheckDigit as ai, didYouMean as an, generateSquareAppearance as ao, removeBookmark as ar, layoutTextFlow as at, buildBlackPointCompensationExtGState as b, addFieldLock as ba, canDirectEmbed as bi, evaluateFunction as bn, MissingOnValueCheckError as br, TrustStore as bt, validatePdfUa2 as c, getLinearizationInfo as ca, encodeEan13 as ci, generateCiiXml as cn, generateUnderlineAppearance as co, flattenForm as cr, validatePdfX as ct, tagHeading as d, computeObjectHash as da, itfToOperators as di, buildPdfX6OutputIntent as dn, buildXmpMetadata as do, EncryptedPdfError as dr, normalizeComponentDepth as dt, buildOutputIntent as ea, dataMatrixToOperators as ei, generateXRechnungCii as en, generateCircleAppearance as eo, batchMerge as er, buildCertificateChain as et, tagLink as f, findChangedObjects as fa, code39ToOperators as fi, validateBoxGeometry as fn, createXmpStream as fo, ExceededMaxLengthError as fr, offsetSignedToUnsigned as ft, tagTable as g, hasLtvData as ga, encodeCode128 as gi, buildType1Halftone as gn, buildSeparationColorSpace as go, ForeignPageError as gr, decodeTile as gt, tagParagraph as h, embedLtvData as ha, code128ToOperators as hi, buildThresholdHalftone as hn, buildDeviceNColorSpace as ho, FontNotEmbeddedError as hr, assembleTiles as ht, convertPdfAConformanceXmp as i, flattenTransparency as ia, upcAToOperators as ii, sampleShadingColor as in, generateLineAppearance as io, removeAllBookmarks as ir, layoutParagraph as it, registerEmbeddedFile as j, parseExistingTrailer as ja, analyzeJpegMarkers as ji, DEFAULT_SARIF_TOOL_NAME as jn, toAlpha as jr, setFieldVisibility as jt, buildPageOutputIntent as k, appendIncrementalUpdate as ka, extractJpegMetadata as ki, buildLab as kn, formatDate$1 as kr, setFieldValue as kt, LIST_NUMBERING_KEY as l, isLinearized as la, encodeEan8 as li, buildBoxDict as ln, PdfLinkAnnotation as lo, BatchProcessingError as lr, downscale16To8 as lt, tagListItem as m, buildDssDictionary as ma, encodeCode39 as mi, buildSampledTransferFunction as mn, PDFOperator as mo, FieldExistsAsNonTerminalError as mr, upscale8To16 as mt, buildPdfRIdentificationXmp as n, generateSrgbIccProfile as na, calculateUpcCheckDigit as ni, pdfA4Rules as nn, generateHighlightAppearance as no, addBookmark as nr, findHyphenationPoints as nt, autoTagPage as o, validatePdfA as oa, ean13ToOperators as oi, levenshtein as on, generateSquigglyAppearance as oo, flattenField as or, buildPdfXOutputIntent as ot, tagList as p, optimizeIncrementalSave as pa, computeCode39CheckDigit as pi, STANDARD_SPOT_FUNCTIONS as pn, parseXmpMetadata$1 as po, FieldAlreadyExistsError as pr, summarizeBitDepth as pt, interpretPage as q, PdfPolygonAnnotation as qa, getProfile as qi, metadataPlugin as qn, readCode39 as qr, gtsPdfVtVersion as qt, buildWtpdfIdentificationXmp as r, detectTransparency as ra, encodeUpcA as ri, buildFunctionShading as rn, generateInkAppearance as ro, getBookmarks as rr, layoutColumns as rt, buildPdfUa2Xmp as s, delinearizePdf as sa, ean8ToOperators as si, renderCodeFrame as sn, generateStrikeOutAppearance as so, flattenFields as sr, enforcePdfX as st, initWasm as t, SRGB_ICC_PROFILE as ta, encodeDataMatrix as ti, buildPdfA4Xmp as tn, generateFreeTextAppearance as to, processBatch as tr, validateCertificateChain as tt, tagFigure as u, linearizePdf as ua, encodeItf as ui, buildGtsPdfxVersion as un, PdfTextAnnotation as uo, CombedTextLayoutError as ur, getComponentDepths as ut, tagTableHeaderCell as v, getCounterSignatures as va, valuesToModules as vi, identityTransferFunction as vn, saveDocumentIncremental as vo, InvalidFieldNamePartError as vr, parseTileInfo as vt, buildSoftMaskGroupExtGState as w, MdpPermission as wa, webpToJpeg as wi, reconstructParagraphs as wn, RichTextFieldReadError as wr, checkCertificateStatus as wt, buildColorKeyMask as x, buildFieldLockDict as xa, embedTiffDirect as xi, markdownToPdf as xn, NoSuchFieldError as xr, downloadCrl as xt, tagTableRow as y, diffSignedContent as ya, PdfWorker as yi, nameHalftone as yn, saveIncremental as yo, InvalidPageSizeError as yr, verifySignatureDetailed as yt, extractFonts as z, PdfCaretAnnotation as za, generatePdfAXmpBytes as zi, buildPieceInfo as zn, applyPreset as zr, decodeWoff as zt };
30465
31282
 
30466
- //# sourceMappingURL=src-s9zNsZAT.mjs.map
31283
+ //# sourceMappingURL=src-DNe0XZhx.mjs.map