Merge branch 'main' into feat/change-radio-direction

This commit is contained in:
Ephraim Atta-Duncan
2025-10-20 14:03:51 +00:00
441 changed files with 27799 additions and 8936 deletions

View File

@ -1,6 +1,6 @@
import type { PDFDocument } from '@cantoo/pdf-lib';
import { TextAlignment, rgb, setFontAndSize } from '@cantoo/pdf-lib';
import fontkit from '@pdf-lib/fontkit';
import type { PDFDocument } from 'pdf-lib';
import { TextAlignment, rgb, setFontAndSize } from 'pdf-lib';
import { NEXT_PUBLIC_WEBAPP_URL } from '../../constants/app';
import { getPageSize } from './get-page-size';

View File

@ -1,4 +1,4 @@
import { PDFAnnotation, PDFRef } from 'pdf-lib';
import { PDFAnnotation, PDFRef } from '@cantoo/pdf-lib';
import {
PDFDict,
type PDFDocument,
@ -8,7 +8,7 @@ import {
pushGraphicsState,
rotateInPlace,
translate,
} from 'pdf-lib';
} from '@cantoo/pdf-lib';
export const flattenAnnotations = (document: PDFDocument) => {
const pages = document.getPages();

View File

@ -1,5 +1,4 @@
import fontkit from '@pdf-lib/fontkit';
import type { PDFField, PDFWidgetAnnotation } from 'pdf-lib';
import type { PDFField, PDFWidgetAnnotation } from '@cantoo/pdf-lib';
import {
PDFCheckBox,
PDFDict,
@ -12,7 +11,8 @@ import {
pushGraphicsState,
rotateInPlace,
translate,
} from 'pdf-lib';
} from '@cantoo/pdf-lib';
import fontkit from '@pdf-lib/fontkit';
import { NEXT_PUBLIC_WEBAPP_URL } from '../../constants/app';

View File

@ -1,4 +1,4 @@
import type { PDFPage } from 'pdf-lib';
import type { PDFPage } from '@cantoo/pdf-lib';
/**
* Gets the effective page size for PDF operations.

View File

@ -1,7 +1,5 @@
// https://github.com/Hopding/pdf-lib/issues/20#issuecomment-412852821
import fontkit from '@pdf-lib/fontkit';
import { FieldType } from '@prisma/client';
import type { PDFDocument, PDFFont, PDFTextField } from 'pdf-lib';
import type { PDFDocument, PDFFont, PDFTextField } from '@cantoo/pdf-lib';
import {
RotationTypes,
TextAlignment,
@ -9,7 +7,9 @@ import {
radiansToDegrees,
rgb,
setFontAndSize,
} from 'pdf-lib';
} from '@cantoo/pdf-lib';
import fontkit from '@pdf-lib/fontkit';
import { FieldType } from '@prisma/client';
import { P, match } from 'ts-pattern';
import {
@ -35,7 +35,7 @@ import {
} from '../../types/field-meta';
import { getPageSize } from './get-page-size';
export const insertFieldInPDF = async (pdf: PDFDocument, field: FieldWithSignature) => {
export const insertFieldInPDFV1 = async (pdf: PDFDocument, field: FieldWithSignature) => {
const [fontCaveat, fontNoto] = await Promise.all([
fetch(`${NEXT_PUBLIC_WEBAPP_URL()}/fonts/caveat.ttf`).then(async (res) => res.arrayBuffer()),
fetch(`${NEXT_PUBLIC_WEBAPP_URL()}/fonts/noto-sans.ttf`).then(async (res) => res.arrayBuffer()),

View File

@ -0,0 +1,133 @@
import type { PDFDocument } from '@cantoo/pdf-lib';
import { RotationTypes, radiansToDegrees } from '@cantoo/pdf-lib';
import fontkit from '@pdf-lib/fontkit';
import Konva from 'konva';
import 'konva/skia-backend';
import fs from 'node:fs';
import type { Canvas } from 'skia-canvas';
import { match } from 'ts-pattern';
import { isSignatureFieldType } from '@documenso/prisma/guards/is-signature-field';
import type { FieldWithSignature } from '@documenso/prisma/types/field-with-signature';
import { NEXT_PUBLIC_WEBAPP_URL } from '../../constants/app';
import { renderField } from '../../universal/field-renderer/render-field';
import { getPageSize } from './get-page-size';
// const font = await pdf.embedFont(
// isSignatureField ? fontCaveat : fontNoto,
// isSignatureField ? { features: { calt: false } } : undefined,
// );
// const minFontSize = isSignatureField ? MIN_HANDWRITING_FONT_SIZE : MIN_STANDARD_FONT_SIZE;
// const maxFontSize = isSignatureField ? DEFAULT_HANDWRITING_FONT_SIZE : DEFAULT_STANDARD_FONT_SIZE;
export const insertFieldInPDFV2 = async (pdf: PDFDocument, field: FieldWithSignature) => {
const [fontCaveat, fontNoto] = await Promise.all([
fetch(`${NEXT_PUBLIC_WEBAPP_URL()}/fonts/caveat.ttf`).then(async (res) => res.arrayBuffer()),
fetch(`${NEXT_PUBLIC_WEBAPP_URL()}/fonts/noto-sans.ttf`).then(async (res) => res.arrayBuffer()),
]);
const isSignatureField = isSignatureFieldType(field.type);
pdf.registerFontkit(fontkit);
const pages = pdf.getPages();
const page = pages.at(field.page - 1);
if (!page) {
throw new Error(`Page ${field.page} does not exist`);
}
const pageRotation = page.getRotation();
let pageRotationInDegrees = match(pageRotation.type)
.with(RotationTypes.Degrees, () => pageRotation.angle)
.with(RotationTypes.Radians, () => radiansToDegrees(pageRotation.angle))
.exhaustive();
// Round to the closest multiple of 90 degrees.
pageRotationInDegrees = Math.round(pageRotationInDegrees / 90) * 90;
const isPageRotatedToLandscape = pageRotationInDegrees === 90 || pageRotationInDegrees === 270;
// Todo: Evenloeps - getPageSize this had extra logic? Ask lucas
console.log({
cropBox: page.getCropBox(),
mediaBox: page.getMediaBox(),
mediaBox2: page.getSize(),
});
const { width: pageWidth, height: pageHeight } = getPageSize(page);
// PDFs can have pages that are rotated, which are correctly rendered in the frontend.
// However when we load the PDF in the backend, the rotation is applied.
//
// To account for this, we swap the width and height for pages that are rotated by 90/270
// degrees. This is so we can calculate the virtual position the field was placed if it
// was correctly oriented in the frontend.
//
// Then when we insert the fields, we apply a transformation to the position of the field
// so it is rotated correctly.
if (isPageRotatedToLandscape) {
// [pageWidth, pageHeight] = [pageHeight, pageWidth];
}
console.log({
pageWidth,
pageHeight,
fieldWidth: field.width,
fieldHeight: field.height,
});
const stage = new Konva.Stage({ width: pageWidth, height: pageHeight });
const layer = new Konva.Layer();
// Will render onto the layer.
renderField({
field: {
renderId: field.id.toString(),
...field,
width: Number(field.width),
height: Number(field.height),
positionX: Number(field.positionX),
positionY: Number(field.positionY),
},
pageLayer: layer,
pageWidth,
pageHeight,
mode: 'export',
});
stage.add(layer);
const canvas = layer.canvas._canvas as unknown as Canvas;
const renderedField = await canvas.toBuffer('svg');
fs.writeFileSync(
`rendered-field-${field.envelopeId}--${field.id}.svg`,
renderedField.toString('utf-8'),
);
// Embed the SVG into the PDF
const svgElement = await pdf.embedSvg(renderedField.toString('utf-8'));
// Calculate position to cover the whole page
// pdf-lib coordinates: (0,0) is bottom-left, y increases upward
const svgWidth = pageWidth; // Use full page width
const svgHeight = pageHeight; // Use full page height
const x = 0; // Start from left edge
const y = pageHeight; // Start from bottom edge
// Draw the SVG on the page
page.drawSvg(svgElement, {
x: x,
y: y,
width: svgWidth,
height: svgHeight,
});
return pdf;
};

View File

@ -1,4 +1,10 @@
import { PDFCheckBox, PDFDocument, PDFDropdown, PDFRadioGroup, PDFTextField } from 'pdf-lib';
import {
PDFCheckBox,
PDFDocument,
PDFDropdown,
PDFRadioGroup,
PDFTextField,
} from '@cantoo/pdf-lib';
export type InsertFormValuesInPdfOptions = {
pdf: Buffer;

View File

@ -1,4 +1,4 @@
import { PDFDocument } from 'pdf-lib';
import { PDFDocument } from '@cantoo/pdf-lib';
export async function insertImageInPDF(
pdfAsBase64: string,

View File

@ -1,5 +1,5 @@
import { PDFDocument, StandardFonts, rgb } from '@cantoo/pdf-lib';
import fontkit from '@pdf-lib/fontkit';
import { PDFDocument, StandardFonts, rgb } from 'pdf-lib';
import { CAVEAT_FONT_PATH } from '../../constants/pdf';

View File

@ -1,8 +1,8 @@
// https://github.com/Hopding/pdf-lib/issues/20#issuecomment-412852821
import type { PDFDocument } from '@cantoo/pdf-lib';
import { RotationTypes, degrees, radiansToDegrees, rgb } from '@cantoo/pdf-lib';
import fontkit from '@pdf-lib/fontkit';
import { FieldType } from '@prisma/client';
import type { PDFDocument } from 'pdf-lib';
import { RotationTypes, degrees, radiansToDegrees, rgb } from 'pdf-lib';
import { P, match } from 'ts-pattern';
import {

View File

@ -1,4 +1,4 @@
import { PDFDocument } from 'pdf-lib';
import { PDFDocument } from '@cantoo/pdf-lib';
import { flattenAnnotations } from './flatten-annotations';
import { flattenForm, removeOptionalContentGroups } from './flatten-form';

View File

@ -1,5 +1,5 @@
import type { PDFDocument } from 'pdf-lib';
import { PDFSignature, rectangle } from 'pdf-lib';
import type { PDFDocument } from '@cantoo/pdf-lib';
import { PDFSignature, rectangle } from '@cantoo/pdf-lib';
export const normalizeSignatureAppearances = (document: PDFDocument) => {
const form = document.getForm();