diff --git a/mobile/openapi/README.md b/mobile/openapi/README.md index 81827a9079e5a..fecbbf482be54 100644 --- a/mobile/openapi/README.md +++ b/mobile/openapi/README.md @@ -416,7 +416,6 @@ Class | Method | HTTP request | Description - [SystemConfigDto](doc//SystemConfigDto.md) - [SystemConfigFFmpegDto](doc//SystemConfigFFmpegDto.md) - [SystemConfigFacesDto](doc//SystemConfigFacesDto.md) - - [SystemConfigGeneratedImageDto](doc//SystemConfigGeneratedImageDto.md) - [SystemConfigImageDto](doc//SystemConfigImageDto.md) - [SystemConfigJobDto](doc//SystemConfigJobDto.md) - [SystemConfigLibraryDto](doc//SystemConfigLibraryDto.md) diff --git a/mobile/openapi/lib/api.dart b/mobile/openapi/lib/api.dart index 8be44029805d5..22b48df2fbcb1 100644 --- a/mobile/openapi/lib/api.dart +++ b/mobile/openapi/lib/api.dart @@ -229,7 +229,6 @@ part 'model/stack_update_dto.dart'; part 'model/system_config_dto.dart'; part 'model/system_config_f_fmpeg_dto.dart'; part 'model/system_config_faces_dto.dart'; -part 'model/system_config_generated_image_dto.dart'; part 'model/system_config_image_dto.dart'; part 'model/system_config_job_dto.dart'; part 'model/system_config_library_dto.dart'; diff --git a/mobile/openapi/lib/api_client.dart b/mobile/openapi/lib/api_client.dart index 9e38eaf30a8a9..3db3297acb091 100644 --- a/mobile/openapi/lib/api_client.dart +++ b/mobile/openapi/lib/api_client.dart @@ -512,8 +512,6 @@ class ApiClient { return SystemConfigFFmpegDto.fromJson(value); case 'SystemConfigFacesDto': return SystemConfigFacesDto.fromJson(value); - case 'SystemConfigGeneratedImageDto': - return SystemConfigGeneratedImageDto.fromJson(value); case 'SystemConfigImageDto': return SystemConfigImageDto.fromJson(value); case 'SystemConfigJobDto': diff --git a/mobile/openapi/lib/model/system_config_generated_image_dto.dart b/mobile/openapi/lib/model/system_config_generated_image_dto.dart deleted file mode 100644 index 2192a7cb0cbd5..0000000000000 --- a/mobile/openapi/lib/model/system_config_generated_image_dto.dart +++ /dev/null @@ -1,118 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.18 - -// ignore_for_file: unused_element, unused_import -// ignore_for_file: always_put_required_named_parameters_first -// ignore_for_file: constant_identifier_names -// ignore_for_file: lines_longer_than_80_chars - -part of openapi.api; - -class SystemConfigGeneratedImageDto { - /// Returns a new [SystemConfigGeneratedImageDto] instance. - SystemConfigGeneratedImageDto({ - required this.format, - required this.quality, - required this.size, - }); - - ImageFormat format; - - /// Minimum value: 1 - /// Maximum value: 100 - int quality; - - /// Minimum value: 1 - int size; - - @override - bool operator ==(Object other) => identical(this, other) || other is SystemConfigGeneratedImageDto && - other.format == format && - other.quality == quality && - other.size == size; - - @override - int get hashCode => - // ignore: unnecessary_parenthesis - (format.hashCode) + - (quality.hashCode) + - (size.hashCode); - - @override - String toString() => 'SystemConfigGeneratedImageDto[format=$format, quality=$quality, size=$size]'; - - Map toJson() { - final json = {}; - json[r'format'] = this.format; - json[r'quality'] = this.quality; - json[r'size'] = this.size; - return json; - } - - /// Returns a new [SystemConfigGeneratedImageDto] instance and imports its values from - /// [value] if it's a [Map], null otherwise. - // ignore: prefer_constructors_over_static_methods - static SystemConfigGeneratedImageDto? fromJson(dynamic value) { - upgradeDto(value, "SystemConfigGeneratedImageDto"); - if (value is Map) { - final json = value.cast(); - - return SystemConfigGeneratedImageDto( - format: ImageFormat.fromJson(json[r'format'])!, - quality: mapValueOfType(json, r'quality')!, - size: mapValueOfType(json, r'size')!, - ); - } - return null; - } - - static List listFromJson(dynamic json, {bool growable = false,}) { - final result = []; - if (json is List && json.isNotEmpty) { - for (final row in json) { - final value = SystemConfigGeneratedImageDto.fromJson(row); - if (value != null) { - result.add(value); - } - } - } - return result.toList(growable: growable); - } - - static Map mapFromJson(dynamic json) { - final map = {}; - if (json is Map && json.isNotEmpty) { - json = json.cast(); // ignore: parameter_assignments - for (final entry in json.entries) { - final value = SystemConfigGeneratedImageDto.fromJson(entry.value); - if (value != null) { - map[entry.key] = value; - } - } - } - return map; - } - - // maps a json object with a list of SystemConfigGeneratedImageDto-objects as value to a dart map - static Map> mapListFromJson(dynamic json, {bool growable = false,}) { - final map = >{}; - if (json is Map && json.isNotEmpty) { - // ignore: parameter_assignments - json = json.cast(); - for (final entry in json.entries) { - map[entry.key] = SystemConfigGeneratedImageDto.listFromJson(entry.value, growable: growable,); - } - } - return map; - } - - /// The list of required keys that must be present in a JSON. - static const requiredKeys = { - 'format', - 'quality', - 'size', - }; -} - diff --git a/mobile/openapi/lib/model/system_config_image_dto.dart b/mobile/openapi/lib/model/system_config_image_dto.dart index 5309f7745c44d..681a8c00c3bc0 100644 --- a/mobile/openapi/lib/model/system_config_image_dto.dart +++ b/mobile/openapi/lib/model/system_config_image_dto.dart @@ -15,42 +15,64 @@ class SystemConfigImageDto { SystemConfigImageDto({ required this.colorspace, required this.extractEmbedded, - required this.preview, - required this.thumbnail, + required this.previewFormat, + required this.previewSize, + required this.quality, + required this.thumbnailFormat, + required this.thumbnailSize, }); Colorspace colorspace; bool extractEmbedded; - SystemConfigGeneratedImageDto preview; + ImageFormat previewFormat; - SystemConfigGeneratedImageDto thumbnail; + /// Minimum value: 1 + int previewSize; + + /// Minimum value: 1 + /// Maximum value: 100 + int quality; + + ImageFormat thumbnailFormat; + + /// Minimum value: 1 + int thumbnailSize; @override bool operator ==(Object other) => identical(this, other) || other is SystemConfigImageDto && other.colorspace == colorspace && other.extractEmbedded == extractEmbedded && - other.preview == preview && - other.thumbnail == thumbnail; + other.previewFormat == previewFormat && + other.previewSize == previewSize && + other.quality == quality && + other.thumbnailFormat == thumbnailFormat && + other.thumbnailSize == thumbnailSize; @override int get hashCode => // ignore: unnecessary_parenthesis (colorspace.hashCode) + (extractEmbedded.hashCode) + - (preview.hashCode) + - (thumbnail.hashCode); + (previewFormat.hashCode) + + (previewSize.hashCode) + + (quality.hashCode) + + (thumbnailFormat.hashCode) + + (thumbnailSize.hashCode); @override - String toString() => 'SystemConfigImageDto[colorspace=$colorspace, extractEmbedded=$extractEmbedded, preview=$preview, thumbnail=$thumbnail]'; + String toString() => 'SystemConfigImageDto[colorspace=$colorspace, extractEmbedded=$extractEmbedded, previewFormat=$previewFormat, previewSize=$previewSize, quality=$quality, thumbnailFormat=$thumbnailFormat, thumbnailSize=$thumbnailSize]'; Map toJson() { final json = {}; json[r'colorspace'] = this.colorspace; json[r'extractEmbedded'] = this.extractEmbedded; - json[r'preview'] = this.preview; - json[r'thumbnail'] = this.thumbnail; + json[r'previewFormat'] = this.previewFormat; + json[r'previewSize'] = this.previewSize; + json[r'quality'] = this.quality; + json[r'thumbnailFormat'] = this.thumbnailFormat; + json[r'thumbnailSize'] = this.thumbnailSize; return json; } @@ -65,8 +87,11 @@ class SystemConfigImageDto { return SystemConfigImageDto( colorspace: Colorspace.fromJson(json[r'colorspace'])!, extractEmbedded: mapValueOfType(json, r'extractEmbedded')!, - preview: SystemConfigGeneratedImageDto.fromJson(json[r'preview'])!, - thumbnail: SystemConfigGeneratedImageDto.fromJson(json[r'thumbnail'])!, + previewFormat: ImageFormat.fromJson(json[r'previewFormat'])!, + previewSize: mapValueOfType(json, r'previewSize')!, + quality: mapValueOfType(json, r'quality')!, + thumbnailFormat: ImageFormat.fromJson(json[r'thumbnailFormat'])!, + thumbnailSize: mapValueOfType(json, r'thumbnailSize')!, ); } return null; @@ -116,8 +141,11 @@ class SystemConfigImageDto { static const requiredKeys = { 'colorspace', 'extractEmbedded', - 'preview', - 'thumbnail', + 'previewFormat', + 'previewSize', + 'quality', + 'thumbnailFormat', + 'thumbnailSize', }; } diff --git a/open-api/immich-openapi-specs.json b/open-api/immich-openapi-specs.json index 1077762ac3a56..6afd0d792ff34 100644 --- a/open-api/immich-openapi-specs.json +++ b/open-api/immich-openapi-specs.json @@ -11654,48 +11654,42 @@ ], "type": "object" }, - "SystemConfigGeneratedImageDto": { + "SystemConfigImageDto": { "properties": { - "format": { + "colorspace": { + "$ref": "#/components/schemas/Colorspace" + }, + "extractEmbedded": { + "type": "boolean" + }, + "previewFormat": { "$ref": "#/components/schemas/ImageFormat" }, - "quality": { - "maximum": 100, + "previewSize": { "minimum": 1, "type": "integer" }, - "size": { + "quality": { + "maximum": 100, "minimum": 1, "type": "integer" - } - }, - "required": [ - "format", - "quality", - "size" - ], - "type": "object" - }, - "SystemConfigImageDto": { - "properties": { - "colorspace": { - "$ref": "#/components/schemas/Colorspace" - }, - "extractEmbedded": { - "type": "boolean" }, - "preview": { - "$ref": "#/components/schemas/SystemConfigGeneratedImageDto" + "thumbnailFormat": { + "$ref": "#/components/schemas/ImageFormat" }, - "thumbnail": { - "$ref": "#/components/schemas/SystemConfigGeneratedImageDto" + "thumbnailSize": { + "minimum": 1, + "type": "integer" } }, "required": [ "colorspace", "extractEmbedded", - "preview", - "thumbnail" + "previewFormat", + "previewSize", + "quality", + "thumbnailFormat", + "thumbnailSize" ], "type": "object" }, diff --git a/open-api/typescript-sdk/src/fetch-client.ts b/open-api/typescript-sdk/src/fetch-client.ts index e88f431e8c787..b1ae5d28764f2 100644 --- a/open-api/typescript-sdk/src/fetch-client.ts +++ b/open-api/typescript-sdk/src/fetch-client.ts @@ -1100,16 +1100,14 @@ export type SystemConfigFFmpegDto = { transcode: TranscodePolicy; twoPass: boolean; }; -export type SystemConfigGeneratedImageDto = { - format: ImageFormat; - quality: number; - size: number; -}; export type SystemConfigImageDto = { colorspace: Colorspace; extractEmbedded: boolean; - preview: SystemConfigGeneratedImageDto; - thumbnail: SystemConfigGeneratedImageDto; + previewFormat: ImageFormat; + previewSize: number; + quality: number; + thumbnailFormat: ImageFormat; + thumbnailSize: number; }; export type JobSettingsDto = { concurrency: number; diff --git a/server/src/config.ts b/server/src/config.ts index 3317351f9ff3a..1522371487e3b 100644 --- a/server/src/config.ts +++ b/server/src/config.ts @@ -20,7 +20,6 @@ import { VideoContainer, } from 'src/enum'; import { ConcurrentQueueName, QueueName } from 'src/interfaces/job.interface'; -import { ImageOutputConfig } from 'src/interfaces/media.interface'; export interface SystemConfig { ffmpeg: { @@ -110,8 +109,11 @@ export interface SystemConfig { template: string; }; image: { - thumbnail: ImageOutputConfig; - preview: ImageOutputConfig; + thumbnailFormat: ImageFormat; + thumbnailSize: number; + previewFormat: ImageFormat; + previewSize: number; + quality: number; colorspace: Colorspace; extractEmbedded: boolean; }; @@ -257,16 +259,11 @@ export const defaults = Object.freeze({ template: '{{y}}/{{y}}-{{MM}}-{{dd}}/{{filename}}', }, image: { - thumbnail: { - format: ImageFormat.WEBP, - size: 250, - quality: 80, - }, - preview: { - format: ImageFormat.JPEG, - size: 1440, - quality: 80, - }, + thumbnailFormat: ImageFormat.WEBP, + thumbnailSize: 250, + previewFormat: ImageFormat.JPEG, + previewSize: 1440, + quality: 80, colorspace: Colorspace.P3, extractEmbedded: false, }, diff --git a/server/src/dtos/system-config.dto.ts b/server/src/dtos/system-config.dto.ts index c12a54cd613e6..4a3ca37691604 100644 --- a/server/src/dtos/system-config.dto.ts +++ b/server/src/dtos/system-config.dto.ts @@ -473,35 +473,33 @@ export class SystemConfigThemeDto { customCss!: string; } -class SystemConfigGeneratedImageDto { +class SystemConfigImageDto { @IsEnum(ImageFormat) @ApiProperty({ enumName: 'ImageFormat', enum: ImageFormat }) - format!: ImageFormat; + thumbnailFormat!: ImageFormat; @IsInt() @Min(1) - @Max(100) @Type(() => Number) @ApiProperty({ type: 'integer' }) - quality!: number; + thumbnailSize!: number; + + @IsEnum(ImageFormat) + @ApiProperty({ enumName: 'ImageFormat', enum: ImageFormat }) + previewFormat!: ImageFormat; @IsInt() @Min(1) @Type(() => Number) @ApiProperty({ type: 'integer' }) - size!: number; -} + previewSize!: number; -class SystemConfigImageDto { - @Type(() => SystemConfigGeneratedImageDto) - @ValidateNested() - @IsObject() - thumbnail!: SystemConfigGeneratedImageDto; - - @Type(() => SystemConfigGeneratedImageDto) - @ValidateNested() - @IsObject() - preview!: SystemConfigGeneratedImageDto; + @IsInt() + @Min(1) + @Max(100) + @Type(() => Number) + @ApiProperty({ type: 'integer' }) + quality!: number; @IsEnum(Colorspace) @ApiProperty({ enumName: 'Colorspace', enum: Colorspace }) diff --git a/server/src/interfaces/media.interface.ts b/server/src/interfaces/media.interface.ts index 64ba6236e80f0..7193684e7acc1 100644 --- a/server/src/interfaces/media.interface.ts +++ b/server/src/interfaces/media.interface.ts @@ -10,14 +10,11 @@ export interface CropOptions { height: number; } -export interface ImageOutputConfig { - format: ImageFormat; - quality: number; +export interface ThumbnailOptions { size: number; -} - -export interface ThumbnailOptions extends ImageOutputConfig { + format: ImageFormat; colorspace: string; + quality: number; crop?: CropOptions; processInvalidImages: boolean; } diff --git a/server/src/migrations/1727471863507-SeparateQualityForThumbnailAndPreview.ts b/server/src/migrations/1727471863507-SeparateQualityForThumbnailAndPreview.ts deleted file mode 100644 index e02203997f723..0000000000000 --- a/server/src/migrations/1727471863507-SeparateQualityForThumbnailAndPreview.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class SeparateQualityForThumbnailAndPreview1727471863507 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - update system_metadata - set value = jsonb_set(value, '{image}', jsonb_strip_nulls( - jsonb_build_object( - 'preview', jsonb_build_object( - 'format', value->'image'->'previewFormat', - 'quality', value->'image'->'quality', - 'size', value->'image'->'previewSize'), - 'thumbnail', jsonb_build_object( - 'format', value->'image'->'thumbnailFormat', - 'quality', value->'image'->'quality', - 'size', value->'image'->'thumbnailSize'), - 'extractEmbedded', value->'extractEmbedded', - 'colorspace', value->'colorspace' - ))) - where key = 'system-config'`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - update system_metadata - set value = jsonb_set(value, '{image}', jsonb_strip_nulls(jsonb_build_object( - 'previewFormat', value->'image'->'preview'->'format', - 'previewSize', value->'image'->'preview'->'size', - 'thumbnailFormat', value->'image'->'thumbnail'->'format', - 'thumbnailSize', value->'image'->'thumbnail'->'size', - 'extractEmbedded', value->'extractEmbedded', - 'colorspace', value->'colorspace', - 'quality', value->'image'->'preview'->'quality' - ))) - where key = 'system-config'`); - } -} diff --git a/server/src/services/media.service.spec.ts b/server/src/services/media.service.spec.ts index c0903fa101412..ddda8f64fc74f 100644 --- a/server/src/services/media.service.spec.ts +++ b/server/src/services/media.service.spec.ts @@ -285,7 +285,7 @@ describe(MediaService.name, () => { }); it.each(Object.values(ImageFormat))('should generate a %s preview for an image when specified', async (format) => { - systemMock.get.mockResolvedValue({ image: { preview: { format } } }); + systemMock.get.mockResolvedValue({ image: { previewFormat: format } }); assetMock.getByIds.mockResolvedValue([assetStub.image]); const previewPath = `upload/thumbs/user-id/as/se/asset-id-preview.${format}`; @@ -307,7 +307,7 @@ describe(MediaService.name, () => { }); it('should delete previous preview if different path', async () => { - systemMock.get.mockResolvedValue({ image: { thumbnail: { format: ImageFormat.WEBP } } }); + systemMock.get.mockResolvedValue({ image: { thumbnailFormat: ImageFormat.WEBP } }); assetMock.getByIds.mockResolvedValue([assetStub.image]); await sut.handleGeneratePreview({ id: assetStub.image.id }); @@ -464,7 +464,7 @@ describe(MediaService.name, () => { it.each(Object.values(ImageFormat))( 'should generate a %s thumbnail for an image when specified', async (format) => { - systemMock.get.mockResolvedValue({ image: { thumbnail: { format } } }); + systemMock.get.mockResolvedValue({ image: { thumbnailFormat: format } }); assetMock.getByIds.mockResolvedValue([assetStub.image]); const thumbnailPath = `upload/thumbs/user-id/as/se/asset-id-thumbnail.${format}`; @@ -487,7 +487,7 @@ describe(MediaService.name, () => { ); it('should delete previous thumbnail if different path', async () => { - systemMock.get.mockResolvedValue({ image: { thumbnail: { format: ImageFormat.WEBP } } }); + systemMock.get.mockResolvedValue({ image: { thumbnailFormat: ImageFormat.WEBP } }); assetMock.getByIds.mockResolvedValue([assetStub.image]); await sut.handleGenerateThumbnail({ id: assetStub.image.id }); diff --git a/server/src/services/media.service.ts b/server/src/services/media.service.ts index 1b69c5acd5504..720bef6c7661b 100644 --- a/server/src/services/media.service.ts +++ b/server/src/services/media.service.ts @@ -10,6 +10,7 @@ import { AssetType, AudioCodec, Colorspace, + ImageFormat, LogLevel, StorageFolder, TranscodeHWAccel, @@ -174,15 +175,18 @@ export class MediaService { return JobStatus.FAILED; } - await this.storageCore.moveAssetImage(asset, AssetPathType.PREVIEW, image.preview.format); - await this.storageCore.moveAssetImage(asset, AssetPathType.THUMBNAIL, image.thumbnail.format); + await this.storageCore.moveAssetImage(asset, AssetPathType.PREVIEW, image.previewFormat); + await this.storageCore.moveAssetImage(asset, AssetPathType.THUMBNAIL, image.thumbnailFormat); await this.storageCore.moveAssetVideo(asset); return JobStatus.SUCCESS; } async handleGeneratePreview({ id }: IEntityJob): Promise { - const [asset] = await this.assetRepository.getByIds([id], { exifInfo: true, files: true }); + const [{ image }, [asset]] = await Promise.all([ + this.configCore.getConfig({ withCache: true }), + this.assetRepository.getByIds([id], { exifInfo: true, files: true }), + ]); if (!asset) { return JobStatus.FAILED; } @@ -191,7 +195,7 @@ export class MediaService { return JobStatus.SKIPPED; } - const previewPath = await this.generateThumbnail(asset, AssetPathType.PREVIEW); + const previewPath = await this.generateThumbnail(asset, AssetPathType.PREVIEW, image.previewFormat); if (!previewPath) { return JobStatus.SKIPPED; } @@ -209,9 +213,9 @@ export class MediaService { return JobStatus.SUCCESS; } - private async generateThumbnail(asset: AssetEntity, type: GeneratedImageType) { + private async generateThumbnail(asset: AssetEntity, type: GeneratedImageType, format: ImageFormat) { const { image, ffmpeg } = await this.configCore.getConfig({ withCache: true }); - const { size, format, quality } = image[type]; + const size = type === AssetPathType.PREVIEW ? image.previewSize : image.thumbnailSize; const path = StorageCore.getImagePath(asset, type, format); this.storageCore.ensureFolders(path); @@ -222,13 +226,13 @@ export class MediaService { const didExtract = shouldExtract && (await this.mediaRepository.extract(asset.originalPath, extractedPath)); try { - const useExtracted = didExtract && (await this.shouldUseExtractedImage(extractedPath, image.preview.size)); + const useExtracted = didExtract && (await this.shouldUseExtractedImage(extractedPath, image.previewSize)); const colorspace = this.isSRGB(asset) ? Colorspace.SRGB : image.colorspace; const imageOptions = { format, size, colorspace, - quality, + quality: image.quality, processInvalidImages: process.env.IMMICH_PROCESS_INVALID_IMAGES === 'true', }; @@ -270,7 +274,10 @@ export class MediaService { } async handleGenerateThumbnail({ id }: IEntityJob): Promise { - const [asset] = await this.assetRepository.getByIds([id], { exifInfo: true, files: true }); + const [{ image }, [asset]] = await Promise.all([ + this.configCore.getConfig({ withCache: true }), + this.assetRepository.getByIds([id], { exifInfo: true, files: true }), + ]); if (!asset) { return JobStatus.FAILED; } @@ -279,7 +286,7 @@ export class MediaService { return JobStatus.SKIPPED; } - const thumbnailPath = await this.generateThumbnail(asset, AssetPathType.THUMBNAIL); + const thumbnailPath = await this.generateThumbnail(asset, AssetPathType.THUMBNAIL, image.thumbnailFormat); if (!thumbnailPath) { return JobStatus.SKIPPED; } diff --git a/server/src/services/person.service.ts b/server/src/services/person.service.ts index 651c8eebee54e..7cb76d1a71535 100644 --- a/server/src/services/person.service.ts +++ b/server/src/services/person.service.ts @@ -574,7 +574,7 @@ export class PersonService { format: ImageFormat.JPEG, size: FACE_THUMBNAIL_SIZE, colorspace: image.colorspace, - quality: image.thumbnail.quality, + quality: image.quality, crop: this.getCrop({ old: { width: oldWidth, height: oldHeight }, new: { width, height } }, { x1, y1, x2, y2 }), processInvalidImages: process.env.IMMICH_PROCESS_INVALID_IMAGES === 'true', } as const; diff --git a/server/src/services/system-config.service.spec.ts b/server/src/services/system-config.service.spec.ts index 514d8aa0f8d58..8b4fb0bc2fd3c 100644 --- a/server/src/services/system-config.service.spec.ts +++ b/server/src/services/system-config.service.spec.ts @@ -135,16 +135,11 @@ const updatedConfig = Object.freeze({ template: '{{y}}/{{y}}-{{MM}}-{{dd}}/{{filename}}', }, image: { - thumbnail: { - size: 250, - format: ImageFormat.WEBP, - quality: 80, - }, - preview: { - size: 1440, - format: ImageFormat.JPEG, - quality: 80, - }, + thumbnailFormat: ImageFormat.WEBP, + thumbnailSize: 250, + previewFormat: ImageFormat.JPEG, + previewSize: 1440, + quality: 80, colorspace: Colorspace.P3, extractEmbedded: false, }, diff --git a/web/src/lib/components/admin-page/settings/image/image-settings.svelte b/web/src/lib/components/admin-page/settings/image/image-settings.svelte index b5e381d5f87a0..d6fc814b98e4c 100644 --- a/web/src/lib/components/admin-page/settings/image/image-settings.svelte +++ b/web/src/lib/components/admin-page/settings/image/image-settings.svelte @@ -11,7 +11,6 @@ SettingInputFieldType, } from '$lib/components/shared-components/settings/setting-input-field.svelte'; import { t } from 'svelte-i18n'; - import SettingAccordion from '$lib/components/shared-components/settings/setting-accordion.svelte'; export let savedConfig: SystemConfigDto; export let defaultConfig: SystemConfigDto; @@ -25,96 +24,73 @@
- - - - + - - + - - + - + - - +