Store animated images as lossless webp

This commit is contained in:
rubikscraft
2022-12-28 16:49:45 +01:00
committed by Caramel
parent d24e4a7723
commit 10dfb3a579
4 changed files with 45 additions and 30 deletions

View File

@@ -2,21 +2,28 @@ import { Injectable } from '@nestjs/common';
import ms from 'ms';
import { ImageRequestParams } from 'picsur-shared/dist/dto/api/image.dto';
import {
FileType,
SupportedFileTypeCategory,
FileType,
SupportedFileTypeCategory,
} from 'picsur-shared/dist/dto/mimes.dto';
import { SysPreference } from 'picsur-shared/dist/dto/sys-preferences.enum';
import {
AsyncFailable,
Fail,
FT,
HasFailed,
AsyncFailable,
Fail,
FT,
HasFailed,
} from 'picsur-shared/dist/types/failable';
import { SharpOptions } from 'sharp';
import { SysPreferenceDbService } from '../../collections/preference-db/sys-preference-db.service.js';
import { SharpWrapper } from '../../workers/sharp.wrapper.js';
import { ImageResult } from './imageresult.js';
interface InternalConvertOptions {
lossless?: boolean;
effort?: number;
}
export type ConvertOptions = ImageRequestParams & InternalConvertOptions;
@Injectable()
export class ImageConverterService {
constructor(private readonly sysPref: SysPreferenceDbService) {}
@@ -25,7 +32,7 @@ export class ImageConverterService {
image: Buffer,
sourceFiletype: FileType,
targetFiletype: FileType,
options: ImageRequestParams,
options: ConvertOptions,
): AsyncFailable<ImageResult> {
if (
sourceFiletype.identifier === targetFiletype.identifier &&
@@ -37,23 +44,22 @@ export class ImageConverterService {
};
}
if (targetFiletype.category === SupportedFileTypeCategory.Image) {
return this.convertStill(image, sourceFiletype, targetFiletype, options);
} else if (
if (
targetFiletype.category === SupportedFileTypeCategory.Image ||
targetFiletype.category === SupportedFileTypeCategory.Animation
) {
return this.convertStill(image, sourceFiletype, targetFiletype, options);
return this.convertImage(image, sourceFiletype, targetFiletype, options);
//return this.convertAnimation(image, targetmime, options);
} else {
return Fail(FT.SysValidation, 'Unsupported mime type');
}
}
private async convertStill(
private async convertImage(
image: Buffer,
sourceFiletype: FileType,
targetFiletype: FileType,
options: ImageRequestParams,
options: ConvertOptions,
): AsyncFailable<ImageResult> {
const [memLimit, timeLimit] = await Promise.all([
this.sysPref.getNumberPreference(SysPreference.ConversionMemoryLimit),

View File

@@ -1,15 +1,15 @@
import { Injectable } from '@nestjs/common';
import {
FileType,
ImageFileType,
SupportedFileTypeCategory,
FileType,
ImageFileType,
SupportedFileTypeCategory,
} from 'picsur-shared/dist/dto/mimes.dto';
import {
AsyncFailable,
Fail,
FT,
HasFailed,
AsyncFailable,
Fail,
FT,
HasFailed,
} from 'picsur-shared/dist/types/failable';
import { ParseFileType } from 'picsur-shared/dist/util/parse-mime';
import { ImageConverterService } from './image-converter.service.js';
@@ -46,10 +46,12 @@ export class ImageProcessorService {
image: Buffer,
filetype: FileType,
): AsyncFailable<ImageResult> {
// Webps and gifs are stored as is for now
return {
image: image,
filetype: filetype.identifier,
};
const outputFileType = ParseFileType(AnimFileType.WEBP);
if (HasFailed(outputFileType)) return outputFileType;
return this.imageConverter.convert(image, filetype, outputFileType, {
lossless: true,
effort: 0,
});
}
}

View File

@@ -26,6 +26,10 @@ export type SharpWorkerOperation =
export interface SharpWorkerFinishOptions {
quality?: number;
// Only for internal use
lossless?: boolean;
effort?: number;
}
// Messages

View File

@@ -2,10 +2,11 @@ import { BMPdecode, BMPencode } from 'bmp-img';
import {
AnimFileType,
FileType,
ImageFileType,
ImageFileType
} from 'picsur-shared/dist/dto/mimes.dto';
import { QOIdecode, QOIencode } from 'qoi-img';
import sharp, { Sharp, SharpOptions } from 'sharp';
import { SharpWorkerFinishOptions } from './sharp.message';
export interface SharpResult {
data: Buffer;
@@ -72,9 +73,7 @@ function qoiSharpIn(image: Buffer, options?: SharpOptions) {
export async function UniversalSharpOut(
image: Sharp,
filetype: FileType,
options?: {
quality?: number;
},
options?: SharpWorkerFinishOptions,
): Promise<SharpResult> {
let result: SharpResult | undefined;
@@ -103,7 +102,11 @@ export async function UniversalSharpOut(
case ImageFileType.WEBP:
case AnimFileType.WEBP:
result = await image
.webp({ quality: options?.quality })
.webp({
quality: options?.quality,
lossless: options?.lossless,
effort: options?.effort,
})
.toBuffer({ resolveWithObject: true });
break;
case AnimFileType.GIF: