Client-side
SPLIT PDF
Extract specific pages or page ranges from a PDF document. Enter ranges like 1-3, 5, 8-10.
Drag & drop a PDF file here, or click to browse
Supports single .pdf file
About Split PDF Tool
Split PDF allows you to extract specific page ranges or divide a large PDF document into separate, smaller files. The process executes entirely on your client-side browser, ensuring absolute privacy for your personal or corporate files.
You can specify individual pages (e.g. 1, 3, 5) or page ranges (e.g. 2-5, 8-10) to separate them from the source file. The generated documents are compressed to maintain high quality and a small footprint.
Developer Reference
Core Algorithm & Standalone Script
Standalone, zero-dependency JavaScript implementation powering this tool. Free to inspect, copy, and build upon.
let currentPdfBytes = null;
let totalPages = 0;
let fileNameStr = '';
const uploadZone = document.getElementById('uploadZone');
const fileInput = document.getElementById('fileInput');
const configPanel = document.getElementById('configPanel');
const fileNameEl = document.getElementById('fileName');
const pageCountEl = document.getElementById('pageCount');
const rangeInput = document.getElementById('rangeInput');
const splitBtn = document.getElementById('splitBtn');
const loadingContainer = document.getElementById('loadingContainer');
const resultContainer = document.getElementById('resultContainer');
const resultInfo = document.getElementById('resultInfo');
const downloadBtn = document.getElementById('downloadBtn');
// Drag and drop event listeners
['dragenter', 'dragover'].forEach(eventName => {
uploadZone.addEventListener(eventName, e => {
e.preventDefault();
uploadZone.classList.add('dragover');
}, false);
});
['dragleave', 'drop'].forEach(eventName => {
uploadZone.addEventListener(eventName, e => {
e.preventDefault();
uploadZone.classList.remove('dragover');
}, false);
});
uploadZone.addEventListener('drop', e => {
const dt = e.dataTransfer;
const files = dt.files;
if (files.length > 0) handleFile(files[0]);
});
fileInput.addEventListener('change', e => {
if (e.target.files.length > 0) handleFile(e.target.files[0]);
});
async function handleFile(file) {
if (file.type !== 'application/pdf') return;
fileNameStr = file.name;
try {
currentPdfBytes = await file.arrayBuffer();
const { PDFDocument } = PDFLib;
const pdf = await PDFDocument.load(currentPdfBytes);
totalPages = pdf.getPageCount();
fileNameEl.textContent = file.name;
pageCountEl.textContent = `${totalPages} page${totalPages > 1 ? 's' : ''}`;
rangeInput.value = `1-${totalPages}`;
configPanel.classList.remove('hidden');
resultContainer.classList.add('hidden');
} catch (err) {
console.error(err);
alert('Could not read PDF. Make sure it is not password protected.');
}
}
function parseRanges(rangeStr, maxPage) {
const pages = [];
const parts = rangeStr.split(',');
for (let part of parts) {
part = part.trim();
if (!part) continue;
if (part.includes('-')) {
const [startStr, endStr] = part.split('-');
const start = parseInt(startStr, 10);
const end = parseInt(endStr, 10);
if (isNaN(start) || isNaN(end) || start < 1 || end > maxPage || start > end) {
throw new Error(`Invalid range: ${part}`);
}
for (let i = start; i <= end; i++) {
pages.push(i - 1); // 0-indexed internally
}
} else {
const page = parseInt(part, 10);
if (isNaN(page) || page < 1 || page > maxPage) {
throw new Error(`Invalid page number: ${part}`);
}
pages.push(page - 1); // 0-indexed internally
}
}
// Remove duplicates and sort
return Array.from(new Set(pages)).sort((a, b) => a - b);
}
function formatBytes(bytes, decimals = 2) {
if (bytes === 0) return '0 Bytes';
const k = 1024;
const dm = decimals < 0 ? 0 : decimals;
const sizes = ['Bytes', 'KB', 'MB', 'GB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i];
}
splitBtn.addEventListener('click', async () => {
if (!currentPdfBytes) return;
const rangeStr = rangeInput.value.trim();
let pageIndices = [];
try {
pageIndices = parseRanges(rangeStr, totalPages);
} catch (err) {
alert(err.message + `. Please enter valid ranges within 1 to ${totalPages}.`);
return;
}
if (pageIndices.length === 0) {
alert('Please specify at least one page to extract.');
return;
}
configPanel.classList.add('hidden');
loadingContainer.classList.remove('hidden');
resultContainer.classList.add('hidden');
try {
const { PDFDocument } = PDFLib;
const srcPdf = await PDFDocument.load(currentPdfBytes);
const splitPdf = await PDFDocument.create();
const copiedPages = await splitPdf.copyPages(srcPdf, pageIndices);
copiedPages.forEach((page) => splitPdf.addPage(page));
const splitPdfBytes = await splitPdf.save();
const blob = new Blob([splitPdfBytes], { type: 'application/pdf' });
const blobUrl = URL.createObjectURL(blob);
downloadBtn.href = blobUrl;
const nameWithoutExt = fileNameStr.replace(/\.[^/.]+$/, "");
downloadBtn.download = `${nameWithoutExt}_split.pdf`;
resultInfo.textContent = `Extracted ${pageIndices.length} pages. File size: ${formatBytes(blob.size)}.`;
loadingContainer.classList.add('hidden');
resultContainer.classList.remove('hidden');
} catch (err) {
console.error(err);
alert('An error occurred while splitting the PDF.');
loadingContainer.classList.add('hidden');
configPanel.classList.remove('hidden');
}
});