Parse wip

This commit is contained in:
Manav Rathi
2024-07-26 11:57:46 +05:30
parent bac49c7058
commit beace4cbde
5 changed files with 314 additions and 363 deletions

View File

@@ -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 (
<FileInfoSidebar open={open} onClose={onClose}>
<Titlebar
onClose={onClose}
title={t("exif")}
caption={filename}
onRootClose={handleRootClose}
actionButton={
<CopyButton
code={JSON.stringify(exif)}
color={"secondary"}
/>
}
/>
<Stack py={3} px={1} spacing={2}>
{[...Object.entries(exif)]
.sort((a, b) => a[0].localeCompare(b[0]))
.map(([key, value]) =>
value ? (
<ExifItem key={key}>
<Typography
variant="small"
color={"text.muted"}
>
{key}
</Typography>
<Typography
sx={{
width: "100%",
textOverflow: "ellipsis",
whiteSpace: "nowrap",
overflow: "hidden",
}}
>
{parseExifValue(value)}
</Typography>
</ExifItem>
) : (
<React.Fragment key={key}></React.Fragment>
),
)}
</Stack>
</FileInfoSidebar>
);
}

View File

@@ -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 (
<FlexWrapper gap={1}>
{captionParts.map((caption) => (
<Box key={caption}> {caption}</Box>
))}
</FlexWrapper>
);
};
export function RenderFileName({
parsedExifData,
shouldDisableEdits,
file,
scheduleUpdate,
}: {
parsedExifData: Record<string, any>;
shouldDisableEdits: boolean;
file: EnteFile;
scheduleUpdate: () => void;
}) {
const [isInEditMode, setIsInEditMode] = useState(false);
const openEditMode = () => setIsInEditMode(true);
const closeEditMode = () => setIsInEditMode(false);
const [filename, setFilename] = useState<string>();
const [extension, setExtension] = useState<string>();
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 (
<>
<InfoItem
icon={
file.metadata.fileType === FILE_TYPE.VIDEO ? (
<VideocamOutlined />
) : (
<PhotoOutlined />
)
}
title={getFileTitle(filename, extension)}
caption={getCaption(file, parsedExifData)}
openEditor={openEditMode}
hideEditOption={shouldDisableEdits || isInEditMode}
/>
<FileNameEditDialog
isInEditMode={isInEditMode}
closeEditMode={closeEditMode}
filename={filename}
extension={extension}
saveEdits={saveEdits}
/>
</>
);
}

View File

@@ -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) => (
<EnteDrawer {...props} anchor="right" />
))({
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<number, number[]>;
@@ -55,33 +57,12 @@ interface FileInfoProps {
closePhotoViewer: () => void;
}
function BasicDeviceCamera({
parsedExifData,
}: {
parsedExifData: Record<string, any>;
}) {
return (
<FlexWrapper gap={1}>
<Box>{parsedExifData["fNumber"]}</Box>
<Box>{parsedExifData["exposureTime"]}</Box>
<Box>{parsedExifData["ISO"]}</Box>
</FlexWrapper>
);
}
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<FileInfoProps> = ({
shouldDisableEdits,
showInfo,
handleCloseInfo,
file,
rawExif,
exif,
scheduleUpdate,
refreshPhotoswipe,
fileToCollectionsMap,
@@ -95,11 +76,10 @@ export const FileInfo: React.FC<FileInfoProps> = ({
PublicCollectionGalleryContext,
);
const [parsedExifData, setParsedExifData] = useState<Record<string, any>>();
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<FileInfoProps> = ({
};
}
}
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<FileInfoProps> = ({
<EnteSpinner size={11.33} />
) : exif !== null ? (
<LinkButton
onClick={openExif}
onClick={() => setOpenRawExif(true)}
sx={{
textDecoration: "none",
color: "text.muted",
@@ -329,9 +273,9 @@ export const FileInfo: React.FC<FileInfoProps> = ({
)}
</Stack>
<ExifData
exif={exif}
open={showExif}
onClose={closeExif}
exif={exif.tags}
open={openRawExif}
onClose={() => setOpenRawExif(false)}
onInfoClose={handleCloseInfo}
filename={file.metadata.title}
/>
@@ -339,54 +283,276 @@ export const FileInfo: React.FC<FileInfoProps> = ({
);
};
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) => (
<EnteDrawer {...props} anchor="right" />
))({
zIndex: 1501,
"& .MuiPaper-root": {
padding: 8,
},
});
function RenderFileName({
parsedExifData,
shouldDisableEdits,
file,
scheduleUpdate,
}: {
parsedExifData: Record<string, any>;
shouldDisableEdits: boolean;
file: EnteFile;
scheduleUpdate: () => void;
}) {
const [isInEditMode, setIsInEditMode] = useState(false);
const openEditMode = () => setIsInEditMode(true);
const closeEditMode = () => setIsInEditMode(false);
const [filename, setFilename] = useState<string>();
const [extension, setExtension] = useState<string>();
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 (
<>
<InfoItem
icon={
file.metadata.fileType === FILE_TYPE.VIDEO ? (
<VideocamOutlined />
) : (
<PhotoOutlined />
)
}
title={getFileTitle(filename, extension)}
caption={getCaption(file, parsedExifData)}
openEditor={openEditMode}
hideEditOption={shouldDisableEdits || isInEditMode}
/>
<FileNameEditDialog
isInEditMode={isInEditMode}
closeEditMode={closeEditMode}
filename={filename}
extension={extension}
saveEdits={saveEdits}
/>
</>
);
}
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 (
<FlexWrapper gap={1}>
{captionParts.map((caption) => (
<Box key={caption}> {caption}</Box>
))}
</FlexWrapper>
);
};
function BasicDeviceCamera({
parsedExifData,
}: {
parsedExifData: Record<string, any>;
}) {
return (
<FlexWrapper gap={1}>
<Box>{parsedExifData["fNumber"]}</Box>
<Box>{parsedExifData["exposureTime"]}</Box>
<Box>{parsedExifData["ISO"]}</Box>
</FlexWrapper>
);
}
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 (
<FileInfoSidebar open={open} onClose={onClose}>
<Titlebar
onClose={onClose}
title={t("exif")}
caption={filename}
onRootClose={handleRootClose}
actionButton={
<CopyButton
code={JSON.stringify(exif)}
color={"secondary"}
/>
}
/>
<Stack py={3} px={1} spacing={2}>
{[...Object.entries(exif)]
.sort((a, b) => a[0].localeCompare(b[0]))
.map(([key, value]) =>
value ? (
<ExifItem key={key}>
<Typography
variant="small"
color={"text.muted"}
>
{key}
</Typography>
<Typography
sx={{
width: "100%",
textOverflow: "ellipsis",
whiteSpace: "nowrap",
overflow: "hidden",
}}
>
{parseExifValue(value)}
</Typography>
</ExifItem>
) : (
<React.Fragment key={key}></React.Fragment>
),
)}
</Stack>
</FileInfoSidebar>
);
}

View File

@@ -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<Photoswipe<Photoswipe.Options>>();
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}

View File

@@ -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. */