diff --git a/web/packages/gallery/components/viewer/data-source.ts b/web/packages/gallery/components/viewer/data-source.ts index 5b388e98f2..6c5d4a3727 100644 --- a/web/packages/gallery/components/viewer/data-source.ts +++ b/web/packages/gallery/components/viewer/data-source.ts @@ -7,7 +7,7 @@ import { type HLSPlaylistData, } from "ente-gallery/services/video"; import type { EnteFile } from "ente-media/file"; -import { fileCaption } from "ente-media/file-metadata"; +import { fileCaption, filePublicMagicMetadata } from "ente-media/file-metadata"; import { FileType } from "ente-media/file-type"; import { ensureString } from "ente-utils/ensure"; @@ -498,8 +498,16 @@ const enqueueUpdates = async ( const thumbnailData = await withDimensionsIfPossible( ensureString(thumbnailURL), ); + + // If the aspect ratio of the original file matches the aspect ratio of + // the thumbnail, then render the thumbnail using the original's + // dimensions for a better visual experience. + const { width, height } = thumbnailDimensions(thumbnailData, file); + update({ ...thumbnailData, + width, + height, isContentLoading: true, isContentZoomable: false, }); @@ -624,6 +632,29 @@ const withDimensionsIfPossible = ( image.src = imageURL; }); +/** + * Return the dimensions to use for the thumbnail associated with {@link file}. + * + * If the aspect ratio of the thumbnail is (approximately) equal to that of the + * dimensions we have on record for the original image (obtained from the file + * metadata), then use the dimensions of the original image in lieu of the + * thumbnail dimensions for a more graceful transition during image loads. + */ +const thumbnailDimensions = ( + { width: thumbnailWidth, height: thumbnailHeight }: Partial, + file: EnteFile, +) => { + const { w: imageWidth, h: imageHeight } = + filePublicMagicMetadata(file) ?? {}; + if (thumbnailWidth && thumbnailHeight && imageWidth && imageHeight) { + const arThumb = thumbnailWidth / thumbnailHeight; + const arImage = imageWidth / imageHeight; + if (Math.abs(arThumb - arImage) < 0.1) { + return { width: imageWidth, height: imageHeight }; + } + } + return { width: thumbnailWidth, height: thumbnailHeight }; +}; /** * Return a new validity for a HLS playlist containing presigned URLs. *