@signiphi/page-assembly 0.2.0-beta.12 → 0.2.0-beta.14
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 +68 -14
- package/dist/index.d.ts +68 -14
- package/dist/index.js +112 -66
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +113 -67
- package/dist/index.mjs.map +1 -1
- package/dist/styles/index.css +12 -0
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -14,7 +14,7 @@ import * as AlertDialogPrimitive from '@radix-ui/react-alert-dialog';
|
|
|
14
14
|
import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu';
|
|
15
15
|
import * as TooltipPrimitive from '@radix-ui/react-tooltip';
|
|
16
16
|
import * as pdfjsLib from 'pdfjs-dist';
|
|
17
|
-
import { PDFDocument, PDFTextField, PDFCheckBox, PDFDropdown, PDFRadioGroup, StandardFonts, rgb,
|
|
17
|
+
import { PDFDocument, PDFName, PDFTextField, PDFCheckBox, PDFDropdown, PDFRadioGroup, PDFHexString, StandardFonts, rgb, PDFString, PDFDict, PDFArray, PDFInvalidObject, PDFObjectParser, PDFRawStream, PDFObjectStreamParser, PDFRef, PDFBool, PDFNumber } from 'pdf-lib';
|
|
18
18
|
|
|
19
19
|
// src/components/PageAssembler.tsx
|
|
20
20
|
function cn(...inputs) {
|
|
@@ -1372,6 +1372,51 @@ function downloadPdf(pdfBytes, filename) {
|
|
|
1372
1372
|
a.click();
|
|
1373
1373
|
URL.revokeObjectURL(url);
|
|
1374
1374
|
}
|
|
1375
|
+
function toCombinedPage(entry, page) {
|
|
1376
|
+
if (!entry.position && !entry.radioPositions && !entry.radioOptions) return entry;
|
|
1377
|
+
const carried = { ...entry };
|
|
1378
|
+
if (entry.position) carried.position = { ...entry.position, page };
|
|
1379
|
+
if (entry.radioPositions) carried.radioPositions = entry.radioPositions.map((p) => ({ ...p, page }));
|
|
1380
|
+
if (entry.radioOptions) {
|
|
1381
|
+
carried.radioOptions = entry.radioOptions.map((o) => ({ ...o, position: { ...o.position, page } }));
|
|
1382
|
+
}
|
|
1383
|
+
return carried;
|
|
1384
|
+
}
|
|
1385
|
+
function mergeSourceMetadata(sources) {
|
|
1386
|
+
const merged = { version: "1.0", fields: {}, fieldIdIndex: {} };
|
|
1387
|
+
let radioLabelsBaked;
|
|
1388
|
+
let textLabelsBaked;
|
|
1389
|
+
for (const source of sources) {
|
|
1390
|
+
const meta = source.metadata;
|
|
1391
|
+
if (!meta || source.fields.length === 0) continue;
|
|
1392
|
+
if (meta.radioLabelsBaked === false) radioLabelsBaked = false;
|
|
1393
|
+
else if (meta.radioLabelsBaked === true && radioLabelsBaked === void 0) radioLabelsBaked = true;
|
|
1394
|
+
if (meta.textLabelsBaked === false) textLabelsBaked = false;
|
|
1395
|
+
else if (meta.textLabelsBaked === true && textLabelsBaked === void 0) textLabelsBaked = true;
|
|
1396
|
+
}
|
|
1397
|
+
for (const source of sources) {
|
|
1398
|
+
const meta = source.metadata;
|
|
1399
|
+
if (!meta) continue;
|
|
1400
|
+
const sourceTextLabelsBaked = meta.textLabelsBaked !== false;
|
|
1401
|
+
for (const { name, page } of source.fields) {
|
|
1402
|
+
const key = `${name}_p${page}`;
|
|
1403
|
+
const entry = meta.fields?.[name];
|
|
1404
|
+
if (entry) {
|
|
1405
|
+
const carried = toCombinedPage(entry, page);
|
|
1406
|
+
merged.fields[key] = textLabelsBaked === false && sourceTextLabelsBaked ? { ...carried, textLabelBaked: true } : carried;
|
|
1407
|
+
}
|
|
1408
|
+
const fieldId = meta.fieldIdIndex?.[name];
|
|
1409
|
+
if (fieldId) merged.fieldIdIndex[key] = fieldId;
|
|
1410
|
+
}
|
|
1411
|
+
}
|
|
1412
|
+
if (radioLabelsBaked !== void 0) merged.radioLabelsBaked = radioLabelsBaked;
|
|
1413
|
+
if (textLabelsBaked !== void 0) merged.textLabelsBaked = textLabelsBaked;
|
|
1414
|
+
const hasEntries = Object.keys(merged.fields).length > 0;
|
|
1415
|
+
const hasMarkers = radioLabelsBaked !== void 0 || textLabelsBaked !== void 0;
|
|
1416
|
+
if (!hasEntries && !hasMarkers) return null;
|
|
1417
|
+
if (Object.keys(merged.fieldIdIndex).length === 0) delete merged.fieldIdIndex;
|
|
1418
|
+
return merged;
|
|
1419
|
+
}
|
|
1375
1420
|
function getSigniphiMetadata(pdfDoc) {
|
|
1376
1421
|
try {
|
|
1377
1422
|
const infoRef = pdfDoc.context.trailerInfo.Info;
|
|
@@ -1387,12 +1432,17 @@ function getSigniphiMetadata(pdfDoc) {
|
|
|
1387
1432
|
if (!metadataObj) {
|
|
1388
1433
|
return null;
|
|
1389
1434
|
}
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
jsonStr = metadataStr
|
|
1435
|
+
let jsonStr;
|
|
1436
|
+
if (typeof metadataObj.decodeText === "function") {
|
|
1437
|
+
jsonStr = metadataObj.decodeText();
|
|
1438
|
+
} else {
|
|
1439
|
+
const metadataStr = metadataObj.toString();
|
|
1440
|
+
jsonStr = metadataStr;
|
|
1441
|
+
if (metadataStr.startsWith("(") && metadataStr.endsWith(")")) {
|
|
1442
|
+
jsonStr = metadataStr.slice(1, -1);
|
|
1443
|
+
} else if (metadataStr.startsWith("<") && metadataStr.endsWith(">")) {
|
|
1444
|
+
jsonStr = metadataStr.slice(1, -1);
|
|
1445
|
+
}
|
|
1396
1446
|
}
|
|
1397
1447
|
const metadata = JSON.parse(jsonStr);
|
|
1398
1448
|
return metadata;
|
|
@@ -1585,7 +1635,7 @@ function setSigniphiMetadata(pdfDoc, metadata) {
|
|
|
1585
1635
|
}
|
|
1586
1636
|
const infoDict = infoObj;
|
|
1587
1637
|
const metadataString = JSON.stringify(metadata);
|
|
1588
|
-
infoDict.set(PDFName.of("SigniphiMetadata"),
|
|
1638
|
+
infoDict.set(PDFName.of("SigniphiMetadata"), PDFHexString.fromText(metadataString));
|
|
1589
1639
|
} catch (error) {
|
|
1590
1640
|
console.error("Failed to set Signiphi metadata:", error);
|
|
1591
1641
|
throw error;
|
|
@@ -1945,6 +1995,7 @@ function mapFieldPositionsAfterAssembly(fields, pageMapping) {
|
|
|
1945
1995
|
return pageMapping.has(mappingKey) || pageMapping.size === 0;
|
|
1946
1996
|
});
|
|
1947
1997
|
}
|
|
1998
|
+
var VISIBLE_PAGE_ROWS = 2;
|
|
1948
1999
|
var isMultiSelectModifier = (event) => {
|
|
1949
2000
|
return event.ctrlKey || event.metaKey;
|
|
1950
2001
|
};
|
|
@@ -2271,21 +2322,48 @@ var ReorderablePageGrid = ({
|
|
|
2271
2322
|
newPages.splice(hoverIndex, 0, draggedPage);
|
|
2272
2323
|
onReorderPages(file.id, newPages);
|
|
2273
2324
|
}, [file.id, file.pages, onReorderPages]);
|
|
2274
|
-
|
|
2275
|
-
|
|
2325
|
+
const gridRef = useRef(null);
|
|
2326
|
+
const [maxHeight, setMaxHeight] = useState(void 0);
|
|
2327
|
+
useEffect(() => {
|
|
2328
|
+
const grid = gridRef.current;
|
|
2329
|
+
if (!grid || typeof ResizeObserver === "undefined") return;
|
|
2330
|
+
const measure = () => {
|
|
2331
|
+
const firstThumbnail = grid.firstElementChild;
|
|
2332
|
+
if (!firstThumbnail) return;
|
|
2333
|
+
const rowHeight = firstThumbnail.getBoundingClientRect().height;
|
|
2334
|
+
if (rowHeight <= 0) return;
|
|
2335
|
+
const rowGap = parseFloat(getComputedStyle(grid).rowGap) || 0;
|
|
2336
|
+
setMaxHeight(Math.ceil(rowHeight * VISIBLE_PAGE_ROWS + rowGap * (VISIBLE_PAGE_ROWS - 1)));
|
|
2337
|
+
};
|
|
2338
|
+
measure();
|
|
2339
|
+
const observer = new ResizeObserver(measure);
|
|
2340
|
+
observer.observe(grid);
|
|
2341
|
+
if (grid.firstElementChild) observer.observe(grid.firstElementChild);
|
|
2342
|
+
return () => observer.disconnect();
|
|
2343
|
+
}, [file.pages]);
|
|
2344
|
+
return /* @__PURE__ */ jsx(
|
|
2345
|
+
"div",
|
|
2276
2346
|
{
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2347
|
+
ref: gridRef,
|
|
2348
|
+
className: "grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-6 gap-4 overflow-y-auto overflow-x-hidden",
|
|
2349
|
+
style: { maxHeight },
|
|
2350
|
+
children: file.pages.map((page, index) => /* @__PURE__ */ jsx(
|
|
2351
|
+
DraggablePageThumbnail,
|
|
2352
|
+
{
|
|
2353
|
+
page,
|
|
2354
|
+
fileId: file.id,
|
|
2355
|
+
index,
|
|
2356
|
+
isSelected: selectedPageIds.includes(page.id),
|
|
2357
|
+
onSingleSelect: onSingleSelectPage,
|
|
2358
|
+
onToggleSelect: onTogglePageSelect,
|
|
2359
|
+
onRangeSelect: onRangeSelectPage,
|
|
2360
|
+
movePageInFile,
|
|
2361
|
+
isDraggingPageRef
|
|
2362
|
+
},
|
|
2363
|
+
page.id
|
|
2364
|
+
))
|
|
2365
|
+
}
|
|
2366
|
+
);
|
|
2289
2367
|
};
|
|
2290
2368
|
var FileDropZone = ({
|
|
2291
2369
|
targetIndex,
|
|
@@ -2870,7 +2948,7 @@ var PageAssembler = forwardRef(
|
|
|
2870
2948
|
setIsLoading(true);
|
|
2871
2949
|
setProcessingStatus("Assembling PDF...");
|
|
2872
2950
|
try {
|
|
2873
|
-
const { PDFDocument: PDFDocument5, PDFName: PDFName4
|
|
2951
|
+
const { PDFDocument: PDFDocument5, PDFName: PDFName4 } = await import('pdf-lib');
|
|
2874
2952
|
const loadedPdfs = /* @__PURE__ */ new Map();
|
|
2875
2953
|
const fileMap = /* @__PURE__ */ new Map();
|
|
2876
2954
|
const pdfFiles = state.files.filter((f) => f.type === "pdf" && f.originalBytes?.length > 0);
|
|
@@ -2949,11 +3027,7 @@ var PageAssembler = forwardRef(
|
|
|
2949
3027
|
}
|
|
2950
3028
|
console.log("[PageAssembler] Starting multi-PDF assembly with field preservation");
|
|
2951
3029
|
const allExtractedFields = [];
|
|
2952
|
-
const
|
|
2953
|
-
version: "1.0",
|
|
2954
|
-
fields: {},
|
|
2955
|
-
fieldIdIndex: {}
|
|
2956
|
-
};
|
|
3030
|
+
const metadataSources = [];
|
|
2957
3031
|
const filePageUsage = /* @__PURE__ */ new Map();
|
|
2958
3032
|
for (const file of state.files) {
|
|
2959
3033
|
for (const page of file.pages) {
|
|
@@ -2978,28 +3052,12 @@ var PageAssembler = forwardRef(
|
|
|
2978
3052
|
}
|
|
2979
3053
|
console.log("[PageAssembler] Page mapping:", Object.fromEntries(pageIdToNewPageNumber));
|
|
2980
3054
|
const extractAndMapFields = async (fileId, fileName, pdfBytes2, sourcePdf) => {
|
|
2981
|
-
|
|
2982
|
-
if (sourcePdf) {
|
|
2983
|
-
|
|
2984
|
-
const sourceInfoRef = sourcePdf.context.trailerInfo.Info;
|
|
2985
|
-
if (sourceInfoRef) {
|
|
2986
|
-
const sourceInfoDict = sourcePdf.context.lookup(sourceInfoRef);
|
|
2987
|
-
if (sourceInfoDict && typeof sourceInfoDict.get === "function") {
|
|
2988
|
-
const metadataObj = sourceInfoDict.get(PDFName4.of("SigniphiMetadata"));
|
|
2989
|
-
if (metadataObj) {
|
|
2990
|
-
const metadataStr = metadataObj.toString();
|
|
2991
|
-
let jsonStr = metadataStr;
|
|
2992
|
-
if (metadataStr.startsWith("(") && metadataStr.endsWith(")")) {
|
|
2993
|
-
jsonStr = metadataStr.slice(1, -1);
|
|
2994
|
-
}
|
|
2995
|
-
sourceMetadata = JSON.parse(jsonStr);
|
|
2996
|
-
}
|
|
2997
|
-
}
|
|
2998
|
-
}
|
|
2999
|
-
} catch (metadataError) {
|
|
3000
|
-
console.warn(`Could not read metadata from PDF ${fileName}:`, metadataError);
|
|
3001
|
-
}
|
|
3055
|
+
const sourceMetadata = sourcePdf ? getSigniphiMetadata(sourcePdf) : null;
|
|
3056
|
+
if (sourcePdf && !sourceMetadata) {
|
|
3057
|
+
console.warn(`[PageAssembler] No readable SigniphiMetadata in "${fileName}"`);
|
|
3002
3058
|
}
|
|
3059
|
+
const placements = [];
|
|
3060
|
+
metadataSources.push({ metadata: sourceMetadata, fields: placements });
|
|
3003
3061
|
console.log(`[PageAssembler] Extracting fields from "${fileName}"`);
|
|
3004
3062
|
const extractedFields = await extractFieldsFromPdf(pdfBytes2);
|
|
3005
3063
|
console.log(`[PageAssembler] Found ${extractedFields.length} fields in "${fileName}"`);
|
|
@@ -3033,13 +3091,7 @@ var PageAssembler = forwardRef(
|
|
|
3033
3091
|
};
|
|
3034
3092
|
allExtractedFields.push(trackedField);
|
|
3035
3093
|
console.log(`[PageAssembler] Mapped field "${field.name}" from page ${originalPage} to page ${newPageNumber}`);
|
|
3036
|
-
|
|
3037
|
-
if (sourceMetadata?.fields?.[field.name]) {
|
|
3038
|
-
mergedMetadata.fields[metadataKey] = sourceMetadata.fields[field.name];
|
|
3039
|
-
}
|
|
3040
|
-
if (sourceMetadata?.fieldIdIndex?.[field.name]) {
|
|
3041
|
-
mergedMetadata.fieldIdIndex[metadataKey] = sourceMetadata.fieldIdIndex[field.name];
|
|
3042
|
-
}
|
|
3094
|
+
placements.push({ name: field.name, page: newPageNumber });
|
|
3043
3095
|
}
|
|
3044
3096
|
}
|
|
3045
3097
|
}
|
|
@@ -3117,21 +3169,15 @@ var PageAssembler = forwardRef(
|
|
|
3117
3169
|
}
|
|
3118
3170
|
}
|
|
3119
3171
|
}
|
|
3120
|
-
|
|
3172
|
+
const mergedMetadata = mergeSourceMetadata(metadataSources);
|
|
3173
|
+
if (mergedMetadata) {
|
|
3121
3174
|
try {
|
|
3122
|
-
|
|
3123
|
-
if (newInfoRef) {
|
|
3124
|
-
const newInfoDict = combinedDoc.context.lookup(newInfoRef);
|
|
3125
|
-
if (newInfoDict && typeof newInfoDict.set === "function") {
|
|
3126
|
-
newInfoDict.set(
|
|
3127
|
-
PDFName4.of("SigniphiMetadata"),
|
|
3128
|
-
PDFString4.of(JSON.stringify(mergedMetadata))
|
|
3129
|
-
);
|
|
3130
|
-
}
|
|
3131
|
-
}
|
|
3175
|
+
setSigniphiMetadata(combinedDoc, mergedMetadata);
|
|
3132
3176
|
} catch (metadataError) {
|
|
3133
3177
|
console.warn("Could not write merged metadata:", metadataError);
|
|
3134
3178
|
}
|
|
3179
|
+
} else {
|
|
3180
|
+
console.warn("[PageAssembler] No source metadata survived the merge; the assembled document will read as unprepared downstream");
|
|
3135
3181
|
}
|
|
3136
3182
|
let pdfBytes = await combinedDoc.save();
|
|
3137
3183
|
if (allExtractedFields.length > 0) {
|