Initial commit with Email Import Wizard and Task Processor updates
This commit is contained in:
@@ -0,0 +1,98 @@
|
||||
import { Injectable, Logger } from '@nestjs/common';
|
||||
import { execFile } from 'child_process';
|
||||
import { promisify } from 'util';
|
||||
import * as path from 'path';
|
||||
import * as fs from 'fs/promises';
|
||||
import * as os from 'os';
|
||||
|
||||
const execFileAsync = promisify(execFile);
|
||||
|
||||
@Injectable()
|
||||
export class PdfService {
|
||||
private readonly logger = new Logger(PdfService.name);
|
||||
|
||||
/**
|
||||
* Konvertiert eine PDF-Seite in ein PNG-Bild via Ghostscript.
|
||||
* Gibt den Pfad zum temporären Bild zurück.
|
||||
*/
|
||||
async pdfPageToImage(pdfPath: string, page = 1, dpi = 300): Promise<string> {
|
||||
const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), 'pdf-'));
|
||||
const outputPath = path.join(tmpDir, `page-${page}.png`);
|
||||
|
||||
await execFileAsync('gs', [
|
||||
'-dNOPAUSE',
|
||||
'-dBATCH',
|
||||
'-dSAFER',
|
||||
'-sDEVICE=png16m',
|
||||
`-dFirstPage=${page}`,
|
||||
`-dLastPage=${page}`,
|
||||
`-r${dpi}`,
|
||||
`-sOutputFile=${outputPath}`,
|
||||
pdfPath,
|
||||
]);
|
||||
|
||||
this.logger.debug(`PDF Seite ${page} konvertiert: ${outputPath}`);
|
||||
return outputPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Konvertiert alle Seiten einer PDF in Bilder.
|
||||
*/
|
||||
async pdfToImages(pdfPath: string, dpi = 200): Promise<string[]> {
|
||||
const pageCount = await this.getPageCount(pdfPath);
|
||||
const images: string[] = [];
|
||||
|
||||
for (let i = 1; i <= pageCount; i++) {
|
||||
const imgPath = await this.pdfPageToImage(pdfPath, i, dpi);
|
||||
images.push(imgPath);
|
||||
}
|
||||
|
||||
return images;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ermittelt die Seitenanzahl einer PDF via Ghostscript.
|
||||
*/
|
||||
async getPageCount(pdfPath: string): Promise<number> {
|
||||
const { stdout } = await execFileAsync('gs', [
|
||||
'-q',
|
||||
'-dNODISPLAY',
|
||||
'-dNOSAFER',
|
||||
`-c`,
|
||||
`(${pdfPath.replace(/\\/g, '/')}) (r) file runpdfbegin pdfpagecount = quit`,
|
||||
]);
|
||||
return parseInt(stdout.trim(), 10) || 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bereinigt eine PDF (entschlüsselt sie ggf. wenn nur Owner-Passwort gesetzt ist)
|
||||
* via Ghostscript pdfwrite.
|
||||
*/
|
||||
async sanitizePdf(inputPath: string): Promise<string> {
|
||||
const outputPath = path.join(os.tmpdir(), `sanitized-${Date.now()}.pdf`);
|
||||
await execFileAsync('gs', [
|
||||
'-dNOPAUSE',
|
||||
'-dBATCH',
|
||||
'-dSAFER',
|
||||
'-sDEVICE=pdfwrite',
|
||||
`-sOutputFile=${outputPath}`,
|
||||
inputPath,
|
||||
]);
|
||||
return outputPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Räumt temporäre Bilder auf.
|
||||
*/
|
||||
async cleanup(imagePaths: string[]): Promise<void> {
|
||||
for (const imgPath of imagePaths) {
|
||||
try {
|
||||
await fs.unlink(imgPath);
|
||||
const dir = path.dirname(imgPath);
|
||||
await fs.rmdir(dir).catch(() => {});
|
||||
} catch {
|
||||
// Ignorieren
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user