From 6523d1367685b66ae3ebc658ebfa6957eb0abaa3 Mon Sep 17 00:00:00 2001 From: anonymous Date: Sat, 31 Jan 2026 21:07:49 +0530 Subject: [PATCH] Add libreoffice powerpoint to pdf converter --- .gitignore | 5 ++ src/converters/libreoffice.ts | 44 ++++++++++++++++- tests/converters/libreoffice.test.ts | 71 +++++++++++++++++++++++++++- 3 files changed, 117 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 6fb8d4d6..d76dd611 100644 --- a/.gitignore +++ b/.gitignore @@ -25,6 +25,7 @@ yarn-debug.log* yarn-error.log* # local env files +.env .env.local .env.development.local .env.test.local @@ -50,3 +51,7 @@ package-lock.json /Bruno /tsconfig.tsbuildinfo /public/generated.css + + +.specstory/ +.cursorindexingignore \ No newline at end of file diff --git a/src/converters/libreoffice.ts b/src/converters/libreoffice.ts index 02f389a5..33aa1c96 100644 --- a/src/converters/libreoffice.ts +++ b/src/converters/libreoffice.ts @@ -46,6 +46,20 @@ export const properties = { "xml", "zabw", ], + impress: [ + "ppt", + "pptx", + "pps", + "ppsx", + "pptm", + "pot", + "potx", + "potm", + "odp", + "otp", + "fodp", + "sxi", + ], }, to: { text: [ @@ -72,10 +86,19 @@ export const properties = { "xhtml", "xml", ], + impress: [ + "pdf", + "ppt", + "pptx", + "odp", + "otp", + "fodp", + "html", + ], }, }; -type FileCategories = "text" | "calc"; +type FileCategories = "text" | "calc" | "impress"; const filters: Record> = { text: { @@ -121,6 +144,22 @@ const filters: Record> = { zabw: "AbiWord", }, calc: {}, + impress: { + ppt: "MS PowerPoint 97", + pptx: "Impress MS PowerPoint 2007 XML", + pps: "MS PowerPoint 97", + ppsx: "Impress MS PowerPoint 2007 XML", + pptm: "Impress MS PowerPoint 2007 XML VBA", + pot: "MS PowerPoint 97 Vorlage", + potx: "Impress MS PowerPoint 2007 XML Template", + potm: "Impress MS PowerPoint 2007 XML Template", + odp: "impress8", + otp: "impress8_template", + fodp: "OpenDocument Presentation Flat XML", + sxi: "StarOffice XML (Impress)", + pdf: "impress_pdf_Export", + html: "impress_html_Export", + }, }; const getFilters = (fileType: string, converto: string) => { @@ -128,6 +167,8 @@ const getFilters = (fileType: string, converto: string) => { return [filters.text[fileType], filters.text[converto]]; } else if (fileType in filters.calc && converto in filters.calc) { return [filters.calc[fileType], filters.calc[converto]]; + } else if (fileType in filters.impress && converto in filters.impress) { + return [filters.impress[fileType], filters.impress[converto]]; } return [null, null]; }; @@ -145,6 +186,7 @@ export function convert( // Build arguments array const args: string[] = []; args.push("--headless"); + args.push("--invisible"); const [inFilter, outFilter] = getFilters(fileType, convertTo); if (inFilter) { diff --git a/tests/converters/libreoffice.test.ts b/tests/converters/libreoffice.test.ts index 4d07f1ed..64cb1dc1 100644 --- a/tests/converters/libreoffice.test.ts +++ b/tests/converters/libreoffice.test.ts @@ -63,6 +63,7 @@ test("invokes soffice with --headless and outdir derived from targetPath", async expect(cmd).toBe("soffice"); expect(args).toEqual([ "--headless", + "--invisible", `--infilter="MS Word 2007 XML"`, "--convert-to", "odt:writer8", @@ -78,7 +79,7 @@ test("uses only outFilter when input has no filter (e.g., pdf -> txt)", async () const { args } = requireDefined(calls[0], "Expected at least one execFile call"); expect(args).not.toContainEqual(expect.stringMatching(/^--infilter=/)); - expect(args).toEqual(["--headless", "--convert-to", "txt", "--outdir", "out", "in.pdf"]); + expect(args).toEqual(["--headless", "--invisible", "--convert-to", "txt", "--outdir", "out", "in.pdf"]); }); test("uses only infilter when convertTo has no out filter (e.g., docx -> pdf)", async () => { @@ -87,7 +88,7 @@ test("uses only infilter when convertTo has no out filter (e.g., docx -> pdf)", const { args } = requireDefined(calls[0], "Expected at least one execFile call"); // If docx has an infilter, it should be present - expect(args).toEqual(["--headless", "--convert-to", "pdf", "--outdir", "out", "in.docx"]); + expect(args).toEqual(["--headless", "--invisible", "--convert-to", "pdf", "--outdir", "out", "in.docx"]); const i = args.indexOf("--convert-to"); expect(i).toBeGreaterThanOrEqual(0); @@ -159,3 +160,69 @@ test("logs stderr on exec error as well", async () => { // The callback still provided stderr; your implementation logs it before settling expect(errors).toContain("stderr: EPIPE"); }); + +// --- PowerPoint/Impress conversions ------------------------------------------ +test("converts pptx to pdf with impress filters", async () => { + await convert("in.pptx", "pptx", "pdf", "out/out.pdf", undefined, mockExecFile); + + const { cmd, args } = requireDefined(calls[0], "Expected at least one execFile call"); + expect(cmd).toBe("soffice"); + expect(args).toEqual([ + "--headless", + "--invisible", + `--infilter="Impress MS PowerPoint 2007 XML"`, + "--convert-to", + "pdf:impress_pdf_Export", + "--outdir", + "out", + "in.pptx", + ]); +}); + +test("converts ppt to pdf with impress filters", async () => { + await convert("in.ppt", "ppt", "pdf", "out/out.pdf", undefined, mockExecFile); + + const { args } = requireDefined(calls[0], "Expected at least one execFile call"); + expect(args).toEqual([ + "--headless", + "--invisible", + `--infilter="MS PowerPoint 97"`, + "--convert-to", + "pdf:impress_pdf_Export", + "--outdir", + "out", + "in.ppt", + ]); +}); + +test("converts pptx to odp with impress filters", async () => { + await convert("in.pptx", "pptx", "odp", "out/out.odp", undefined, mockExecFile); + + const { args } = requireDefined(calls[0], "Expected at least one execFile call"); + expect(args).toEqual([ + "--headless", + "--invisible", + `--infilter="Impress MS PowerPoint 2007 XML"`, + "--convert-to", + "odp:impress8", + "--outdir", + "out", + "in.pptx", + ]); +}); + +test("converts odp to pptx with impress filters", async () => { + await convert("in.odp", "odp", "pptx", "out/out.pptx", undefined, mockExecFile); + + const { args } = requireDefined(calls[0], "Expected at least one execFile call"); + expect(args).toEqual([ + "--headless", + "--invisible", + `--infilter="impress8"`, + "--convert-to", + "pptx:Impress MS PowerPoint 2007 XML", + "--outdir", + "out", + "in.odp", + ]); +});