From beace4cbdee1b5f54c3970782578773587c4d6ec Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Fri, 26 Jul 2024 11:57:46 +0530 Subject: [PATCH] Parse wip --- .../PhotoViewer/FileInfo/ExifData.tsx | 94 ---- .../PhotoViewer/FileInfo/RenderFileName.tsx | 113 ----- .../components/PhotoViewer/FileInfo/index.tsx | 404 ++++++++++++------ .../src/components/PhotoViewer/index.tsx | 64 ++- web/packages/new/photos/services/exif.ts | 2 +- 5 files changed, 314 insertions(+), 363 deletions(-) delete mode 100644 web/apps/photos/src/components/PhotoViewer/FileInfo/ExifData.tsx delete mode 100644 web/apps/photos/src/components/PhotoViewer/FileInfo/RenderFileName.tsx diff --git a/web/apps/photos/src/components/PhotoViewer/FileInfo/ExifData.tsx b/web/apps/photos/src/components/PhotoViewer/FileInfo/ExifData.tsx deleted file mode 100644 index c047fa18cc..0000000000 --- a/web/apps/photos/src/components/PhotoViewer/FileInfo/ExifData.tsx +++ /dev/null @@ -1,94 +0,0 @@ -import { Titlebar } from "@/base/components/Titlebar"; -import CopyButton from "@ente/shared/components/CodeBlock/CopyButton"; -import { formatDateTimeFull } from "@ente/shared/time/format"; -import { Box, Stack, styled, Typography } from "@mui/material"; -import { t } from "i18next"; -import React from "react"; -import { FileInfoSidebar } from "."; - -const ExifItem = styled(Box)` - padding-left: 8px; - padding-right: 8px; - display: flex; - flex-direction: column; - gap: 4px; -`; - -function parseExifValue(value: any) { - switch (typeof value) { - case "string": - case "number": - return value; - default: - if (value instanceof Date) { - return formatDateTimeFull(value); - } - try { - return JSON.stringify(Array.from(value)); - } catch (e) { - return null; - } - } -} -export function ExifData(props: { - exif: any; - open: boolean; - onClose: () => void; - filename: string; - onInfoClose: () => void; -}) { - const { exif, open, onClose, filename, onInfoClose } = props; - - if (!exif) { - return <>; - } - const handleRootClose = () => { - onClose(); - onInfoClose(); - }; - - return ( - - - } - /> - - {[...Object.entries(exif)] - .sort((a, b) => a[0].localeCompare(b[0])) - .map(([key, value]) => - value ? ( - - - {key} - - - {parseExifValue(value)} - - - ) : ( - - ), - )} - - - ); -} diff --git a/web/apps/photos/src/components/PhotoViewer/FileInfo/RenderFileName.tsx b/web/apps/photos/src/components/PhotoViewer/FileInfo/RenderFileName.tsx deleted file mode 100644 index e9443c84c1..0000000000 --- a/web/apps/photos/src/components/PhotoViewer/FileInfo/RenderFileName.tsx +++ /dev/null @@ -1,113 +0,0 @@ -import { nameAndExtension } from "@/base/file"; -import log from "@/base/log"; -import { FILE_TYPE } from "@/media/file-type"; -import { EnteFile } from "@/new/photos/types/file"; -import { formattedByteSize } from "@/new/photos/utils/units"; -import { FlexWrapper } from "@ente/shared/components/Container"; -import PhotoOutlined from "@mui/icons-material/PhotoOutlined"; -import VideocamOutlined from "@mui/icons-material/VideocamOutlined"; -import Box from "@mui/material/Box"; -import { useEffect, useState } from "react"; -import { changeFileName, updateExistingFilePubMetadata } from "utils/file"; -import { FileNameEditDialog } from "./FileNameEditDialog"; -import InfoItem from "./InfoItem"; - -const getFileTitle = (filename, extension) => { - if (extension) { - return filename + "." + extension; - } else { - return filename; - } -}; - -const getCaption = (file: EnteFile, parsedExifData) => { - const megaPixels = parsedExifData?.["megaPixels"]; - const resolution = parsedExifData?.["resolution"]; - const fileSize = file.info?.fileSize; - - const captionParts = []; - if (megaPixels) { - captionParts.push(megaPixels); - } - if (resolution) { - captionParts.push(resolution); - } - if (fileSize) { - captionParts.push(formattedByteSize(fileSize)); - } - return ( - - {captionParts.map((caption) => ( - {caption} - ))} - - ); -}; - -export function RenderFileName({ - parsedExifData, - shouldDisableEdits, - file, - scheduleUpdate, -}: { - parsedExifData: Record; - shouldDisableEdits: boolean; - file: EnteFile; - scheduleUpdate: () => void; -}) { - const [isInEditMode, setIsInEditMode] = useState(false); - const openEditMode = () => setIsInEditMode(true); - const closeEditMode = () => setIsInEditMode(false); - const [filename, setFilename] = useState(); - const [extension, setExtension] = useState(); - - useEffect(() => { - const [filename, extension] = nameAndExtension(file.metadata.title); - setFilename(filename); - setExtension(extension); - }, [file]); - - const saveEdits = async (newFilename: string) => { - try { - if (file) { - if (filename === newFilename) { - closeEditMode(); - return; - } - setFilename(newFilename); - const newTitle = getFileTitle(newFilename, extension); - const updatedFile = await changeFileName(file, newTitle); - updateExistingFilePubMetadata(file, updatedFile); - scheduleUpdate(); - } - } catch (e) { - log.error("failed to update file name", e); - throw e; - } - }; - - return ( - <> - - ) : ( - - ) - } - title={getFileTitle(filename, extension)} - caption={getCaption(file, parsedExifData)} - openEditor={openEditMode} - hideEditOption={shouldDisableEdits || isInEditMode} - /> - - - ); -} diff --git a/web/apps/photos/src/components/PhotoViewer/FileInfo/index.tsx b/web/apps/photos/src/components/PhotoViewer/FileInfo/index.tsx index 453f56bf33..84af0f5f4d 100644 --- a/web/apps/photos/src/components/PhotoViewer/FileInfo/index.tsx +++ b/web/apps/photos/src/components/PhotoViewer/FileInfo/index.tsx @@ -1,9 +1,13 @@ import { EnteDrawer } from "@/base/components/EnteDrawer"; import { Titlebar } from "@/base/components/Titlebar"; +import { nameAndExtension } from "@/base/file"; +import log from "@/base/log"; +import { FILE_TYPE } from "@/media/file-type"; import { UnidentifiedFaces } from "@/new/photos/components/PeopleList"; -import type { RawExifTags } from "@/new/photos/services/exif"; +import type { ParsedExif, RawExifTags } from "@/new/photos/services/exif"; import { isMLEnabled } from "@/new/photos/services/ml"; import { EnteFile } from "@/new/photos/types/file"; +import { formattedByteSize } from "@/new/photos/utils/units"; import CopyButton from "@ente/shared/components/CodeBlock/CopyButton"; import { FlexWrapper } from "@ente/shared/components/Container"; import EnteSpinner from "@ente/shared/components/EnteSpinner"; @@ -12,7 +16,9 @@ import BackupOutlined from "@mui/icons-material/BackupOutlined"; import CameraOutlined from "@mui/icons-material/CameraOutlined"; import FolderOutlined from "@mui/icons-material/FolderOutlined"; import LocationOnOutlined from "@mui/icons-material/LocationOnOutlined"; +import PhotoOutlined from "@mui/icons-material/PhotoOutlined"; import TextSnippetOutlined from "@mui/icons-material/TextSnippetOutlined"; +import VideocamOutlined from "@mui/icons-material/VideocamOutlined"; import { Box, DialogProps, Link, Stack, styled } from "@mui/material"; import { Chip } from "components/Chip"; import LinkButton from "components/pages/gallery/LinkButton"; @@ -20,33 +26,29 @@ import { t } from "i18next"; import { AppContext } from "pages/_app"; import { GalleryContext } from "pages/gallery"; import React, { useContext, useEffect, useMemo, useState } from "react"; +import { changeFileName, updateExistingFilePubMetadata } from "utils/file"; import { PublicCollectionGalleryContext } from "utils/publicCollectionGallery"; import { getMapDisableConfirmationDialog, getMapEnableConfirmationDialog, } from "utils/ui"; import { ExifData } from "./ExifData"; +import { FileNameEditDialog } from "./FileNameEditDialog"; import InfoItem from "./InfoItem"; import MapBox from "./MapBox"; import { RenderCaption } from "./RenderCaption"; import { RenderCreationTime } from "./RenderCreationTime"; -import { RenderFileName } from "./RenderFileName"; - -export const FileInfoSidebar = styled((props: DialogProps) => ( - -))({ - zIndex: 1501, - "& .MuiPaper-root": { - padding: 8, - }, -}); +export interface FileInfoExif { + tags: RawExifTags; + parsed: ParsedExif; +} interface FileInfoProps { shouldDisableEdits?: boolean; showInfo: boolean; handleCloseInfo: () => void; file: EnteFile; - rawExif: RawExifTags | undefined; + exif: FileInfoExif | undefined; scheduleUpdate: () => void; refreshPhotoswipe: () => void; fileToCollectionsMap?: Map; @@ -55,33 +57,12 @@ interface FileInfoProps { closePhotoViewer: () => void; } -function BasicDeviceCamera({ - parsedExifData, -}: { - parsedExifData: Record; -}) { - return ( - - {parsedExifData["fNumber"]} - {parsedExifData["exposureTime"]} - {parsedExifData["ISO"]} - - ); -} - -function getOpenStreetMapLink(location: { - latitude: number; - longitude: number; -}) { - return `https://www.openstreetmap.org/?mlat=${location.latitude}&mlon=${location.longitude}#map=15/${location.latitude}/${location.longitude}`; -} - export const FileInfo: React.FC = ({ shouldDisableEdits, showInfo, handleCloseInfo, file, - rawExif, + exif, scheduleUpdate, refreshPhotoswipe, fileToCollectionsMap, @@ -95,11 +76,10 @@ export const FileInfo: React.FC = ({ PublicCollectionGalleryContext, ); - const [parsedExifData, setParsedExifData] = useState>(); - const [showExif, setShowExif] = useState(false); - - const openExif = () => setShowExif(true); - const closeExif = () => setShowExif(false); + const [parsedExif, setParsedExif] = useState< + ParsedFileInfoExif | undefined + >(); + const [openRawExif, setOpenRawExif] = useState(false); const location = useMemo(() => { if (file && file.metadata) { @@ -113,48 +93,12 @@ export const FileInfo: React.FC = ({ }; } } - return null; + return exif.parsed.location; }, [file]); useEffect(() => { - setParsedExifData(parseInfoExif(rawExif)); - - if (!exif) { - setParsedExifData({}); - return; - } - const parsedExifData = {}; - if (exif["fNumber"]) { - parsedExifData["fNumber"] = `f/${Math.ceil(exif["FNumber"])}`; - } else if (exif["ApertureValue"] && exif["FocalLength"]) { - parsedExifData["fNumber"] = `f/${Math.ceil( - exif["FocalLength"] / exif["ApertureValue"], - )}`; - } - const imageWidth = exif["ImageWidth"] ?? exif["ExifImageWidth"]; - const imageHeight = exif["ImageHeight"] ?? exif["ExifImageHeight"]; - if (imageWidth && imageHeight) { - parsedExifData["resolution"] = `${imageWidth} x ${imageHeight}`; - const megaPixels = Math.round((imageWidth * imageHeight) / 1000000); - if (megaPixels) { - parsedExifData["megaPixels"] = `${Math.round( - (imageWidth * imageHeight) / 1000000, - )}MP`; - } - } - if (exif["Make"] && exif["Model"]) { - parsedExifData["takenOnDevice"] = - `${exif["Make"]} ${exif["Model"]}`; - } - if (exif["ExposureTime"]) { - parsedExifData["exposureTime"] = `1/${ - 1 / parseFloat(exif["ExposureTime"]) - }`; - } - if (exif["ISO"]) { - parsedExifData["ISO"] = `ISO${exif["ISO"]}`; - } - }, [rawExif]); + setParsedExif(exif ? parseFileInfoExif(exif) : undefined); + }, [exif]); if (!file) { return <>; @@ -272,7 +216,7 @@ export const FileInfo: React.FC = ({ ) : exif !== null ? ( setOpenRawExif(true)} sx={{ textDecoration: "none", color: "text.muted", @@ -329,9 +273,9 @@ export const FileInfo: React.FC = ({ )} setOpenRawExif(false)} onInfoClose={handleCloseInfo} filename={file.metadata.title} /> @@ -339,54 +283,276 @@ export const FileInfo: React.FC = ({ ); }; -interface ParsedInfoExif { +/** + * Some immediate fields of interest, in the form that we want to display on the + * info panel for a file. + */ +type ParsedFileInfoExif = FileInfoExif & { resolution?: string; megaPixels?: string; takenOnDevice?: string; fNumber?: string; exposureTime?: string; iso?: string; -} +}; -/** - * Extract some immediate fields of interest and in the form that we want to - * display on the info panel for a file. - */ -const parseInfoExif = (rawExif: RawExifTags | undefined): ParsedInfoExif => { - const parsed = {}; - if (!rawExif) return {}; +const parseFileInfoExif = (fileInfoExif: FileInfoExif): ParsedFileInfoExif => { + const parsed: ParsedFileInfoExif = { ...fileInfoExif }; - - if (rawExif.exif) - if (exif["fNumber"]) { - parsedExifData["fNumber"] = `f/${Math.ceil(exif["FNumber"])}`; - } else if (exif["ApertureValue"] && exif["FocalLength"]) { - parsedExifData["fNumber"] = `f/${Math.ceil( - exif["FocalLength"] / exif["ApertureValue"], - )}`; + const { width, height } = fileInfoExif.parsed; + if (width && height) { + parsed.resolution = `${width} x ${height}`; + const mp = Math.round((width * height) / 1000000); + if (mp) parsed.megaPixels = `${mp}MP`; } - const imageWidth = exif["ImageWidth"] ?? exif["ExifImageWidth"]; - const imageHeight = exif["ImageHeight"] ?? exif["ExifImageHeight"]; - if (imageWidth && imageHeight) { - parsedExifData["resolution"] = `${imageWidth} x ${imageHeight}`; - const megaPixels = Math.round((imageWidth * imageHeight) / 1000000); - if (megaPixels) { - parsedExifData["megaPixels"] = `${Math.round( - (imageWidth * imageHeight) / 1000000, - )}MP`; + + const { tags } = fileInfoExif; + const { exif } = tags; + + if (exif) { + if (exif.Make && exif.Model) { + parsed["takenOnDevice"] = + `${exif.Make.description} ${exif.Model.description}`; + } + + if (exif.FNumber) { + parsed.fNumber = `f/${Math.ceil(exif.FNumber.value)}`; + } else if (exif.FocalLength && exif.ApertureValue) { + parsed.fNumber = `f/${Math.ceil( + exif.FocalLength.value / exif.ApertureValue.value, + )}`; + } + + if (exif.ExposureTime) { + parsed["exposureTime"] = `1/${1 / exif.ExposureTime.value}`; + } + + if (exif.ISOSpeedRatings) { + const iso = exif.ISOSpeedRatings; + const n = Array.isArray(iso) ? (iso[0] ?? 0) / (iso[1] ?? 1) : iso; + parsed.iso = `ISO${n}`; } } - if (exif["Make"] && exif["Model"]) { - parsedExifData["takenOnDevice"] = - `${exif["Make"]} ${exif["Model"]}`; + return parsed; +}; + +const FileInfoSidebar = styled((props: DialogProps) => ( + +))({ + zIndex: 1501, + "& .MuiPaper-root": { + padding: 8, + }, +}); + +function RenderFileName({ + parsedExifData, + shouldDisableEdits, + file, + scheduleUpdate, +}: { + parsedExifData: Record; + shouldDisableEdits: boolean; + file: EnteFile; + scheduleUpdate: () => void; +}) { + const [isInEditMode, setIsInEditMode] = useState(false); + const openEditMode = () => setIsInEditMode(true); + const closeEditMode = () => setIsInEditMode(false); + const [filename, setFilename] = useState(); + const [extension, setExtension] = useState(); + + useEffect(() => { + const [filename, extension] = nameAndExtension(file.metadata.title); + setFilename(filename); + setExtension(extension); + }, [file]); + + const saveEdits = async (newFilename: string) => { + try { + if (file) { + if (filename === newFilename) { + closeEditMode(); + return; + } + setFilename(newFilename); + const newTitle = getFileTitle(newFilename, extension); + const updatedFile = await changeFileName(file, newTitle); + updateExistingFilePubMetadata(file, updatedFile); + scheduleUpdate(); + } + } catch (e) { + log.error("failed to update file name", e); + throw e; + } + }; + + return ( + <> + + ) : ( + + ) + } + title={getFileTitle(filename, extension)} + caption={getCaption(file, parsedExifData)} + openEditor={openEditMode} + hideEditOption={shouldDisableEdits || isInEditMode} + /> + + + ); +} + +const getFileTitle = (filename, extension) => { + if (extension) { + return filename + "." + extension; + } else { + return filename; } - if (exif["ExposureTime"]) { - parsedExifData["exposureTime"] = `1/${ - 1 / parseFloat(exif["ExposureTime"]) - }`; +}; + +const getCaption = (file: EnteFile, parsedExifData) => { + const megaPixels = parsedExifData?.["megaPixels"]; + const resolution = parsedExifData?.["resolution"]; + const fileSize = file.info?.fileSize; + + const captionParts = []; + if (megaPixels) { + captionParts.push(megaPixels); } - if (exif["ISO"]) { - parsedExifData["ISO"] = `ISO${exif["ISO"]}`; + if (resolution) { + captionParts.push(resolution); } - setParsedExifData(parsedExifData); -}, [exif]); + if (fileSize) { + captionParts.push(formattedByteSize(fileSize)); + } + return ( + + {captionParts.map((caption) => ( + {caption} + ))} + + ); +}; + +function BasicDeviceCamera({ + parsedExifData, +}: { + parsedExifData: Record; +}) { + return ( + + {parsedExifData["fNumber"]} + {parsedExifData["exposureTime"]} + {parsedExifData["ISO"]} + + ); +} + +function getOpenStreetMapLink(location: { + latitude: number; + longitude: number; +}) { + return `https://www.openstreetmap.org/?mlat=${location.latitude}&mlon=${location.longitude}#map=15/${location.latitude}/${location.longitude}`; +} + +import { formatDateTimeFull } from "@ente/shared/time/format"; +import { Typography } from "@mui/material"; +import { FileInfoSidebar } from "."; + +const ExifItem = styled(Box)` + padding-left: 8px; + padding-right: 8px; + display: flex; + flex-direction: column; + gap: 4px; +`; + +function parseExifValue(value: any) { + switch (typeof value) { + case "string": + case "number": + return value; + default: + if (value instanceof Date) { + return formatDateTimeFull(value); + } + try { + return JSON.stringify(Array.from(value)); + } catch (e) { + return null; + } + } +} +export function ExifData(props: { + exif: any; + open: boolean; + onClose: () => void; + filename: string; + onInfoClose: () => void; +}) { + const { exif, open, onClose, filename, onInfoClose } = props; + + if (!exif) { + return <>; + } + const handleRootClose = () => { + onClose(); + onInfoClose(); + }; + + return ( + + + } + /> + + {[...Object.entries(exif)] + .sort((a, b) => a[0].localeCompare(b[0])) + .map(([key, value]) => + value ? ( + + + {key} + + + {parseExifValue(value)} + + + ) : ( + + ), + )} + + + ); +} diff --git a/web/apps/photos/src/components/PhotoViewer/index.tsx b/web/apps/photos/src/components/PhotoViewer/index.tsx index 768daf46f4..4d623992aa 100644 --- a/web/apps/photos/src/components/PhotoViewer/index.tsx +++ b/web/apps/photos/src/components/PhotoViewer/index.tsx @@ -18,7 +18,7 @@ import { lowercaseExtension } from "@/base/file"; import { FILE_TYPE } from "@/media/file-type"; import { isHEICExtension, needsJPEGConversion } from "@/media/formats"; import downloadManager from "@/new/photos/services/download"; -import { extractRawExif, type RawExifTags } from "@/new/photos/services/exif"; +import { extractRawExif, parseExif } from "@/new/photos/services/exif"; import type { LoadedLivePhotoSourceURL } from "@/new/photos/types/file"; import { FlexWrapper } from "@ente/shared/components/Container"; import EnteSpinner from "@ente/shared/components/EnteSpinner"; @@ -52,7 +52,7 @@ import { isClipboardItemPresent } from "utils/common"; import { pauseVideo, playVideo } from "utils/photoFrame"; import { PublicCollectionGalleryContext } from "utils/publicCollectionGallery"; import { getTrashFileMessage } from "utils/ui"; -import { FileInfo } from "./FileInfo"; +import { FileInfo, type FileInfoExif } from "./FileInfo"; import ImageEditorOverlay from "./ImageEditorOverlay"; import CircularProgressWithLabel from "./styledComponents/CircularProgressWithLabel"; import { ConversionFailedNotification } from "./styledComponents/ConversionFailedNotification"; @@ -107,11 +107,11 @@ function PhotoViewer(props: Iprops) { useState>(); const [isFav, setIsFav] = useState(false); const [showInfo, setShowInfo] = useState(false); - const [rawExif, setRawExif] = useState<{ + const [exif, setExif] = useState<{ key: string; - value: RawExifTags; + value: FileInfoExif | undefined; }>(); - const rawExifCopy = useRef(null); + const exifCopy = useRef(null); const [livePhotoBtnOptions, setLivePhotoBtnOptions] = useState( defaultLivePhotoDefaultOptions, ); @@ -290,8 +290,8 @@ function PhotoViewer(props: Iprops) { }, [photoSwipe?.currItem, isOpen, isSourceLoaded]); useEffect(() => { - rawExifCopy.current = rawExif; - }, [rawExif]); + exifCopy.current = exif; + }, [exif]); function updateFavButton(file: EnteFile) { setIsFav(isInFav(file)); @@ -306,14 +306,14 @@ function PhotoViewer(props: Iprops) { function updateExif(file: EnteFile) { if (file.metadata.fileType === FILE_TYPE.VIDEO) { - setRawExif({ key: file.src, value: null }); + setExif({ key: file.src, value: undefined }); return; } if (!file.isSourceLoaded || file.conversionFailed) { return; } - if (!file || !rawExifCopy?.current?.value === null) { + if (!file || !exifCopy?.current?.value) { return; } const key = @@ -321,10 +321,10 @@ function PhotoViewer(props: Iprops) { ? file.src : (file.srcURLs.url as LoadedLivePhotoSourceURL).image; - if (rawExifCopy?.current?.key === key) { + if (exifCopy?.current?.key === key) { return; } - setRawExif({ key, value: undefined }); + setExif({ key, value: undefined }); checkExifAvailable(file); } @@ -584,40 +584,32 @@ function PhotoViewer(props: Iprops) { } }; - const checkExifAvailable = async (file: EnteFile) => { + const checkExifAvailable = async (enteFile: EnteFile) => { try { - if (exifExtractionInProgress.current === file.src) { + if (exifExtractionInProgress.current === enteFile.src) { return; } try { - exifExtractionInProgress.current = file.src; - let fileObject: File; - if (file.metadata.fileType === FILE_TYPE.IMAGE) { - fileObject = await getFileFromURL( - file.src as string, - file.metadata.title, - ); - } else { - const url = (file.srcURLs.url as LoadedLivePhotoSourceURL) - .image; - fileObject = await getFileFromURL(url, file.metadata.title); - } - const rawExif = await extractRawExif(fileObject); - // TODO: Exif - // if (await wipNewLib()) { - // const newLib = await extractExif(fileObject); - // cmpNewLib(file.metadata, newLib); - // } - if (exifExtractionInProgress.current === file.src) { - setRawExif({ key: file.src, value: rawExif }); + exifExtractionInProgress.current = enteFile.src; + const file = await getFileFromURL( + enteFile.metadata.fileType === FILE_TYPE.IMAGE + ? (enteFile.src as string) + : (enteFile.srcURLs.url as LoadedLivePhotoSourceURL) + .image, + enteFile.metadata.title, + ); + const tags = await extractRawExif(file); + const parsed = parseExif(tags); + if (exifExtractionInProgress.current === enteFile.src) { + setExif({ key: enteFile.src, value: { tags, parsed } }); } } finally { exifExtractionInProgress.current = null; } } catch (e) { - setRawExif({ key: file.src, value: null }); + setExif({ key: enteFile.src, value: undefined }); log.error( - `checkExifAvailable failed for file ${file.metadata.title}`, + `checkExifAvailable failed for file ${enteFile.metadata.title}`, e, ); } @@ -946,7 +938,7 @@ function PhotoViewer(props: Iprops) { showInfo={showInfo} handleCloseInfo={handleCloseInfo} file={photoSwipe?.currItem as EnteFile} - rawExif={rawExif?.value} + exif={exif?.value} scheduleUpdate={scheduleUpdate} refreshPhotoswipe={refreshPhotoswipe} fileToCollectionsMap={props.fileToCollectionsMap} diff --git a/web/packages/new/photos/services/exif.ts b/web/packages/new/photos/services/exif.ts index 9dd4612adb..1066fb260d 100644 --- a/web/packages/new/photos/services/exif.ts +++ b/web/packages/new/photos/services/exif.ts @@ -34,7 +34,7 @@ export const cmpNewLib = ( * be attached to an {@link EnteFile} allows us to perform operations using * these attributes without needing to re-download the original image. */ -interface ParsedExif { +export interface ParsedExif { /** The width of the image, in pixels. */ width?: number; /** The height of the image, in pixels. */