From 31b746eb4b4b86bf133c1a932458f18bcc6403ad Mon Sep 17 00:00:00 2001 From: Felix Kaspar Date: Sun, 22 Oct 2023 18:30:45 +0200 Subject: [PATCH] editMetadata function & some jsdoc --- CONTRIBUTE.md | 2 ++ README.md | 2 +- functions.js | 5 +++ public/functions.js | 5 +++ public/functions/editMetadata.js | 52 ++++++++++++++++++++++++++++++++ public/traverseOperations.js | 13 ++++++++ 6 files changed, 78 insertions(+), 1 deletion(-) create mode 100644 public/functions/editMetadata.js diff --git a/CONTRIBUTE.md b/CONTRIBUTE.md index 460783c6..f941117b 100644 --- a/CONTRIBUTE.md +++ b/CONTRIBUTE.md @@ -15,6 +15,8 @@ Backend functions can have different implementations than their frontend counter Registering functions will also pass them their dependencies for the specific target platform (Node, Browser) +[Traverse Operations](/public/traverseOperations.js)\ + ### Backend [Register Functions](/functions.js)\ diff --git a/README.md b/README.md index d3e3567d..353cf1fe 100644 --- a/README.md +++ b/README.md @@ -96,7 +96,7 @@ Current functions of spdf and their progress in this repo. | ✔️ | Multi-Page-Layout | | | ✔️ | Adjust page size/scale | | | 🚧 | Organize | | -| 🚧 | Change Metadata | | +| ✔️ | Change Metadata | | | ❌ | Add Watermark | | | Status | Feature | Description | diff --git a/functions.js b/functions.js index c6260f4a..7ee98ea2 100644 --- a/functions.js +++ b/functions.js @@ -8,6 +8,7 @@ import { rotatePages as dependantRotatePages } from './public/functions/rotatePa import { scaleContent as dependantScaleContent} from './public/functions/scaleContent.js'; 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'; export async function extractPages(snapshot, pagesToExtractArray) { return dependantExtractPages(snapshot, pagesToExtractArray, PDFLib); @@ -35,4 +36,8 @@ export async function scalePage(snapshot, pageSize) { export async function splitPDF(snapshot, splitAfterPageArray) { return dependantSplitPDF(snapshot, splitAfterPageArray, PDFLib); +} + +export async function editMetadata(snapshot, metadata) { + return dependantEditMetadata(snapshot, metadata, PDFLib); } \ No newline at end of file diff --git a/public/functions.js b/public/functions.js index ad7ae00e..6575ba3b 100644 --- a/public/functions.js +++ b/public/functions.js @@ -8,6 +8,7 @@ import { rotatePages as dependantRotatePages } from './functions/rotatePages.js' import { scaleContent as dependantScaleContent} from './functions/scaleContent.js'; import { scalePage as dependantScalePage } from './functions/scalePage.js'; import { splitPDF as dependantSplitPDF } from './functions/splitPDF.js'; +import { editMetadata as dependantEditMetadata} from "./functions/editMetadata.js"; export async function extractPages(snapshot, pagesToExtractArray) { return dependantExtractPages(snapshot, pagesToExtractArray, PDFLib); @@ -35,4 +36,8 @@ export async function scalePage(snapshot, pageSize) { export async function splitPDF(snapshot, splitAfterPageArray) { return dependantSplitPDF(snapshot, splitAfterPageArray, PDFLib); +} + +export async function editMetadata(snapshot, metadata) { + return dependantEditMetadata(snapshot, metadata, PDFLib); } \ No newline at end of file diff --git a/public/functions/editMetadata.js b/public/functions/editMetadata.js new file mode 100644 index 00000000..3e437243 --- /dev/null +++ b/public/functions/editMetadata.js @@ -0,0 +1,52 @@ +/** + * @typedef {Object} Metadata + * @property {string | null | undefined} Title - The title of the document. + * @property {string | null | undefined} Author - The author of the document. + * @property {string | null | undefined} Subject - The subject of the document. + * @property {string[] | null | undefined} Keywords - An array of keywords associated with the document. + * @property {string | null | undefined} Producer - The producer of the document. + * @property {string | null | undefined} Creator - The creator of the document. + * @property {Date | null | undefined} CreationDate - The date when the document was created. + * @property {Date | null | undefined} ModificationDate - The date when the document was last modified. + */ + +/** + * + * @param {Uint16Array} snapshot + * @param {Metadata} metadata - Set property to null or "" to clear, undefined properties will be skipped. + * @param {import('pdf-lib')} PDFLib + * @returns + */ +export async function editMetadata(snapshot, metadata, PDFLib) { + // Load the original PDF file + const pdfDoc = await PDFLib.PDFDocument.load(snapshot, { + parseSpeed: PDFLib.ParseSpeeds.Fastest, + }); + + if(metadata.Title !== undefined) + pdfDoc.setTitle(metadata.Title); + + if(metadata.Author !== undefined) + pdfDoc.setAuthor(metadata.Author) + + if(metadata.Subject !== undefined) + pdfDoc.setSubject(metadata.Subject) + + if(metadata.Keywords !== undefined) + pdfDoc.setKeywords(metadata.Keywords) + + if(metadata.Producer !== undefined) + pdfDoc.setProducer(metadata.Producer) + + if(metadata.Creator !== undefined) + pdfDoc.setCreator(metadata.Creator) + + if(metadata.CreationDate !== undefined) + pdfDoc.setCreationDate(metadata.CreationDate) + + if(metadata.ModificationDate !== undefined) + pdfDoc.setModificationDate(metadata.ModificationDate) + + // Serialize the modified document + return pdfDoc.save(); +}; \ No newline at end of file diff --git a/public/traverseOperations.js b/public/traverseOperations.js index c9a0c455..ffe9f39f 100644 --- a/public/traverseOperations.js +++ b/public/traverseOperations.js @@ -1,5 +1,12 @@ import { organizeWaitOperations } from "./organizeWaitOperations.js"; +/** + * + * @param {*} operations + * @param {*} input + * @param {import('./functions.js')} Functions + * @returns + */ export async function * traverseOperations(operations, input, Functions) { const waitOperations = organizeWaitOperations(operations); let results = []; @@ -90,6 +97,12 @@ export async function * traverseOperations(operations, input, Functions) { input = splits; }); break; + case "editMetadata": + yield* nToN(input, operation, async (input) => { + input.fileName += "_metadataEdited"; + input.buffer = await Functions.editMetadata(input.buffer, operation.values["metadata"]); + }); + break; default: throw new Error(`${operation.type} not implemented yet.`); break;