[web] Exif improvements - Part 2/x (#2516)
Refs: - https://photo.stackexchange.com/questions/130570/can-i-assume-the-datetimeoriginal-of-an-image-without-an-offsettimeoriginal-is-a
This commit is contained in:
@@ -52,7 +52,7 @@ export const updateExifIfNeededAndPossible = async (
|
||||
} catch (e) {
|
||||
log.error(`Failed to modify Exif date for ${fileName}`, e);
|
||||
// We used the file's extension to determine if this was a JPEG, but
|
||||
// this is not a guarantee. Misnamed files, while rare, do exist. So in
|
||||
// this is not a guarantee. Misnamed files, while rare, do exist. So if
|
||||
// that is the error thrown by the underlying library, fallback to the
|
||||
// original instead of causing the entire download or export to fail.
|
||||
if (
|
||||
@@ -125,39 +125,53 @@ const dataURLToBlob = (dataURI: string) =>
|
||||
*
|
||||
* [Note: Exif dates]
|
||||
*
|
||||
* Summary:
|
||||
*
|
||||
* DateTimeOriginal is in local time, not UTC. Which local time? The
|
||||
* OffsetTimeOriginal specifies the time zone. But support for it is limited.
|
||||
*
|
||||
* Details:
|
||||
*
|
||||
* Common Exif date time tags, an in particular "DateTimeOriginal", are
|
||||
* specified in the form:
|
||||
*
|
||||
* yyyy:MM:DD HH:mm:ss
|
||||
*
|
||||
* These values thus do not have an associated UTC offset or TZ. The common
|
||||
* convention (based on my current understanding) is that these times are
|
||||
* interpreted to be the local time where the photo was taken.
|
||||
* These values thus do not have an associated UTC offset or TZ.
|
||||
*
|
||||
* Recently, there seems to be increasing support for the (newly standardized)
|
||||
* "OffsetTimeOriginal" and related fields, which specifies time zone for
|
||||
* The common convention is that these times are interpreted to be the local
|
||||
* time where the photo was taken.
|
||||
*
|
||||
* > The reason (I assume) for this omission is because (prior to smartphones),
|
||||
* > cameras did not have a good way of being aware of their time zone.
|
||||
*
|
||||
* Recently, there seems to be increasing support for the newly standardized
|
||||
* "OffsetTimeOriginal" and siblings, which specify time zone for
|
||||
* "DateTimeOriginal" (and related fields).
|
||||
*
|
||||
* However, when the offset time tag is not present (a frequent occurrence, not
|
||||
* just for older photos but also for screenshots generated by OSes as of 2024),
|
||||
* we don't really know, and stick with the common convention:
|
||||
* However, support is still not universal, and there will anyways be older
|
||||
* photos. So when the offset is missing, we stick with the common convention:
|
||||
*
|
||||
* - When reading, assume that the Exif date is in the local TZ when deriving
|
||||
* a UTC timestamp from it.
|
||||
*
|
||||
* - When writing, convert the UTC timestamp to local time.
|
||||
*
|
||||
* These assumptions are fallible, because the local time where we're uploading
|
||||
* or downloading the photo is not necessarily the same as the local time where
|
||||
* the photo was taken.
|
||||
*/
|
||||
const convertToExifDateFormat = (date: Date) => {
|
||||
// TODO: Exif - Handle offsettime if present
|
||||
const yyyy = date.getFullYear();
|
||||
const MM = zeroPad2(date.getMonth() + 1);
|
||||
const dd = zeroPad2(date.getDate());
|
||||
const HH = zeroPad2(date.getHours());
|
||||
const mm = zeroPad2(date.getMinutes());
|
||||
const ss = zeroPad2(date.getSeconds());
|
||||
const MM = zeroPad(date.getMonth() + 1, 2);
|
||||
const dd = zeroPad(date.getDate(), 2);
|
||||
const HH = zeroPad(date.getHours(), 2);
|
||||
const mm = zeroPad(date.getMinutes(), 2);
|
||||
const ss = zeroPad(date.getSeconds(), 2);
|
||||
|
||||
return `${yyyy}:${MM}:${dd} ${HH}:${mm}:${ss}`;
|
||||
};
|
||||
|
||||
/** Zero pad the given number to 2 digits. */
|
||||
const zeroPad2 = (n: number) => (n < 10 ? `0${n}` : `${n}`);
|
||||
/** Zero pad the given number to {@link d} digits. */
|
||||
const zeroPad = (n: number, d: number) => n.toString().padStart(d, "0");
|
||||
|
||||
Reference in New Issue
Block a user