Nodemon Fixes, PdfFile cleanup

This commit is contained in:
Felix Kaspar 2023-11-14 20:22:37 +01:00
parent 02957f7757
commit 7bf100daff
8 changed files with 89 additions and 106 deletions

6
server-node/nodemon.json Normal file
View File

@ -0,0 +1,6 @@
{
"watch": ["src"],
"ext": "ts,json",
"ignore": ["src/**/*.spec.ts"],
"exec": "node --trace-warnings --experimental-specifier-resolution=node --loader ts-node/esm ./src/index.ts"
}

View File

@ -6,7 +6,7 @@
"scripts": { "scripts": {
"build": "npx tsc", "build": "npx tsc",
"start": "node dist/index.js", "start": "node dist/index.js",
"dev": "nodemon --watch './**/*.ts' --exec node --experimental-specifier-resolution=node --loader ts-node/esm ./src/index.ts" "dev": "nodemon"
}, },
"keywords": [], "keywords": [],
"author": "", "author": "",

View File

@ -1,7 +1,7 @@
import Operations from '../../utils/pdf-operations'; import Operations from '../../utils/pdf-operations';
import { respondWithPdfFile, response_mustHaveExactlyOneFile } from '../../utils/endpoint-utils'; import { respondWithPdfFile, response_mustHaveExactlyOneFile } from '../../utils/endpoint-utils';
import { PdfFile, PdfFileSchema, fromMulterFile, fromMulterFiles } from '@stirling-pdf/shared-operations/src/wrappers/PdfFile' import { PdfFile, PdfFileSchema } from '@stirling-pdf/shared-operations/src/wrappers/PdfFile'
import express, { Request, Response, RequestHandler } from 'express'; import express, { Request, Response, RequestHandler } from 'express';
const router = express.Router(); const router = express.Router();
@ -18,14 +18,14 @@ function registerEndpoint(endpoint: string,
router.post(endpoint, fileHandler, async function(req: Request, res: Response) { router.post(endpoint, fileHandler, async function(req: Request, res: Response) {
const body = req.body; const body = req.body;
if (req.file) { if (req.file) {
body.file = fromMulterFile(req.file); body.file = PdfFile.fromMulterFile(req.file);
} }
if (req.files) { if (req.files) {
if (Array.isArray(req.files)) if (Array.isArray(req.files))
body.files = fromMulterFiles(req.files); body.files = PdfFile.fromMulterFiles(req.files);
else { else {
const flattenedFiles = Object.values(req.files).flatMap(va => va); const flattenedFiles = Object.values(req.files).flatMap(va => va);
body.files = fromMulterFiles(flattenedFiles); body.files = PdfFile.fromMulterFiles(flattenedFiles);
} }
} }

View File

@ -111,4 +111,9 @@
"src", "src",
"declarations/*.d.ts" "declarations/*.d.ts"
], ],
"ts-node": {
"experimentalSpecifierResolution": "node",
"transpileOnly": true,
"esm": true,
},
} }

View File

@ -1,5 +1,3 @@
import { PdfFile, fromPdfLib } from '../wrappers/PdfFile';
export type ImposeParamsType = { export type ImposeParamsType = {
file: any; file: any;
nup: number; nup: number;

View File

@ -1,22 +1,19 @@
import { PDFDocument } from 'pdf-lib'; import { PDFDocument } from 'pdf-lib';
import { PdfFile, convertAllToPdfLibFile, fromPdfLib } from '../wrappers/PdfFile'; import { PdfFile } from '../wrappers/PdfFile';
export type MergeParamsType = { export type MergeParamsType = {
files: PdfFile[]; files: PdfFile[];
} }
export async function mergePDFs(params: MergeParamsType): Promise<PdfFile> { export async function mergePDFs(params: MergeParamsType): Promise<PdfFile> {
const pdfLibFiles = await convertAllToPdfLibFile(params.files);
const mergedPdf = await PDFDocument.create(); const mergedPdf = await PDFDocument.create();
for (let i = 0; i < pdfLibFiles.length; i++) { for (let i = 0; i < params.files.length; i++) {
const pdfToMerge = await pdfLibFiles[i].getAsPdfLib(); const pdfToMerge = await params.files[i].pdflibDocument;
const copiedPages = await mergedPdf.copyPages(pdfToMerge, pdfToMerge.getPageIndices()); const copiedPages = await mergedPdf.copyPages(pdfToMerge, pdfToMerge.getPageIndices());
copiedPages.forEach((page) => mergedPdf.addPage(page)); copiedPages.forEach((page) => mergedPdf.addPage(page));
} }
return fromPdfLib(mergedPdf, params.files[0].filename); return new PdfFile(params.files.map(f => ), mergedPdf, params.files[0].filename);
}; };

View File

@ -1,6 +1,6 @@
import { degrees } from 'pdf-lib'; import { degrees } from 'pdf-lib';
import { PdfFile, fromPdfLib } from '../wrappers/PdfFile'; import { PdfFile } from '../wrappers/PdfFile';
export type RotateParamsType = { export type RotateParamsType = {
file: PdfFile; file: PdfFile;
@ -10,8 +10,7 @@ export type RotateParamsType = {
export async function rotatePages(params: RotateParamsType): Promise<PdfFile> { export async function rotatePages(params: RotateParamsType): Promise<PdfFile> {
const { file, rotation } = params; const { file, rotation } = params;
const pdfDoc = await file.getAsPdfLib(); const pages = (await file.pdflibDocument).getPages();
const pages = pdfDoc.getPages();
if (Array.isArray(rotation)) { if (Array.isArray(rotation)) {
if (rotation.length != pages.length) { if (rotation.length != pages.length) {
@ -29,5 +28,5 @@ export async function rotatePages(params: RotateParamsType): Promise<PdfFile> {
}); });
} }
return fromPdfLib(pdfDoc, file.filename); return file;
}; };

View File

@ -1,106 +1,84 @@
import { PDFDocument } from 'pdf-lib';
import * as PDFJS from 'pdfjs-dist'; import * as PDFJS from 'pdfjs-dist';
import { PDFDocumentProxy } from 'pdfjs-dist/types/src/display/api'; import { PDFDocumentProxy as PDFJSDocument } from 'pdfjs-dist/types/src/display/api';
import { PDFDocument as PDFLibDocument } from 'pdf-lib';
import Joi from 'joi'; import Joi from 'joi';
export class PdfFile { export class PdfFile {
byteArray: Uint8Array | null; private representation: Uint8Array | PDFLibDocument | PDFJSDocument;
pdfLib: PDFDocument | null; originalFilename: string;
pdfJs: PDFDocumentProxy | null;
filename: string; filename: string;
constructor() { get uint8Array() : Promise<Uint8Array> {
this.byteArray = null; switch (this.representation.constructor) {
this.pdfLib = null; case Uint8Array:
this.pdfJs = null; return new Promise((resolve, reject) => {
this.filename = ""; resolve(this.representation as Uint8Array);
} });
case PDFLibDocument:
async convertToByteArrayFile(): Promise<PdfFile> { return (this.representation as PDFLibDocument).save();
if (this.byteArray) return this; case PDFJSDocument:
return (this.representation as PDFJSDocument).getData();
var byteArray: Uint8Array|null = null; default:
if (this.pdfLib) { throw Error("unhandeled PDF type");
byteArray = await this.pdfLib.save();
} else if (this.pdfJs) {
byteArray = await this.pdfJs.getData();
} }
return fromUint8Array(byteArray!, this.filename);
} }
async convertToPdfLibFile(): Promise<PdfFile> { set uint8Array(value: Uint8Array) {
if (this.pdfLib) return this; this.representation = value;
const byteFile = await this.convertToByteArrayFile();
const pdfLib = await PDFDocument.load(byteFile.byteArray!, {
updateMetadata: false,
});
return fromPdfLib(pdfLib, this.filename);
}
async convertToPdfJsFile(): Promise<PdfFile> {
if (this.pdfJs) return this;
const byteFile = await this.convertToByteArrayFile();
const pdfJs = await PDFJS.getDocument(byteFile.byteArray!).promise;
return fromPdfJs(pdfJs, this.filename);
} }
async getAsByteArray(): Promise<Uint8Array> { get pdflibDocument() : Promise<PDFLibDocument> {
const file = await this.convertToByteArrayFile(); switch (this.representation.constructor) {
return file.byteArray!; case PDFLibDocument: // PDFLib
return new Promise((resolve, reject) => {
resolve(this.representation as PDFLibDocument);
});
default:
return new Promise(async (resolve, reject) => {
resolve(PDFLibDocument.load(await this.uint8Array, {
updateMetadata: false,
}));
});
}
} }
async getAsPdfLib(): Promise<PDFDocument> { set pdflibDocument(value: PDFLibDocument) {
const file = await this.convertToPdfLibFile(); this.representation = value;
return file.pdfLib!;
} }
async getAsPdfJs(): Promise<PDFDocumentProxy> {
const file = await this.convertToPdfJsFile(); get pdfjsDocuemnt() : Promise<PDFJSDocument> {
return file.pdfJs!; switch (this.representation.constructor) {
case PDFJSDocument:
return new Promise((resolve, reject) => {
resolve(this.representation as PDFJSDocument);
});
default:
return new Promise(async (resolve, reject) => {
resolve(await PDFJS.getDocument(await this.uint8Array).promise);
});
}
}
set pdfjsDocuemnt(value: PDFJSDocument) {
this.representation = value;
}
constructor(originalFilename: string, representation: Uint8Array | PDFLibDocument | PDFJSDocument, filename?: string) {
this.originalFilename = originalFilename;
this.filename = filename ? filename : originalFilename;
this.representation = representation;
}
static fromMulterFile(value: Express.Multer.File): PdfFile {
return new PdfFile(value.originalname, value.buffer as Uint8Array)
}
static fromMulterFiles(values: Express.Multer.File[]): PdfFile[] {
return values.map(v => PdfFile.fromMulterFile(v));
} }
} }
export const PdfFileSchema = Joi.any().custom((value, helpers) => { export const PdfFileSchema = Joi.any().custom((value, helpers) => {
if (!(value instanceof PdfFile)) { if (!(value instanceof PdfFile)) {
throw new Error('value is not a PdfFile'); throw new Error('value is not a PdfFile');
} }
return value; return value;
}, "PdfFile validation"); }, "PdfFile validation");
export function fromMulterFile(value: Express.Multer.File): PdfFile {
return fromUint8Array(value.buffer, value.originalname)
}
export function fromMulterFiles(values: Express.Multer.File[]): PdfFile[] {
return values.map(v => fromUint8Array(v.buffer, v.originalname));
}
export function fromUint8Array(value: Uint8Array, filename: string): PdfFile {
const out = new PdfFile();
out.byteArray = value;
out.filename = filename;
return out;
}
export function fromPdfLib(value: PDFDocument, filename: string): PdfFile {
const out = new PdfFile();
out.pdfLib = value;
out.filename = filename;
return out;
}
export function fromPdfJs(value: PDFDocumentProxy, filename: string): PdfFile {
const out = new PdfFile();
out.pdfJs = value;
out.filename = filename;
return out;
}
export async function convertAllToByteArrayFile(files: PdfFile[]): Promise<(PdfFile)[]> {
const pdfPromises = files.map(s => s.convertToByteArrayFile());
return await Promise.all(pdfPromises);
}
export async function convertAllToPdfLibFile(files: PdfFile[]): Promise<(PdfFile)[]> {
const pdfPromises = files.map(s => s.convertToPdfLibFile());
return await Promise.all(pdfPromises);
}
export async function convertAllToPdfJsFile(files: PdfFile[]): Promise<(PdfFile)[]> {
const pdfPromises = files.map(s => s.convertToPdfJsFile());
return await Promise.all(pdfPromises);
}