pdfnative 1.0.2 → 1.0.4
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.
- package/README.md +43 -0
- package/dist/index.cjs +71 -22
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +5 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +71 -22
- package/dist/index.js.map +1 -1
- package/dist/worker/index.cjs +232 -12
- package/dist/worker/index.cjs.map +1 -1
- package/dist/worker/index.js +232 -12
- package/dist/worker/index.js.map +1 -1
- package/package.json +4 -2
package/dist/index.d.cts
CHANGED
|
@@ -1167,6 +1167,11 @@ declare function validateAttachments(attachments: readonly PdfAttachment[] | und
|
|
|
1167
1167
|
* Greedy line-filling algorithm with CJK character-level breaking.
|
|
1168
1168
|
* Latin text breaks at word boundaries (spaces).
|
|
1169
1169
|
* CJK characters break individually (no spaces needed).
|
|
1170
|
+
*
|
|
1171
|
+
* If a single segment exceeds maxWidth (e.g. a long word, URL, or
|
|
1172
|
+
* non-breaking-space-joined compound), it is hard-broken at character
|
|
1173
|
+
* boundaries to prevent overflow past the right margin. This is critical
|
|
1174
|
+
* for headings and titles that may contain long compounds without spaces.
|
|
1170
1175
|
*/
|
|
1171
1176
|
declare function wrapText(text: string, maxWidth: number, fontSize: number, enc: EncodingContext): string[];
|
|
1172
1177
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1167,6 +1167,11 @@ declare function validateAttachments(attachments: readonly PdfAttachment[] | und
|
|
|
1167
1167
|
* Greedy line-filling algorithm with CJK character-level breaking.
|
|
1168
1168
|
* Latin text breaks at word boundaries (spaces).
|
|
1169
1169
|
* CJK characters break individually (no spaces needed).
|
|
1170
|
+
*
|
|
1171
|
+
* If a single segment exceeds maxWidth (e.g. a long word, URL, or
|
|
1172
|
+
* non-breaking-space-joined compound), it is hard-broken at character
|
|
1173
|
+
* boundaries to prevent overflow past the right margin. This is critical
|
|
1174
|
+
* for headings and titles that may contain long compounds without spaces.
|
|
1170
1175
|
*/
|
|
1171
1176
|
declare function wrapText(text: string, maxWidth: number, fontSize: number, enc: EncodingContext): string[];
|
|
1172
1177
|
|
package/dist/index.js
CHANGED
|
@@ -4621,9 +4621,26 @@ function buildStructureTree(root, startObjNum, pageObjToStructParents) {
|
|
|
4621
4621
|
totalObjects: nextObj - startObjNum
|
|
4622
4622
|
};
|
|
4623
4623
|
}
|
|
4624
|
-
function
|
|
4624
|
+
function buildPdfMetadata(now = /* @__PURE__ */ new Date()) {
|
|
4625
|
+
const pad2 = (n) => String(n).padStart(2, "0");
|
|
4626
|
+
const yyyy = now.getFullYear();
|
|
4627
|
+
const mm = pad2(now.getMonth() + 1);
|
|
4628
|
+
const dd = pad2(now.getDate());
|
|
4629
|
+
const hh = pad2(now.getHours());
|
|
4630
|
+
const mi = pad2(now.getMinutes());
|
|
4631
|
+
const ss = pad2(now.getSeconds());
|
|
4632
|
+
const tzMinutes = -now.getTimezoneOffset();
|
|
4633
|
+
const tzSign = tzMinutes >= 0 ? "+" : "-";
|
|
4634
|
+
const tzAbs = Math.abs(tzMinutes);
|
|
4635
|
+
const tzH = pad2(Math.floor(tzAbs / 60));
|
|
4636
|
+
const tzM = pad2(tzAbs % 60);
|
|
4637
|
+
const pdfDate = `D:${yyyy}${mm}${dd}${hh}${mi}${ss}${tzSign}${tzH}'${tzM}'`;
|
|
4638
|
+
const xmpDate = `${yyyy}-${mm}-${dd}T${hh}:${mi}:${ss}${tzSign}${tzH}:${tzM}`;
|
|
4639
|
+
return { pdfDate, xmpDate };
|
|
4640
|
+
}
|
|
4641
|
+
function buildXMPMetadata(title, createDate, pdfaPart = 2, pdfaConformance = "B", author) {
|
|
4625
4642
|
const escapedTitle = escapeXml(title);
|
|
4626
|
-
|
|
4643
|
+
const lines = [
|
|
4627
4644
|
'<?xpacket begin="\xEF\xBB\xBF" id="W5M0MpCehiHzreSzNTczkc9d"?>',
|
|
4628
4645
|
'<x:xmpmeta xmlns:x="adobe:ns:meta/">',
|
|
4629
4646
|
' <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">',
|
|
@@ -4632,17 +4649,24 @@ function buildXMPMetadata(title, createDate, pdfaPart = 2, pdfaConformance = "B"
|
|
|
4632
4649
|
' xmlns:pdf="http://ns.adobe.com/pdf/1.3/"',
|
|
4633
4650
|
' xmlns:xmp="http://ns.adobe.com/xap/1.0/"',
|
|
4634
4651
|
' xmlns:pdfaid="http://www.aiim.org/pdfa/ns/id/">',
|
|
4635
|
-
` <dc:title><rdf:Alt><rdf:li xml:lang="x-default">${escapedTitle}</rdf:li></rdf:Alt></dc:title
|
|
4636
|
-
|
|
4652
|
+
` <dc:title><rdf:Alt><rdf:li xml:lang="x-default">${escapedTitle}</rdf:li></rdf:Alt></dc:title>`
|
|
4653
|
+
];
|
|
4654
|
+
if (author !== void 0 && author !== "") {
|
|
4655
|
+
lines.push(` <dc:creator><rdf:Seq><rdf:li>${escapeXml(author)}</rdf:li></rdf:Seq></dc:creator>`);
|
|
4656
|
+
}
|
|
4657
|
+
lines.push(
|
|
4637
4658
|
" <pdf:Producer>pdfnative</pdf:Producer>",
|
|
4638
4659
|
` <xmp:CreateDate>${createDate}</xmp:CreateDate>`,
|
|
4660
|
+
` <xmp:ModifyDate>${createDate}</xmp:ModifyDate>`,
|
|
4661
|
+
` <xmp:MetadataDate>${createDate}</xmp:MetadataDate>`,
|
|
4639
4662
|
` <pdfaid:part>${pdfaPart}</pdfaid:part>`,
|
|
4640
4663
|
` <pdfaid:conformance>${pdfaConformance}</pdfaid:conformance>`,
|
|
4641
4664
|
" </rdf:Description>",
|
|
4642
4665
|
" </rdf:RDF>",
|
|
4643
4666
|
"</x:xmpmeta>",
|
|
4644
4667
|
'<?xpacket end="w"?>'
|
|
4645
|
-
|
|
4668
|
+
);
|
|
4669
|
+
return lines.join("\n");
|
|
4646
4670
|
}
|
|
4647
4671
|
function buildOutputIntentDict(iccStreamObjNum, subtype = "GTS_PDFA1") {
|
|
4648
4672
|
return `<< /Type /OutputIntent /S /${subtype} /OutputConditionIdentifier (sRGB IEC61966-2.1) /RegistryName (http://www.color.org) /DestOutputProfile ${iccStreamObjNum} 0 R >>`;
|
|
@@ -5254,7 +5278,7 @@ endstream`);
|
|
|
5254
5278
|
_offset += d;
|
|
5255
5279
|
}, objOffsets, parts };
|
|
5256
5280
|
}
|
|
5257
|
-
function writeXrefTrailer(w, totalObjs, infoObjNum, encState) {
|
|
5281
|
+
function writeXrefTrailer(w, totalObjs, infoObjNum, encState, idSeed = "") {
|
|
5258
5282
|
let encryptObjNum = 0;
|
|
5259
5283
|
if (encState) {
|
|
5260
5284
|
encryptObjNum = totalObjs + 1;
|
|
@@ -5272,11 +5296,13 @@ function writeXrefTrailer(w, totalObjs, infoObjNum, encState) {
|
|
|
5272
5296
|
`);
|
|
5273
5297
|
}
|
|
5274
5298
|
w.emit("trailer\n");
|
|
5299
|
+
const docId = encState ? encState.docId : md5(new TextEncoder().encode(`pdfnative|${idSeed}|${totalObjs}`));
|
|
5300
|
+
const idArray = buildIdArray(docId);
|
|
5275
5301
|
if (encState) {
|
|
5276
|
-
w.emit(`<< /Size ${totalObjs + 1} /Root 1 0 R /Info ${infoObjNum} 0 R /Encrypt ${encryptObjNum} 0 R /ID ${
|
|
5302
|
+
w.emit(`<< /Size ${totalObjs + 1} /Root 1 0 R /Info ${infoObjNum} 0 R /Encrypt ${encryptObjNum} 0 R /ID ${idArray} >>
|
|
5277
5303
|
`);
|
|
5278
5304
|
} else {
|
|
5279
|
-
w.emit(`<< /Size ${totalObjs + 1} /Root 1 0 R /Info ${infoObjNum} 0 R >>
|
|
5305
|
+
w.emit(`<< /Size ${totalObjs + 1} /Root 1 0 R /Info ${infoObjNum} 0 R /ID ${idArray} >>
|
|
5280
5306
|
`);
|
|
5281
5307
|
}
|
|
5282
5308
|
w.emit("startxref\n");
|
|
@@ -6012,10 +6038,7 @@ function buildPDF(params, layoutOptions) {
|
|
|
6012
6038
|
}
|
|
6013
6039
|
const baseObjCount = enc.isUnicode ? 4 + fontEntries.length * 5 + wmExtraObjs + totalPages * 2 : 4 + wmExtraObjs + totalPages * 2;
|
|
6014
6040
|
const infoObjNum = baseObjCount + 1;
|
|
6015
|
-
const
|
|
6016
|
-
const pad2 = (n) => String(n).padStart(2, "0");
|
|
6017
|
-
const pdfDate = `D:${now.getFullYear()}${pad2(now.getMonth() + 1)}${pad2(now.getDate())}${pad2(now.getHours())}${pad2(now.getMinutes())}${pad2(now.getSeconds())}`;
|
|
6018
|
-
const isoDate = `${now.getFullYear()}-${pad2(now.getMonth() + 1)}-${pad2(now.getDate())}T${pad2(now.getHours())}:${pad2(now.getMinutes())}:${pad2(now.getSeconds())}`;
|
|
6041
|
+
const { pdfDate, xmpDate: isoDate } = buildPdfMetadata();
|
|
6019
6042
|
const infoTitle = params.docTitle || title || "";
|
|
6020
6043
|
emitObj(
|
|
6021
6044
|
infoObjNum,
|
|
@@ -6095,7 +6118,7 @@ endobj
|
|
|
6095
6118
|
}
|
|
6096
6119
|
}
|
|
6097
6120
|
const writer = { emit, emitObj, emitStreamObj, offset: getOffset, adjustOffset, objOffsets, parts };
|
|
6098
|
-
writeXrefTrailer(writer, totalObjs, infoObjNum, encState);
|
|
6121
|
+
writeXrefTrailer(writer, totalObjs, infoObjNum, encState, `${infoTitle}|${pdfDate}`);
|
|
6099
6122
|
return parts.join("");
|
|
6100
6123
|
}
|
|
6101
6124
|
function buildPDFBytes(params, layoutOptions) {
|
|
@@ -8442,6 +8465,22 @@ function tokenizeForWrap(text) {
|
|
|
8442
8465
|
if (buf) segments.push(buf);
|
|
8443
8466
|
return segments;
|
|
8444
8467
|
}
|
|
8468
|
+
function hardBreakSegment(seg, maxWidth, fontSize, enc) {
|
|
8469
|
+
const pieces = [];
|
|
8470
|
+
let buf = "";
|
|
8471
|
+
for (const ch of seg) {
|
|
8472
|
+
const candidate = buf + ch;
|
|
8473
|
+
const w = measureText(candidate, fontSize, enc);
|
|
8474
|
+
if (w <= maxWidth || buf === "") {
|
|
8475
|
+
buf = candidate;
|
|
8476
|
+
} else {
|
|
8477
|
+
pieces.push(buf);
|
|
8478
|
+
buf = ch;
|
|
8479
|
+
}
|
|
8480
|
+
}
|
|
8481
|
+
if (buf) pieces.push(buf);
|
|
8482
|
+
return pieces.length > 0 ? pieces : [seg];
|
|
8483
|
+
}
|
|
8445
8484
|
function wrapText(text, maxWidth, fontSize, enc) {
|
|
8446
8485
|
if (!text) return [""];
|
|
8447
8486
|
if (maxWidth <= 0) return [text];
|
|
@@ -8452,12 +8491,25 @@ function wrapText(text, maxWidth, fontSize, enc) {
|
|
|
8452
8491
|
for (const seg of segments) {
|
|
8453
8492
|
const candidate = currentLine + seg;
|
|
8454
8493
|
const w = measureText(candidate, fontSize, enc);
|
|
8455
|
-
if (w <= maxWidth
|
|
8494
|
+
if (w <= maxWidth) {
|
|
8456
8495
|
currentLine = candidate;
|
|
8457
|
-
|
|
8496
|
+
continue;
|
|
8497
|
+
}
|
|
8498
|
+
if (currentLine !== "") {
|
|
8458
8499
|
lines.push(currentLine.trimEnd());
|
|
8459
|
-
currentLine =
|
|
8500
|
+
currentLine = "";
|
|
8460
8501
|
}
|
|
8502
|
+
const segTrim = seg.trimStart();
|
|
8503
|
+
const segW = measureText(segTrim, fontSize, enc);
|
|
8504
|
+
if (segW <= maxWidth) {
|
|
8505
|
+
currentLine = segTrim;
|
|
8506
|
+
continue;
|
|
8507
|
+
}
|
|
8508
|
+
const pieces = hardBreakSegment(segTrim, maxWidth, fontSize, enc);
|
|
8509
|
+
for (let pi = 0; pi < pieces.length - 1; pi++) {
|
|
8510
|
+
lines.push(pieces[pi].trimEnd());
|
|
8511
|
+
}
|
|
8512
|
+
currentLine = pieces[pieces.length - 1];
|
|
8461
8513
|
}
|
|
8462
8514
|
if (currentLine) lines.push(currentLine.trimEnd());
|
|
8463
8515
|
return lines;
|
|
@@ -9672,10 +9724,7 @@ function buildDocumentPDF(params, layoutOptions) {
|
|
|
9672
9724
|
}
|
|
9673
9725
|
const baseObjCount = enc.isUnicode ? 4 + fontEntries.length * 5 + imageCount + wmExtraObjs + totalPages * 2 + totalAnnots + totalFormObjs + formFontObjs : 4 + imageCount + wmExtraObjs + totalPages * 2 + totalAnnots + totalFormObjs + formFontObjs;
|
|
9674
9726
|
const infoObjNum = baseObjCount + 1;
|
|
9675
|
-
const
|
|
9676
|
-
const pad2 = (n) => String(n).padStart(2, "0");
|
|
9677
|
-
const pdfDate = `D:${now.getFullYear()}${pad2(now.getMonth() + 1)}${pad2(now.getDate())}${pad2(now.getHours())}${pad2(now.getMinutes())}${pad2(now.getSeconds())}`;
|
|
9678
|
-
const isoDate = `${now.getFullYear()}-${pad2(now.getMonth() + 1)}-${pad2(now.getDate())}T${pad2(now.getHours())}:${pad2(now.getMinutes())}:${pad2(now.getSeconds())}`;
|
|
9727
|
+
const { pdfDate, xmpDate: isoDate } = buildPdfMetadata();
|
|
9679
9728
|
const infoTitle = params.title ?? "";
|
|
9680
9729
|
const metaParts = [`/Title ${encodePdfTextString(infoTitle)}`, "/Producer (pdfnative)", `/CreationDate (${pdfDate})`];
|
|
9681
9730
|
if (params.metadata?.author) {
|
|
@@ -9703,7 +9752,7 @@ function buildDocumentPDF(params, layoutOptions) {
|
|
|
9703
9752
|
structTreeRootObjNum = tree.structTreeRootObjNum;
|
|
9704
9753
|
totalObjs = treeStart + tree.totalObjects - 1;
|
|
9705
9754
|
xmpObjNum = totalObjs + 1;
|
|
9706
|
-
const xmpContent = buildXMPMetadata(infoTitle, isoDate, pdfaConfig.pdfaPart, pdfaConfig.pdfaConformance);
|
|
9755
|
+
const xmpContent = buildXMPMetadata(infoTitle, isoDate, pdfaConfig.pdfaPart, pdfaConfig.pdfaConformance, params.metadata?.author);
|
|
9707
9756
|
emitStreamObj(
|
|
9708
9757
|
xmpObjNum,
|
|
9709
9758
|
`<< /Type /Metadata /Subtype /XML /Length ${xmpContent.length}`,
|
|
@@ -9809,7 +9858,7 @@ endobj
|
|
|
9809
9858
|
}
|
|
9810
9859
|
}
|
|
9811
9860
|
const writer = { emit, emitObj, emitStreamObj, offset: getOffset, adjustOffset, objOffsets, parts };
|
|
9812
|
-
writeXrefTrailer(writer, totalObjs, infoObjNum, encState);
|
|
9861
|
+
writeXrefTrailer(writer, totalObjs, infoObjNum, encState, `${infoTitle}|${pdfDate}`);
|
|
9813
9862
|
return parts.join("");
|
|
9814
9863
|
}
|
|
9815
9864
|
function buildDocumentPDFBytes(params, layoutOptions) {
|