1
0
Fork 0
mirror of https://github.com/immich-app/immich.git synced 2025-01-04 02:46:47 +01:00

feat: move full-size preview config to standalone entry

This commit is contained in:
Eli Gao 2024-12-23 00:21:12 +08:00
parent cb0831364d
commit 6160790dc8
5 changed files with 79 additions and 20 deletions

View file

@ -12,7 +12,7 @@ import {
VideoContainer, VideoContainer,
} from 'src/enum'; } from 'src/enum';
import { ConcurrentQueueName, QueueName } from 'src/interfaces/job.interface'; import { ConcurrentQueueName, QueueName } from 'src/interfaces/job.interface';
import { ImageOptions } from 'src/interfaces/media.interface'; import { FullsizeImageOptions, ImageOptions } from 'src/interfaces/media.interface';
export interface SystemConfig { export interface SystemConfig {
backup: { backup: {
@ -112,7 +112,7 @@ export interface SystemConfig {
preview: ImageOptions; preview: ImageOptions;
colorspace: Colorspace; colorspace: Colorspace;
extractEmbedded: boolean; extractEmbedded: boolean;
fullsizePreview: boolean; fullsize: FullsizeImageOptions;
}; };
newVersionCheck: { newVersionCheck: {
enabled: boolean; enabled: boolean;
@ -282,7 +282,11 @@ export const defaults = Object.freeze<SystemConfig>({
}, },
colorspace: Colorspace.P3, colorspace: Colorspace.P3,
extractEmbedded: false, extractEmbedded: false,
fullsizePreview: false, fullsize: {
enabled: false,
format: ImageFormat.JPEG,
quality: 80,
},
}, },
newVersionCheck: { newVersionCheck: {
enabled: true, enabled: true,

View file

@ -530,6 +530,24 @@ class SystemConfigGeneratedImageDto {
size!: number; size!: number;
} }
class SystemConfigGeneratedFullsizeImageDto {
@IsBoolean()
@Type(() => Boolean)
@ApiProperty({ type: 'boolean' })
enabled!: boolean;
@IsEnum(ImageFormat)
@ApiProperty({ enumName: 'ImageFormat', enum: ImageFormat })
format!: ImageFormat;
@IsInt()
@Min(1)
@Max(100)
@Type(() => Number)
@ApiProperty({ type: 'integer' })
quality!: number;
}
export class SystemConfigImageDto { export class SystemConfigImageDto {
@Type(() => SystemConfigGeneratedImageDto) @Type(() => SystemConfigGeneratedImageDto)
@ValidateNested() @ValidateNested()
@ -541,15 +559,17 @@ export class SystemConfigImageDto {
@IsObject() @IsObject()
preview!: SystemConfigGeneratedImageDto; preview!: SystemConfigGeneratedImageDto;
@Type(() => SystemConfigGeneratedFullsizeImageDto)
@ValidateNested()
@IsObject()
fullsize!: SystemConfigGeneratedFullsizeImageDto;
@IsEnum(Colorspace) @IsEnum(Colorspace)
@ApiProperty({ enumName: 'Colorspace', enum: Colorspace }) @ApiProperty({ enumName: 'Colorspace', enum: Colorspace })
colorspace!: Colorspace; colorspace!: Colorspace;
@ValidateBoolean() @ValidateBoolean()
extractEmbedded!: boolean; extractEmbedded!: boolean;
@ValidateBoolean()
fullsizePreview!: boolean;
} }
class SystemConfigTrashDto { class SystemConfigTrashDto {

View file

@ -11,6 +11,12 @@ export interface CropOptions {
height: number; height: number;
} }
export interface FullsizeImageOptions {
format: ImageFormat;
quality: number;
enabled: boolean;
}
export interface ImageOptions { export interface ImageOptions {
format: ImageFormat; format: ImageFormat;
quality: number; quality: number;

View file

@ -235,7 +235,8 @@ export class MediaService extends BaseService {
const imageIsWebSupported = mimeTypes.isWebSupportedImage(asset.originalFileName); const imageIsWebSupported = mimeTypes.isWebSupportedImage(asset.originalFileName);
const imageIsRaw = mimeTypes.isRaw(asset.originalFileName); const imageIsRaw = mimeTypes.isRaw(asset.originalFileName);
const shouldConvertFullsize = !imageIsWebSupported && image.fullsizePreview; const { enabled: enableFullsizeImage, ...fullsizeImageOptions } = image.fullsize;
const shouldConvertFullsize = !imageIsWebSupported && enableFullsizeImage;
const shouldExtractEmbedded = imageIsRaw && image.extractEmbedded; const shouldExtractEmbedded = imageIsRaw && image.extractEmbedded;
const decodeOptions: DecodeToBufferOptions = { const decodeOptions: DecodeToBufferOptions = {
colorspace, colorspace,
@ -246,7 +247,8 @@ export class MediaService extends BaseService {
let useExtracted = false; let useExtracted = false;
let decodeInputPath: string = asset.originalPath; let decodeInputPath: string = asset.originalPath;
// Converted or extracted image from non-web-supported formats (e.g. RAW) // Converted or extracted image from non-web-supported formats (e.g. RAW)
let fullsizePath: string | undefined; let fullsizePath: string = StorageCore.getImagePath(asset, AssetPathType.FULLSIZE, image.preview.format);
if (shouldConvertFullsize) { if (shouldConvertFullsize) {
// unset size to decode fullsize image // unset size to decode fullsize image
decodeOptions.size = undefined; decodeOptions.size = undefined;
@ -275,8 +277,6 @@ export class MediaService extends BaseService {
extractedPath, extractedPath,
); );
} }
} else {
fullsizePath = StorageCore.getImagePath(asset, AssetPathType.FULLSIZE, image.preview.format);
} }
} }
@ -291,7 +291,7 @@ export class MediaService extends BaseService {
!useExtracted && // did not extract a usable image from RAW !useExtracted && // did not extract a usable image from RAW
this.mediaRepository.generateThumbnail( this.mediaRepository.generateThumbnail(
data, data,
{ ...image.preview, ...thumbnailOptions, size: undefined }, { ...fullsizeImageOptions, ...thumbnailOptions, size: undefined },
fullsizePath, fullsizePath,
), ),
]); ]);

View file

@ -132,6 +132,44 @@
/> />
</SettingAccordion> </SettingAccordion>
<SettingAccordion
key="fullsize-settings"
title={$t('admin.image_fullsize_title')}
subtitle={$t('admin.image_fullsize_description')}
isOpen={openByDefault}
>
<SettingSwitch
title={$t('admin.image_fullsize_enabled')}
subtitle={$t('admin.image_fullsize_enabled_description')}
checked={config.image.fullsize.enabled}
onToggle={(isChecked) => (config.image.fullsize.enabled = isChecked)}
isEdited={config.image.fullsize.enabled !== savedConfig.image.fullsize.enabled}
{disabled}
/>
<SettingSelect
label={$t('admin.image_format')}
desc={$t('admin.image_format_description')}
bind:value={config.image.fullsize.format}
options={[
{ value: ImageFormat.Jpeg, text: 'JPEG' },
{ value: ImageFormat.Webp, text: 'WebP' },
]}
name="format"
isEdited={config.image.fullsize.format !== savedConfig.image.fullsize.format}
disabled={disabled || !config.image.fullsize.enabled}
/>
<SettingInputField
inputType={SettingInputFieldType.NUMBER}
label={$t('admin.image_quality')}
description={$t('admin.image_fullsize_quality_description')}
bind:value={config.image.fullsize.quality}
isEdited={config.image.fullsize.quality !== savedConfig.image.fullsize.quality}
disabled={disabled || !config.image.fullsize.enabled}
/>
</SettingAccordion>
<SettingSwitch <SettingSwitch
title={$t('admin.image_prefer_wide_gamut')} title={$t('admin.image_prefer_wide_gamut')}
subtitle={$t('admin.image_prefer_wide_gamut_setting_description')} subtitle={$t('admin.image_prefer_wide_gamut_setting_description')}
@ -149,15 +187,6 @@
isEdited={config.image.extractEmbedded !== savedConfig.image.extractEmbedded} isEdited={config.image.extractEmbedded !== savedConfig.image.extractEmbedded}
{disabled} {disabled}
/> />
<SettingSwitch
title={$t('admin.image_enable_original_size_preview')}
subtitle={$t('admin.image_enable_original_size_preview_setting_description')}
checked={config.image.fullsizePreview}
onToggle={(isChecked) => (config.image.fullsizePreview = isChecked)}
isEdited={config.image.fullsizePreview !== savedConfig.image.fullsizePreview}
{disabled}
/>
</div> </div>
<div class="ml-4"> <div class="ml-4">