mindee
Version:
Mindee Client Library for Node.js
94 lines (93 loc) • 3.24 kB
JavaScript
import tmp from "tmp";
import * as fs from "node:fs";
import { MindeePdfError } from "../errors/index.js";
import { loadOptionalDependency } from "../dependency/index.js";
import { logger } from "../logger.js";
function getConcatenatedText(pages) {
return pages.flatMap(page => page.content.map(item => item.str)).join(" ");
}
/**
* Extracts text from a full PDF document.
*
* @returns A Promise containing the extracted text as a string.
* @param pdfBuffer PDF handle, as a buffer.
*/
export async function extractTextFromPdf(pdfBuffer) {
const pdfJsExtract = await loadOptionalDependency("pdf.js-extract", "PDF text extraction");
const pdfJs = pdfJsExtract.pdfjs || pdfJsExtract;
const pdfExtract = new pdfJs.PDFExtract();
const options = {};
const pdf = await new Promise((resolve, reject) => {
pdfExtract.extractBuffer(pdfBuffer, options, (err, result) => {
if (err)
reject(err);
if (result === undefined)
reject(new MindeePdfError("Couldn't process result."));
else
resolve(result);
});
});
const pages = pdf.pages.map((page, index) => ({
pageNumber: index + 1,
content: page.content.map((item) => ({
str: item.str,
x: item.x,
y: item.y,
width: item.width,
height: item.height,
fontName: item.fontName,
})),
}));
return {
pages,
getConcatenatedText: () => getConcatenatedText(pages),
};
}
/**
* Checks if a PDF contains source text.
*
* @param pdfData Buffer representing the content of the PDF file.
*
* @returns A Promise containing a boolean indicating if the PDF has source text.
*/
export async function hasSourceText(pdfData) {
const text = await extractTextFromPdf(pdfData);
return text.getConcatenatedText().trim().length > 0;
}
/**
* Rasterizes a PDF page.
*
* @param pdfData Buffer representation of the entire PDF file.
* @param index Index of the page to rasterize.
* @param quality Quality to apply during rasterization.
* @return Buffer containing the rasterized image data.
*/
export async function rasterizePage(pdfData, index, quality = 85) {
const popplerImport = await loadOptionalDependency("node-poppler", "Image Processing");
const poppler = popplerImport.default || popplerImport;
const popplerInstance = new poppler.Poppler();
const tmpPdf = tmp.fileSync();
const tempPdfPath = tmpPdf.name;
const antialiasOption = "best";
try {
await fs.promises.writeFile(tempPdfPath, pdfData);
const options = {
antialias: antialiasOption,
firstPageToConvert: index,
lastPageToConvert: index,
jpegFile: true,
jpegOptions: `quality=${quality}`,
singleFile: true
};
const jpegBuffer = await popplerInstance.pdfToCairo(tempPdfPath, undefined, options);
await fs.promises.unlink(tempPdfPath);
return Buffer.from(jpegBuffer, "binary");
}
catch (error) {
logger.error("Error rasterizing PDF:", error);
throw error;
}
finally {
tmpPdf.removeCallback();
}
}