mirror of
				https://github.com/CaramelFur/Picsur.git
				synced 2025-10-31 17:35:48 +01:00 
			
		
		
		
	Store animated images as lossless webp
This commit is contained in:
		| @@ -17,6 +17,13 @@ import { SysPreferenceDbService } from '../../collections/preference-db/sys-pref | |||||||
| import { SharpWrapper } from '../../workers/sharp.wrapper.js'; | import { SharpWrapper } from '../../workers/sharp.wrapper.js'; | ||||||
| import { ImageResult } from './imageresult.js'; | import { ImageResult } from './imageresult.js'; | ||||||
|  |  | ||||||
|  | interface InternalConvertOptions { | ||||||
|  |   lossless?: boolean; | ||||||
|  |   effort?: number; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export type ConvertOptions = ImageRequestParams & InternalConvertOptions; | ||||||
|  |  | ||||||
| @Injectable() | @Injectable() | ||||||
| export class ImageConverterService { | export class ImageConverterService { | ||||||
|   constructor(private readonly sysPref: SysPreferenceDbService) {} |   constructor(private readonly sysPref: SysPreferenceDbService) {} | ||||||
| @@ -25,7 +32,7 @@ export class ImageConverterService { | |||||||
|     image: Buffer, |     image: Buffer, | ||||||
|     sourceFiletype: FileType, |     sourceFiletype: FileType, | ||||||
|     targetFiletype: FileType, |     targetFiletype: FileType, | ||||||
|     options: ImageRequestParams, |     options: ConvertOptions, | ||||||
|   ): AsyncFailable<ImageResult> { |   ): AsyncFailable<ImageResult> { | ||||||
|     if ( |     if ( | ||||||
|       sourceFiletype.identifier === targetFiletype.identifier && |       sourceFiletype.identifier === targetFiletype.identifier && | ||||||
| @@ -37,23 +44,22 @@ export class ImageConverterService { | |||||||
|       }; |       }; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     if (targetFiletype.category === SupportedFileTypeCategory.Image) { |     if ( | ||||||
|       return this.convertStill(image, sourceFiletype, targetFiletype, options); |       targetFiletype.category === SupportedFileTypeCategory.Image || | ||||||
|     } else if ( |  | ||||||
|       targetFiletype.category === SupportedFileTypeCategory.Animation |       targetFiletype.category === SupportedFileTypeCategory.Animation | ||||||
|     ) { |     ) { | ||||||
|       return this.convertStill(image, sourceFiletype, targetFiletype, options); |       return this.convertImage(image, sourceFiletype, targetFiletype, options); | ||||||
|       //return this.convertAnimation(image, targetmime, options); |       //return this.convertAnimation(image, targetmime, options); | ||||||
|     } else { |     } else { | ||||||
|       return Fail(FT.SysValidation, 'Unsupported mime type'); |       return Fail(FT.SysValidation, 'Unsupported mime type'); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   private async convertStill( |   private async convertImage( | ||||||
|     image: Buffer, |     image: Buffer, | ||||||
|     sourceFiletype: FileType, |     sourceFiletype: FileType, | ||||||
|     targetFiletype: FileType, |     targetFiletype: FileType, | ||||||
|     options: ImageRequestParams, |     options: ConvertOptions, | ||||||
|   ): AsyncFailable<ImageResult> { |   ): AsyncFailable<ImageResult> { | ||||||
|     const [memLimit, timeLimit] = await Promise.all([ |     const [memLimit, timeLimit] = await Promise.all([ | ||||||
|       this.sysPref.getNumberPreference(SysPreference.ConversionMemoryLimit), |       this.sysPref.getNumberPreference(SysPreference.ConversionMemoryLimit), | ||||||
|   | |||||||
| @@ -46,10 +46,12 @@ export class ImageProcessorService { | |||||||
|     image: Buffer, |     image: Buffer, | ||||||
|     filetype: FileType, |     filetype: FileType, | ||||||
|   ): AsyncFailable<ImageResult> { |   ): AsyncFailable<ImageResult> { | ||||||
|     // Webps and gifs are stored as is for now |     const outputFileType = ParseFileType(AnimFileType.WEBP); | ||||||
|     return { |     if (HasFailed(outputFileType)) return outputFileType; | ||||||
|       image: image, |  | ||||||
|       filetype: filetype.identifier, |     return this.imageConverter.convert(image, filetype, outputFileType, { | ||||||
|     }; |       lossless: true, | ||||||
|  |       effort: 0, | ||||||
|  |     }); | ||||||
|   } |   } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -26,6 +26,10 @@ export type SharpWorkerOperation = | |||||||
|  |  | ||||||
| export interface SharpWorkerFinishOptions { | export interface SharpWorkerFinishOptions { | ||||||
|   quality?: number; |   quality?: number; | ||||||
|  |  | ||||||
|  |   // Only for internal use | ||||||
|  |   lossless?: boolean; | ||||||
|  |   effort?: number; | ||||||
| } | } | ||||||
|  |  | ||||||
| // Messages | // Messages | ||||||
|   | |||||||
| @@ -2,10 +2,11 @@ import { BMPdecode, BMPencode } from 'bmp-img'; | |||||||
| import { | import { | ||||||
|   AnimFileType, |   AnimFileType, | ||||||
|   FileType, |   FileType, | ||||||
|   ImageFileType, |   ImageFileType | ||||||
| } from 'picsur-shared/dist/dto/mimes.dto'; | } from 'picsur-shared/dist/dto/mimes.dto'; | ||||||
| import { QOIdecode, QOIencode } from 'qoi-img'; | import { QOIdecode, QOIencode } from 'qoi-img'; | ||||||
| import sharp, { Sharp, SharpOptions } from 'sharp'; | import sharp, { Sharp, SharpOptions } from 'sharp'; | ||||||
|  | import { SharpWorkerFinishOptions } from './sharp.message'; | ||||||
|  |  | ||||||
| export interface SharpResult { | export interface SharpResult { | ||||||
|   data: Buffer; |   data: Buffer; | ||||||
| @@ -72,9 +73,7 @@ function qoiSharpIn(image: Buffer, options?: SharpOptions) { | |||||||
| export async function UniversalSharpOut( | export async function UniversalSharpOut( | ||||||
|   image: Sharp, |   image: Sharp, | ||||||
|   filetype: FileType, |   filetype: FileType, | ||||||
|   options?: { |   options?: SharpWorkerFinishOptions, | ||||||
|     quality?: number; |  | ||||||
|   }, |  | ||||||
| ): Promise<SharpResult> { | ): Promise<SharpResult> { | ||||||
|   let result: SharpResult | undefined; |   let result: SharpResult | undefined; | ||||||
|  |  | ||||||
| @@ -103,7 +102,11 @@ export async function UniversalSharpOut( | |||||||
|     case ImageFileType.WEBP: |     case ImageFileType.WEBP: | ||||||
|     case AnimFileType.WEBP: |     case AnimFileType.WEBP: | ||||||
|       result = await image |       result = await image | ||||||
|         .webp({ quality: options?.quality }) |         .webp({ | ||||||
|  |           quality: options?.quality, | ||||||
|  |           lossless: options?.lossless, | ||||||
|  |           effort: options?.effort, | ||||||
|  |         }) | ||||||
|         .toBuffer({ resolveWithObject: true }); |         .toBuffer({ resolveWithObject: true }); | ||||||
|       break; |       break; | ||||||
|     case AnimFileType.GIF: |     case AnimFileType.GIF: | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user