From 4e29f1e03aafeb6cd6fb7c8304ffaca875093525 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Wed, 24 Jul 2024 18:44:38 +0530 Subject: [PATCH 1/9] Return pairs --- web/packages/new/photos/services/exif.ts | 63 +++++++++++++++--------- 1 file changed, 39 insertions(+), 24 deletions(-) diff --git a/web/packages/new/photos/services/exif.ts b/web/packages/new/photos/services/exif.ts index ffe632642a..3ff9e84ba6 100644 --- a/web/packages/new/photos/services/exif.ts +++ b/web/packages/new/photos/services/exif.ts @@ -204,30 +204,45 @@ const parseLocation = (tags: ExifReader.ExpandedTags) => ({ * Parse the width and height of the image from the metadata embedded in the * file. */ -const parseDimensions = (tags: ExifReader.ExpandedTags) => ({ - ImageWidth: [ - // Take the first (defined) non-zero value. - tags.exif?.ImageWidth?.value, - tags.exif?.PixelXDimension?.value, - parseXMPNum(tags.xmp?.ImageWidth), - parseXMPNum(tags.xmp?.PixelXDimension), - tags.pngFile?.["Image Width"]?.value, - tags.gif?.["Image Width"]?.value, - tags.riff?.ImageWidth?.value, - tags.file?.["Image Width"]?.value, - ].find((x) => x), - ImageHeight: [ - // Note: The Exif spec calls it ImageLength, not ImageHeight. - tags.exif?.ImageLength?.value, - tags.exif?.PixelYDimension?.value, - parseXMPNum(tags.xmp?.ImageLength), - parseXMPNum(tags.xmp?.PixelYDimension), - tags.pngFile?.["Image Height"]?.value, - tags.gif?.["Image Height"]?.value, - tags.riff?.ImageHeight?.value, - tags.file?.["Image Height"]?.value, - ].find((x) => x), -}); +const parseDimensions = (tags: ExifReader.ExpandedTags) => { + // Go through all possiblities in order, returning the first pair with both + // the width and height defined, and non-zero. + const pair = (w: number | undefined, h: number | undefined) => + w && h ? { ImageWidth: w, ImageHeight: h } : undefined; + + return ( + pair( + tags.exif?.ImageWidth?.value, + /* The Exif spec calls it ImageLength, not ImageHeight. */ + tags.exif?.ImageLength?.value, + ) ?? + pair( + tags.exif?.PixelXDimension?.value, + tags.exif?.PixelYDimension?.value, + ) ?? + pair( + parseXMPNum(tags.xmp?.ImageWidth), + parseXMPNum(tags.xmp?.ImageLength), + ) ?? + pair( + parseXMPNum(tags.xmp?.PixelXDimension), + parseXMPNum(tags.xmp?.PixelYDimension), + ) ?? + pair( + tags.pngFile?.["Image Width"]?.value, + tags.pngFile?.["Image Height"]?.value, + ) ?? + pair( + tags.gif?.["Image Width"]?.value, + tags.gif?.["Image Height"]?.value, + ) ?? + pair(tags.riff?.ImageWidth?.value, tags.riff?.ImageHeight?.value) ?? + pair( + tags.file?.["Image Width"]?.value, + tags.file?.["Image Height"]?.value, + ) + ); +}; /** * Try to parse the given XMP tag as a number. From ae0b701319e4db32012089690ab379965ed6e40d Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Wed, 24 Jul 2024 19:29:04 +0530 Subject: [PATCH 2/9] Parse IPTC dates --- web/packages/new/photos/services/exif.ts | 48 ++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/web/packages/new/photos/services/exif.ts b/web/packages/new/photos/services/exif.ts index 3ff9e84ba6..e0b1a04110 100644 --- a/web/packages/new/photos/services/exif.ts +++ b/web/packages/new/photos/services/exif.ts @@ -192,6 +192,54 @@ const parseXMPDate = (xmpTag: ExifReader.XmpTag | undefined) => { return new Date(s); }; +/** + * Parse an IPTC date tag. + * + * [Note: IPTC dates] + * + * IPTC date time values are split across two tag: + * + * - A tag containing the date as as 8 digit number of the form `YYYYMMDD`. + * + * - A tag containing the time as an 11 character string of the form + * `HHMMSS±HHMM`. + * + * They lack separators, but together these tags are meant to encode the same + * information as the ISO 8601 date format (that XMP and JavaScript also use). + * + * Reference: + * - http://www.iptc.org/std/IIM/4.1/specification/IIMV4.1.pdf + * + * --- + * + * @param dateTag The tag containing the date part of the date. + * + * @param timeTag The tag containing the time part of the date. + */ +const parseIPTCDate = ( + dateTag: ExifReader.NumberArrayTag | undefined, + timeTag: ExifReader.NumberArrayTag | undefined, +) => { + // The library we use (ExifReader) parses them into a usable representation, + // which we can use directly. Some notes: + // + // - There are currently no separate TypeScript types for the IPTC tags, + // and instead they are listed as part of the ExifTags. + // + // - For the date, ExifReader parses the raw data into a description of + // the form 'YYYY-MM-DD' (See `getCreationDate` in its source code). + // + // - For the time, ExifReader parses the raw data into a description + // either of the form 'HH:mm:ss` or `HH:mm:ss±HH:mm` (See + // `getCreationTime` in its source code). + if (!dateTag) return undefined; + let s = dateTag.description; + + if (timeTag) s = s + "T" + timeTag.description; + + return new Date(s); +}; + /** * Parse GPS location from the metadata embedded in the file. */ From 16ec4db5463d4127079d95f63cf5e036ff9be622 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Wed, 24 Jul 2024 19:39:47 +0530 Subject: [PATCH 3/9] Use --- web/packages/new/photos/services/exif.ts | 48 +++++++++++++++++------- 1 file changed, 34 insertions(+), 14 deletions(-) diff --git a/web/packages/new/photos/services/exif.ts b/web/packages/new/photos/services/exif.ts index e0b1a04110..8b52bb68f1 100644 --- a/web/packages/new/photos/services/exif.ts +++ b/web/packages/new/photos/services/exif.ts @@ -1,4 +1,3 @@ -import log from "@/base/log"; import ExifReader from "exifreader"; import type { EnteFile } from "../types/file"; @@ -32,11 +31,18 @@ export const extractExif = () => {}; */ const parseDates = (tags: ExifReader.ExpandedTags) => { const exif = parseExifDates(tags); + const iptc = parseIPTCDates(tags); const xmp = parseXMPDates(tags); return { - DateTimeOriginal: xmp.DateTimeOriginal ?? exif.DateTimeOriginal, + DateTimeOriginal: + xmp.DateTimeOriginal ?? + iptc.DateTimeOriginal ?? + exif.DateTimeOriginal, DateTimeDigitized: - xmp.DateTimeDigitized ?? exif.DateTimeDigitized ?? xmp.CreateDate, + xmp.DateTimeDigitized ?? + iptc.DateTimeDigitized ?? + exif.DateTimeDigitized ?? + xmp.CreateDate, DateTime: xmp.DateTime ?? exif.DateTime ?? xmp.ModifyDate, MetadataDate: xmp.MetadataDate, DateCreated: xmp.DateCreated, @@ -123,24 +129,23 @@ const parseExifDate = ( const [dateString] = dateTag?.value ?? []; if (!dateString) return undefined; - const components = dateString.trim().replace(" ", ":").split(":"); - const [YYYY, MM, DD, HH, mm, ss] = components; - if (!YYYY || !MM || !DD || !HH || !mm || !ss) { - log.warn(`Ignoring malformed Exif date ${dateString}`); - return undefined; - } - const [offsetString] = offsetTag?.value ?? []; - // Use the string components we have from the Exif date (and optional - // offset) to construct a string in the Javascript date time string format. + // Perform minor syntactic changes to the Exif date, and add the optional + // offset, to construct a string in the Javascript date time string format. // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date#date_time_string_format // + // YYYY:MM:DD HH:mm:ss±HH:mm + // YYYY-MM-DDTHH:mm:ss±HH:mm + // // When the offset string is missing, the date time is interpreted as local - // time. This is the behaviour we want (See: [Note: Exif dates]). + // time. This is the behaviour we want. + // + // For details see [Note: Exif dates] return new Date( - `${YYYY}-${MM}-${DD}T${HH}:${mm}:${ss}${offsetString ?? ""}`, + dateString.replace(":", "-").replace(":", "-").replace(" ", "T") + + (offsetString ?? ""), ); }; @@ -153,6 +158,7 @@ const parseExifDate = ( * For a list of XMP tags, see https://exiftool.org/TagNames/XMP.html. */ const parseXMPDates = ({ xmp }: ExifReader.ExpandedTags) => ({ + /* XMP namespace is indicated for each group */ // exif: DateTimeOriginal: parseXMPDate(xmp?.DateTimeOriginal), DateTimeDigitized: parseXMPDate(xmp?.DateTimeDigitized), @@ -192,6 +198,20 @@ const parseXMPDate = (xmpTag: ExifReader.XmpTag | undefined) => { return new Date(s); }; +/** + * Parse date related tags from IPTC. + */ +const parseIPTCDates = ({ iptc }: ExifReader.ExpandedTags) => ({ + DateTimeOriginal: parseIPTCDate( + iptc?.["Date Created"], + iptc?.["Time Created"], + ), + DateTimeDigitized: parseIPTCDate( + iptc?.["Digital Creation Date"], + iptc?.["Digital Creation Time"], + ), +}); + /** * Parse an IPTC date tag. * From 5a36e37e936022d83cf0dbaeb2ea3ccbafc9aead Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Wed, 24 Jul 2024 19:54:39 +0530 Subject: [PATCH 4/9] Fuse --- web/packages/new/photos/services/exif.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/web/packages/new/photos/services/exif.ts b/web/packages/new/photos/services/exif.ts index 8b52bb68f1..d1a53ea6e7 100644 --- a/web/packages/new/photos/services/exif.ts +++ b/web/packages/new/photos/services/exif.ts @@ -27,7 +27,8 @@ import type { EnteFile } from "../types/file"; export const extractExif = () => {}; /** - * Parse all date related fields from the metadata embedded in the file. + * Parse all date related fields from the metadata embedded in the file, + * grouping them into chunks that somewhat reflect the Exif ontology. */ const parseDates = (tags: ExifReader.ExpandedTags) => { const exif = parseExifDates(tags); @@ -37,7 +38,8 @@ const parseDates = (tags: ExifReader.ExpandedTags) => { DateTimeOriginal: xmp.DateTimeOriginal ?? iptc.DateTimeOriginal ?? - exif.DateTimeOriginal, + exif.DateTimeOriginal ?? + xmp.DateCreated, DateTimeDigitized: xmp.DateTimeDigitized ?? iptc.DateTimeDigitized ?? @@ -45,7 +47,6 @@ const parseDates = (tags: ExifReader.ExpandedTags) => { xmp.CreateDate, DateTime: xmp.DateTime ?? exif.DateTime ?? xmp.ModifyDate, MetadataDate: xmp.MetadataDate, - DateCreated: xmp.DateCreated, }; }; From c835984e406ddd27453dadaffbc60b6701e47747 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Wed, 24 Jul 2024 20:08:08 +0530 Subject: [PATCH 5/9] Single date --- web/packages/new/photos/services/exif.ts | 41 +++++++++++++++++------- 1 file changed, 30 insertions(+), 11 deletions(-) diff --git a/web/packages/new/photos/services/exif.ts b/web/packages/new/photos/services/exif.ts index d1a53ea6e7..ea6fae2d16 100644 --- a/web/packages/new/photos/services/exif.ts +++ b/web/packages/new/photos/services/exif.ts @@ -26,27 +26,46 @@ import type { EnteFile } from "../types/file"; // eslint-disable-next-line @typescript-eslint/no-empty-function export const extractExif = () => {}; +/** + * Parse a single "best" creation date for an image from the metadata embedded + * in the file. + * + * A file has multiple types of metadata, and each of these has multiple types + * of dates, so we use some an a heuristic ordering (based on experience with + * the photos we find out in the wild) to pick a "best" date. + */ +const parseCreationDate = (tags: ExifReader.ExpandedTags) => { + const { DateTimeOriginal, DateTimeDigitized, MetadataDate, DateTime } = + parseDates(tags); + return DateTimeOriginal ?? DateTimeDigitized ?? MetadataDate ?? DateTime; +}; + /** * Parse all date related fields from the metadata embedded in the file, * grouping them into chunks that somewhat reflect the Exif ontology. */ const parseDates = (tags: ExifReader.ExpandedTags) => { + // We have come across real examples of customer photos with Exif dates set + // to "0000:00:00 00:00:00". So ignore any date whose epoch is 0, so that we + // can try with a subsequent (possibly correct) date in the sequence. + const valid = (d: Date | undefined) => (d?.getTime() ? d : undefined); + const exif = parseExifDates(tags); const iptc = parseIPTCDates(tags); const xmp = parseXMPDates(tags); return { DateTimeOriginal: - xmp.DateTimeOriginal ?? - iptc.DateTimeOriginal ?? - exif.DateTimeOriginal ?? - xmp.DateCreated, + valid(xmp.DateTimeOriginal) ?? + valid(iptc.DateTimeOriginal) ?? + valid(exif.DateTimeOriginal) ?? + valid(xmp.DateCreated), DateTimeDigitized: - xmp.DateTimeDigitized ?? - iptc.DateTimeDigitized ?? - exif.DateTimeDigitized ?? - xmp.CreateDate, - DateTime: xmp.DateTime ?? exif.DateTime ?? xmp.ModifyDate, - MetadataDate: xmp.MetadataDate, + valid(xmp.DateTimeDigitized) ?? + valid(iptc.DateTimeDigitized) ?? + valid(exif.DateTimeDigitized) ?? + valid(xmp.CreateDate), + MetadataDate: valid(xmp.MetadataDate), + DateTime: valid(xmp.DateTime ?? exif.DateTime ?? xmp.ModifyDate), }; }; @@ -436,7 +455,7 @@ const backfill = (enteFile: EnteFile, tags: ExifReader.ExpandedTags) => { // TODO:Exif: Testing console.log([ enteFile, - parseDates(tags), + parseCreationDate(tags), parseLocation(tags), parseDimensions(tags), ]); From 719f056841cd0cb4ce302cd7d1106adc52050580 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Wed, 24 Jul 2024 20:28:03 +0530 Subject: [PATCH 6/9] Interface --- web/packages/new/photos/services/exif.ts | 47 ++++++++++++++++++------ 1 file changed, 35 insertions(+), 12 deletions(-) diff --git a/web/packages/new/photos/services/exif.ts b/web/packages/new/photos/services/exif.ts index ea6fae2d16..848d780d21 100644 --- a/web/packages/new/photos/services/exif.ts +++ b/web/packages/new/photos/services/exif.ts @@ -1,6 +1,25 @@ import ExifReader from "exifreader"; import type { EnteFile } from "../types/file"; +/** + * Data extracted from the Exif and other metadata embedded in the original + * image, and saved in the metadata associated with an {@link EnteFile}. + * + * These are the bits of information that are commonly needed, and having them + * be attached to an {@link EnteFile} allows us to perform operations using + * these attributes without needing to re-download the original image. + */ +interface ParsedMetadata { + /** The width of the image, in pixels. */ + width?: number; + /** The height of the image, in pixels. */ + height?: number; + /** The time when this photo was taken. */ + creationTime?: number; + /** The GPS coordinates where the photo was taken. */ + location?: { latitude: number; longitude: number }; +} + /** * Extract Exif and other metadata from the given file. * @@ -22,7 +41,6 @@ import type { EnteFile } from "../types/file"; * * The library we use is https://github.com/mattiasw/ExifReader. */ - // eslint-disable-next-line @typescript-eslint/no-empty-function export const extractExif = () => {}; @@ -283,10 +301,13 @@ const parseIPTCDate = ( /** * Parse GPS location from the metadata embedded in the file. */ -const parseLocation = (tags: ExifReader.ExpandedTags) => ({ - Latitude: tags.gps?.Latitude, - Longitude: tags.gps?.Longitude, -}); +const parseLocation = (tags: ExifReader.ExpandedTags) => { + const latitude = tags.gps?.Latitude; + const longitude = tags.gps?.Longitude; + return latitude !== undefined && longitude !== undefined + ? { latitude, longitude } + : undefined; +}; /** * Parse the width and height of the image from the metadata embedded in the @@ -296,7 +317,7 @@ const parseDimensions = (tags: ExifReader.ExpandedTags) => { // Go through all possiblities in order, returning the first pair with both // the width and height defined, and non-zero. const pair = (w: number | undefined, h: number | undefined) => - w && h ? { ImageWidth: w, ImageHeight: h } : undefined; + w && h ? { width: w, height: h } : undefined; return ( pair( @@ -453,10 +474,12 @@ export const indexExif = async (enteFile: EnteFile, blob: Blob) => { const backfill = (enteFile: EnteFile, tags: ExifReader.ExpandedTags) => { // const date = // TODO:Exif: Testing - console.log([ - enteFile, - parseCreationDate(tags), - parseLocation(tags), - parseDimensions(tags), - ]); + const location = parseLocation(tags); + const creationDate = parseCreationDate(tags); + const dimensions = parseDimensions(tags); + const metadata: ParsedMetadata = dimensions ?? {}; + if (creationDate) metadata.creationTime = creationDate.getTime() * 1000; + if (location) metadata.location = location; + console.log(enteFile, metadata); + return metadata; }; From 218a5ce5f9dc22e0c6ee97febbf62e9e8ba14be2 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Wed, 24 Jul 2024 20:37:48 +0530 Subject: [PATCH 7/9] Tie together --- web/packages/media/types/file.ts | 8 +++++- web/packages/new/photos/services/exif.ts | 34 +++++++++++++++-------- web/packages/new/photos/services/files.ts | 4 ++- 3 files changed, 33 insertions(+), 13 deletions(-) diff --git a/web/packages/media/types/file.ts b/web/packages/media/types/file.ts index b6314b7cdd..f41a34219e 100644 --- a/web/packages/media/types/file.ts +++ b/web/packages/media/types/file.ts @@ -57,7 +57,13 @@ export interface Metadata { * See: [Note: File name for local EnteFile objects] */ title: string; - creationTime: number; + /** + * The time when this file was created. + * + * For photos (and images in general), this is the time when the photo was + * taken, or when the screenshot was captured. + */ + creationTime: number | undefined; modificationTime: number; latitude: number; longitude: number; diff --git a/web/packages/new/photos/services/exif.ts b/web/packages/new/photos/services/exif.ts index 848d780d21..67b9d44fd3 100644 --- a/web/packages/new/photos/services/exif.ts +++ b/web/packages/new/photos/services/exif.ts @@ -41,8 +41,21 @@ interface ParsedMetadata { * * The library we use is https://github.com/mattiasw/ExifReader. */ -// eslint-disable-next-line @typescript-eslint/no-empty-function -export const extractExif = () => {}; +export const extractMetadata = async (file: File) => { + const tags = await ExifReader.load(await file.arrayBuffer(), { + async: true, + expanded: true, + }); + + const location = parseLocation(tags); + const creationDate = parseCreationDate(tags); + const dimensions = parseDimensions(tags); + + const metadata: ParsedMetadata = dimensions ?? {}; + if (creationDate) metadata.creationTime = creationDate.getTime() * 1000; + if (location) metadata.location = location; + return metadata; +}; /** * Parse a single "best" creation date for an image from the metadata embedded @@ -472,14 +485,13 @@ export const indexExif = async (enteFile: EnteFile, blob: Blob) => { }; const backfill = (enteFile: EnteFile, tags: ExifReader.ExpandedTags) => { - // const date = - // TODO:Exif: Testing - const location = parseLocation(tags); const creationDate = parseCreationDate(tags); - const dimensions = parseDimensions(tags); - const metadata: ParsedMetadata = dimensions ?? {}; - if (creationDate) metadata.creationTime = creationDate.getTime() * 1000; - if (location) metadata.location = location; - console.log(enteFile, metadata); - return metadata; + if (!creationDate) return; + + const creationTime = creationDate.getTime() * 1000; + + if (enteFile.metadata.creationTime == creationTime) return; + + // TODO: Exif: backfill + console.log(enteFile, creationTime); }; diff --git a/web/packages/new/photos/services/files.ts b/web/packages/new/photos/services/files.ts index 6a0ad4faa1..9d29a5e160 100644 --- a/web/packages/new/photos/services/files.ts +++ b/web/packages/new/photos/services/files.ts @@ -68,7 +68,9 @@ const sortTrashFiles = (files: EnteFile[]) => { b.metadata.modificationTime - a.metadata.modificationTime ); } - return b.metadata.creationTime - a.metadata.creationTime; + return ( + (b.metadata.creationTime ?? 0) - (a.metadata.creationTime ?? 0) + ); } return (a.deleteBy ?? 0) - (b.deleteBy ?? 0); }); From 0d313825d66ba149ff03d38e4c822e47b0b0b7fd Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Wed, 24 Jul 2024 20:46:16 +0530 Subject: [PATCH 8/9] debug logging --- web/apps/photos/src/components/PhotoViewer/index.tsx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/web/apps/photos/src/components/PhotoViewer/index.tsx b/web/apps/photos/src/components/PhotoViewer/index.tsx index 1c16a7a773..2464f4aea3 100644 --- a/web/apps/photos/src/components/PhotoViewer/index.tsx +++ b/web/apps/photos/src/components/PhotoViewer/index.tsx @@ -14,10 +14,12 @@ import { } from "utils/file"; import { isDesktop } from "@/base/app"; +import { isDevBuild } from "@/base/env"; 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 { extractMetadata } from "@/new/photos/services/exif"; import type { LoadedLivePhotoSourceURL } from "@/new/photos/types/file"; import { detectFileTypeInfo } from "@/new/photos/utils/detect-type"; import { FlexWrapper } from "@ente/shared/components/Container"; @@ -608,6 +610,10 @@ function PhotoViewer(props: Iprops) { fileObject, fileTypeInfo, ); + if (isDesktop && isDevBuild) { + const newLib = await extractMetadata(fileObject); + log.debug(() => ["exif", { oldLib: exifData, newLib }]); + } if (exifExtractionInProgress.current === file.src) { if (exifData) { setExif({ key: file.src, value: exifData }); From adf68a82c538bf86e19eb3d826ea0bd8009aeafe Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Wed, 24 Jul 2024 21:00:51 +0530 Subject: [PATCH 9/9] Add some debugging code --- .../photos/src/components/PhotoViewer/index.tsx | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/web/apps/photos/src/components/PhotoViewer/index.tsx b/web/apps/photos/src/components/PhotoViewer/index.tsx index 2464f4aea3..39a7dfb274 100644 --- a/web/apps/photos/src/components/PhotoViewer/index.tsx +++ b/web/apps/photos/src/components/PhotoViewer/index.tsx @@ -14,12 +14,10 @@ import { } from "utils/file"; import { isDesktop } from "@/base/app"; -import { isDevBuild } from "@/base/env"; 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 { extractMetadata } from "@/new/photos/services/exif"; import type { LoadedLivePhotoSourceURL } from "@/new/photos/types/file"; import { detectFileTypeInfo } from "@/new/photos/utils/detect-type"; import { FlexWrapper } from "@ente/shared/components/Container"; @@ -610,10 +608,14 @@ function PhotoViewer(props: Iprops) { fileObject, fileTypeInfo, ); - if (isDesktop && isDevBuild) { - const newLib = await extractMetadata(fileObject); - log.debug(() => ["exif", { oldLib: exifData, newLib }]); - } + // TODO: Exif debugging code. + // if (isDesktop && isDevBuild) { + // const newLib = await extractMetadata(fileObject); + // log.debug(() => [ + // "exif", + // { oldLib: file.metadata, newLib }, + // ]); + // } if (exifExtractionInProgress.current === file.src) { if (exifData) { setExif({ key: file.src, value: exifData });