perf: optimize PDF to image conversion by using a single Ghostscript execution and improve cleanup logic
Build and Push Multi-Platform Images / build-and-push (push) Successful in 28s

This commit is contained in:
2026-05-04 15:45:19 +02:00
parent fe6055a38d
commit fcca31bc4f
@@ -37,16 +37,37 @@ export class PdfService {
/**
* Konvertiert alle Seiten einer PDF in Bilder.
* Verwendet einen einzigen Ghostscript-Aufruf mit %d-Platzhalter für alle Seiten.
*/
async pdfToImages(pdfPath: string, dpi = 200): Promise<string[]> {
const pageCount = await this.getPageCount(pdfPath);
const images: string[] = [];
if (pageCount === 0) return [];
const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), 'pdf-'));
const outputPattern = path.join(tmpDir, 'page-%d.png');
await execFileAsync('gs', [
'-dNOPAUSE',
'-dBATCH',
'-dSAFER',
'-sDEVICE=png16m',
`-r${dpi}`,
`-sOutputFile=${outputPattern}`,
pdfPath,
]);
const images: string[] = [];
for (let i = 1; i <= pageCount; i++) {
const imgPath = await this.pdfPageToImage(pdfPath, i, dpi);
images.push(imgPath);
const imgPath = path.join(tmpDir, `page-${i}.png`);
try {
await fs.access(imgPath);
images.push(imgPath);
} catch {
this.logger.warn(`Ghostscript hat Seite ${i} nicht erstellt: ${imgPath}`);
}
}
this.logger.debug(`PDF konvertiert: ${images.length}/${pageCount} Seite(n) in ${tmpDir}`);
return images;
}
@@ -82,17 +103,16 @@ export class PdfService {
}
/**
* Räumt temporäre Bilder auf.
* Räumt temporäre Bilder und ihre Verzeichnisse auf.
*/
async cleanup(imagePaths: string[]): Promise<void> {
const dirs = new Set<string>();
for (const imgPath of imagePaths) {
try {
await fs.unlink(imgPath);
const dir = path.dirname(imgPath);
await fs.rmdir(dir).catch(() => {});
} catch {
// Ignorieren
}
try { await fs.unlink(imgPath); } catch {}
dirs.add(path.dirname(imgPath));
}
for (const dir of dirs) {
await fs.rmdir(dir).catch(() => {});
}
}
}