Skip to content

Instantly share code, notes, and snippets.

@enosh
Created November 12, 2024 17:49
Show Gist options
  • Select an option

  • Save enosh/e3caf4f730473e37659433e9959dab88 to your computer and use it in GitHub Desktop.

Select an option

Save enosh/e3caf4f730473e37659433e9959dab88 to your computer and use it in GitHub Desktop.
PDF Splitter applet in-browser locally using pdf-lib
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>PDF Splitter</title>
<script src="https://unpkg.com/[email protected]/dist/pdf-lib.min.js"></script>
</head>
<body>
<h2>PDF Splitter</h2>
<p>PDF text direction and rotations might mess with the layout direction.</p>
<input type="file" id="fileInput" accept="application/pdf">
<label for="layoutDirection">Layout Direction:</label>
<select id="layoutDirection">
<option value="ltr">Vertically: Left to Right</option>
<option value="rtl">Vertically: Right to Left</option>
<option value="ttb">Horizontally: Top to Buttom</option>
<option value="btt">Horizontally: Bottom to Top</option>
</select>
<button id="processButton">Process</button>
<button id="downloadButton" disabled>Download</button>
<br />
<script>
const fileInput = document.getElementById('fileInput');
const layoutDirection = document.getElementById('layoutDirection');
const processButton = document.getElementById('processButton');
const downloadButton = document.getElementById('downloadButton');
let modifiedPdfBytes = null;
/* Copies a PDFPage object */
const copyPage = (originalPage) => {
const cloneNode = originalPage.node.clone();
const { Contents, Annots } = originalPage.node.normalizedEntries();
if (Contents) cloneNode.set(PDFLib.PDFName.of("Contents"), Contents.clone());
if (Annots) cloneNode.set(PDFLib.PDFName.of("Annots"), Annots.clone());
const cloneRef = originalPage.doc.context.register(cloneNode);
const clonePage = PDFLib.PDFPage.of(cloneNode, cloneRef, originalPage.doc);
return clonePage;
};
processButton.addEventListener('click', async () => {
const file = fileInput.files[0];
if (!file) {
alert('Please select a PDF file first.');
return;
}
const fileReader = new FileReader();
fileReader.onload = async (event) => {
const pdfBytes = new Uint8Array(event.target.result);
const pdfDoc = await PDFLib.PDFDocument.load(pdfBytes);
const splitPdfDoc = await PDFLib.PDFDocument.create();
const pages = pdfDoc.getPages();
const direction = layoutDirection.value;
for (let index = 0; index < pages.length; index++) {
const page = pages[index];
const { width, height } = page.getSize();
if (['rtl', 'ltr'].includes(direction)) {
const [pageLeft] = await splitPdfDoc.copyPages(pdfDoc, [index]);
const pageRight = copyPage(pageLeft);
pageLeft.setCropBox(0, 0, width / 2, height);
pageRight.setCropBox(width / 2, 0, width, height);
if (direction === 'rtl') {
splitPdfDoc.addPage(pageRight);
splitPdfDoc.addPage(pageLeft);
} else {
splitPdfDoc.addPage(pageLeft);
splitPdfDoc.addPage(pageRight);
}
} else if (['ttb', 'btt'].includes(direction)) {
const [pageTop] = await splitPdfDoc.copyPages(pdfDoc, [index]);
const pageButtom = copyPage(pageTop);
pageTop.setCropBox(0, height / 2, width, height);
pageButtom.setCropBox(0, 0, width, height / 2);
if (direction === 'ttb') {
splitPdfDoc.addPage(pageTop);
splitPdfDoc.addPage(pageButtom);
} else {
splitPdfDoc.addPage(pageButtom);
splitPdfDoc.addPage(pageTop);
}
}
}
modifiedPdfBytes = await splitPdfDoc.save();
downloadButton.disabled = false;
};
fileReader.readAsArrayBuffer(file);
});
downloadButton.addEventListener('click', () => {
if (modifiedPdfBytes) {
const blob = new Blob([modifiedPdfBytes], { type: 'application/pdf' });
const link = document.createElement('a');
link.href = URL.createObjectURL(blob);
link.download = 'split_pdf.pdf';
link.click();
}
});
// Disable download button on file input or layout direction change
fileInput.addEventListener('change', () => {
downloadButton.disabled = true;
modifiedPdfBytes = null; // Reset modified PDF data
});
layoutDirection.addEventListener('change', () => {
downloadButton.disabled = true;
modifiedPdfBytes = null; // Reset modified PDF data
});
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment