import { Inject, Injectable } from '@nestjs/common'; import fs from 'fs-extra'; import { WINSTON_MODULE_PROVIDER } from 'nest-winston'; import sharp from 'sharp'; import { Logger } from 'winston'; @Injectable() export class FileService { constructor(@Inject(WINSTON_MODULE_PROVIDER) private readonly logger: Logger) { fs.ensureDirSync(`./pictures`); fs.ensureDirSync(`./pictures/profile`); fs.ensureDirSync(`./pictures/logo`); fs.ensureDirSync(`./pictures/property`); } // ############ // Profile // ############ async storeProfilePicture(file: Express.Multer.File, adjustedEmail: string) { const quality = 50; const output = await sharp(file.buffer) .resize({ width: 300 }) .avif({ quality }) // Verwende AVIF //.webp({ quality }) // Verwende Webp .toBuffer(); await sharp(output).toFile(`./pictures/profile/${adjustedEmail}.avif`); } hasProfile(adjustedEmail: string) { return fs.existsSync(`./pictures/profile/${adjustedEmail}.avif`); } // ############ // Logo // ############ async storeCompanyLogo(file: Express.Multer.File, adjustedEmail: string) { const quality = 50; const output = await sharp(file.buffer) .resize({ width: 300 }) .avif({ quality }) // Verwende AVIF //.webp({ quality }) // Verwende Webp .toBuffer(); await sharp(output).toFile(`./pictures/logo/${adjustedEmail}.avif`); // Ersetze Dateierweiterung // await fs.outputFile(`./pictures/logo/${userId}`, file.buffer); } hasCompanyLogo(adjustedEmail: string) { return fs.existsSync(`./pictures/logo/${adjustedEmail}.avif`) ? true : false; } // ############ // Property // ############ async getPropertyImages(imagePath: string, serial: string): Promise { const result: string[] = []; const directory = `./pictures/property/${imagePath}/${serial}`; if (fs.existsSync(directory)) { const files = await fs.readdir(directory); files.forEach(f => { result.push(f); }); return result; } else { return []; } } async hasPropertyImages(imagePath: string, serial: string): Promise { const directory = `./pictures/property/${imagePath}/${serial}`; if (fs.existsSync(directory)) { const files = await fs.readdir(directory); return files.length > 0; } else { return false; } } async storePropertyPicture(file: Express.Multer.File, imagePath: string, serial: string): Promise { const directory = `./pictures/property/${imagePath}/${serial}`; fs.ensureDirSync(`${directory}`); const imageName = await this.getNextImageName(directory); //await fs.outputFile(`${directory}/${imageName}`, file.buffer); await this.resizeImageToAVIF(file.buffer, 150 * 1024, imageName, directory); return `${imageName}.avif`; } // ############ // utils // ############ async getNextImageName(directory) { try { const files = await fs.readdir(directory); const imageNumbers = files .map(file => parseInt(file, 10)) // Dateinamen direkt in Zahlen umwandeln .filter(number => !isNaN(number)) // Sicherstellen, dass die Konvertierung gültig ist .sort((a, b) => a - b); // Aufsteigend sortieren const nextNumber = imageNumbers.length > 0 ? Math.max(...imageNumbers) + 1 : 1; return `${nextNumber}`; // Keine Endung für den Dateinamen } catch (error) { console.error('Fehler beim Lesen des Verzeichnisses:', error); return null; } } async resizeImageToAVIF(buffer: Buffer, maxSize: number, imageName: string, directory: string) { const quality = 50; // AVIF kann mit niedrigeren Qualitätsstufen gute Ergebnisse erzielen const start = Date.now(); const output = await sharp(buffer) .resize({ width: 1500 }) .avif({ quality }) // Verwende AVIF //.webp({ quality }) // Verwende Webp .toBuffer(); await sharp(output).toFile(`${directory}/${imageName}.avif`); // Ersetze Dateierweiterung const timeTaken = Date.now() - start; this.logger.info(`Quality: ${quality} - Time: ${timeTaken} milliseconds`); } deleteImage(path: string) { fs.unlinkSync(path); } deleteDirectoryIfExists(imagePath) { const dirPath = `pictures/property/${imagePath}`; try { const exists = fs.pathExistsSync(); if (exists) { fs.removeSync(dirPath); console.log(`Directory ${dirPath} was deleted.`); } else { console.log(`Directory ${dirPath} does not exist.`); } } catch (error) { console.error(`Error while deleting ${dirPath}:`, error); } } }