1
0
Fork 0
mirror of https://github.com/immich-app/immich.git synced 2024-12-29 15:11:58 +00: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,
} from 'src/enum';
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 {
backup: {
@ -112,7 +112,7 @@ export interface SystemConfig {
preview: ImageOptions;
colorspace: Colorspace;
extractEmbedded: boolean;
fullsizePreview: boolean;
fullsize: FullsizeImageOptions;
};
newVersionCheck: {
enabled: boolean;
@ -282,7 +282,11 @@ export const defaults = Object.freeze<SystemConfig>({
},
colorspace: Colorspace.P3,
extractEmbedded: false,
fullsizePreview: false,
fullsize: {
enabled: false,
format: ImageFormat.JPEG,
quality: 80,
},
},
newVersionCheck: {
enabled: true,

View file

@ -530,6 +530,24 @@ class SystemConfigGeneratedImageDto {
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 {
@Type(() => SystemConfigGeneratedImageDto)
@ValidateNested()
@ -541,15 +559,17 @@ export class SystemConfigImageDto {
@IsObject()
preview!: SystemConfigGeneratedImageDto;
@Type(() => SystemConfigGeneratedFullsizeImageDto)
@ValidateNested()
@IsObject()
fullsize!: SystemConfigGeneratedFullsizeImageDto;
@IsEnum(Colorspace)
@ApiProperty({ enumName: 'Colorspace', enum: Colorspace })
colorspace!: Colorspace;
@ValidateBoolean()
extractEmbedded!: boolean;
@ValidateBoolean()
fullsizePreview!: boolean;
}
class SystemConfigTrashDto {

View file

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

View file

@ -235,7 +235,8 @@ export class MediaService extends BaseService {
const imageIsWebSupported = mimeTypes.isWebSupportedImage(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 decodeOptions: DecodeToBufferOptions = {
colorspace,
@ -246,7 +247,8 @@ export class MediaService extends BaseService {
let useExtracted = false;
let decodeInputPath: string = asset.originalPath;
// 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) {
// unset size to decode fullsize image
decodeOptions.size = undefined;
@ -275,8 +277,6 @@ export class MediaService extends BaseService {
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
this.mediaRepository.generateThumbnail(
data,
{ ...image.preview, ...thumbnailOptions, size: undefined },
{ ...fullsizeImageOptions, ...thumbnailOptions, size: undefined },
fullsizePath,
),
]);

View file

@ -132,6 +132,44 @@
/>
</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
title={$t('admin.image_prefer_wide_gamut')}
subtitle={$t('admin.image_prefer_wide_gamut_setting_description')}
@ -149,15 +187,6 @@
isEdited={config.image.extractEmbedded !== savedConfig.image.extractEmbedded}
{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 class="ml-4">