mindee
Version:
Mindee Client Library for Node.js
120 lines (119 loc) • 4.46 kB
JavaScript
import { errorHandler } from "../errors/handler.js";
import { PageOptionsOperation } from "../input/pageOptions.js";
import { MindeeError, MindeeInputSourceError } from "../errors/index.js";
import { logger } from "../logger.js";
import { loadOptionalDependency } from "../dependency/index.js";
let pdfLib = null;
async function getPdfLib() {
if (!pdfLib) {
const pdfLibImport = await loadOptionalDependency("@cantoo/pdf-lib", "Text Embedding");
pdfLib = pdfLibImport.default || pdfLibImport;
}
return pdfLib;
}
/**
* Cut pages from a PDF file. If pages indexes are out of bounds, it will throw an error.
* @param file
* @param pageOptions
* @returns the new cut PDF file.
*/
export async function extractPages(file, pageOptions) {
const pdfLib = await getPdfLib();
const currentPdf = await pdfLib.PDFDocument.load(file, {
ignoreEncryption: true,
password: ""
});
const newPdf = await pdfLib.PDFDocument.create();
const pageCount = currentPdf.getPageCount();
if (pageCount < pageOptions.onMinPages) {
logger.debug(`File skipped because it had less than ${pageOptions} pages (${pageCount}).`);
return { file: file, totalPagesRemoved: 0 };
}
if (pageOptions.pageIndexes.length > pageCount) {
errorHandler.throw(new MindeeError("The total indexes of pages to cut is superior to the total page count of the file (" +
pageCount +
")."));
}
const pageIndexes = [];
pageOptions.pageIndexes.forEach((pageIndex) => {
if (pageIndex < 0) {
pageIndexes.push(pageCount - Math.abs(pageIndex));
}
else {
pageIndexes.push(pageIndex);
}
});
if (!pageIndexes.every((v) => currentPdf.getPageIndices().includes(v))) {
errorHandler.throw(new MindeeError(`Some indexes pages
(${pageIndexes.join(",")})
don't exist in the file
(${currentPdf.getPageIndices().join(", ")})`));
}
if (pageOptions.operation === PageOptionsOperation.KeepOnly) {
const keptPages = await newPdf.copyPages(currentPdf, pageIndexes);
keptPages.forEach((keptPage) => {
newPdf.addPage(keptPage);
});
}
else if (pageOptions.operation === PageOptionsOperation.Remove) {
const pagesToKeep = currentPdf
.getPageIndices()
.filter((v) => !pageIndexes.includes(v));
const keptPages = await newPdf.copyPages(currentPdf, pagesToKeep);
keptPages.forEach((keptPage) => {
newPdf.addPage(keptPage);
});
}
else {
throw new Error(`The operation ${pageOptions.operation} is not available.`);
}
const sumRemovedPages = pageCount - newPdf.getPageCount();
const fileBuffer = Buffer.from(await newPdf.save());
return { file: fileBuffer, totalPagesRemoved: sumRemovedPages };
}
/**
* Count the number of pages in a PDF file.
* @param file
* @returns the number of pages in the file.
*/
export async function countPages(file) {
const pdfLib = await getPdfLib();
const currentPdf = await pdfLib.PDFDocument.load(file, {
ignoreEncryption: true,
password: ""
});
return currentPdf.getPageCount();
}
/**
* Creates a PDF from a local file. Converts images to PDFs if needed.
* @param inputSource The input source to create a PDF from.
*/
export async function createPdfFromInputSource(inputSource) {
const pdfLib = await getPdfLib();
let pdfDoc;
if (!["image/jpeg", "image/jpg", "image/png", "application/pdf"].includes(inputSource.mimeType)) {
throw new MindeeInputSourceError('Unsupported file type "' +
inputSource.mimeType +
'" Currently supported types are .png, .jpg and .pdf');
}
else if (inputSource.isPdf()) {
pdfDoc = await pdfLib.PDFDocument.load(inputSource.fileObject, {
ignoreEncryption: true,
password: ""
});
}
else {
pdfDoc = await pdfLib.PDFDocument.create();
let image;
if (inputSource.mimeType === "image/png") {
image = await pdfDoc.embedPng(inputSource.fileObject);
}
else {
image = await pdfDoc.embedJpg(inputSource.fileObject);
}
const imageDims = image.scale(1);
const pageImage = pdfDoc.addPage([imageDims.width, imageDims.height]);
pageImage.drawImage(image);
}
return pdfDoc;
}