mirror of
https://github.com/kmc7468/arkvault.git
synced 2026-11-04 08:10:28 +09:00
53 lines
2.0 KiB
TypeScript
53 lines
2.0 KiB
TypeScript
import ExifReader from "exifreader";
|
|
|
|
const isInteger = (value: number | undefined): value is number => Number.isInteger(value);
|
|
|
|
export const extractExifDateTime = (fileBuffer: ArrayBuffer) => {
|
|
const exif = ExifReader.load(fileBuffer);
|
|
const dateTimeOriginal = exif["DateTimeOriginal"]?.description;
|
|
const offsetTimeOriginal = exif["OffsetTimeOriginal"]?.description;
|
|
if (!dateTimeOriginal) return undefined;
|
|
|
|
const [date, time] = dateTimeOriginal.split(" ");
|
|
if (!date || !time) return undefined;
|
|
|
|
const [year, month, day] = date.split(":").map(Number);
|
|
const [hour, minute, second] = time.split(":").map(Number);
|
|
// Hours, minutes, and seconds may be 0, so they are checked differently
|
|
if (!year || !month || !day || !isInteger(hour) || !isInteger(minute) || !isInteger(second)) {
|
|
return undefined;
|
|
}
|
|
|
|
if (!offsetTimeOriginal) {
|
|
// No timezone information.. Assume local timezone
|
|
return new Date(year, month - 1, day, hour, minute, second);
|
|
}
|
|
|
|
const offsetSign = offsetTimeOriginal[0] === "+" ? 1 : -1;
|
|
const [offsetHour, offsetMinute] = offsetTimeOriginal.slice(1).split(":").map(Number);
|
|
|
|
const utcDate = Date.UTC(year, month - 1, day, hour, minute, second);
|
|
const offsetMs = offsetSign * ((offsetHour ?? 0) * 60 + (offsetMinute ?? 0)) * 60 * 1000;
|
|
return new Date(utcDate - offsetMs);
|
|
};
|
|
|
|
const EXIF_SEARCH_SIZE = 1024 * 1024; // 1 MiB
|
|
const MAX_FULL_READ_SIZE = 64 * 1024 * 1024; // 64 MiB
|
|
|
|
const tryExtractExifDateTime = (buffer: ArrayBuffer) => {
|
|
try {
|
|
return extractExifDateTime(buffer);
|
|
} catch {
|
|
return undefined;
|
|
}
|
|
};
|
|
|
|
// EXIF is usually at the beginning of the file, so the whole file is read only if not found
|
|
export const readExifDateTime = async (file: Blob) => {
|
|
const dateTime = tryExtractExifDateTime(await file.slice(0, EXIF_SEARCH_SIZE).arrayBuffer());
|
|
if (dateTime || file.size <= EXIF_SEARCH_SIZE || file.size > MAX_FULL_READ_SIZE) {
|
|
return dateTime;
|
|
}
|
|
return tryExtractExifDateTime(await file.arrayBuffer());
|
|
};
|