mindee
Version:
Mindee Client Library for Node.js
84 lines (83 loc) • 3.48 kB
JavaScript
import { MindeeError, MindeeInputSourceError } from "../../../errors/index.js";
import { InvoiceSplitterV1 } from "../../../v1/product/index.js";
import { ExtractedInvoiceSplitterImage } from "../../../v1/extraction/index.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;
}
async function splitPdf(pdfDoc, invoicePageGroups) {
const pdfLib = await getPdfLib();
if (invoicePageGroups.length === 0) {
return [];
}
const generatedPdfs = [];
for (let i = 0; i < invoicePageGroups.length; i++) {
const subdocument = await pdfLib.PDFDocument.create();
const fullIndexes = [];
for (let j = invoicePageGroups[i][0]; j <= invoicePageGroups[i][invoicePageGroups[i].length - 1]; j++) {
fullIndexes.push(j);
}
const copiedPages = await subdocument.copyPages(pdfDoc, fullIndexes);
copiedPages.map((page) => {
subdocument.addPage(page);
});
const subdocumentBytes = await subdocument.save();
generatedPdfs.push(new ExtractedInvoiceSplitterImage(subdocumentBytes, [invoicePageGroups[i][0], invoicePageGroups[i][invoicePageGroups[i].length - 1]]));
}
return generatedPdfs;
}
async function getPdfDoc(inputFile) {
const pdfLib = await getPdfLib();
await inputFile.init();
if (!inputFile.isPdf()) {
throw new MindeeInputSourceError("Invoice Splitter is only compatible with PDF documents.");
}
const pdfDoc = await pdfLib.PDFDocument.load(inputFile.fileObject, {
ignoreEncryption: true,
password: ""
});
if (pdfDoc.getPageCount() < 2) {
throw new MindeeInputSourceError("Invoice Splitter is only compatible with multi-page PDF documents.");
}
return pdfDoc;
}
/**
* Extracts & cuts the pages of a main document invoice according to the provided indexes.
*
* @param inputFile File to extract sub-invoices from.
* @param indexes List of indexes to cut the document according to.
* Can be provided either as a InvoiceSplitterV1 inference, or a direct list of splits.
* @param strict If set to true, doesn't cut pages where the API isn't 100% confident.
* @returns A promise of extracted images, as an array of ExtractedInvoiceSplitterImage.
*/
export async function extractInvoices(inputFile, indexes, strict = false) {
if (!indexes) {
throw new MindeeError("No possible receipts candidates found for MultiReceipts extraction.");
}
let customIndexes = [];
if (indexes instanceof InvoiceSplitterV1) {
indexes.prediction.invoicePageGroups.map((invoicePageGroup) => {
if (!strict || invoicePageGroup.confidence === 1) {
customIndexes.push(invoicePageGroup.pageIndexes ?? []);
}
});
}
else {
customIndexes = indexes;
}
const pdfDoc = await getPdfDoc(inputFile);
const pageCount = pdfDoc.getPageCount();
customIndexes.forEach((pageGroup) => {
pageGroup.forEach((index) => {
if (index >= pageCount) {
throw new MindeeError(`Given index ${index} doesn't exist in page range (0-${pageCount - 1})`);
}
});
});
return await splitPdf(pdfDoc, customIndexes);
}