mirror of
https://github.com/C4illin/ConvertX.git
synced 2026-09-12 09:57:46 +02:00
feat(pdftops): added pdftops converter (#611)
This commit is contained in:
@@ -47,6 +47,7 @@ A self-hosted online file converter. Supports over a thousand different formats.
|
|||||||
| [Potrace](https://potrace.sourceforge.net/) | Raster to vector | 4 | 11 |
|
| [Potrace](https://potrace.sourceforge.net/) | Raster to vector | 4 | 11 |
|
||||||
| [VTracer](https://github.com/visioncortex/vtracer) | Raster to vector | 8 | 1 |
|
| [VTracer](https://github.com/visioncortex/vtracer) | Raster to vector | 8 | 1 |
|
||||||
| [Markitdown](https://github.com/microsoft/markitdown) | Documents | 6 | 1 |
|
| [Markitdown](https://github.com/microsoft/markitdown) | Documents | 6 | 1 |
|
||||||
|
| [pdftops](https://poppler.freedesktop.org/) | Documents | 1 | 2 |
|
||||||
|
|
||||||
<!-- many ffmpeg fileformats are duplicates -->
|
<!-- many ffmpeg fileformats are duplicates -->
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import { convert as convertLibjxl, properties as propertiesLibjxl } from "./libj
|
|||||||
import { convert as convertLibreOffice, properties as propertiesLibreOffice } from "./libreoffice";
|
import { convert as convertLibreOffice, properties as propertiesLibreOffice } from "./libreoffice";
|
||||||
import { convert as convertMsgconvert, properties as propertiesMsgconvert } from "./msgconvert";
|
import { convert as convertMsgconvert, properties as propertiesMsgconvert } from "./msgconvert";
|
||||||
import { convert as convertPandoc, properties as propertiesPandoc } from "./pandoc";
|
import { convert as convertPandoc, properties as propertiesPandoc } from "./pandoc";
|
||||||
|
import { convert as convertPdftops, properties as propertiesPdftops } from "./pdftops";
|
||||||
import { convert as convertPotrace, properties as propertiesPotrace } from "./potrace";
|
import { convert as convertPotrace, properties as propertiesPotrace } from "./potrace";
|
||||||
import { convert as convertresvg, properties as propertiesresvg } from "./resvg";
|
import { convert as convertresvg, properties as propertiesresvg } from "./resvg";
|
||||||
import { convert as convertImage, properties as propertiesImage } from "./vips";
|
import { convert as convertImage, properties as propertiesImage } from "./vips";
|
||||||
@@ -137,6 +138,10 @@ const properties: Record<
|
|||||||
properties: propertiesMarkitdown,
|
properties: propertiesMarkitdown,
|
||||||
converter: convertMarkitdown,
|
converter: convertMarkitdown,
|
||||||
},
|
},
|
||||||
|
pdftops: {
|
||||||
|
properties: propertiesPdftops,
|
||||||
|
converter: convertPdftops,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
function chunks<T>(arr: T[], size: number): T[][] {
|
function chunks<T>(arr: T[], size: number): T[][] {
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
import { execFile as execFileOriginal } from "node:child_process";
|
||||||
|
import { ExecFileFn } from "./types";
|
||||||
|
|
||||||
|
export const properties = {
|
||||||
|
from: {
|
||||||
|
document: ["pdf"],
|
||||||
|
},
|
||||||
|
to: {
|
||||||
|
document: ["eps", "ps"],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export async function convert(
|
||||||
|
filePath: string,
|
||||||
|
fileType: string,
|
||||||
|
convertTo: string,
|
||||||
|
targetPath: string,
|
||||||
|
options?: unknown,
|
||||||
|
execFile: ExecFileFn = execFileOriginal, // to make it mockable
|
||||||
|
): Promise<string> {
|
||||||
|
const args: string[] = [];
|
||||||
|
|
||||||
|
if (convertTo === "eps") {
|
||||||
|
args.push("-eps");
|
||||||
|
}
|
||||||
|
|
||||||
|
args.push(filePath, targetPath);
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
execFile("pdftops", args, (error, stdout, stderr) => {
|
||||||
|
if (error) {
|
||||||
|
reject(`error: ${error}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stdout) {
|
||||||
|
console.log(`stdout: ${stdout}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stderr) {
|
||||||
|
console.error(`stderr: ${stderr}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve("Done");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
import { beforeEach, expect, test } from "bun:test";
|
||||||
|
import { convert } from "../../src/converters/pdftops";
|
||||||
|
import { runCommonTests } from "./helpers/commonTests";
|
||||||
|
|
||||||
|
runCommonTests(convert);
|
||||||
|
|
||||||
|
let calls: string[][] = [];
|
||||||
|
|
||||||
|
function mockExecFile(
|
||||||
|
_cmd: string,
|
||||||
|
args: string[],
|
||||||
|
callback: (err: Error | null, stdout: string, stderr: string) => void,
|
||||||
|
) {
|
||||||
|
calls.push(args);
|
||||||
|
if (args.includes("fail.pdf")) {
|
||||||
|
callback(new Error("mock failure"), "", "Fake stderr: fail");
|
||||||
|
} else {
|
||||||
|
callback(null, "Fake stdout", "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
calls = [];
|
||||||
|
});
|
||||||
|
|
||||||
|
test("converts a normal file to ps", async () => {
|
||||||
|
const originalConsoleLog = console.log;
|
||||||
|
|
||||||
|
let loggedMessage = "";
|
||||||
|
console.log = (msg) => {
|
||||||
|
loggedMessage = msg;
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = await convert("in.pdf", "pdf", "ps", "out.ps", undefined, mockExecFile);
|
||||||
|
|
||||||
|
console.log = originalConsoleLog;
|
||||||
|
|
||||||
|
expect(result).toBe("Done");
|
||||||
|
expect(calls[0]).toEqual(["in.pdf", "out.ps"]);
|
||||||
|
expect(loggedMessage).toBe("stdout: Fake stdout");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("adds -eps flag for eps output", async () => {
|
||||||
|
const result = await convert("in.pdf", "pdf", "eps", "out.eps", undefined, mockExecFile);
|
||||||
|
|
||||||
|
expect(result).toBe("Done");
|
||||||
|
expect(calls[0]).toEqual(["-eps", "in.pdf", "out.eps"]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("fails on exec error", async () => {
|
||||||
|
expect(convert("fail.pdf", "pdf", "ps", "output.ps", undefined, mockExecFile)).rejects.toMatch(
|
||||||
|
/error: Error: mock failure/,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("logs stderr when execFile returns only stderr and no error", async () => {
|
||||||
|
const originalConsoleError = console.error;
|
||||||
|
|
||||||
|
let loggedMessage = "";
|
||||||
|
console.error = (msg) => {
|
||||||
|
loggedMessage = msg;
|
||||||
|
};
|
||||||
|
|
||||||
|
const mockExecFileStderrOnly = (
|
||||||
|
_cmd: string,
|
||||||
|
_args: string[],
|
||||||
|
callback: (err: Error | null, stdout: string, stderr: string) => void,
|
||||||
|
) => {
|
||||||
|
callback(null, "", "Only stderr output");
|
||||||
|
};
|
||||||
|
|
||||||
|
await convert("input.pdf", "pdf", "ps", "output.ps", undefined, mockExecFileStderrOnly);
|
||||||
|
|
||||||
|
console.error = originalConsoleError;
|
||||||
|
|
||||||
|
expect(loggedMessage).toBe("stderr: Only stderr output");
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user