mirror of
https://github.com/documenso/documenso.git
synced 2026-07-11 05:25:08 +10:00
77 lines
2.0 KiB
TypeScript
77 lines
2.0 KiB
TypeScript
import type { FieldWithSignature } from '@documenso/prisma/types/field-with-signature';
|
|
import { PDF } from '@libpdf/core';
|
|
import { groupBy } from 'remeda';
|
|
|
|
import { insertFieldInPDFV2 } from './insert-field-in-pdf-v2';
|
|
|
|
type GeneratePartialSignedPdfOptions = {
|
|
pdfData: Uint8Array;
|
|
fields: FieldWithSignature[];
|
|
};
|
|
|
|
/**
|
|
* Generates a PDF with all currently-inserted fields burned in. Used to serve
|
|
* partially signed envelopes during the `PENDING` window before the seal job
|
|
* has had a chance to produce the final sealed PDF.
|
|
*
|
|
* No PKI signature, no certificate page, no audit log appendix - this is a
|
|
* preview of the in-progress envelope, not a final executed document.
|
|
*/
|
|
export const generatePartialSignedPdf = async ({ pdfData, fields }: GeneratePartialSignedPdfOptions) => {
|
|
const pdfDoc = await PDF.load(pdfData);
|
|
|
|
pdfDoc.flattenAll();
|
|
pdfDoc.upgradeVersion('1.7');
|
|
|
|
const fieldsGroupedByPage = groupBy(fields, (field) => field.page);
|
|
|
|
for (const [pageNumber, pageFields] of Object.entries(fieldsGroupedByPage)) {
|
|
const page = pdfDoc.getPage(Number(pageNumber) - 1);
|
|
|
|
if (!page) {
|
|
throw new Error(`Page ${pageNumber} does not exist`);
|
|
}
|
|
|
|
const pageWidth = page.width;
|
|
const pageHeight = page.height;
|
|
const overlayBytes = await insertFieldInPDFV2({
|
|
pageWidth,
|
|
pageHeight,
|
|
fields: pageFields,
|
|
});
|
|
|
|
const overlayPdf = await PDF.load(overlayBytes);
|
|
const embeddedPage = await pdfDoc.embedPage(overlayPdf, 0);
|
|
|
|
let translateX = 0;
|
|
let translateY = 0;
|
|
|
|
switch (page.rotation) {
|
|
case 90:
|
|
translateX = pageHeight;
|
|
translateY = 0;
|
|
break;
|
|
case 180:
|
|
translateX = pageWidth;
|
|
translateY = pageHeight;
|
|
break;
|
|
case 270:
|
|
translateX = 0;
|
|
translateY = pageWidth;
|
|
break;
|
|
}
|
|
|
|
page.drawPage(embeddedPage, {
|
|
x: translateX,
|
|
y: translateY,
|
|
rotate: {
|
|
angle: page.rotation,
|
|
},
|
|
});
|
|
}
|
|
|
|
pdfDoc.flattenAll();
|
|
|
|
return await pdfDoc.save({ useXRefStream: true });
|
|
};
|