From a54e01ef2fa9256b647d7538f7b8be0cb4df3c20 Mon Sep 17 00:00:00 2001 From: Michel Heusschen <59014050+michelheusschen@users.noreply.github.com> Date: Thu, 13 Jun 2024 12:57:46 +0200 Subject: [PATCH] fix: load original image for gifs (#10252) --- .../openapi/lib/model/asset_response_dto.dart | Bin 13285 -> 13628 bytes open-api/immich-openapi-specs.json | 4 ++ open-api/typescript-sdk/src/fetch-client.ts | 1 + server/src/dtos/asset-response.dto.ts | 4 ++ server/test/fixtures/shared-link.stub.ts | 2 + .../asset-viewer/photo-viewer.spec.ts | 49 ++++++++++++++++++ .../asset-viewer/photo-viewer.svelte | 3 +- web/src/lib/utils/asset-utils.ts | 18 +++---- web/src/test-data/factories/asset-factory.ts | 1 + 9 files changed, 72 insertions(+), 10 deletions(-) create mode 100644 web/src/lib/components/asset-viewer/photo-viewer.spec.ts diff --git a/mobile/openapi/lib/model/asset_response_dto.dart b/mobile/openapi/lib/model/asset_response_dto.dart index 090eebdf85d3d2442834f131801ee0dbdb20dccb..ced0230f3ee0c41b5279ac32af977ba6601bfb03 100644 GIT binary patch delta 210 zcmaEwz9(zLEM|7!%-qzF%7V$~nM5b&F>`F5#k`LNCb-#|qn%wEsv=dv)>a|EC^J1X zFEIzEtC3%P^C|v^EUaLG$@XHRn-_~bWtN2Lu~k9SvAI^Fl1&jNtsbjjt5A}WS*(Yy l?4Fz&7Y9t) { + const meta = await originalImport(); + return { + ...meta, + getAssetOriginalUrl: vi.fn(), + getAssetThumbnailUrl: vi.fn(), + }; +}); + +describe('PhotoViewer component', () => { + let getAssetOriginalUrlSpy: MockInstance; + let getAssetThumbnailUrlSpy: MockInstance; + + beforeAll(() => { + getAssetOriginalUrlSpy = vi.spyOn(utils, 'getAssetOriginalUrl'); + getAssetThumbnailUrlSpy = vi.spyOn(utils, 'getAssetThumbnailUrl'); + }); + + afterEach(() => { + vi.resetAllMocks(); + }); + + it('loads the thumbnail', () => { + const asset = assetFactory.build({ originalPath: 'image.jpg', originalMimeType: 'image/jpeg' }); + render(PhotoViewer, { asset }); + + expect(getAssetThumbnailUrlSpy).toBeCalledWith({ + id: asset.id, + size: AssetMediaSize.Preview, + checksum: asset.checksum, + }); + expect(getAssetOriginalUrlSpy).not.toBeCalled(); + }); + + it('loads the original image for gifs', () => { + const asset = assetFactory.build({ originalPath: 'image.gif', originalMimeType: 'image/gif' }); + render(PhotoViewer, { asset }); + + expect(getAssetThumbnailUrlSpy).not.toBeCalled(); + expect(getAssetOriginalUrlSpy).toBeCalledWith({ id: asset.id, checksum: asset.checksum }); + }); +}); diff --git a/web/src/lib/components/asset-viewer/photo-viewer.svelte b/web/src/lib/components/asset-viewer/photo-viewer.svelte index 384b3ebc1..47d92b0d5 100644 --- a/web/src/lib/components/asset-viewer/photo-viewer.svelte +++ b/web/src/lib/components/asset-viewer/photo-viewer.svelte @@ -38,7 +38,8 @@ $: useOriginalByDefault = isWebCompatible && $alwaysLoadOriginalFile; $: useOriginalImage = useOriginalByDefault || forceUseOriginal; // when true, will force loading of the original image - $: forceUseOriginal = forceUseOriginal || ($photoZoomState.currentZoom > 1 && isWebCompatible); + $: forceUseOriginal = + forceUseOriginal || asset.originalMimeType === 'image/gif' || ($photoZoomState.currentZoom > 1 && isWebCompatible); $: preload(useOriginalImage, preloadAssets); $: imageLoaderUrl = getAssetUrl(asset.id, useOriginalImage, asset.checksum); diff --git a/web/src/lib/utils/asset-utils.ts b/web/src/lib/utils/asset-utils.ts index b6624770a..9fa851aa3 100644 --- a/web/src/lib/utils/asset-utils.ts +++ b/web/src/lib/utils/asset-utils.ts @@ -257,20 +257,20 @@ export function getAssetRatio(asset: AssetResponseDto) { } // list of supported image extensions from https://developer.mozilla.org/en-US/docs/Web/Media/Formats/Image_types excluding svg -const supportedImageExtensions = new Set(['apng', 'avif', 'gif', 'jpg', 'jpeg', 'jfif', 'pjpeg', 'pjp', 'png', 'webp']); +const supportedImageMimeTypes = new Set([ + 'image/apng', + 'image/avif', + 'image/gif', + 'image/jpeg', + 'image/png', + 'image/webp', +]); /** * Returns true if the asset is an image supported by web browsers, false otherwise */ export function isWebCompatibleImage(asset: AssetResponseDto): boolean { - // originalPath is undefined when public shared link has metadata option turned off - if (!asset.originalPath) { - return false; - } - - const imgExtension = getFilenameExtension(asset.originalPath); - - return supportedImageExtensions.has(imgExtension); + return supportedImageMimeTypes.has(asset.originalMimeType); } export const getAssetType = (type: AssetTypeEnum) => { diff --git a/web/src/test-data/factories/asset-factory.ts b/web/src/test-data/factories/asset-factory.ts index 6b1e1a6ce..e76138fe5 100644 --- a/web/src/test-data/factories/asset-factory.ts +++ b/web/src/test-data/factories/asset-factory.ts @@ -11,6 +11,7 @@ export const assetFactory = Sync.makeFactory({ type: Sync.each(() => faker.helpers.enumValue(AssetTypeEnum)), originalPath: Sync.each(() => faker.system.filePath()), originalFileName: Sync.each(() => faker.system.fileName()), + originalMimeType: Sync.each(() => faker.system.mimeType()), resized: true, thumbhash: Sync.each(() => faker.string.alphanumeric(28)), fileCreatedAt: Sync.each(() => faker.date.past().toISOString()),