PDF to EPUB

PDF to EPUB Converter – Free Online Tool | SnapToolSet
Free Online Converter

Convert PDF to EPUB
Instantly & Privately

Extract text from any PDF and generate a valid EPUB 3 e-book — entirely in your browser. No server upload. No account. No waiting.

Client-side only Files never leave your device Valid EPUB 3 output No file size limit
PDF

Drop your PDF here

Drag & drop a PDF file or click to browse. Supports text-based PDFs of any size.

PDF
document.pdf
0 KB
Initializing… 0%
Loading PDF with PDF.js
Extracting text from pages
Structuring chapters
Building EPUB package
Generating download file
An error occurred. Please try again.
EPUB Generated Successfully
Ready for download
Pages
Chapters
Words

Why Use This Converter?

No Server Upload
Your PDF is processed 100% inside your browser using PDF.js. Nothing is sent to any server.
EPUB 3 Standard
Generates valid EPUB 3 files compatible with Kindle (via calibre), iBooks, Kobo, and all major e-readers.
Auto Chapter Detection
Automatically splits content into chapters by heading or per page — configurable before conversion.
Fast Processing
Processes most PDFs within seconds, leveraging native browser APIs and WebWorkers via PDF.js.
Text Extraction
Extracts and preserves all text content from text-based PDFs with proper paragraph spacing.
Fully Free
No subscription, no watermark, no login required. Unlimited conversions, always free.

How It Works

01
Upload PDF
Drag & drop or browse to select your PDF file.
02
Configure
Set title, author, chapter split mode, and font size.
03
Convert
Click Convert — PDF.js extracts text and builds EPUB in seconds.
04
Download
Download the .epub file and open it in any e-reader.

Frequently Asked Questions

Is my PDF file uploaded to a server?
No. This tool runs entirely in your browser using PDF.js and JSZip. Your file is never uploaded to any server. It remains on your device throughout the process — 100% private.
What types of PDFs can be converted?
Text-based PDFs (digitally created documents, e-books, reports) are fully supported. Scanned/image-only PDFs require OCR preprocessing — this tool focuses on PDFs with embedded text data.
Can I open the EPUB on Kindle?
Kindle natively supports EPUB (since 2022). Older Kindles require converting to MOBI using Calibre (free). The EPUB also opens directly in Apple Books, Kobo, Google Play Books, and Readium.
Is there a file size limit?
There is no artificial limit. The practical limit is your browser's available memory. Most modern browsers handle PDFs up to 200–500MB without issue, depending on RAM.
What does the "Chapter Split" option do?
By Heading — detects ALL-CAPS or short lines as headings and creates a chapter break. Best for books and reports.

Per Page — each PDF page becomes its own EPUB chapter. Good for presentations.

Single Chapter — all text goes into one chapter. Best for short documents.
Converting…'; hideError(); hideResult(); resetProgress(); progressWrap.classList.add('active'); try { /* ── STEP 1: Load PDF ── */ setProgress(5, 'Loading PDF with PDF.js…', 0); const arrayBuffer = await readFileAsArrayBuffer(selectedFile); const pdf = await pdfjsLib.getDocument({ data: arrayBuffer }).promise; const totalPages = pdf.numPages; setProgress(15, `PDF loaded — ${totalPages} pages found`, 0); steps[0].classList.remove('active'); steps[0].classList.add('done'); /* ── STEP 2: Extract text ── */ setProgress(20, 'Extracting text from pages…', 1); const pageTexts = []; for (let i = 1; i <= totalPages; i++) { const page = await pdf.getPage(i); const content = await page.getTextContent(); const pageText = content.items.map(item => item.str).join(' '); pageTexts.push(pageText.trim()); const pct = 20 + Math.round((i / totalPages) * 35); setProgress(pct, `Extracting page ${i} of ${totalPages}…`, 1); } steps[1].classList.remove('active'); steps[1].classList.add('done'); /* ── STEP 3: Structure chapters ── */ setProgress(58, 'Structuring chapters…', 2); const mode = chapterMode.value; const title = bookTitle.value.trim() || bookTitle.placeholder || 'Untitled'; const author = bookAuthor.value.trim() || 'Unknown Author'; const chapters = buildChapters(pageTexts, mode, title); const wordCount = pageTexts.join(' ').split(/\s+/).filter(Boolean).length; steps[2].classList.remove('active'); steps[2].classList.add('done'); /* ── STEP 4: Build EPUB ── */ setProgress(68, 'Building EPUB package…', 3); const zip = await buildEPUB(title, author, chapters, fontSizeSetting.value); steps[3].classList.remove('active'); steps[3].classList.add('done'); /* ── STEP 5: Generate blob ── */ setProgress(90, 'Generating download file…', 4); epubBlob = await zip.generateAsync({ type: 'blob', compression: 'DEFLATE', compressionOptions: { level: 6 } }); setProgress(100, 'Done!', 4); steps[4].classList.remove('active'); steps[4].classList.add('done'); /* ── Show result ── */ setTimeout(() => { progressWrap.classList.remove('active'); statPages.textContent = totalPages; statChapters.textContent = chapters.length; statWords.textContent = wordCount > 1000 ? (wordCount / 1000).toFixed(1) + 'k' : wordCount; resultSub.textContent = `${formatBytes(epubBlob.size)} · Valid EPUB 3`; resultPanel.classList.add('active'); }, 600); } catch (err) { console.error('Conversion error:', err); showError('Conversion failed: ' + (err.message || 'Unknown error. Please ensure the PDF contains extractable text.')); progressWrap.classList.remove('active'); } finally { isConverting = false; btnConvert.disabled = !selectedFile; btnConvert.innerHTML = ` Convert to EPUB`; } } /* ======================== CHAPTER BUILDER ======================== */ function buildChapters(pageTexts, mode, bookTitle) { if (mode === 'single') { return [{ title: bookTitle, content: pageTexts.join('\n\n') }]; } if (mode === 'page') { return pageTexts.map((text, i) => ({ title: `Page ${i + 1}`, content: text || '(Empty page)' })); } // mode === 'heading': detect headings const chapters = []; let current = { title: bookTitle, content: '' }; for (let pageText of pageTexts) { const lines = pageText.split(/\s{2,}|\n/).map(l => l.trim()).filter(Boolean); for (let line of lines) { if (isHeading(line) && current.content.trim().length > 30) { chapters.push(current); current = { title: toTitleCase(line), content: '' }; } else { current.content += (current.content ? ' ' : '') + line; } } current.content += '\n\n'; } if (current.content.trim()) chapters.push(current); if (chapters.length === 0) { return [{ title: bookTitle, content: pageTexts.join('\n\n') }]; } return chapters; } function isHeading(line) { if (!line || line.length < 2) return false; const trimmed = line.trim(); // All caps heading (2–80 chars, no period ending) if (trimmed === trimmed.toUpperCase() && trimmed.length >= 3 && trimmed.length <= 80 && !/\.$/.test(trimmed)) { return /[A-Z]/.test(trimmed); // at least one letter } // Short line: fewer than 8 words and doesn't end with period/comma const words = trimmed.split(/\s+/); if (words.length <= 6 && !/[,;:]$/.test(trimmed) && !/\.$/.test(trimmed) && trimmed.length >= 3) { // Bonus: starts with capital if (/^[A-Z0-9]/.test(trimmed)) return true; } // Chapter N pattern if (/^(chapter|section|part|unit)\s+[\divxlc]+/i.test(trimmed)) return true; return false; } function toTitleCase(str) { return str.toLowerCase().replace(/\b\w/g, c => c.toUpperCase()); } /* ======================== EPUB BUILDER ======================== */ async function buildEPUB(title, author, chapters, fontSize) { const zip = new JSZip(); const uid = 'urn:uuid:' + generateUUID(); const now = new Date().toISOString().replace(/\.\d{3}Z$/, 'Z'); /* ── mimetype (MUST be first, uncompressed) ── */ zip.file('mimetype', 'application/epub+zip', { compression: 'STORE' }); /* ── META-INF/container.xml ── */ zip.folder('META-INF').file('container.xml', ` `); const oebps = zip.folder('OEBPS'); const styles = oebps.folder('Styles'); const text = oebps.folder('Text'); /* ── Stylesheet ── */ styles.file('style.css', ` @charset "UTF-8"; body { font-family: Georgia, "Times New Roman", serif; font-size: ${fontSize}; line-height: 1.75; margin: 1.5em 2em; color: #1a1a1a; background: #fff; } h1, h2, h3, h4 { font-family: "Helvetica Neue", Arial, sans-serif; font-weight: 700; margin-top: 1.5em; margin-bottom: 0.5em; color: #111; page-break-after: avoid; } h1 { font-size: 1.6em; } h2 { font-size: 1.35em; border-bottom: 1px solid #ddd; padding-bottom: 0.2em; } h3 { font-size: 1.1em; } p { margin: 0 0 1em; text-align: justify; orphans: 2; widows: 2; } .chapter-title { font-size: 1.8em; font-weight: 800; margin-bottom: 1.5em; padding-bottom: 0.5em; border-bottom: 2px solid #333; page-break-before: always; } .chapter-title:first-child { page-break-before: avoid; } `); /* ── Cover page ── */ text.file('cover.xhtml', ` ${escapeXml(title)}
${escapeXml(title)}
${escapeXml(author)}
Generated by SnapToolSet PDF to EPUB Converter
`); /* ── Chapter files ── */ const chapterManifestItems = []; const chapterSpineItems = []; const tocPoints = []; for (let i = 0; i < chapters.length; i++) { const ch = chapters[i]; const chId = `chapter${String(i + 1).padStart(3, '0')}`; const chFile = `${chId}.xhtml`; const chTitle = ch.title || `Chapter ${i + 1}`; // Format content: split by double newlines → paragraphs const paragraphs = ch.content .split(/\n\n+/) .map(p => p.replace(/\n/g, ' ').trim()) .filter(p => p.length > 0) .map(p => `

${escapeXml(p)}

`) .join('\n'); const xhtml = ` ${escapeXml(chTitle)}

${escapeXml(chTitle)}

${paragraphs || '

(No text content on this page)

'} `; text.file(chFile, xhtml); chapterManifestItems.push(` `); chapterSpineItems.push(` `); tocPoints.push({ id: chId, file: `Text/${chFile}`, title: chTitle, order: i + 2 }); } /* ── content.opf ── */ oebps.file('content.opf', ` ${escapeXml(title)} ${escapeXml(author)} en ${uid} SnapToolSet PDF to EPUB Converter ${now} ${chapterManifestItems.join('\n')} ${chapterSpineItems.join('\n')} `); /* ── toc.ncx ── */ const ncxNavPoints = tocPoints.map(p => ` ${escapeXml(p.title)} `).join(''); oebps.file('toc.ncx', ` ${escapeXml(title)} Cover ${ncxNavPoints} `); /* ── nav.xhtml (EPUB 3 navigation) ── */ const navItems = tocPoints.map(p => `
  • ${escapeXml(p.title)}
  • ` ).join('\n'); oebps.file('nav.xhtml', ` Table of Contents `); return zip; } /* ======================== UTILITIES ======================== */ function readFileAsArrayBuffer(file) { return new Promise((resolve, reject) => { const reader = new FileReader(); reader.onload = e => resolve(e.target.result); reader.onerror = () => reject(new Error('Failed to read file')); reader.readAsArrayBuffer(file); }); } function escapeXml(str) { if (!str) return ''; return String(str) .replace(/&/g, '&') .replace(//g, '>') .replace(/"/g, '"') .replace(/'/g, '''); } function generateUUID() { return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => { const r = Math.random() * 16 | 0; const v = c === 'x' ? r : (r & 0x3 | 0x8); return v.toString(16); }); } /* ======================== DOWNLOAD ======================== */ btnDownload.addEventListener('click', () => { if (!epubBlob) return; const url = URL.createObjectURL(epubBlob); const a = document.createElement('a'); a.href = url; a.download = epubFilename; document.body.appendChild(a); a.click(); document.body.removeChild(a); setTimeout(() => URL.revokeObjectURL(url), 5000); }); /* ======================== RESET ======================== */ function resetTool() { selectedFile = null; epubBlob = null; fileInput.value = ''; bookTitle.value = ''; bookTitle.placeholder = 'Auto-detected from PDF'; bookAuthor.value = ''; filePreview.classList.remove('active'); btnConvert.disabled = true; hideError(); hideResult(); resetProgress(); } /* ======================== FAQ ACCORDION ======================== */ function toggleFaq(el) { const item = el.closest('.faq-item'); const wasOpen = item.classList.contains('open'); document.querySelectorAll('.faq-item.open').forEach(i => i.classList.remove('open')); if (!wasOpen) item.classList.add('open'); }

    This website uses cookies.