mirror of
https://github.com/CaramelFur/Picsur.git
synced 2025-11-13 23:35:39 +01:00
add exif stripping, and convert to png by default
This commit is contained in:
@@ -1,10 +1,12 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { ImageDBModule } from '../../collections/imagedb/imagedb.module';
|
||||
import { PreferenceModule } from '../../collections/preferencesdb/preferencedb.module';
|
||||
import { ImageManagerService } from './imagemanager.service';
|
||||
import { ImageProcessorService } from './imageprocessor.service';
|
||||
|
||||
@Module({
|
||||
imports: [ImageDBModule],
|
||||
providers: [ImageManagerService],
|
||||
imports: [ImageDBModule, PreferenceModule],
|
||||
providers: [ImageManagerService, ImageProcessorService],
|
||||
exports: [ImageManagerService],
|
||||
})
|
||||
export class ImageManagerModule {}
|
||||
|
||||
@@ -5,6 +5,7 @@ import { ImageDBService } from '../../collections/imagedb/imagedb.service';
|
||||
import { MimesService } from '../../collections/imagedb/mimes.service';
|
||||
import { FullMime } from '../../models/dto/mimes.dto';
|
||||
import { EImageBackend } from '../../models/entities/image.entity';
|
||||
import { ImageProcessorService } from './imageprocessor.service';
|
||||
|
||||
// Right now this service is mostly a wrapper for the imagedbservice.
|
||||
// But in the future the actual image logic will happend here
|
||||
@@ -15,6 +16,7 @@ export class ImageManagerService {
|
||||
constructor(
|
||||
private readonly imagesService: ImageDBService,
|
||||
private readonly mimesService: MimesService,
|
||||
private readonly processService: ImageProcessorService,
|
||||
) {}
|
||||
|
||||
public async retrieveInfo(hash: string): AsyncFailable<EImageBackend> {
|
||||
@@ -23,15 +25,25 @@ export class ImageManagerService {
|
||||
|
||||
// Image data buffer is not included by default, this also returns that buffer
|
||||
// Dont send to client, keep in backend
|
||||
public async retrieveComplete(hash: string): AsyncFailable<Required<EImageBackend>> {
|
||||
public async retrieveComplete(
|
||||
hash: string,
|
||||
): AsyncFailable<Required<EImageBackend>> {
|
||||
return await this.imagesService.findOne(hash, true);
|
||||
}
|
||||
|
||||
public async upload(image: Buffer): AsyncFailable<EImageBackend> {
|
||||
public async upload(
|
||||
image: Buffer,
|
||||
userid: string,
|
||||
): AsyncFailable<EImageBackend> {
|
||||
const fullMime = await this.getFullMimeFromBuffer(image);
|
||||
if (HasFailed(fullMime)) return fullMime;
|
||||
|
||||
const processedImage: Buffer = await this.process(image, fullMime);
|
||||
const processedImage = await this.processService.process(
|
||||
image,
|
||||
fullMime,
|
||||
userid,
|
||||
);
|
||||
if (HasFailed(processedImage)) return processedImage;
|
||||
|
||||
const imageEntity = await this.imagesService.create(
|
||||
processedImage,
|
||||
@@ -42,11 +54,6 @@ export class ImageManagerService {
|
||||
return imageEntity;
|
||||
}
|
||||
|
||||
private async process(image: Buffer, mime: FullMime): Promise<Buffer> {
|
||||
// nothing happens right now
|
||||
return image;
|
||||
}
|
||||
|
||||
private async getFullMimeFromBuffer(image: Buffer): AsyncFailable<FullMime> {
|
||||
const mime: FileTypeResult | undefined = await fileTypeFromBuffer(image);
|
||||
const fullMime = await this.mimesService.getFullMime(
|
||||
|
||||
82
backend/src/managers/imagemanager/imageprocessor.service.ts
Normal file
82
backend/src/managers/imagemanager/imageprocessor.service.ts
Normal file
@@ -0,0 +1,82 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import icoToPng from 'ico-to-png';
|
||||
import { AsyncFailable, Fail } from 'picsur-shared/dist/types';
|
||||
import sharp from 'sharp';
|
||||
import { UsrPreferenceService } from '../../collections/preferencesdb/usrpreferencedb.service';
|
||||
import {
|
||||
FullMime,
|
||||
ImageMime,
|
||||
SupportedMimeCategory
|
||||
} from '../../models/dto/mimes.dto';
|
||||
|
||||
@Injectable()
|
||||
export class ImageProcessorService {
|
||||
constructor(private readonly userPref: UsrPreferenceService) {}
|
||||
|
||||
public async process(
|
||||
image: Buffer,
|
||||
mime: FullMime,
|
||||
userid: string,
|
||||
): AsyncFailable<Buffer> {
|
||||
if (mime.type === SupportedMimeCategory.Image) {
|
||||
return await this.processStill(image, mime, {});
|
||||
} else if (mime.type === SupportedMimeCategory.Animation) {
|
||||
return await this.processAnimation(image, mime, {});
|
||||
} else {
|
||||
return Fail('Unsupported mime type');
|
||||
}
|
||||
|
||||
// // nothing happens right now
|
||||
// const keepOriginal = await this.userPref.getBooleanPreference(
|
||||
// userid,
|
||||
// UsrPreference.KeepOriginal,
|
||||
// );
|
||||
// if (HasFailed(keepOriginal)) return keepOriginal;
|
||||
|
||||
// if (keepOriginal) {
|
||||
// }
|
||||
}
|
||||
|
||||
private async processStill(
|
||||
image: Buffer,
|
||||
mime: FullMime,
|
||||
options: {},
|
||||
): AsyncFailable<Buffer> {
|
||||
let processedImage = image;
|
||||
|
||||
switch (mime.mime) {
|
||||
case ImageMime.ICO:
|
||||
processedImage = await icoToPng(processedImage, 512);
|
||||
mime.mime = ImageMime.PNG;
|
||||
break;
|
||||
|
||||
case ImageMime.BMP:
|
||||
case ImageMime.TIFF:
|
||||
case ImageMime.WEBP:
|
||||
case ImageMime.PNG:
|
||||
case ImageMime.JPEG:
|
||||
processedImage = await sharp(processedImage)
|
||||
.png({
|
||||
compressionLevel: 9,
|
||||
effort: 10,
|
||||
})
|
||||
.toBuffer();
|
||||
mime.mime = ImageMime.PNG;
|
||||
break;
|
||||
|
||||
default:
|
||||
return Fail('Unsupported mime type');
|
||||
}
|
||||
|
||||
return processedImage;
|
||||
}
|
||||
|
||||
private async processAnimation(
|
||||
image: Buffer,
|
||||
mime: FullMime,
|
||||
options: {},
|
||||
): AsyncFailable<Buffer> {
|
||||
// Apng and gif are stored as is for now
|
||||
return image;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user