add exif stripping, and convert to png by default

This commit is contained in:
rubikscraft
2022-04-15 12:52:53 +02:00
parent 9ad802b05f
commit 2e6e868f89
12 changed files with 457 additions and 36 deletions

View File

@@ -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 {}

View File

@@ -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(

View 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;
}
}