📄 PDF Editor SDK

Complete PDF Editing Solution for Your Web Applications

📖 Overview

The PDF Editor SDK is a powerful, framework-agnostic solution that allows you to integrate a complete PDF editing experience into your web applications. Built on top of Fabric.js and Vue 3, it provides a rich set of features for manipulating PDF documents directly in the browser.

✨ Key Features

📝 Text Editing

Add, edit, and style text with full typography control

🖼️ Image Management

Insert, resize, and manipulate images

🎨 Shape Drawing

Create lines, rectangles, circles, and custom shapes

📊 QR & Barcodes

Generate QR codes and barcodes on the fly

✍️ Digital Signatures

Add signature images to documents

💧 Watermarks

Protect documents with custom watermarks

📤 Export Options

Export to PDF, PNG, or JPEG formats

📄 Multi-page Support

Work with multiple pages seamlessly

📦 Installation

⚠️ Private Library: This is a premium/private SDK. Distribution method may vary based on your licensing agreement.

Option 1: Direct File Integration

Copy the built library files to your project:

// Copy these files from dist/lib/ to your project
pdf-editor-sdk.es.js
pdf-editor-sdk.umd.js
pdf-editor-sdk.css
pdf-editor-sdk.d.ts

Option 2: Private NPM Registry

npm install @your-company/pdf-editor-sdk
# or
yarn add @your-company/pdf-editor-sdk

Option 3: Git Repository

npm install git+https://github.com/your-company/pdf-editor-sdk.git
# or add to package.json
{
  "dependencies": {
    "pdf-editor-sdk": "git+https://github.com/your-company/pdf-editor-sdk.git"
  }
}

Required Peer Dependencies

npm install vue@^3.4.0 pinia@^2.1.0
# or
yarn add vue@^3.4.0 pinia@^2.1.0
⚠️ Important for UMD Build: WHEN USING THE UMD BUILD (via script tag), you must load all peer dependencies in this specific order:
<!-- A. CSS -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/element-plus/dist/index.css">

<!-- B. JS Dependencies -->
<script src="https://cdn.jsdelivr.net/npm/vue@3.4.30/dist/vue.global.prod.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vue-demi@0.14.6/lib/index.iife.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/pinia@2.1.7/dist/pinia.iife.prod.js"></script>
<script src="https://cdn.jsdelivr.net/npm/element-plus/dist/index.full.min.js"></script>

<!-- C. PDF Editor SDK -->
<script src="./pdf-editor-sdk.umd.js"></script>

🚀 Quick Start

1. Import the SDK

import PDFEditorSDK from 'pdf-editor-sdk'
import 'pdf-editor-sdk/style.css'

2. Create a Container

<div id="editor-container" style="width: 100%; height: 600px;"></div>

3. Initialize the Editor

const editor = new PDFEditorSDK({
  container: '#editor-container',
  width: 800,
  height: 600,
  onReady: () => {
    console.log('Editor ready!')
  },
  onError: (error) => {
    console.error('Editor error:', error)
  }
})

// Load a PDF
await editor.loadPDF('/path/to/document.pdf')

// Add some text
editor.addText('Hello World', { 
  fontSize: 24,
  fontFamily: 'Arial'
})

// Export to PDF
const blob = await editor.exportToPDF()
// Download or upload the blob
✅ That's it! You now have a fully functional PDF editor in your application.

⚙️ Configuration Options

Option Type Default Description
container HTMLElement | string required Container element or CSS selector
width number 800 Canvas width in pixels
height number 600 Canvas height in pixels
theme 'light' | 'dark' 'light' Color theme
locale 'en' | 'vi' | 'zh' 'en' Language
initialPDF string | File | ArrayBuffer undefined PDF to load on init
wasmUrl string undefined URL to pdfcore.wasm file (required)
features object all enabled Enable/disable features
onReady function undefined Called when ready
onExport function undefined Called on export
onError function undefined Called on error

Features Configuration

const editor = new PDFEditorSDK({
  container: '#editor',
  features: {
    text: true,      // Enable text editing
    image: true,     // Enable image insertion
    shape: true,     // Enable shape drawing
    qrcode: true,    // Enable QR codes
    barcode: true,   // Enable barcodes
    signature: false, // Disable signatures
    watermark: false  // Disable watermarks
  }
})

📚 API Reference

Canvas Control

getCanvas(): Canvas | null

Returns the underlying Fabric.js canvas instance for advanced manipulation.

const canvas = editor.getCanvas()
if (canvas) {
  canvas.setBackgroundColor('#f0f0f0', canvas.renderAll.bind(canvas))
}

setZoom(zoom: number): void

Set the canvas zoom level (1 = 100%).

editor.setZoom(1.5) // 150% zoom

getZoom(): number

Get the current zoom level.

const currentZoom = editor.getZoom()

fitToScreen(): void

Automatically fit the canvas to the container size.

editor.fitToScreen()

Element Creation

addText(text?: string, options?: TextOptions): void

Add a text element to the canvas.

editor.addText('My Text', {
  fontSize: 32,
  fontFamily: 'Helvetica',
  fontWeight: 'bold',
  fill: '#333333',
  opacity: 1
})

addImage(url: string, options?: ImageOptions): void

Add an image from a URL.

editor.addImage('/path/to/image.jpg', {
  scaleX: 0.5,
  scaleY: 0.5,
  opacity: 0.8
})

addQRCode(content: string, options?: QRCodeOptions): void

Generate and add a QR code.

editor.addQRCode('https://example.com', {
  size: 200,
  errorCorrectionLevel: 'H'
})

addBarCode(content: string, options?: BarCodeOptions): void

Generate and add a barcode.

editor.addBarCode('123456789', {
  format: 'CODE128',
  displayValue: true
})

addWatermark(text: string, options?: TextOptions): void

Add a semi-transparent watermark.

editor.addWatermark('CONFIDENTIAL', {
  fontSize: 72,
  opacity: 0.2,
  fill: '#ff0000'
})

Element Manipulation

deleteSelected(): void

Delete currently selected element(s).

duplicateSelected(): void

Duplicate currently selected element(s).

selectAll(): void

Select all elements on the canvas.

clearSelection(): void

Deselect all elements.

editor.selectAll()
editor.duplicateSelected()
editor.clearSelection()

PDF Operations

loadPDF(file: File | ArrayBuffer | string): Promise<void>

Load a PDF file from various sources.

// From URL
await editor.loadPDF('/documents/sample.pdf')

// From File input
const fileInput = document.querySelector('input[type="file"]')
fileInput.addEventListener('change', async (e) => {
  const file = e.target.files[0]
  await editor.loadPDF(file)
})

getPageCount(): number

Get the total number of pages.

goToPage(pageNumber: number): void

Navigate to a specific page (1-indexed).

addPage(): void

Add a new blank page.

deletePage(pageNumber: number): void

Delete a specific page.

const totalPages = editor.getPageCount()
console.log(`Total pages: ${totalPages}`)

editor.goToPage(2) // Go to page 2
editor.addPage()   // Add new page

Export Methods

exportToPDF(options?: ExportOptions): Promise<Blob>

Export the document as PDF.

const pdfBlob = await editor.exportToPDF({
  pages: 'all', // 'all', 'current', or [1, 2, 3]
  quality: 1,
  dpi: 300
})

// Download the PDF
const url = URL.createObjectURL(pdfBlob)
const a = document.createElement('a')
a.href = url
a.download = 'document.pdf'
a.click()

exportToPNG(options?: ExportOptions): Promise<Blob>

Export as PNG image.

const pngBlob = await editor.exportToPNG({
  quality: 1,
  dpi: 150
})

exportToJPEG(options?: ExportOptions): Promise<Blob>

Export as JPEG image.

const jpegBlob = await editor.exportToJPEG({
  quality: 0.9,
  dpi: 72
})

Lifecycle Methods

mount(): void

Mount the editor to the DOM (if unmounted).

unmount(): void

Unmount the editor from the DOM without destroying it.

destroy(): void

Completely destroy the editor and cleanup resources.

// Cleanup on component unmount
onBeforeUnmount(() => {
  editor.destroy()
})

💡 Integration Examples

Vanilla JavaScript

<!DOCTYPE html>
<html>
<head>
  <link rel="stylesheet" href="pdf-editor-sdk.css">
</head>
<body>
  <div id="editor"></div>

  <!-- Load peer dependencies first -->
  <script src="https://cdn.jsdelivr.net/npm/vue@3.4.30/dist/vue.global.prod.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/pinia@2.1.7/dist/pinia.iife.prod.js"></script>

  <!-- Load SDK (UMD build for browser) -->
  <script src="./pdf-editor-sdk.umd.js"></script>

  <script>
    // Access SDK from global variable
    const PDFEditorSDK = window.PDFEditorSDK?.default || window.PDFEditorSDK
    
    const editor = new PDFEditorSDK({
      container: '#editor',
      width: 800,
      height: 600,
      onReady: () => {
        console.log('Ready!')
      }
    })
  </script>
</body>
</html>

Vue 3 Composition API

<template>
  <div>
    <div ref="editorContainer"></div>
    <button @click="addText">Add Text</button>
    <button @click="exportPDF">Export PDF</button>
  </div>
</template>

<script setup>
import { ref, onMounted, onBeforeUnmount } from 'vue'
import PDFEditorSDK from 'pdf-editor-sdk'
import 'pdf-editor-sdk/style.css'

const editorContainer = ref(null)
let editor = null

onMounted(() => {
  editor = new PDFEditorSDK({
    container: editorContainer.value,
    width: 800,
    height: 600
  })
})

const addText = () => {
  editor?.addText('Hello from Vue!')
}

const exportPDF = async () => {
  const blob = await editor?.exportToPDF()
  // Handle blob...
}

onBeforeUnmount(() => {
  editor?.destroy()
})
</script>

React

import React, { useEffect, useRef } from 'react'
import PDFEditorSDK from 'pdf-editor-sdk'
import 'pdf-editor-sdk/style.css'

function PDFEditor() {
  const containerRef = useRef(null)
  const editorRef = useRef(null)

  useEffect(() => {
    if (containerRef.current) {
      editorRef.current = new PDFEditorSDK({
        container: containerRef.current,
        width: 800,
        height: 600
      })
    }

    return () => {
      editorRef.current?.destroy()
    }
  }, [])

  const handleAddText = () => {
    editorRef.current?.addText('Hello from React!')
  }

  return (
    <div>
      <div ref={containerRef}></div>
      <button onClick={handleAddText}>Add Text</button>
    </div>
  )
}

export default PDFEditor

File Upload Integration

<input type="file" id="pdfUpload" accept=".pdf">

<script>
document.getElementById('pdfUpload')
  .addEventListener('change', async (e) => {
    const file = e.target.files[0]
    if (file) {
      try {
        await editor.loadPDF(file)
        console.log('PDF loaded successfully')
      } catch (error) {
        console.error('Error loading PDF:', error)
      }
    }
  })
</script>

🎨 Styling & Customization

Custom Container Styles

You can style the editor container to fit your application's design:

.pdf-editor-wrapper {
  border: 2px solid #e5e7eb;
  border-radius: 12px;
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
  background: #ffffff;
}

.pdf-editor-wrapper canvas {
  cursor: crosshair;
}

Dark Theme

Apply dark theme styles:

const editor = new PDFEditorSDK({
  container: '#editor',
  theme: 'dark'
})

/* Custom dark theme CSS */
.pdf-editor-wrapper[data-theme="dark"] {
  background: #1f2937;
  color: #f3f4f6;
}

Responsive Design

<style>
@media (max-width: 768px) {
  .pdf-editor-wrapper {
    width: 100% !important;
    height: 100vh !important;
  }
}
</style>

<script>
// Auto-resize on window resize
window.addEventListener('resize', () => {
  editor.fitToScreen()
})
</script>

🔧 Troubleshooting

Common Issues

Issue: "Container element not found"

Solution: Ensure the container element exists in the DOM before initializing the SDK. If using a framework, make sure to initialize in the mounted/useEffect hook.

Issue: Canvas not rendering

Solution: Check that you've imported the CSS file and that the container has a defined width and height.

Issue: PDF not loading

Solution: Verify the PDF file is accessible (not blocked by CORS). For cross-origin PDFs, ensure proper CORS headers are set on the server.

Issue: Export not working

Solution: Wait for the editor to be ready (use onReady callback) before calling export methods. Large documents may take time to process.

Browser Compatibility

Browser Version Support
Chrome 90+ ✅ Full Support
Firefox 88+ ✅ Full Support
Safari 14+ ✅ Full Support
Edge 90+ ✅ Full Support

Performance Tips

  • For large PDFs (\u003e100 pages), consider implementing pagination
  • Optimize images before adding them to the canvas
  • Use lower DPI for screen display (72-96), higher for print (300)
  • Call destroy() when unmounting to prevent memory leaks
  • Debounce canvas events for better performance

Debug Mode

// Access internal canvas for debugging
const canvas = editor.getCanvas()
console.log('Canvas objects:', canvas.getObjects())
console.log('Active object:', canvas.getActiveObject())

// Listen to canvas events
canvas.on('object:added', (e) => {
  console.log('Object added:', e.target)
})
💡 Need Help? For additional support or custom integration assistance, please contact your account manager or refer to the source code documentation.