@signiphi/page-assembly 0.2.0-beta.13 → 0.2.0-beta.15
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/dist/index.d.mts +83 -14
- package/dist/index.d.ts +83 -14
- package/dist/index.js +102 -53
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +103 -54
- package/dist/index.mjs.map +1 -1
- package/dist/styles/index.css +6 -0
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -309,24 +309,93 @@ interface ExtractedField {
|
|
|
309
309
|
signer?: string;
|
|
310
310
|
}
|
|
311
311
|
/**
|
|
312
|
-
*
|
|
312
|
+
* One field's metadata entry, as stored in the block.
|
|
313
|
+
*/
|
|
314
|
+
interface SigniphiFieldMetadata {
|
|
315
|
+
fieldId?: string;
|
|
316
|
+
label?: string;
|
|
317
|
+
signer?: string;
|
|
318
|
+
placeholder?: string;
|
|
319
|
+
required?: boolean;
|
|
320
|
+
options?: string[];
|
|
321
|
+
acknowledgements?: Array<{
|
|
322
|
+
id: string;
|
|
323
|
+
title: string;
|
|
324
|
+
description: string;
|
|
325
|
+
}>;
|
|
326
|
+
/**
|
|
327
|
+
* TEXT_LABEL only: this entry's text is already in the page stream, so the
|
|
328
|
+
* sign-time pass must not redraw it. See `mergeSourceMetadata`, which sets it
|
|
329
|
+
* when a source that had baked its labels is merged with one that deferred.
|
|
330
|
+
*/
|
|
331
|
+
textLabelBaked?: boolean;
|
|
332
|
+
/**
|
|
333
|
+
* CHECKBOX only: this field's caption is already in the page stream, written
|
|
334
|
+
* by document-prepare's bake. Declared so the merge carries it through — it
|
|
335
|
+
* is what pdf-signer's `checkboxLabelSource` actually decides on, the
|
|
336
|
+
* document-level `checkboxLabelsBaked` below being only the bake's mode.
|
|
337
|
+
* Nothing here sets or reads it.
|
|
338
|
+
*/
|
|
339
|
+
checkboxCaptionBaked?: boolean;
|
|
340
|
+
/**
|
|
341
|
+
* Persisted geometry, written by `document-prepare` for RADIO and TEXT_LABEL
|
|
342
|
+
* fields only. Declared here for ONE reason: its `page` is the SOURCE
|
|
343
|
+
* document's page number, and the merge has to rewrite it to the combined
|
|
344
|
+
* one. Nothing in page-assembly reads x/y/width/height.
|
|
345
|
+
*/
|
|
346
|
+
position?: SigniphiFieldPosition;
|
|
347
|
+
/** Radio-only, per-option. Re-paged alongside {@link SigniphiFieldMetadata.position}. */
|
|
348
|
+
radioPositions?: SigniphiFieldPosition[];
|
|
349
|
+
/** Radio-only bound list (options ↔ circle positions); its pages are re-paged too. */
|
|
350
|
+
radioOptions?: Array<{
|
|
351
|
+
label: string;
|
|
352
|
+
exportValue: string;
|
|
353
|
+
position: SigniphiFieldPosition;
|
|
354
|
+
}>;
|
|
355
|
+
}
|
|
356
|
+
/**
|
|
357
|
+
* A persisted field rect, as `document-prepare` writes it. `page` is 1-indexed
|
|
358
|
+
* and scoped to the document it was written in — which is exactly why the merge
|
|
359
|
+
* cannot carry it across unchanged.
|
|
360
|
+
*/
|
|
361
|
+
interface SigniphiFieldPosition {
|
|
362
|
+
x: number;
|
|
363
|
+
y: number;
|
|
364
|
+
width: number;
|
|
365
|
+
height: number;
|
|
366
|
+
page: number;
|
|
367
|
+
}
|
|
368
|
+
/**
|
|
369
|
+
* SigniphiMetadata structure stored in PDF Info dictionary.
|
|
370
|
+
*
|
|
371
|
+
* Exported because `getSigniphiMetadata` / `setSigniphiMetadata` are public
|
|
372
|
+
* (`utils/index.ts`) and a caller cannot name their argument otherwise — which
|
|
373
|
+
* is what pushed the call sites here into `as never` casts that would have
|
|
374
|
+
* silenced any future shape mismatch.
|
|
313
375
|
*/
|
|
314
376
|
interface SigniphiMetadata {
|
|
315
377
|
version: string;
|
|
316
|
-
fields: Record<string,
|
|
317
|
-
fieldId?: string;
|
|
318
|
-
label?: string;
|
|
319
|
-
signer?: string;
|
|
320
|
-
placeholder?: string;
|
|
321
|
-
required?: boolean;
|
|
322
|
-
options?: string[];
|
|
323
|
-
acknowledgements?: Array<{
|
|
324
|
-
id: string;
|
|
325
|
-
title: string;
|
|
326
|
-
description: string;
|
|
327
|
-
}>;
|
|
328
|
-
}>;
|
|
378
|
+
fields: Record<string, SigniphiFieldMetadata>;
|
|
329
379
|
fieldIdIndex?: Record<string, string>;
|
|
380
|
+
/**
|
|
381
|
+
* Document-level: radio group and option text is already drawn into the page
|
|
382
|
+
* stream, so the sign-time pass must not redraw it. Absent on legacy PDFs,
|
|
383
|
+
* which pdf-signer reads as "draw".
|
|
384
|
+
*/
|
|
385
|
+
radioLabelsBaked?: boolean;
|
|
386
|
+
/**
|
|
387
|
+
* Document-level: `false` means TEXT_LABEL text was deliberately NOT baked
|
|
388
|
+
* (multi-signer), so the sign-time pass redraws it per signer. Absent/`true`
|
|
389
|
+
* means it is already in the page stream.
|
|
390
|
+
*/
|
|
391
|
+
textLabelsBaked?: boolean;
|
|
392
|
+
/**
|
|
393
|
+
* Document-level: `false` means CHECKBOX captions were deliberately NOT baked
|
|
394
|
+
* beside their boxes (multi-signer), so the sign-time pass draws them per
|
|
395
|
+
* signer. `true` means they are already in the page stream. Absent means the
|
|
396
|
+
* source predates baked captions, which pdf-signer also reads as "draw".
|
|
397
|
+
*/
|
|
398
|
+
checkboxLabelsBaked?: boolean;
|
|
330
399
|
}
|
|
331
400
|
/**
|
|
332
401
|
* Extract SigniphiMetadata from a PDF document
|
package/dist/index.d.ts
CHANGED
|
@@ -309,24 +309,93 @@ interface ExtractedField {
|
|
|
309
309
|
signer?: string;
|
|
310
310
|
}
|
|
311
311
|
/**
|
|
312
|
-
*
|
|
312
|
+
* One field's metadata entry, as stored in the block.
|
|
313
|
+
*/
|
|
314
|
+
interface SigniphiFieldMetadata {
|
|
315
|
+
fieldId?: string;
|
|
316
|
+
label?: string;
|
|
317
|
+
signer?: string;
|
|
318
|
+
placeholder?: string;
|
|
319
|
+
required?: boolean;
|
|
320
|
+
options?: string[];
|
|
321
|
+
acknowledgements?: Array<{
|
|
322
|
+
id: string;
|
|
323
|
+
title: string;
|
|
324
|
+
description: string;
|
|
325
|
+
}>;
|
|
326
|
+
/**
|
|
327
|
+
* TEXT_LABEL only: this entry's text is already in the page stream, so the
|
|
328
|
+
* sign-time pass must not redraw it. See `mergeSourceMetadata`, which sets it
|
|
329
|
+
* when a source that had baked its labels is merged with one that deferred.
|
|
330
|
+
*/
|
|
331
|
+
textLabelBaked?: boolean;
|
|
332
|
+
/**
|
|
333
|
+
* CHECKBOX only: this field's caption is already in the page stream, written
|
|
334
|
+
* by document-prepare's bake. Declared so the merge carries it through — it
|
|
335
|
+
* is what pdf-signer's `checkboxLabelSource` actually decides on, the
|
|
336
|
+
* document-level `checkboxLabelsBaked` below being only the bake's mode.
|
|
337
|
+
* Nothing here sets or reads it.
|
|
338
|
+
*/
|
|
339
|
+
checkboxCaptionBaked?: boolean;
|
|
340
|
+
/**
|
|
341
|
+
* Persisted geometry, written by `document-prepare` for RADIO and TEXT_LABEL
|
|
342
|
+
* fields only. Declared here for ONE reason: its `page` is the SOURCE
|
|
343
|
+
* document's page number, and the merge has to rewrite it to the combined
|
|
344
|
+
* one. Nothing in page-assembly reads x/y/width/height.
|
|
345
|
+
*/
|
|
346
|
+
position?: SigniphiFieldPosition;
|
|
347
|
+
/** Radio-only, per-option. Re-paged alongside {@link SigniphiFieldMetadata.position}. */
|
|
348
|
+
radioPositions?: SigniphiFieldPosition[];
|
|
349
|
+
/** Radio-only bound list (options ↔ circle positions); its pages are re-paged too. */
|
|
350
|
+
radioOptions?: Array<{
|
|
351
|
+
label: string;
|
|
352
|
+
exportValue: string;
|
|
353
|
+
position: SigniphiFieldPosition;
|
|
354
|
+
}>;
|
|
355
|
+
}
|
|
356
|
+
/**
|
|
357
|
+
* A persisted field rect, as `document-prepare` writes it. `page` is 1-indexed
|
|
358
|
+
* and scoped to the document it was written in — which is exactly why the merge
|
|
359
|
+
* cannot carry it across unchanged.
|
|
360
|
+
*/
|
|
361
|
+
interface SigniphiFieldPosition {
|
|
362
|
+
x: number;
|
|
363
|
+
y: number;
|
|
364
|
+
width: number;
|
|
365
|
+
height: number;
|
|
366
|
+
page: number;
|
|
367
|
+
}
|
|
368
|
+
/**
|
|
369
|
+
* SigniphiMetadata structure stored in PDF Info dictionary.
|
|
370
|
+
*
|
|
371
|
+
* Exported because `getSigniphiMetadata` / `setSigniphiMetadata` are public
|
|
372
|
+
* (`utils/index.ts`) and a caller cannot name their argument otherwise — which
|
|
373
|
+
* is what pushed the call sites here into `as never` casts that would have
|
|
374
|
+
* silenced any future shape mismatch.
|
|
313
375
|
*/
|
|
314
376
|
interface SigniphiMetadata {
|
|
315
377
|
version: string;
|
|
316
|
-
fields: Record<string,
|
|
317
|
-
fieldId?: string;
|
|
318
|
-
label?: string;
|
|
319
|
-
signer?: string;
|
|
320
|
-
placeholder?: string;
|
|
321
|
-
required?: boolean;
|
|
322
|
-
options?: string[];
|
|
323
|
-
acknowledgements?: Array<{
|
|
324
|
-
id: string;
|
|
325
|
-
title: string;
|
|
326
|
-
description: string;
|
|
327
|
-
}>;
|
|
328
|
-
}>;
|
|
378
|
+
fields: Record<string, SigniphiFieldMetadata>;
|
|
329
379
|
fieldIdIndex?: Record<string, string>;
|
|
380
|
+
/**
|
|
381
|
+
* Document-level: radio group and option text is already drawn into the page
|
|
382
|
+
* stream, so the sign-time pass must not redraw it. Absent on legacy PDFs,
|
|
383
|
+
* which pdf-signer reads as "draw".
|
|
384
|
+
*/
|
|
385
|
+
radioLabelsBaked?: boolean;
|
|
386
|
+
/**
|
|
387
|
+
* Document-level: `false` means TEXT_LABEL text was deliberately NOT baked
|
|
388
|
+
* (multi-signer), so the sign-time pass redraws it per signer. Absent/`true`
|
|
389
|
+
* means it is already in the page stream.
|
|
390
|
+
*/
|
|
391
|
+
textLabelsBaked?: boolean;
|
|
392
|
+
/**
|
|
393
|
+
* Document-level: `false` means CHECKBOX captions were deliberately NOT baked
|
|
394
|
+
* beside their boxes (multi-signer), so the sign-time pass draws them per
|
|
395
|
+
* signer. `true` means they are already in the page stream. Absent means the
|
|
396
|
+
* source predates baked captions, which pdf-signer also reads as "draw".
|
|
397
|
+
*/
|
|
398
|
+
checkboxLabelsBaked?: boolean;
|
|
330
399
|
}
|
|
331
400
|
/**
|
|
332
401
|
* Extract SigniphiMetadata from a PDF document
|
package/dist/index.js
CHANGED
|
@@ -1399,6 +1399,55 @@ function downloadPdf(pdfBytes, filename) {
|
|
|
1399
1399
|
a.click();
|
|
1400
1400
|
URL.revokeObjectURL(url);
|
|
1401
1401
|
}
|
|
1402
|
+
function toCombinedPage(entry, page) {
|
|
1403
|
+
if (!entry.position && !entry.radioPositions && !entry.radioOptions) return entry;
|
|
1404
|
+
const carried = { ...entry };
|
|
1405
|
+
if (entry.position) carried.position = { ...entry.position, page };
|
|
1406
|
+
if (entry.radioPositions) carried.radioPositions = entry.radioPositions.map((p) => ({ ...p, page }));
|
|
1407
|
+
if (entry.radioOptions) {
|
|
1408
|
+
carried.radioOptions = entry.radioOptions.map((o) => ({ ...o, position: { ...o.position, page } }));
|
|
1409
|
+
}
|
|
1410
|
+
return carried;
|
|
1411
|
+
}
|
|
1412
|
+
function mergeSourceMetadata(sources) {
|
|
1413
|
+
const merged = { version: "1.0", fields: {}, fieldIdIndex: {} };
|
|
1414
|
+
let radioLabelsBaked;
|
|
1415
|
+
let textLabelsBaked;
|
|
1416
|
+
let checkboxLabelsBaked;
|
|
1417
|
+
for (const source of sources) {
|
|
1418
|
+
const meta = source.metadata;
|
|
1419
|
+
if (!meta || source.fields.length === 0) continue;
|
|
1420
|
+
if (meta.radioLabelsBaked === false) radioLabelsBaked = false;
|
|
1421
|
+
else if (meta.radioLabelsBaked === true && radioLabelsBaked === void 0) radioLabelsBaked = true;
|
|
1422
|
+
if (meta.textLabelsBaked === false) textLabelsBaked = false;
|
|
1423
|
+
else if (meta.textLabelsBaked === true && textLabelsBaked === void 0) textLabelsBaked = true;
|
|
1424
|
+
if (meta.checkboxLabelsBaked === false) checkboxLabelsBaked = false;
|
|
1425
|
+
else if (meta.checkboxLabelsBaked === true && checkboxLabelsBaked === void 0) checkboxLabelsBaked = true;
|
|
1426
|
+
}
|
|
1427
|
+
for (const source of sources) {
|
|
1428
|
+
const meta = source.metadata;
|
|
1429
|
+
if (!meta) continue;
|
|
1430
|
+
const sourceTextLabelsBaked = meta.textLabelsBaked !== false;
|
|
1431
|
+
for (const { name, page } of source.fields) {
|
|
1432
|
+
const key = `${name}_p${page}`;
|
|
1433
|
+
const entry = meta.fields?.[name];
|
|
1434
|
+
if (entry) {
|
|
1435
|
+
const carried = toCombinedPage(entry, page);
|
|
1436
|
+
merged.fields[key] = textLabelsBaked === false && sourceTextLabelsBaked ? { ...carried, textLabelBaked: true } : carried;
|
|
1437
|
+
}
|
|
1438
|
+
const fieldId = meta.fieldIdIndex?.[name];
|
|
1439
|
+
if (fieldId) merged.fieldIdIndex[key] = fieldId;
|
|
1440
|
+
}
|
|
1441
|
+
}
|
|
1442
|
+
if (radioLabelsBaked !== void 0) merged.radioLabelsBaked = radioLabelsBaked;
|
|
1443
|
+
if (textLabelsBaked !== void 0) merged.textLabelsBaked = textLabelsBaked;
|
|
1444
|
+
if (checkboxLabelsBaked !== void 0) merged.checkboxLabelsBaked = checkboxLabelsBaked;
|
|
1445
|
+
const hasEntries = Object.keys(merged.fields).length > 0;
|
|
1446
|
+
const hasMarkers = radioLabelsBaked !== void 0 || textLabelsBaked !== void 0 || checkboxLabelsBaked !== void 0;
|
|
1447
|
+
if (!hasEntries && !hasMarkers) return null;
|
|
1448
|
+
if (Object.keys(merged.fieldIdIndex).length === 0) delete merged.fieldIdIndex;
|
|
1449
|
+
return merged;
|
|
1450
|
+
}
|
|
1402
1451
|
function getSigniphiMetadata(pdfDoc) {
|
|
1403
1452
|
try {
|
|
1404
1453
|
const infoRef = pdfDoc.context.trailerInfo.Info;
|
|
@@ -1414,12 +1463,17 @@ function getSigniphiMetadata(pdfDoc) {
|
|
|
1414
1463
|
if (!metadataObj) {
|
|
1415
1464
|
return null;
|
|
1416
1465
|
}
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
jsonStr = metadataStr
|
|
1466
|
+
let jsonStr;
|
|
1467
|
+
if (typeof metadataObj.decodeText === "function") {
|
|
1468
|
+
jsonStr = metadataObj.decodeText();
|
|
1469
|
+
} else {
|
|
1470
|
+
const metadataStr = metadataObj.toString();
|
|
1471
|
+
jsonStr = metadataStr;
|
|
1472
|
+
if (metadataStr.startsWith("(") && metadataStr.endsWith(")")) {
|
|
1473
|
+
jsonStr = metadataStr.slice(1, -1);
|
|
1474
|
+
} else if (metadataStr.startsWith("<") && metadataStr.endsWith(">")) {
|
|
1475
|
+
jsonStr = metadataStr.slice(1, -1);
|
|
1476
|
+
}
|
|
1423
1477
|
}
|
|
1424
1478
|
const metadata = JSON.parse(jsonStr);
|
|
1425
1479
|
return metadata;
|
|
@@ -1612,12 +1666,13 @@ function setSigniphiMetadata(pdfDoc, metadata) {
|
|
|
1612
1666
|
}
|
|
1613
1667
|
const infoDict = infoObj;
|
|
1614
1668
|
const metadataString = JSON.stringify(metadata);
|
|
1615
|
-
infoDict.set(pdfLib.PDFName.of("SigniphiMetadata"), pdfLib.
|
|
1669
|
+
infoDict.set(pdfLib.PDFName.of("SigniphiMetadata"), pdfLib.PDFHexString.fromText(metadataString));
|
|
1616
1670
|
} catch (error) {
|
|
1617
1671
|
console.error("Failed to set Signiphi metadata:", error);
|
|
1618
1672
|
throw error;
|
|
1619
1673
|
}
|
|
1620
1674
|
}
|
|
1675
|
+
var SIGNIPHI_CHECKBOX_LABEL_MARKER = "SiPL_Check";
|
|
1621
1676
|
var FormFieldType = /* @__PURE__ */ ((FormFieldType2) => {
|
|
1622
1677
|
FormFieldType2["TEXT"] = "text";
|
|
1623
1678
|
FormFieldType2["SIGNATURE"] = "signature";
|
|
@@ -1703,6 +1758,7 @@ async function addFormFieldsToPdf(pdfBytes, formFields, options = {}) {
|
|
|
1703
1758
|
}
|
|
1704
1759
|
}
|
|
1705
1760
|
const font = await pdfDoc.embedFont(pdfLib.StandardFonts.Helvetica);
|
|
1761
|
+
const bakedCheckboxCaptions = /* @__PURE__ */ new Map();
|
|
1706
1762
|
const fieldNamePages = /* @__PURE__ */ new Map();
|
|
1707
1763
|
for (const field of formFields) {
|
|
1708
1764
|
const baseName = field.name;
|
|
@@ -1799,10 +1855,15 @@ async function addFormFieldsToPdf(pdfBytes, formFields, options = {}) {
|
|
|
1799
1855
|
} catch {
|
|
1800
1856
|
}
|
|
1801
1857
|
if (drawLabels) {
|
|
1802
|
-
const fontSize = Math.min(
|
|
1858
|
+
const fontSize = Math.max(1, Math.min(10, field.position.height * 0.4));
|
|
1803
1859
|
const labelX = pdfX + field.position.width + 5;
|
|
1804
1860
|
const labelY = pdfY + (field.position.height - fontSize) / 2;
|
|
1861
|
+
page.pushOperators(
|
|
1862
|
+
pdfLib.PDFOperator.of(pdfLib.PDFOperatorNames.BeginMarkedContent, [pdfLib.PDFName.of(SIGNIPHI_CHECKBOX_LABEL_MARKER)])
|
|
1863
|
+
);
|
|
1805
1864
|
page.drawText(field.label, { x: labelX, y: labelY, size: fontSize, font, color: pdfLib.rgb(0, 0, 0) });
|
|
1865
|
+
page.pushOperators(pdfLib.PDFOperator.of(pdfLib.PDFOperatorNames.EndMarkedContent));
|
|
1866
|
+
bakedCheckboxCaptions.set(encodedName, field);
|
|
1806
1867
|
}
|
|
1807
1868
|
}
|
|
1808
1869
|
break;
|
|
@@ -1954,8 +2015,28 @@ async function addFormFieldsToPdf(pdfBytes, formFields, options = {}) {
|
|
|
1954
2015
|
console.error(`Error adding field ${field.name}:`, error);
|
|
1955
2016
|
}
|
|
1956
2017
|
}
|
|
2018
|
+
recordBakedCheckboxCaptions(pdfDoc, bakedCheckboxCaptions);
|
|
1957
2019
|
return await pdfDoc.save();
|
|
1958
2020
|
}
|
|
2021
|
+
function recordBakedCheckboxCaptions(pdfDoc, captions) {
|
|
2022
|
+
if (captions.size === 0) return;
|
|
2023
|
+
try {
|
|
2024
|
+
const metadata = getSigniphiMetadata(pdfDoc);
|
|
2025
|
+
if (!metadata) return;
|
|
2026
|
+
metadata.fields ?? (metadata.fields = {});
|
|
2027
|
+
for (const [name, field] of captions) {
|
|
2028
|
+
metadata.fields[name] = {
|
|
2029
|
+
signer: field.assignedSignerEmail,
|
|
2030
|
+
label: field.label,
|
|
2031
|
+
...metadata.fields[name],
|
|
2032
|
+
checkboxCaptionBaked: true
|
|
2033
|
+
};
|
|
2034
|
+
}
|
|
2035
|
+
setSigniphiMetadata(pdfDoc, metadata);
|
|
2036
|
+
} catch (error) {
|
|
2037
|
+
console.warn("Failed to record baked checkbox captions:", error);
|
|
2038
|
+
}
|
|
2039
|
+
}
|
|
1959
2040
|
function mapFieldPositionsAfterAssembly(fields, pageMapping) {
|
|
1960
2041
|
return fields.map((field) => {
|
|
1961
2042
|
const mappingKey = String(field.position.page - 1);
|
|
@@ -2925,7 +3006,7 @@ var PageAssembler = React7.forwardRef(
|
|
|
2925
3006
|
setIsLoading(true);
|
|
2926
3007
|
setProcessingStatus("Assembling PDF...");
|
|
2927
3008
|
try {
|
|
2928
|
-
const { PDFDocument: PDFDocument5, PDFName: PDFName4
|
|
3009
|
+
const { PDFDocument: PDFDocument5, PDFName: PDFName4 } = await import('pdf-lib');
|
|
2929
3010
|
const loadedPdfs = /* @__PURE__ */ new Map();
|
|
2930
3011
|
const fileMap = /* @__PURE__ */ new Map();
|
|
2931
3012
|
const pdfFiles = state.files.filter((f) => f.type === "pdf" && f.originalBytes?.length > 0);
|
|
@@ -3004,11 +3085,7 @@ var PageAssembler = React7.forwardRef(
|
|
|
3004
3085
|
}
|
|
3005
3086
|
console.log("[PageAssembler] Starting multi-PDF assembly with field preservation");
|
|
3006
3087
|
const allExtractedFields = [];
|
|
3007
|
-
const
|
|
3008
|
-
version: "1.0",
|
|
3009
|
-
fields: {},
|
|
3010
|
-
fieldIdIndex: {}
|
|
3011
|
-
};
|
|
3088
|
+
const metadataSources = [];
|
|
3012
3089
|
const filePageUsage = /* @__PURE__ */ new Map();
|
|
3013
3090
|
for (const file of state.files) {
|
|
3014
3091
|
for (const page of file.pages) {
|
|
@@ -3033,28 +3110,12 @@ var PageAssembler = React7.forwardRef(
|
|
|
3033
3110
|
}
|
|
3034
3111
|
console.log("[PageAssembler] Page mapping:", Object.fromEntries(pageIdToNewPageNumber));
|
|
3035
3112
|
const extractAndMapFields = async (fileId, fileName, pdfBytes2, sourcePdf) => {
|
|
3036
|
-
|
|
3037
|
-
if (sourcePdf) {
|
|
3038
|
-
|
|
3039
|
-
const sourceInfoRef = sourcePdf.context.trailerInfo.Info;
|
|
3040
|
-
if (sourceInfoRef) {
|
|
3041
|
-
const sourceInfoDict = sourcePdf.context.lookup(sourceInfoRef);
|
|
3042
|
-
if (sourceInfoDict && typeof sourceInfoDict.get === "function") {
|
|
3043
|
-
const metadataObj = sourceInfoDict.get(PDFName4.of("SigniphiMetadata"));
|
|
3044
|
-
if (metadataObj) {
|
|
3045
|
-
const metadataStr = metadataObj.toString();
|
|
3046
|
-
let jsonStr = metadataStr;
|
|
3047
|
-
if (metadataStr.startsWith("(") && metadataStr.endsWith(")")) {
|
|
3048
|
-
jsonStr = metadataStr.slice(1, -1);
|
|
3049
|
-
}
|
|
3050
|
-
sourceMetadata = JSON.parse(jsonStr);
|
|
3051
|
-
}
|
|
3052
|
-
}
|
|
3053
|
-
}
|
|
3054
|
-
} catch (metadataError) {
|
|
3055
|
-
console.warn(`Could not read metadata from PDF ${fileName}:`, metadataError);
|
|
3056
|
-
}
|
|
3113
|
+
const sourceMetadata = sourcePdf ? getSigniphiMetadata(sourcePdf) : null;
|
|
3114
|
+
if (sourcePdf && !sourceMetadata) {
|
|
3115
|
+
console.warn(`[PageAssembler] No readable SigniphiMetadata in "${fileName}"`);
|
|
3057
3116
|
}
|
|
3117
|
+
const placements = [];
|
|
3118
|
+
metadataSources.push({ metadata: sourceMetadata, fields: placements });
|
|
3058
3119
|
console.log(`[PageAssembler] Extracting fields from "${fileName}"`);
|
|
3059
3120
|
const extractedFields = await extractFieldsFromPdf(pdfBytes2);
|
|
3060
3121
|
console.log(`[PageAssembler] Found ${extractedFields.length} fields in "${fileName}"`);
|
|
@@ -3088,13 +3149,7 @@ var PageAssembler = React7.forwardRef(
|
|
|
3088
3149
|
};
|
|
3089
3150
|
allExtractedFields.push(trackedField);
|
|
3090
3151
|
console.log(`[PageAssembler] Mapped field "${field.name}" from page ${originalPage} to page ${newPageNumber}`);
|
|
3091
|
-
|
|
3092
|
-
if (sourceMetadata?.fields?.[field.name]) {
|
|
3093
|
-
mergedMetadata.fields[metadataKey] = sourceMetadata.fields[field.name];
|
|
3094
|
-
}
|
|
3095
|
-
if (sourceMetadata?.fieldIdIndex?.[field.name]) {
|
|
3096
|
-
mergedMetadata.fieldIdIndex[metadataKey] = sourceMetadata.fieldIdIndex[field.name];
|
|
3097
|
-
}
|
|
3152
|
+
placements.push({ name: field.name, page: newPageNumber });
|
|
3098
3153
|
}
|
|
3099
3154
|
}
|
|
3100
3155
|
}
|
|
@@ -3172,21 +3227,15 @@ var PageAssembler = React7.forwardRef(
|
|
|
3172
3227
|
}
|
|
3173
3228
|
}
|
|
3174
3229
|
}
|
|
3175
|
-
|
|
3230
|
+
const mergedMetadata = mergeSourceMetadata(metadataSources);
|
|
3231
|
+
if (mergedMetadata) {
|
|
3176
3232
|
try {
|
|
3177
|
-
|
|
3178
|
-
if (newInfoRef) {
|
|
3179
|
-
const newInfoDict = combinedDoc.context.lookup(newInfoRef);
|
|
3180
|
-
if (newInfoDict && typeof newInfoDict.set === "function") {
|
|
3181
|
-
newInfoDict.set(
|
|
3182
|
-
PDFName4.of("SigniphiMetadata"),
|
|
3183
|
-
PDFString4.of(JSON.stringify(mergedMetadata))
|
|
3184
|
-
);
|
|
3185
|
-
}
|
|
3186
|
-
}
|
|
3233
|
+
setSigniphiMetadata(combinedDoc, mergedMetadata);
|
|
3187
3234
|
} catch (metadataError) {
|
|
3188
3235
|
console.warn("Could not write merged metadata:", metadataError);
|
|
3189
3236
|
}
|
|
3237
|
+
} else {
|
|
3238
|
+
console.warn("[PageAssembler] No source metadata survived the merge; the assembled document will read as unprepared downstream");
|
|
3190
3239
|
}
|
|
3191
3240
|
let pdfBytes = await combinedDoc.save();
|
|
3192
3241
|
if (allExtractedFields.length > 0) {
|