diff --git a/functions.js b/functions.js index 7ee98ea2..5fc7f486 100644 --- a/functions.js +++ b/functions.js @@ -9,6 +9,7 @@ import { scaleContent as dependantScaleContent} from './public/functions/scaleCo import { scalePage as dependantScalePage } from './public/functions/scalePage.js'; import { splitPDF as dependantSplitPDF } from './public/functions/splitPDF.js'; import { editMetadata as dependantEditMetadata } from './public/functions/editMetadata.js'; +import { organizePages as dependantOrganizePages } from './public/functions/organizePages.js'; export async function extractPages(snapshot, pagesToExtractArray) { return dependantExtractPages(snapshot, pagesToExtractArray, PDFLib); @@ -40,4 +41,8 @@ export async function splitPDF(snapshot, splitAfterPageArray) { export async function editMetadata(snapshot, metadata) { return dependantEditMetadata(snapshot, metadata, PDFLib); +} + +export async function organizePages(snapshot, operation, customOrderString) { + return dependantOrganizePages(snapshot, operation, customOrderString, PDFLib); } \ No newline at end of file diff --git a/public/functions.js b/public/functions.js index 6575ba3b..6d1f566d 100644 --- a/public/functions.js +++ b/public/functions.js @@ -9,6 +9,7 @@ import { scaleContent as dependantScaleContent} from './functions/scaleContent.j import { scalePage as dependantScalePage } from './functions/scalePage.js'; import { splitPDF as dependantSplitPDF } from './functions/splitPDF.js'; import { editMetadata as dependantEditMetadata} from "./functions/editMetadata.js"; +import { organizePages as dependantOrganizePages} from "./functions/organizePages.js"; export async function extractPages(snapshot, pagesToExtractArray) { return dependantExtractPages(snapshot, pagesToExtractArray, PDFLib); @@ -40,4 +41,8 @@ export async function splitPDF(snapshot, splitAfterPageArray) { export async function editMetadata(snapshot, metadata) { return dependantEditMetadata(snapshot, metadata, PDFLib); +} + +export async function organizePages(snapshot, operation, customOrderString) { + return dependantOrganizePages(snapshot, operation, customOrderString, PDFLib); } \ No newline at end of file diff --git a/public/functions/organizePages.js b/public/functions/organizePages.js new file mode 100644 index 00000000..a6b3950a --- /dev/null +++ b/public/functions/organizePages.js @@ -0,0 +1,115 @@ +/** + * @typedef {"CUSTOM_PAGE_ORDER"|"REVERSE_ORDER"|"DUPLEX_SORT"|"BOOKLET_SORT"|"ODD_EVEN_SPLIT"|"REMOVE_FIRST"|"REMOVE_LAST"|"REMOVE_FIRST_AND_LAST"} OrderOperation + */ + +/** + * + * @param {Uint16Array} snapshot + * @param {OrderOperation} operation + * @param {string} customOrderString + * @param {import('pdf-lib')} PDFLib + * @returns + */ +export async function organizePages(snapshot, operation, customOrderString, PDFLib) { + const pdfDoc = await PDFLib.PDFDocument.load(snapshot); + let subDocument = await PDFLib.PDFDocument.create(); + const copiedPages = await subDocument.copyPages(pdfDoc, pdfDoc.getPageIndices()); + + + const pageCount = pdfDoc.getPages().length; + + switch (operation) { + case "CUSTOM_PAGE_ORDER": + console.log("Custom Order"); + const pageOrderArray = parseCustomPageOrder(customOrderString, pageCount); + console.log(pageOrderArray); + + const customOrderedPages = pageOrderArray.map((pageIndex) => copiedPages[pageIndex]); + customOrderedPages.forEach((page) => subDocument.addPage(page)); + break; + case "REVERSE_ORDER": + const reversedPages = []; + for (let i = pageCount - 1; i >= 0; i--) { + reversedPages.push(copiedPages[i]); + } + reversedPages.forEach((page) => subDocument.addPage(page)); + break; + case 'DUPLEX_SORT': //TODO: Needs to be checked by someone who knows more about duplex printing. + const duplexPages = []; + const half = (pageCount + 1) / 2 + for (let i = 1; i <= half; i++) { + duplexPages.push(copiedPages[i - 1]); + if (i <= pageCount - half) { + duplexPages.push(copiedPages[pageCount - i]); + } + } + duplexPages.forEach((page) => subDocument.addPage(page)); + break; + case 'BOOKLET_SORT': + const bookletPages = []; + for (let i = 0; i < pageCount / 2; i++) { + bookletPages.push(copiedPages[i]); + bookletPages.push(copiedPages[pageCount - i - 1]); + } + bookletPages.forEach((page) => subDocument.addPage(page)); + break; + case 'ODD_EVEN_SPLIT': + const oddPages = []; + const evenPages = []; + for (let i = 0; i < pageCount; i++) { + if (i % 2 === 0) { + evenPages.push(copiedPages[i]); + } else { + oddPages.push(copiedPages[i]); + } + } + oddPages.forEach((page) => subDocument.addPage(page)); + evenPages.forEach((page) => subDocument.addPage(page)); + break; + case 'REMOVE_FIRST': + pdfDoc.removePage(0); + subDocument = pdfDoc; + break; + case 'REMOVE_LAST': + pdfDoc.removePage(pageCount - 1); + subDocument = pdfDoc; + break; + case 'REMOVE_FIRST_AND_LAST': + pdfDoc.removePage(0); + pdfDoc.removePage(pageCount - 2); + subDocument = pdfDoc; + break; + default: + throw new Error("Operation not supported"); + break; + } + + return subDocument.save(); +}; + +function parseCustomPageOrder(customOrder, pageCount) { + const pageOrderArray = []; + const ranges = customOrder.split(','); + + ranges.forEach((range) => { + if (range.includes('-')) { + const [start, end] = range.split('-').map(Number); + for (let i = start; i <= end; i++) { + pageOrderArray.push(i - 1); + } + } else if (range.includes('n')) { + const [even, odd] = range.split('n').map(Number); + for (let i = 1; i <= pageCount; i++) { + if (i % 2 === 0) { + pageOrderArray.push((i * even) - 1); + } else { + pageOrderArray.push((i * odd) - 1); + } + } + } else { + pageOrderArray.push(Number(range) - 1); + } + }); + + return pageOrderArray; +} \ No newline at end of file diff --git a/public/traverseOperations.js b/public/traverseOperations.js index ffe9f39f..d6e2ab40 100644 --- a/public/traverseOperations.js +++ b/public/traverseOperations.js @@ -103,6 +103,12 @@ export async function * traverseOperations(operations, input, Functions) { input.buffer = await Functions.editMetadata(input.buffer, operation.values["metadata"]); }); break; + case "organizePages": + yield* nToN(input, operation, async (input) => { + input.fileName += "_pagesOrganized"; + input.buffer = await Functions.organizePages(input.buffer, operation.values["operation"], operation.values["customOrderString"]); + }); + break; default: throw new Error(`${operation.type} not implemented yet.`); break;