0
PDFs Processed
โ†‘ This session
0
Total Pages
โ†‘ All time
0
Edits Made
โ†‘ Active
100%
Privacy Score
โ†‘ Local Only
Open PDF
View & edit any PDF
Create PDF
From scratch or images
Convert
PDF โ†” Word/Excel/Img
OCR Scan
Extract text from images
Organize
Merge, split, reorder
Sign & Protect
Digital signatures

Recent Files

Your recently opened PDFs (stored locally)

No recent files

Open a PDF to get started. All files are processed locally on your device.

No PDF Open

Open a PDF file to view, annotate, and edit it.

Text Edit
Images
Links
Watermark
Redact
Text Editing
Edit text directly in your PDF. Open a PDF in the viewer first.
Image Operations
Add, replace, or remove images from your PDF.
Select an image to embed
Watermark
Add text or image watermarks to your PDF pages.
CONFIDENTIAL

Sample Document Content

Redaction Tool
Permanently remove sensitive information. Open a PDF in the viewer and draw redaction boxes.
โ†’ PDF to Word
โ†’ Word to PDF
โ†’ PDF to Image
โ†’ Image to PDF
Create PDF
PDF to Word Converter
Extract text and structure from PDF to editable Word document.

Drop PDF here or click to browse

Converts to .docx format with preserved formatting

Word to PDF Converter
Convert Word documents to PDF format.

Drop Word file here or click to browse

Supports .docx and .txt files

PDF to Image
Convert PDF pages to PNG or JPEG images.

Drop PDF here or click to browse

Export all pages as high-quality images

Image to PDF
Combine multiple images into a single PDF.

Drop images here or click to browse

Select multiple images to combine into PDF

Create PDF from Scratch
Build a PDF document with custom content.
OCR Scanner
Extract text from scanned PDFs and images using Tesseract.js (runs locally in browser).

Drop scanned PDF or image here

Extract text from scanned documents and images

Merge PDFs
Split PDF
Reorder Pages
Rotate Pages
Extract Pages
Merge PDFs
Combine multiple PDF files into one.

Drop PDFs here to merge

Drag and drop multiple PDF files. Reorder by dragging.

Split PDF
Split a PDF into multiple files by page ranges.

Drop PDF to split

Select a PDF and specify page ranges

Reorder Pages
Drag and drop pages to reorder them. Open a PDF first.
Rotate Pages
Rotate individual pages or all pages at once.
Extract Pages
Extract specific pages into a new PDF.
Fill Forms
Create Form
Flatten Form
Fill PDF Forms
Open a PDF with form fields to fill them out.
Create Interactive Form
Add form fields to your PDF: text boxes, checkboxes, radio buttons, dropdowns.
Flatten Form
Convert form fields to static content so they cannot be edited.
Digital Signature
Protect PDF
๐Ÿ“œ Certify
๐Ÿ”“ Remove Password
Digital Signature
Draw your signature or type it to sign documents.
Draw Signature
Type Signature
๐Ÿ“
Upload Image

Saved Signatures

Protect PDF
Add password protection and encryption to your PDF.
Certify PDF
Add a certification stamp to verify document authenticity.
Remove Password
Remove password protection from a PDF file. You must know the current password to unlock it.
๐Ÿ”“

Drop locked PDF here

Select a password-protected PDF file

Batch Processing
Process multiple files at once with the same operation.

Drop files here for batch processing

Select multiple files to process simultaneously

Hello! I'm your PDF AI Assistant.

I can help you with:
โ€ข Summarizing PDF content
โ€ข Extracting key information
โ€ข Answering questions about your documents
โ€ข Generating insights and analysis
โ€ข Translating text

Open a PDF first, then ask me anything about it!
Extract Text
Extract Tables
Extract Images
๐Ÿ“‹ Metadata
Extract All Text
Extract all text content from your PDF.
Extract Tables
Detect and extract tables from your PDF.
Extract Images
Extract all embedded images from your PDF.
Document Metadata
View and edit PDF metadata.
Processing...
'; const blob = new Blob([htmlContent], { type: 'application/msword' }); saveAs(blob, file.name.replace('.pdf', '.doc')); document.getElementById('pdf2docResult').innerHTML = `
โœ…
Converted Successfully
Downloaded as .doc file
`; showToast('success', 'Converted', 'PDF converted to Word document'); } catch(err) { showToast('error', 'Error', err.message); } finally { hideProgress(); } } async function convertDocToPdf(event) { const file = event.target.files[0]; if (!file) return; showProgress('Converting to PDF...'); try { const text = await file.text(); const { jsPDF } = window.jspdf; const doc = new jsPDF(); const lines = doc.splitTextToSize(text, 180); let y = 20; lines.forEach(line => { if (y > 280) { doc.addPage(); y = 20; } doc.text(line, 15, y); y += 7; }); doc.save(file.name.replace(/\.(docx?|txt|html)$/i, '.pdf')); document.getElementById('doc2pdfResult').innerHTML = `
โœ…
Converted Successfully
Downloaded as PDF
`; showToast('success', 'Converted', 'File converted to PDF'); } catch(err) { showToast('error', 'Error', err.message); } finally { hideProgress(); } } async function convertPdfToImages(event) { const file = event.target.files[0]; if (!file) return; showProgress('Converting PDF pages to images...'); try { const arrayBuffer = await file.arrayBuffer(); const pdf = await pdfjsLib.getDocument({ data: arrayBuffer }).promise; const format = document.getElementById('imgFormat').value; const quality = parseInt(document.getElementById('imgQuality').value); const zip = new JSZip(); for (let i = 1; i <= pdf.numPages; i++) { updateProgressSub(`Rendering page ${i} of ${pdf.numPages}`); const page = await pdf.getPage(i); const viewport = page.getViewport({ scale: quality }); const canvas = document.createElement('canvas'); canvas.width = viewport.width; canvas.height = viewport.height; await page.render({ canvasContext: canvas.getContext('2d'), viewport }).promise; const dataUrl = canvas.toDataURL(`image/${format}`); const base64 = dataUrl.split(',')[1]; zip.file(`page_${i}.${format}`, base64, { base64: true }); } const blob = await zip.generateAsync({ type: 'blob' }); saveAs(blob, file.name.replace('.pdf', '_images.zip')); document.getElementById('pdf2imgResult').innerHTML = `
โœ…
${pdf.numPages} pages converted
Downloaded as ZIP archive
`; showToast('success', 'Done', `${pdf.numPages} pages exported as ${format.toUpperCase()}`); } catch(err) { showToast('error', 'Error', err.message); } finally { hideProgress(); } } async function convertImagesToPdf(event) { const files = Array.from(event.target.files); if (!files.length) return; showProgress('Creating PDF from images...'); try { const pdfDoc = await PDFLib.PDFDocument.create(); for (let i = 0; i < files.length; i++) { updateProgressSub(`Adding image ${i+1} of ${files.length}`); const arrayBuffer = await files[i].arrayBuffer(); const bytes = new Uint8Array(arrayBuffer); let img; if (files[i].type === 'image/png') { img = await pdfDoc.embedPng(bytes); } else { img = await pdfDoc.embedJpg(bytes); } const page = pdfDoc.addPage([img.width, img.height]); page.drawImage(img, { x: 0, y: 0, width: img.width, height: img.height }); } const pdfBytes = await pdfDoc.save(); const blob = new Blob([pdfBytes], { type: 'application/pdf' }); saveAs(blob, 'combined_images.pdf'); document.getElementById('img2pdfResult').innerHTML = `
โœ…
${files.length} images combined
Downloaded as combined_images.pdf
`; showToast('success', 'Done', `${files.length} images merged into PDF`); } catch(err) { showToast('error', 'Error', err.message); } finally { hideProgress(); } } async function createPdfFromScratch() { const title = document.getElementById('createTitle').value || 'New Document'; const content_text = document.getElementById('createContent').value || 'Your content here.'; const pageSize = document.getElementById('createPageSize').value; showProgress('Creating PDF...'); try { const { jsPDF } = window.jspdf; const orientation = document.getElementById('createOrientation').value === 'landscape' ? 'l' : 'p'; const format = pageSize.toLowerCase(); const doc = new jsPDF({ orientation, unit: 'mm', format }); doc.setFontSize(20); doc.setFont(undefined, 'bold'); doc.text(title, 15, 20); doc.setFontSize(12); doc.setFont(undefined, 'normal'); const lines = doc.splitTextToSize(content_text, 180); let y = 35; lines.forEach(line => { if (y > 270) { doc.addPage(); y = 20; } doc.text(line, 15, y); y += 7; }); doc.save(title.replace(/\s+/g,'_') + '.pdf'); showToast('success', 'Created', `PDF created: ${title}`); } catch(err) { showToast('error', 'Error', err.message); } finally { hideProgress(); } } async function runOCR(event) { const file = event.target.files[0]; if (!file) return; showProgress('Running OCR... (this may take a minute)'); try { const lang = document.getElementById('ocrLang').value; let imageSource; if (file.type === 'application/pdf') { const arrayBuffer = await file.arrayBuffer(); const pdf = await pdfjsLib.getDocument({ data: arrayBuffer }).promise; const page = await pdf.getPage(1); const viewport = page.getViewport({ scale: 2 }); const canvas = document.createElement('canvas'); canvas.width = viewport.width; canvas.height = viewport.height; await page.render({ canvasContext: canvas.getContext('2d'), viewport }).promise; imageSource = canvas.toDataURL(); } else { imageSource = await readFileAsDataURL(file); } updateProgressSub('Recognizing text...'); const result = await Tesseract.recognize(imageSource, lang, { logger: m => { if(m.status) updateProgressSub(m.status + ' ' + Math.round((m.progress||0)*100) + '%'); } }); document.getElementById('ocrResult').innerHTML = `
${escapeHtml(result.data.text)}
`; showToast('success', 'OCR Complete', `${result.data.text.length} characters extracted`); } catch(err) { showToast('error', 'OCR Error', err.message); } finally { hideProgress(); } } function handleSplitFile(event) { const file = event.target.files[0]; if (!file) return; currentFileName = file.name; file.arrayBuffer().then(async buf => { currentPdfDoc = await PDFLib.PDFDocument.load(buf); currentPdf = await pdfjsLib.getDocument({ data: buf }).promise; totalPages = currentPdf.numPages; document.getElementById('splitControls').style.display = 'block'; showToast('info', 'Ready', `${file.name} loaded (${totalPages} pages). Enter ranges to split.`); }).catch(err => showToast('error', 'Error', err.message)); } async function splitPdf() { if (!currentPdfDoc) { showToast('warning','No PDF','Load a PDF first'); return; } const rangesStr = document.getElementById('splitRanges').value; if (!rangesStr) { showToast('warning','No Ranges','Enter page ranges like 1-3,5'); return; } showProgress('Splitting PDF...'); try { const ranges = rangesStr.split(',').map(r => r.trim()); for (const range of ranges) { const newDoc = await PDFLib.PDFDocument.create(); let pages = []; if (range.includes('-')) { const [start, end] = range.split('-').map(n => parseInt(n) - 1); for (let i = start; i <= end && i < currentPdfDoc.getPageCount(); i++) pages.push(i); } else { pages.push(parseInt(range) - 1); } const copied = await newDoc.copyPages(currentPdfDoc, pages); copied.forEach(p => newDoc.addPage(p)); const bytes = await newDoc.save(); saveAs(new Blob([bytes], { type: 'application/pdf' }), `${currentFileName.replace('.pdf','')}_pages_${range}.pdf`); } showToast('success', 'Split Complete', `${ranges.length} file(s) created`); } catch(err) { showToast('error','Error', err.message); } finally { hideProgress(); } } function handleMergeDrop(event) { event.preventDefault(); event.stopPropagation(); event.currentTarget.classList.remove('dragover'); handleMergeFiles({ target: { files: event.dataTransfer.files }}); } let mergeFiles = []; function handleMergeFiles(event) { const files = Array.from(event.target.files); mergeFiles = [...mergeFiles, ...files]; const list = document.getElementById('mergeList'); list.innerHTML = mergeFiles.map((f, i) => `
โ ฟ ${f.name}
`).join(''); document.getElementById('mergeBtn').disabled = mergeFiles.length < 2; } async function mergePdfs() { if (mergeFiles.length < 2) { showToast('warning','Need Files','Add at least 2 PDFs'); return; } showProgress('Merging PDFs...'); try { const merged = await PDFLib.PDFDocument.create(); for (let i = 0; i < mergeFiles.length; i++) { updateProgressSub(`Processing ${mergeFiles[i].name} (${i+1}/${mergeFiles.length})`); const bytes = await mergeFiles[i].arrayBuffer(); const doc = await PDFLib.PDFDocument.load(bytes); const pages = await merged.copyPages(doc, doc.getPageIndices()); pages.forEach(p => merged.addPage(p)); } const bytes = await merged.save(); saveAs(new Blob([bytes], { type:'application/pdf' }), 'merged.pdf'); showToast('success', 'Merged', `${mergeFiles.length} PDFs merged successfully`); mergeFiles = []; document.getElementById('mergeList').innerHTML = ''; document.getElementById('mergeBtn').disabled = true; } catch(err) { showToast('error','Merge Failed', err.message); } finally { hideProgress(); } } async function rotatePages() { if (!currentPdfDoc) { showToast('warning','No PDF','Open a PDF first'); return; } const angle = parseInt(document.getElementById('rotateAngle').value); const pagesStr = document.getElementById('rotatePages').value; showProgress('Rotating pages...'); try { const allPages = currentPdfDoc.getPages(); let targetPages = []; if (!pagesStr || pagesStr.toLowerCase() === 'all') { targetPages = allPages; } else { pagesStr.split(',').forEach(p => { const n = parseInt(p.trim()) - 1; if (n >= 0 && n < allPages.length) targetPages.push(allPages[n]); }); } targetPages.forEach(page => { const current = page.getRotation().angle; page.setRotation(PDFLib.degrees((current + angle) % 360)); }); const bytes = await currentPdfDoc.save(); currentPdfBytes = bytes; currentPdf = await pdfjsLib.getDocument({ data: bytes }).promise; await renderPage(currentPage); showToast('success','Rotated', `${targetPages.length} page(s) rotated ${angle}ยฐ`); sessionStats.edits++; updateStats(); } catch(err) { showToast('error','Error', err.message); } finally { hideProgress(); } } async function extractPages() { if (!currentPdfDoc) { showToast('warning','No PDF','Open a PDF first'); return; } const pagesStr = document.getElementById('extractPages').value; if (!pagesStr) { showToast('warning','No Pages','Enter page numbers'); return; } showProgress('Extracting pages...'); try { const newDoc = await PDFLib.PDFDocument.create(); let pageNums = []; pagesStr.split(',').forEach(part => { part = part.trim(); if (part.includes('-')) { const [s, e] = part.split('-').map(n => parseInt(n) - 1); for (let i = s; i <= e; i++) pageNums.push(i); } else { pageNums.push(parseInt(part) - 1); } }); const copied = await newDoc.copyPages(currentPdfDoc, pageNums.filter(n => n >= 0 && n < currentPdfDoc.getPageCount())); copied.forEach(p => newDoc.addPage(p)); const bytes = await newDoc.save(); saveAs(new Blob([bytes], { type:'application/pdf' }), `${currentFileName.replace('.pdf','')}_extracted.pdf`); showToast('success','Extracted', `${copied.length} pages extracted`); } catch(err) { showToast('error','Error', err.message); } finally { hideProgress(); } } async function saveReorderedPdf() { if (!currentPdfDoc) { showToast('warning','No PDF','Open a PDF first'); return; } showProgress('Saving reordered PDF...'); try { const bytes = await currentPdfDoc.save(); saveAs(new Blob([bytes], { type:'application/pdf' }), `${currentFileName.replace('.pdf','')}_reordered.pdf`); showToast('success','Saved','Reordered PDF downloaded'); } catch(err) { showToast('error','Error', err.message); } finally { hideProgress(); } } async function addFormField() { showToast('info','Form Fields','Form field placement requires PDF editing mode - open a PDF first'); } async function flattenForm() { if (!currentPdfDoc) { showToast('warning','No PDF','Open a PDF first'); return; } showProgress('Flattening form...'); try { const form = currentPdfDoc.getForm(); form.flatten(); const bytes = await currentPdfDoc.save(); saveAs(new Blob([bytes], { type:'application/pdf' }), `${currentFileName.replace('.pdf','')}_flattened.pdf`); showToast('success','Flattened','Form fields converted to static content'); } catch(err) { showToast('error','Error', err.message); } finally { hideProgress(); } } async function applyWatermark() { if (!currentPdfDoc) { showToast('warning','No PDF','Open a PDF first'); return; } const text = document.getElementById('wmText').value || 'CONFIDENTIAL'; const fontSize = parseInt(document.getElementById('wmSize').value) || 60; const opacity = parseFloat(document.getElementById('wmOpacity').value) || 0.3; const rotation = parseInt(document.getElementById('wmRotation').value) || -45; const colorHex = document.getElementById('wmColor').value || '#ff0000'; const r = parseInt(colorHex.slice(1,3),16)/255; const g = parseInt(colorHex.slice(3,5),16)/255; const b_val = parseInt(colorHex.slice(5,7),16)/255; showProgress('Applying watermark...'); try { const pages = currentPdfDoc.getPages(); pages.forEach(page => { const { width, height } = page.getSize(); page.drawText(text, { x: width/2 - (text.length * fontSize * 0.3), y: height/2, size: fontSize, color: PDFLib.rgb(r, g, b_val), opacity, rotate: PDFLib.degrees(rotation) }); }); const bytes = await currentPdfDoc.save(); currentPdfBytes = bytes; currentPdf = await pdfjsLib.getDocument({ data: bytes }).promise; await renderPage(currentPage); showToast('success','Watermark Applied', `Applied to all ${pages.length} pages`); sessionStats.edits++; updateStats(); } catch(err) { showToast('error','Error', err.message); } finally { hideProgress(); } } function updateWatermarkPreview() { const text = document.getElementById('wmText')?.value || 'CONFIDENTIAL'; const preview = document.getElementById('wmPreview'); if (preview) { preview.textContent = text; const color = document.getElementById('wmColor')?.value || '#ff0000'; const opacity = document.getElementById('wmOpacity')?.value || '0.3'; const rotation = document.getElementById('wmRotation')?.value || '-45'; preview.style.color = color; preview.style.opacity = opacity; preview.style.transform = `rotate(${rotation}deg)`; } } async function applyRedactions() { if (!currentPdfDoc) { showToast('warning','No PDF','Open a PDF first'); return; } showProgress('Applying redactions...'); try { const bytes = await currentPdfDoc.save(); saveAs(new Blob([bytes], { type:'application/pdf' }), `${currentFileName.replace('.pdf','')}_redacted.pdf`); showToast('success','Redacted','Redactions applied and PDF saved'); } catch(err) { showToast('error','Error', err.message); } finally { hideProgress(); } } function setRedactMode(mode) { document.getElementById('redactDrawBtn').classList.toggle('btn-primary', mode === 'draw'); document.getElementById('redactTextBtn').classList.toggle('btn-primary', mode === 'text'); showToast('info','Redact Mode', mode === 'draw' ? 'Draw boxes over content to redact on the PDF viewer' : 'Type text to find and redact'); } async function findAndReplace() { showToast('info','Find & Replace','Text-level editing is handled via OCR. Use the OCR panel to extract text, edit it, then create a new PDF.'); } function findAllInstances() { showToast('info','Find','Use Ctrl+F in the PDF viewer to search text'); } async function addImageToPDF(event) { if (!currentPdfDoc) { showToast('warning','No PDF','Open a PDF first'); return; } const file = event.target.files[0]; if (!file) return; showProgress('Adding image...'); try { const bytes = await file.arrayBuffer(); let img; if (file.type === 'image/png') { img = await currentPdfDoc.embedPng(new Uint8Array(bytes)); } else { img = await currentPdfDoc.embedJpg(new Uint8Array(bytes)); } const pageNum = parseInt(document.getElementById('imagePageNum').value) - 1; const x = parseInt(document.getElementById('imgX').value); const y = parseInt(document.getElementById('imgY').value); const w = parseInt(document.getElementById('imgW').value); const h = parseInt(document.getElementById('imgH').value); const pages = currentPdfDoc.getPages(); if (pageNum >= 0 && pageNum < pages.length) { pages[pageNum].drawImage(img, { x, y, width: w, height: h }); } const pdfBytes = await currentPdfDoc.save(); currentPdfBytes = pdfBytes; currentPdf = await pdfjsLib.getDocument({ data: pdfBytes }).promise; await renderPage(currentPage); showToast('success','Image Added','Image embedded in PDF'); sessionStats.edits++; updateStats(); } catch(err) { showToast('error','Error', err.message); } finally { hideProgress(); } } async function addLinkToPDF() { if (!currentPdfDoc) { showToast('warning','No PDF','Open a PDF first'); return; } showProgress('Adding link...'); try { const url = document.getElementById('linkUrl').value; const pageNum = parseInt(document.getElementById('linkPage').value) - 1; const x = parseInt(document.getElementById('linkX').value); const y = parseInt(document.getElementById('linkY').value); const w = parseInt(document.getElementById('linkW').value); const h = parseInt(document.getElementById('linkH').value); if (!url) { showToast('warning','No URL','Enter a URL first'); hideProgress(); return; } const pages = currentPdfDoc.getPages(); if (pageNum >= 0 && pageNum < pages.length) { const link = currentPdfDoc.context.register( currentPdfDoc.context.obj({ Type: 'Annot', Subtype: 'Link', Rect: [x, y, x+w, y+h], A: { Type: 'Action', S: 'URI', URI: PDFLib.PDFString.of(url) } }) ); pages[pageNum].node.set(PDFLib.PDFName.of('Annots'), currentPdfDoc.context.obj([link])); } const pdfBytes = await currentPdfDoc.save(); currentPdfBytes = pdfBytes; currentPdf = await pdfjsLib.getDocument({ data: pdfBytes }).promise; await renderPage(currentPage); showToast('success','Link Added','Hyperlink added to PDF'); sessionStats.edits++; updateStats(); } catch(err) { showToast('error','Error', err.message); } finally { hideProgress(); } } // Safe localStorage wrapper function safeLocalStorageSet(key, value) { try { localStorage.setItem(key, value); } catch(e) { console.warn('localStorage not available:', e.message); } } function safeLocalStorageGet(key, fallback) { try { return localStorage.getItem(key) || fallback; } catch(e) { return fallback; } } // Keyboard shortcuts document.addEventListener('keydown', (e) => { if (e.ctrlKey || e.metaKey) { if (e.key === 'o') { e.preventDefault(); triggerFileInput(); } if (e.key === 's') { e.preventDefault(); saveCurrentPDF(); } if (e.key === '=') { e.preventDefault(); zoom(0.2); } if (e.key === '-') { e.preventDefault(); zoom(-0.2); } if (e.key === '0') { e.preventDefault(); scale = 1.0; document.getElementById('zoomDisplay') && (document.getElementById('zoomDisplay').textContent = '100%'); renderPage(currentPage); } } if (e.key === 'PageUp') changePage(-1); if (e.key === 'PageDown') changePage(1); }); console.log('PDFMaster Pro v2.0 loaded'); console.log('Features: PDF viewing, editing, OCR, conversion, signing, batch processing, AI assistant'); console.log('Privacy: All processing is done locally in your browser');