pdf-visual-compare
Version:
Visual regression testing library for PDFs in Js/Ts without binary and OS dependencies.
86 lines (85 loc) • 4 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.comparePdf = comparePdf;
const node_fs_1 = require("node:fs");
const node_path_1 = require("node:path");
const pdf_to_png_converter_1 = require("pdf-to-png-converter");
const png_visual_compare_1 = require("png-visual-compare");
const const_js_1 = require("./const.js");
/**
* Compares two PDF files or buffers and returns a boolean indicating whether they are similar.
*
* @param actualPdf - The file path or buffer of the actual PDF to compare.
* @param expectedPdf - The file path or buffer of the expected PDF to compare against.
* @param opts - Optional comparison options.
* @returns A promise that resolves to a boolean indicating whether the PDFs are similar.
* @throws Will throw an error if the compare threshold is less than 0.
*/
async function comparePdf(actualPdf, expectedPdf, opts = {}) {
// Validate input file types
validateInputFileType(actualPdf);
validateInputFileType(expectedPdf);
// Set default options
const pdfToPngConvertOpts = { ...opts.pdfToPngConvertOptions };
if (!pdfToPngConvertOpts.viewportScale) {
pdfToPngConvertOpts.viewportScale = 2.0;
}
if (!pdfToPngConvertOpts.outputFileMaskFunc) {
pdfToPngConvertOpts.outputFileMaskFunc = (pageNumber) => `comparePdf_${pageNumber}.png`;
}
const diffsOutputFolder = opts?.diffsOutputFolder ?? const_js_1.DEFAULT_DIFFS_FOLDER;
const compareThreshold = opts?.compareThreshold ?? 0;
const excludedAreas = opts?.excludedAreas ?? [];
if (compareThreshold < 0) {
throw Error('Compare Threshold cannot be less than 0.');
}
// Convert PDFs to PNGs
let [actualPdfPngPages, expectedPdfPngPages] = await Promise.all([
(0, pdf_to_png_converter_1.pdfToPng)(actualPdf, pdfToPngConvertOpts),
(0, pdf_to_png_converter_1.pdfToPng)(expectedPdf, pdfToPngConvertOpts),
]);
// Ensure actualPdfPngPages is always the longer array to avoid index out of bounds errors
if (actualPdfPngPages.length < expectedPdfPngPages.length) {
[actualPdfPngPages, expectedPdfPngPages] = [expectedPdfPngPages, actualPdfPngPages];
}
let documentCompareResult = true;
actualPdfPngPages.forEach((pngPage, index) => {
const comparePngOpts = {
...opts?.pdfToPngConvertOptions,
...excludedAreas[index],
throwErrorOnInvalidInputData: false,
};
comparePngOpts.diffFilePath = (0, node_path_1.resolve)(diffsOutputFolder, `diff_${pngPage.name}`);
const pngPageOutputToCompareWith = expectedPdfPngPages.find((p) => p.name === pngPage.name);
const pageCompareResult = (0, png_visual_compare_1.comparePng)(pngPage.content, pngPageOutputToCompareWith?.content ?? '', comparePngOpts);
if (pageCompareResult > compareThreshold) {
documentCompareResult = false;
}
});
return documentCompareResult;
}
/**
* Validates the type of the input file. The input file can either be a Buffer or a string representing a file path.
* If the input file is a Buffer, the function returns without any error.
* If the input file is a string, the function checks if the file exists at the given path.
* If the file does not exist, an error is thrown.
* If the input file is neither a Buffer nor a string, an error is thrown.
*
* @param inputFile - The input file to validate. It can be a Buffer or a string representing a file path.
* @throws {Error} If the input file is a string and the file does not exist.
* @throws {Error} If the input file is neither a Buffer nor a string.
*/
function validateInputFileType(inputFile) {
if (Buffer.isBuffer(inputFile)) {
return;
}
if (typeof inputFile === 'string') {
if ((0, node_fs_1.existsSync)(inputFile)) {
return;
}
else {
throw Error(`PDF file not found: ${inputFile}`);
}
}
throw Error(`Unknown input file type.`);
}