Best way to add dynamic signature images (canvas / text / upload) to PDF after confirmation? #450
Hi 👋
I’m building a signature feature using embed-pdf-viewer and I’d like some guidance on the recommended way to programmatically add signature images to a PDF.
⸻
🔹 Interaction flow (important context)
The signature creation does NOT happen directly on the PDF.
Instead, the flow is:
1. User clicks "Sign" button
2. A modal dialog opens
3. Inside the modal, the user chooses one of three tabs:
• Draw signature (mouse / touch → canvas)
• Text signature (type text, switch between different artistic fonts → canvas)
• Upload image (PNG / JPG)
4. The user previews the result inside the modal
5. Only after clicking "Confirm / Apply", the signature is added to the PDF
So from the PDF viewer’s perspective, the final input is always:
an image generated at runtime (canvas or uploaded file)
⸻
🔹 What I’m trying to achieve
After the user clicks Confirm, I want to:
• Programmatically insert the generated image into the PDF
• Place it on a specific page (or let the user click to place it)
• Control size and position
• Each insertion may use a different image
This is conceptually similar to an image / stamp annotation, but with dynamic image content.
⸻
🔹 What I’ve tried / investigated
• Annotation tools (addTool)
• Works well for predefined tools
• But defaults.imageSrc appears to be static
• Not suitable when the image changes every time
• setActiveTool(toolId)
• Only toggles tools
• No way to pass runtime data (canvas / base64 image)
• I noticed APIs like:
• createAnnotation
• importAnnotations
These seem like the right direction, but I couldn’t find documentation or examples showing:
• Creating an image/stamp annotation programmatically
• Using a canvas or base64 image as the source
• Setting properties like pageIndex, position, and size
⸻
🔹 Questions
1. Is createAnnotation the recommended approach for adding a signature image after user confirmation?
2. Can a canvas or base64 image be used directly as the image source for a stamp/image annotation?
3. Is there a demo or example showing how to:
• Programmatically create image/stamp annotations
• Import annotations with custom image data
4. If this is not the intended usage, what would be the best practice for implementing a signature workflow like this?
Any guidance, examples, or demos would be greatly appreciated 🙏
Thanks for the great work on this project!
All reactions
Happy to announce that we released the signature plugin
For the headless documentation about the signature plugin you can read:
React Headless Signature Plugin
Vue Headless Signature Plugin
Svelte Headless Signature Plugin
For the full ui PDF viewer you can read:
React Full UI Viewer Signature Plugin
Vue Full UI Viewer Signature Plugin
Svelte Full UI Viewer Signature Plugin
Replies: 2 comments 2 replies
Hello,
I am trying to achieve the exact same goal as you (programmatic insertion of annotation as an image).
This works well for square objects (PdfSquareAnnoObject), but the stamp annotation does not seem to offer an imageSrc property. I am not sure how to proceed. Have you found a solution ?
Thanks
All reactions
I am currently working on a hack. Nothing else I've tried worked. The importAnnotations and createAnnotation methods support a context object which accepts an imageData object but that creates the annotation without rendering the image inside it unfortunately. I've been through the source code but to be honest I got lost in it and pnpm fails to install dependencies on my computer so I gave up on really trying to understand how it works internally.
The hack works as follow:
Add an ID to PagePointerProvider
<PagePointerProvider id="pagePointerProvider" :document-id="activeDocumentId" :page-index="page.pageIndex" :page-width="page.width" :page-height="page.height" >
During initialization, add a tool for each image I have (in my project, those are user signatures stored in their user preferences)
async function handleInitialized(registry: PluginRegistry) { // code for loading document is here, I've removed it to focus on the topic at hand const annotationCapability = registry .getPlugin<AnnotationPlugin>("annotation") ?.provides(); const userPrefStore = useUserPreferencesStore(); for (const signature of userPrefStore.signatureObjects) { annotationCapability?.addTool<AnnotationTool<PdfStampAnnoObject>>({ id: `pendingSignature-${signature.id}`, name: `Pending Signature ${signature.id}`, interaction: { exclusive: true }, matchScore: () => 0, behavior: { /*deactivateToolAfterCreate: true,*/ selectAfterCreate: true, }, defaults: { type: PdfAnnotationSubtype.STAMP, imageSrc: await userPrefStore.getSignatureLink(signature.id), }, }); } }
Elsewhere in my code, when a button is clicked, select the appropriate tool and dispatch a "pointerdown" event on the pagePointerProvider html element
async function placePendingSignature(id: number) { if (!props.registry) { return; } const annotationPlugin = props.registry .getPlugin<AnnotationPlugin>("annotation") ?.provides(); annotationPlugin?.setActiveTool(`pendingSignature-${id}`); const el = document.getElementById("pagePointerProvider"); el?.dispatchEvent( new MouseEvent("pointerdown", { clientX: 500, clientY: 500 }) // TODO ); }
Lastly, I've got an event listener on annotation events and I listen for event type === "create", then I do whatever my custom business logic has to do.
const off = annotationApi.value?.onAnnotationEvent(async (event) => { if ( event.type === "create" && event.annotation.type === PdfAnnotationSubtype.STAMP ) { // register new pending sign oject const activeTool = annotationApi.value?.getActiveTool(); if (!activeTool) { throw new Error("Something went wrong: No active tool detected"); } const signObjectId = Number( activeTool.id.replace("pendingSignature-", "") ); const pendingObject = new PendingSignature( () => annotationApi, () => scrollProvide, signObjectId, event.annotation // {} // TODO ); await pendingObject.init(); pendingSignatures.value = [...pendingSignatures.value, pendingObject]; } }) || noop;
All reactions
Happy to announce that we released the signature plugin
For the headless documentation about the signature plugin you can read:
React Headless Signature Plugin
Vue Headless Signature Plugin
Svelte Headless Signature Plugin
For the full ui PDF viewer you can read:
React Full UI Viewer Signature Plugin
Vue Full UI Viewer Signature Plugin
Svelte Full UI Viewer Signature Plugin
All reactions
Thanks 🙏
Is it possible with this new plugin to create a signature annotation programmaticaly without having to hack it by faking a MouseEvent ?
I can signatureCapability.addEntry() then signatureCapability.forDocument().activateSignaturePlacement() but I still have to click with the mouse (or by dispatching a MouseEvent) to place the signature annotation.
I would like to be able to place my signature using annotationScope.createAnnotation with the image used in signatureCapability.addEntry.