Download split.html from Talha912/PDFIX: direct link, hf CLI and curl.
- Browser
- Download file 17.5 kB
-
https://huggingface.co/spaces/Talha912/PDFIX/resolve/main/split.html
- Command line
-
hf download hf://spaces/Talha912/PDFIX/split.html
-
curl -L -o split.html https://huggingface.co/spaces/Talha912/PDFIX/resolve/main/split.html
17.5 kB
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8" /> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0" /> | |
| <meta name="theme-color" content="#f7f8ff" /> | |
| <meta name="description" content="Split PDF files and extract selected pages in your browser with PDFix." /> | |
| <title>Split PDF Files Online — PDFix</title> | |
| <style> | |
| :root { | |
| --bg:#f7f8ff; --ink:#17182d; --muted:#71738a; --line:#e7e8f2; | |
| --primary:#635bff; --primary-dark:#4c43e8; --green:#119b82; --danger:#d94765; | |
| --shadow:0 18px 55px rgba(47,43,112,.09); | |
| } | |
| *{box-sizing:border-box} | |
| body{margin:0;min-height:100vh;color:var(--ink);font-family:Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;line-height:1.5;background:radial-gradient(circle at 85% 5%,rgba(177,171,255,.19),transparent 25rem),radial-gradient(circle at 4% 35%,rgba(115,221,211,.12),transparent 22rem),var(--bg)} | |
| a{color:inherit;text-decoration:none} button,input{font:inherit} button{cursor:pointer} | |
| .container{width:min(1040px,calc(100% - 32px));margin:0 auto} | |
| header{padding:20px 0}.nav{display:flex;align-items:center;justify-content:space-between;gap:18px} | |
| .brand{display:inline-flex;align-items:center;gap:10px;font-size:1.4rem;font-weight:850;letter-spacing:-1px} | |
| .brand-mark{width:39px;height:39px;display:grid;place-items:center;border-radius:13px;color:#fff;background:linear-gradient(145deg,#766dff,#4c43e8);box-shadow:0 8px 20px rgba(99,91,255,.25)} | |
| .brand-mark svg{width:23px;height:23px}.brand-name span{color:var(--primary)} | |
| .back-link{color:#65677d;font-weight:650;font-size:.92rem}.back-link:hover{color:var(--primary)} | |
| main{padding:42px 0 70px}.intro{text-align:center;max-width:700px;margin:0 auto 28px} | |
| .eyebrow{display:inline-flex;gap:8px;align-items:center;padding:7px 12px;border:1px solid #e4e1ff;border-radius:99px;background:rgba(255,255,255,.8);color:#5a52e9;font-size:.82rem;font-weight:750} | |
| h1{margin:18px 0 12px;font-size:clamp(2.4rem,5vw,4rem);line-height:1.06;letter-spacing:-2.7px}h1 span{color:var(--primary)} | |
| .intro p{margin:0;color:var(--muted);font-size:1.05rem} | |
| .workspace{max-width:820px;margin:0 auto;border:1px solid rgba(99,91,255,.14);border-radius:24px;padding:12px;background:rgba(255,255,255,.9);box-shadow:var(--shadow)} | |
| .dropzone{display:flex;flex-direction:column;align-items:center;justify-content:center;min-height:210px;padding:26px 18px;text-align:center;border:2px dashed #cbc8ff;border-radius:17px;background:linear-gradient(135deg,rgba(238,237,255,.72),rgba(239,253,251,.5));transition:.2s ease} | |
| .dropzone.dragover{border-color:var(--primary);background:#efedff;transform:scale(.995)} | |
| .upload-icon{width:54px;height:54px;display:grid;place-items:center;margin-bottom:13px;border-radius:17px;color:var(--primary);background:#fff;box-shadow:0 7px 18px rgba(71,64,160,.1)} | |
| .upload-icon svg{width:28px;height:28px}.dropzone strong{font-size:1.1rem}.dropzone p{margin:5px 0 16px;color:var(--muted);font-size:.9rem} | |
| .btn{border:0;display:inline-flex;align-items:center;justify-content:center;gap:9px;padding:12px 18px;border-radius:13px;font-weight:750;transition:.2s ease} | |
| .btn-primary{color:#fff;background:var(--primary);box-shadow:0 8px 18px rgba(99,91,255,.22)}.btn-primary:hover:not(:disabled){background:var(--primary-dark);transform:translateY(-1px)} | |
| .btn-light{color:#4b4d64;background:#fff;border:1px solid var(--line)}.btn-light:hover{border-color:#c9c5ff;color:var(--primary)} | |
| button:disabled{opacity:.5;cursor:not-allowed;box-shadow:none}input[type=file]{display:none} | |
| .file-panel{display:none;padding:22px 10px 8px}.file-panel.visible{display:block} | |
| .file-row{display:grid;grid-template-columns:auto minmax(0,1fr) auto;align-items:center;gap:12px;padding:13px;border:1px solid var(--line);border-radius:14px;background:#fff} | |
| .file-icon{width:42px;height:46px;display:grid;place-items:center;border-radius:11px;color:#e6536a;background:#fff0f2}.file-icon svg{width:23px;height:23px} | |
| .file-meta{min-width:0}.file-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-weight:700;font-size:.92rem}.file-size{color:var(--muted);font-size:.8rem;margin-top:3px} | |
| .controls{display:grid;grid-template-columns:1fr 1fr;gap:14px;margin-top:20px} | |
| .field{padding:16px;border:1px solid var(--line);border-radius:15px;background:#fff}.field label{display:block;margin-bottom:8px;font-size:.9rem;font-weight:750} | |
| .field input,.field select{width:100%;border:1px solid #dfe0ec;border-radius:10px;padding:11px 12px;outline:none;background:#fff;color:var(--ink)} | |
| .field input:focus,.field select:focus{border-color:#aaa5ff;box-shadow:0 0 0 3px rgba(99,91,255,.1)} | |
| .hint{margin:7px 0 0;color:var(--muted);font-size:.8rem} | |
| .panel-actions{display:flex;justify-content:space-between;align-items:center;gap:12px;flex-wrap:wrap;margin-top:17px} | |
| .privacy{display:flex;align-items:center;gap:7px;color:var(--muted);font-size:.82rem}.privacy svg{width:17px;height:17px;color:var(--green);flex-shrink:0} | |
| .status{display:none;margin-top:17px;padding:13px 15px;border-radius:12px;font-size:.9rem}.status.show{display:block}.status.info{background:#efedff;color:#4c43c9}.status.success{background:#e6fbf3;color:#087d68}.status.error{background:#fff0f2;color:#b52b49} | |
| .tips{display:grid;grid-template-columns:repeat(3,1fr);gap:15px;max-width:820px;margin:24px auto 0} | |
| .tip{padding:18px;border:1px solid var(--line);border-radius:17px;background:rgba(255,255,255,.72)}.tip b{display:block;margin-bottom:5px;font-size:.92rem}.tip p{margin:0;color:var(--muted);font-size:.84rem} | |
| footer{border-top:1px solid var(--line);padding:24px 0;color:var(--muted);font-size:.85rem}.footer-inner{display:flex;justify-content:space-between;align-items:center;gap:14px;flex-wrap:wrap} | |
| .toast{position:fixed;left:50%;bottom:22px;transform:translate(-50%,18px);opacity:0;pointer-events:none;padding:12px 17px;border-radius:13px;background:#20213a;color:#fff;box-shadow:var(--shadow);z-index:10;transition:.22s ease;max-width:calc(100% - 28px);text-align:center;font-size:.9rem}.toast.show{opacity:1;transform:translate(-50%,0)} | |
| @media(max-width:650px){main{padding-top:30px}h1{letter-spacing:-1.8px}.tips{grid-template-columns:1fr}.controls{grid-template-columns:1fr}.file-row{grid-template-columns:auto minmax(0,1fr)}.panel-actions{align-items:stretch;flex-direction:column}.panel-actions .btn{width:100%}} | |
| </style> | |
| </head> | |
| <body> | |
| <header><div class="container nav"> | |
| <a class="brand" href="index.html" aria-label="PDFix homepage"> | |
| <span class="brand-mark"><svg viewBox="0 0 24 24" fill="none" aria-hidden="true"><path d="M7 3.5h7l4 4V20a1.5 1.5 0 0 1-1.5 1.5h-9A1.5 1.5 0 0 1 6 20V5A1.5 1.5 0 0 1 7.5 3.5Z" stroke="currentColor" stroke-width="1.8"/><path d="M14 3.8V8h4M8.5 12h7M8.5 15.5h7" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/></svg></span> | |
| <span class="brand-name">PDF<span>ix</span></span> | |
| </a> | |
| <a class="back-link" href="index.html">← Back to all tools</a> | |
| </div></header> | |
| <main><div class="container"> | |
| <div class="intro"> | |
| <div class="eyebrow">✦ PDFix PDF tools</div> | |
| <h1>Split <span>PDF files</span></h1> | |
| <p>Extract the pages you need from a PDF. Enter page numbers or a range, then download your selected pages as a new PDF.</p> | |
| </div> | |
| <div class="workspace"> | |
| <div class="dropzone" id="dropzone" tabindex="0" role="button" aria-label="Choose or drop a PDF file"> | |
| <div class="upload-icon"><svg viewBox="0 0 24 24" fill="none" aria-hidden="true"><path d="M12 16V4m0 0L7.5 8.5M12 4l4.5 4.5M5 14.5v4A1.5 1.5 0 0 0 6.5 20h11a1.5 1.5 0 0 0 1.5-1.5v-4" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/></svg></div> | |
| <strong>Drop one PDF file here</strong> | |
| <p>Select a PDF to extract specific pages.</p> | |
| <button type="button" class="btn btn-primary" id="chooseFile">Select PDF file <span aria-hidden="true">↑</span></button> | |
| <input id="fileInput" type="file" accept=".pdf,application/pdf" /> | |
| </div> | |
| <div class="file-panel" id="filePanel"> | |
| <div class="file-row"> | |
| <div class="file-icon"><svg viewBox="0 0 24 24" fill="none" aria-hidden="true"><path d="M6.5 3.5h8l4 4V20a1.5 1.5 0 0 1-1.5 1.5h-10A1.5 1.5 0 0 1 5.5 20V5A1.5 1.5 0 0 1 7 3.5Z" stroke="currentColor" stroke-width="1.7"/><path d="M14.5 3.8V8h4M8 12h8M8 15h6" stroke="currentColor" stroke-width="1.7" stroke-linecap="round"/></svg></div> | |
| <div class="file-meta"><div class="file-name" id="fileName">document.pdf</div><div class="file-size" id="fileSize"></div></div> | |
| <button class="btn btn-light" id="changeFile" type="button">Change</button> | |
| </div> | |
| <div class="controls"> | |
| <div class="field"> | |
| <label for="pageRange">Pages to extract</label> | |
| <input id="pageRange" type="text" placeholder="e.g. 1-3, 5, 8-10" autocomplete="off" /> | |
| <p class="hint">Use commas for separate pages and hyphens for ranges.</p> | |
| </div> | |
| <div class="field"> | |
| <label for="splitMode">Output mode</label> | |
| <select id="splitMode"> | |
| <option value="selected">One PDF with selected pages</option> | |
| <option value="each">Separate PDF for each selected page</option> | |
| </select> | |
| <p class="hint">For separate files, each selected page downloads individually.</p> | |
| </div> | |
| </div> | |
| <div class="panel-actions"> | |
| <div class="privacy"><svg viewBox="0 0 24 24" fill="none"><path d="M12 3 19 6v5c0 4.5-2.9 7.7-7 10-4.1-2.3-7-5.5-7-10V6l7-3Z" stroke="currentColor" stroke-width="1.8" stroke-linejoin="round"/><path d="m9 12 2 2 4-4" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/></svg> Your PDF is processed in your browser.</div> | |
| <button type="button" class="btn btn-primary" id="splitBtn" disabled>Split PDF <span aria-hidden="true">→</span></button> | |
| </div> | |
| <div class="status" id="status" role="status" aria-live="polite"></div> | |
| </div> | |
| </div> | |
| <div class="tips"> | |
| <article class="tip"><b>① Choose a PDF</b><p>Select the document whose pages you want to extract.</p></article> | |
| <article class="tip"><b>② Enter page numbers</b><p>For example, type 1-3, 5 to select pages 1, 2, 3, and 5.</p></article> | |
| <article class="tip"><b>③ Download your pages</b><p>Save the extracted pages as one PDF or as separate files.</p></article> | |
| </div> | |
| </div></main> | |
| <footer><div class="container footer-inner"><a class="brand" href="index.html"><span class="brand-name">PDF<span>ix</span></span></a><span>© <span id="year"></span> PDFix · Your documents, made simple.</span></div></footer> | |
| <div class="toast" id="toast" role="status" aria-live="polite"></div> | |
| <script src="https://unpkg.com/pdf-lib@1.17.1/dist/pdf-lib.min.js"></script> | |
| <script> | |
| const fileInput = document.getElementById('fileInput'); | |
| const dropzone = document.getElementById('dropzone'); | |
| const filePanel = document.getElementById('filePanel'); | |
| const pageRange = document.getElementById('pageRange'); | |
| const splitBtn = document.getElementById('splitBtn'); | |
| const statusBox = document.getElementById('status'); | |
| const toast = document.getElementById('toast'); | |
| let selectedFile = null; | |
| let toastTimer; | |
| document.getElementById('year').textContent = new Date().getFullYear(); | |
| function showToast(message) { | |
| toast.textContent = message; | |
| toast.classList.add('show'); | |
| clearTimeout(toastTimer); | |
| toastTimer = setTimeout(() => toast.classList.remove('show'), 3000); | |
| } | |
| function setStatus(message, type='info') { | |
| statusBox.textContent = message; | |
| statusBox.className = `status show ${type}`; | |
| } | |
| function clearStatus() { | |
| statusBox.textContent = ''; | |
| statusBox.className = 'status'; | |
| } | |
| function formatSize(bytes) { | |
| return bytes < 1024*1024 ? `${Math.max(1,Math.round(bytes/1024))} KB` : `${(bytes/(1024*1024)).toFixed(2)} MB`; | |
| } | |
| function choosePdf(files) { | |
| const file = Array.from(files || []).find(f => f.name.toLowerCase().endsWith('.pdf') || f.type === 'application/pdf'); | |
| if (!file) { showToast('Please select a PDF file.'); return; } | |
| selectedFile = file; | |
| document.getElementById('fileName').textContent = file.name; | |
| document.getElementById('fileName').title = file.name; | |
| document.getElementById('fileSize').textContent = formatSize(file.size); | |
| filePanel.style.display = 'block'; | |
| filePanel.classList.add('visible'); | |
| splitBtn.disabled = false; | |
| clearStatus(); | |
| pageRange.value = ''; | |
| } | |
| function parsePageRange(input, pageCount) { | |
| const text = input.trim(); | |
| if (!text) throw new Error('Enter the page numbers or range you want to extract.'); | |
| const pages = new Set(); | |
| const parts = text.split(','); | |
| for (const rawPart of parts) { | |
| const part = rawPart.trim(); | |
| if (!part) throw new Error('Check the page range format. Example: 1-3, 5, 8-10.'); | |
| if (/^\d+$/.test(part)) { | |
| const page = Number(part); | |
| if (page < 1 || page > pageCount) throw new Error(`Page ${page} is outside this PDF. It has ${pageCount} pages.`); | |
| pages.add(page - 1); | |
| } else { | |
| const match = part.match(/^(\d+)\s*-\s*(\d+)$/); | |
| if (!match) throw new Error('Invalid page range. Use a format such as 1-3, 5, 8-10.'); | |
| const start = Number(match[1]); | |
| const end = Number(match[2]); | |
| if (start < 1 || end < 1 || start > end || end > pageCount) { | |
| throw new Error(`Invalid range "${part}". Use page numbers from 1 to ${pageCount}.`); | |
| } | |
| for (let page = start; page <= end; page++) pages.add(page - 1); | |
| } | |
| } | |
| return Array.from(pages).sort((a,b) => a-b); | |
| } | |
| function downloadBytes(bytes, filename) { | |
| const blob = new Blob([bytes], {type:'application/pdf'}); | |
| const url = URL.createObjectURL(blob); | |
| const link = document.createElement('a'); | |
| link.href = url; | |
| link.download = filename; | |
| document.body.appendChild(link); | |
| link.click(); | |
| link.remove(); | |
| setTimeout(() => URL.revokeObjectURL(url), 1500); | |
| } | |
| function safeBaseName(name) { | |
| return name.replace(/\.pdf$/i,'').replace(/[^\w\-]+/g,'_').slice(0,70) || 'document'; | |
| } | |
| document.getElementById('chooseFile').addEventListener('click', e => { e.stopPropagation(); fileInput.click(); }); | |
| document.getElementById('changeFile').addEventListener('click', () => fileInput.click()); | |
| dropzone.addEventListener('click', e => { if (!e.target.closest('button')) fileInput.click(); }); | |
| dropzone.addEventListener('keydown', e => { | |
| if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); fileInput.click(); } | |
| }); | |
| fileInput.addEventListener('change', () => { choosePdf(fileInput.files); fileInput.value = ''; }); | |
| ['dragenter','dragover'].forEach(type => dropzone.addEventListener(type, e => { | |
| e.preventDefault(); dropzone.classList.add('dragover'); | |
| })); | |
| ['dragleave','drop'].forEach(type => dropzone.addEventListener(type, e => { | |
| e.preventDefault(); dropzone.classList.remove('dragover'); | |
| })); | |
| dropzone.addEventListener('drop', e => choosePdf(e.dataTransfer.files)); | |
| splitBtn.addEventListener('click', async () => { | |
| if (!selectedFile) return; | |
| if (!window.PDFLib) { | |
| setStatus('The PDF library could not load. Check your internet connection and reload this page.', 'error'); | |
| return; | |
| } | |
| const originalText = splitBtn.innerHTML; | |
| splitBtn.disabled = true; | |
| splitBtn.textContent = 'Processing…'; | |
| try { | |
| setStatus('Reading your PDF…', 'info'); | |
| const {PDFDocument} = window.PDFLib; | |
| const source = await PDFDocument.load(await selectedFile.arrayBuffer()); | |
| const pageCount = source.getPageCount(); | |
| const pages = parsePageRange(pageRange.value, pageCount); | |
| const mode = document.getElementById('splitMode').value; | |
| const base = safeBaseName(selectedFile.name); | |
| if (mode === 'selected') { | |
| const output = await PDFDocument.create(); | |
| const copied = await output.copyPages(source, pages); | |
| copied.forEach(page => output.addPage(page)); | |
| const bytes = await output.save(); | |
| downloadBytes(bytes, `${base}-split.pdf`); | |
| setStatus(`Done! Extracted ${pages.length} ${pages.length === 1 ? 'page' : 'pages'} from a ${pageCount}-page PDF. Your download should begin shortly.`, 'success'); | |
| } else { | |
| for (let i = 0; i < pages.length; i++) { | |
| setStatus(`Creating PDF ${i+1} of ${pages.length}…`, 'info'); | |
| const output = await PDFDocument.create(); | |
| const [page] = await output.copyPages(source, [pages[i]]); | |
| output.addPage(page); | |
| const bytes = await output.save(); | |
| downloadBytes(bytes, `${base}-page-${pages[i]+1}.pdf`); | |
| // A small pause helps browsers start multiple downloads. | |
| await new Promise(resolve => setTimeout(resolve, 250)); | |
| } | |
| setStatus(`Done! Created ${pages.length} separate PDF file(s). Your browser may ask you to allow multiple downloads.`, 'success'); | |
| } | |
| } catch (error) { | |
| console.error(error); | |
| setStatus(error.message || 'Could not split this PDF. It may be damaged or password-protected.', 'error'); | |
| } finally { | |
| splitBtn.disabled = !selectedFile; | |
| splitBtn.innerHTML = originalText; | |
| } | |
| }); | |
| </script> | |
| </body> | |
| </html> |