From 152daf60fbddd40122dbe3800d3c036d028d450c Mon Sep 17 00:00:00 2001 From: Felix Kaspar Date: Wed, 21 Aug 2024 21:11:07 +0200 Subject: [PATCH] SingleLargePage Feature --- .../public/locales/singleLargePage/en.json | 4 ++ .../src/functions/singleLargePage.schema.ts | 18 ++++++ .../src/functions/singleLargePage.ts | 56 +++++++++++++++++++ 3 files changed, 78 insertions(+) create mode 100644 shared-operations/public/locales/singleLargePage/en.json create mode 100644 shared-operations/src/functions/singleLargePage.schema.ts create mode 100644 shared-operations/src/functions/singleLargePage.ts diff --git a/shared-operations/public/locales/singleLargePage/en.json b/shared-operations/public/locales/singleLargePage/en.json new file mode 100644 index 000000000..ee57487d6 --- /dev/null +++ b/shared-operations/public/locales/singleLargePage/en.json @@ -0,0 +1,4 @@ +{ + "friendlyName": "Single Large Page", + "description": "Merge all pages of a document into a single long page." +} \ No newline at end of file diff --git a/shared-operations/src/functions/singleLargePage.schema.ts b/shared-operations/src/functions/singleLargePage.schema.ts new file mode 100644 index 000000000..eff813c9b --- /dev/null +++ b/shared-operations/src/functions/singleLargePage.schema.ts @@ -0,0 +1,18 @@ +import { OperatorAvailability, OperatorSchema } from "."; +import Joi from "@stirling-tools/joi"; +import { JoiPDFFileSchema } from "../wrappers/PdfFileJoi"; + +import i18next from "i18next"; + +export default new OperatorSchema({ + joi: { + label: i18next.t("friendlyName", { ns: "singleLargePage" }), + description: i18next.t("description", { ns: "singleLargePage" }), + inputSchema: JoiPDFFileSchema.label(i18next.t("inputs.pdffile.name")).description(i18next.t("inputs.pdffile.description")), + valueSchema: Joi.object({}), + outputSchema: JoiPDFFileSchema.label(i18next.t("outputs.pdffile.name")).description(i18next.t("outputs.pdffile.description")), + }, + materialSymbolName: "receipt", + availability: OperatorAvailability.Both +} +); \ No newline at end of file diff --git a/shared-operations/src/functions/singleLargePage.ts b/shared-operations/src/functions/singleLargePage.ts new file mode 100644 index 000000000..c52b4b005 --- /dev/null +++ b/shared-operations/src/functions/singleLargePage.ts @@ -0,0 +1,56 @@ + +import { PdfFile, RepresentationType } from "../wrappers/PdfFile"; +import { Operator, Progress, oneToOne } from "."; + +import { PDFDocument } from "pdf-lib"; + +export class SingleLargePage extends Operator { + /** Merging pages from multiple pdfs into a singe output document. */ + async run(input: PdfFile[], progressCallback: (state: Progress) => void): Promise { + return oneToOne(input, async (input) => { + const source = await input.pdfLibDocument; + const pages = source.getPages(); + + const result = await PDFDocument.create(); + + // Calculate total height and maximum width + let totalHeight = 0; + let maxWidth = 0; + pages.forEach(page => { + const { width, height } = page.getSize(); + totalHeight += height; + if (width > maxWidth) { + maxWidth = width; + } + }); + + // Add a single large page to the new document + const largePage = result.addPage([maxWidth, totalHeight]); + + const pageBytes = await source.save(); + + // Draw each page from the original PDF onto the large page + let currentHeight = 0; + for (const page of pages) { + const { width, height } = page.getSize(); + + // Embed the original page into the new large page + const [embeddedPage] = await result.embedPdf(pageBytes, [pages.indexOf(page)]); + + // Draw the embedded page onto the large page + largePage.drawPage(embeddedPage, { + x: 0, + y: totalHeight - currentHeight - height, + width, + height, + }); + + currentHeight += height; + } + + progressCallback({ curFileProgress: 0, operationProgress: 1 }); + + return new PdfFile("mergedPDF", result, RepresentationType.PDFLibDocument, "extended_" + input.filename); + }); + } +} \ No newline at end of file