diff --git a/src/backend/model/fileprocessing/PhotoProcessing.ts b/src/backend/model/fileprocessing/PhotoProcessing.ts index a0b88de0..4fd6678a 100644 --- a/src/backend/model/fileprocessing/PhotoProcessing.ts +++ b/src/backend/model/fileprocessing/PhotoProcessing.ts @@ -1,18 +1,18 @@ import * as path from 'path'; -import { constants as fsConstants, promises as fsp } from 'fs'; +import {constants as fsConstants, promises as fsp} from 'fs'; import * as os from 'os'; import * as crypto from 'crypto'; -import { ProjectPath } from '../../ProjectPath'; -import { Config } from '../../../common/config/private/Config'; +import {ProjectPath} from '../../ProjectPath'; +import {Config} from '../../../common/config/private/Config'; import { PhotoWorker, RendererInput, ThumbnailSourceType, } from '../threading/PhotoWorker'; -import { ITaskExecuter, TaskExecuter } from '../threading/TaskExecuter'; -import { FaceRegion, PhotoDTO } from '../../../common/entities/PhotoDTO'; -import { SupportedFormats } from '../../../common/SupportedFormats'; -import { PersonWithSampleRegion } from '../../../common/entities/PersonDTO'; +import {ITaskExecuter, TaskExecuter} from '../threading/TaskExecuter'; +import {FaceRegion, PhotoDTO} from '../../../common/entities/PhotoDTO'; +import {SupportedFormats} from '../../../common/SupportedFormats'; +import {PersonWithSampleRegion} from '../../../common/entities/PersonDTO'; export class PhotoProcessing { private static initDone = false; @@ -75,11 +75,11 @@ export class PhotoProcessing { const margin = { x: Math.round( person.sampleRegion.box.width * - Config.Server.Media.Thumbnail.personFaceMargin + Config.Server.Media.Thumbnail.personFaceMargin ), y: Math.round( person.sampleRegion.box.height * - Config.Server.Media.Thumbnail.personFaceMargin + Config.Server.Media.Thumbnail.personFaceMargin ), }; @@ -100,7 +100,8 @@ export class PhotoProcessing { width: person.sampleRegion.box.width + margin.x, height: person.sampleRegion.box.height + margin.y, }, - qualityPriority: Config.Server.Media.Thumbnail.qualityPriority, + useLanczos3: Config.Server.Media.Thumbnail.useLanczos3, + quality: Config.Server.Media.Thumbnail.quality, } as RendererInput; input.cut.width = Math.min( input.cut.width, @@ -111,7 +112,7 @@ export class PhotoProcessing { photo.metadata.size.height - input.cut.top ); - await fsp.mkdir(ProjectPath.FacesFolder, { recursive: true }); + await fsp.mkdir(ProjectPath.FacesFolder, {recursive: true}); await PhotoProcessing.taskQue.execute(input); return thPath; } @@ -121,7 +122,7 @@ export class PhotoProcessing { return path.join( ProjectPath.TranscodedFolder, ProjectPath.getRelativePathToImages(path.dirname(mediaPath)), - file + '_' + size + '.webp' + file + '_' + size + 'q' + Config.Server.Media.Thumbnail.quality + '.webp' ); } @@ -136,17 +137,17 @@ export class PhotoProcessing { .createHash('md5') .update( mediaPath + - '_' + - faceRegion.name + - '_' + - faceRegion.box.left + - '_' + - faceRegion.box.top + '_' + + faceRegion.name + + '_' + + faceRegion.box.left + + '_' + + faceRegion.box.top ) .digest('hex') + - '_' + - size + - '.webp' + '_' + + size + + '.webp' ); } @@ -235,12 +236,13 @@ export class PhotoProcessing { size, outPath, makeSquare, - qualityPriority: Config.Server.Media.Thumbnail.qualityPriority, + useLanczos3: Config.Server.Media.Thumbnail.useLanczos3, + quality: Config.Server.Media.Thumbnail.quality, } as RendererInput; const outDir = path.dirname(input.outPath); - await fsp.mkdir(outDir, { recursive: true }); + await fsp.mkdir(outDir, {recursive: true}); await this.taskQue.execute(input); return outPath; } diff --git a/src/backend/model/threading/PhotoWorker.ts b/src/backend/model/threading/PhotoWorker.ts index ebe30863..8b9bcb6e 100644 --- a/src/backend/model/threading/PhotoWorker.ts +++ b/src/backend/model/threading/PhotoWorker.ts @@ -1,8 +1,8 @@ /* eslint-disable @typescript-eslint/no-var-requires */ -import { Metadata, Sharp } from 'sharp'; -import { Logger } from '../../Logger'; -import { FfmpegCommand, FfprobeData } from 'fluent-ffmpeg'; -import { FFmpegFactory } from '../FFmpegFactory'; +import {Metadata, Sharp} from 'sharp'; +import {Logger} from '../../Logger'; +import {FfmpegCommand, FfprobeData} from 'fluent-ffmpeg'; +import {FFmpegFactory} from '../FFmpegFactory'; export class PhotoWorker { private static imageRenderer: (input: RendererInput) => Promise = null; @@ -44,7 +44,8 @@ export interface RendererInput { size: number; makeSquare: boolean; outPath: string; - qualityPriority: boolean; + quality: number; + useLanczos3: boolean; cut?: { left: number; top: number; @@ -129,15 +130,15 @@ export class ImageRendererFactory { return async (input: RendererInput): Promise => { Logger.silly( '[SharpRenderer] rendering photo:' + - input.mediaPath + - ', size:' + - input.size + input.mediaPath + + ', size:' + + input.size ); - const image: Sharp = sharp(input.mediaPath, { failOnError: false }); + const image: Sharp = sharp(input.mediaPath, {failOnError: false}); const metadata: Metadata = await image.metadata(); const kernel = - input.qualityPriority === true + input.useLanczos3 === true ? sharp.kernel.lanczos3 : sharp.kernel.nearest; @@ -161,7 +162,7 @@ export class ImageRendererFactory { fit: 'cover', }); } - await image.withMetadata().webp({effort: 6, quality: 60}).toFile(input.outPath); + await image.webp({effort: 6, quality: input.quality}).toFile(input.outPath); }; } } diff --git a/src/common/config/private/PrivateConfig.ts b/src/common/config/private/PrivateConfig.ts index a58987b9..8319ac63 100644 --- a/src/common/config/private/PrivateConfig.ts +++ b/src/common/config/private/PrivateConfig.ts @@ -142,8 +142,10 @@ export class ServerDataBaseConfig { @SubConfigClass() export class ServerThumbnailConfig { - @ConfigProperty({description: 'if true, photos will have better quality.'}) - qualityPriority: boolean = true; + @ConfigProperty({description: 'if true, \'lanczos3\' will used to scale photos, otherwise faster but lowe quality \'nearest\'.'}) + useLanczos3: boolean = true; + @ConfigProperty({description: 'Thumbnail image quality', max: 100, min: 1, type: 'unsignedInt'}) + quality = 80; @ConfigProperty({type: 'ratio'}) personFaceMargin: number = 0.6; // in ration [0-1] }