mirror of
https://github.com/snapotter-hq/SnapOtter.git
synced 2026-08-03 07:46:42 +02:00
feat: add Sign PDF tool (draw/type/upload signatures, place on a PDF) (#370)
Draw, type, or upload a signature and place resizable/rotatable copies across PDF pages; output flattened server-side with PyMuPDF. Visual electronic signature, not cryptographic. New interactive-sign display mode (pdf.js + Konva) and a custom docs-pool route.
This commit is contained in:
@@ -45,6 +45,7 @@ export {
|
||||
pdfMetadataSetPy,
|
||||
pdfPageCountPy,
|
||||
pdfRedactPy,
|
||||
pdfSignPy,
|
||||
pdfTextPy,
|
||||
pdfToWordPy,
|
||||
} from "./python-docs.js";
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { runDocsScript } from "@snapotter/ai";
|
||||
import type { SignPlacement } from "@snapotter/shared";
|
||||
|
||||
/** Page count via the docs-profile Python dispatcher (pikepdf). */
|
||||
export async function pdfPageCountPy(absPath: string): Promise<number> {
|
||||
@@ -119,3 +120,30 @@ export async function htmlToPdfPy(
|
||||
throw new Error(`doc_html_pdf failed: ${parsed.error}`);
|
||||
}
|
||||
}
|
||||
|
||||
/** Stamp signature images onto a PDF (PyMuPDF insert_image), flattened. */
|
||||
export async function pdfSignPy(
|
||||
inPath: string,
|
||||
outPath: string,
|
||||
signatures: string[],
|
||||
placements: SignPlacement[],
|
||||
): Promise<{ placed: number }> {
|
||||
const stdout = await runDocsScript("doc_sign", {
|
||||
input: inPath,
|
||||
output: outPath,
|
||||
signatures,
|
||||
placements,
|
||||
});
|
||||
const parsed = JSON.parse(stdout.trim()) as {
|
||||
ok?: boolean;
|
||||
placed?: number;
|
||||
error?: string;
|
||||
};
|
||||
if (parsed.error) {
|
||||
throw new Error(`doc_sign failed: ${parsed.error}`);
|
||||
}
|
||||
if (typeof parsed.placed !== "number") {
|
||||
throw new Error(`doc_sign failed: ${stdout.slice(0, 200)}`);
|
||||
}
|
||||
return { placed: parsed.placed };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user