Created
November 12, 2024 17:49
-
-
Save enosh/e3caf4f730473e37659433e9959dab88 to your computer and use it in GitHub Desktop.
PDF Splitter applet in-browser locally using pdf-lib
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <!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