This commit is contained in:
Manav Rathi 2024-07-22 13:57:59 +05:30
parent d59e50ff93
commit 67d1d6c597
No known key found for this signature in database
4 changed files with 67 additions and 65 deletions

View File

@ -7,7 +7,6 @@ import type {
} from "@/new/photos/types/metadata";
import { validateAndGetCreationUnixTimeInMicroSeconds } from "@ente/shared/time";
import exifr from "exifr";
import piexif from "piexifjs";
type ParsedEXIFData = Record<string, any> &
Partial<{
@ -332,65 +331,3 @@ export function getEXIFTime(exifData: ParsedEXIFData): number {
}
return validateAndGetCreationUnixTimeInMicroSeconds(dateTime);
}
export async function updateFileCreationDateInEXIF(
fileBlob: Blob,
updatedDate: Date,
) {
try {
let imageDataURL = await blobToDataURL(fileBlob);
// Since we pass a Blob without an associated type, we get back a
// generic data URL like "data:application/octet-stream;base64,...".
// Modify it to have a `image/jpeg` MIME type.
imageDataURL =
"data:image/jpeg;base64" +
imageDataURL.slice(imageDataURL.indexOf(","));
const exifObj = piexif.load(imageDataURL);
if (!exifObj["Exif"]) {
exifObj["Exif"] = {};
}
exifObj["Exif"][piexif.ExifIFD.DateTimeOriginal] =
convertToExifDateFormat(updatedDate);
log.debug(() => [
"updateFileCreationDateInEXIF",
{ updatedDate, exifObj },
]);
const exifBytes = piexif.dump(exifObj);
const exifInsertedFile = piexif.insert(exifBytes, imageDataURL);
return dataURLToBlob(exifInsertedFile);
} catch (e) {
log.error("updateFileModifyDateInEXIF failed", e);
return fileBlob;
}
}
/**
* Convert a blob to a `data:` URL.
*/
const blobToDataURL = (blob: Blob) =>
new Promise<string>((resolve) => {
const reader = new FileReader();
// We need to cast to a string here. This should be safe since MDN says:
//
// > the result attribute contains the data as a data: URL representing
// > the file's data as a base64 encoded string.
// >
// > https://developer.mozilla.org/en-US/docs/Web/API/FileReader/readAsDataURL
reader.onload = () => resolve(reader.result as string);
reader.readAsDataURL(blob);
});
/**
* Convert a `data:` URL to a blob.
*
* Requires `connect-src data:` in the CSP (since it internally uses `fetch` to
* perform the conversion).
*/
const dataURLToBlob = (dataURI: string) =>
fetch(dataURI).then((res) => res.blob());
function convertToExifDateFormat(date: Date) {
return `${date.getFullYear()}:${
date.getMonth() + 1
}:${date.getDate()} ${date.getHours()}:${date.getMinutes()}:${date.getSeconds()}`;
}

View File

@ -25,7 +25,7 @@ import type { User } from "@ente/shared/user/types";
import { downloadUsingAnchor } from "@ente/shared/utils";
import { t } from "i18next";
import { moveToHiddenCollection } from "services/collectionService";
import { updateFileCreationDateInEXIF } from "services/exif";
import { updateFileCreationDateInEXIF } from "@/new/photos/services/exif";
import {
deleteFromTrash,
trashFiles,

View File

@ -192,7 +192,8 @@ For more details, see [translations.md](translations.md).
## Media
- [ExifReader](https://github.com/mattiasw/ExifReader) is used for Exif
parsing.
parsing. [piexifjs](https://github.com/hMatoba/piexifjs) is used for writing
back Exif (only supports JPEG).
- [jszip](https://github.com/Stuk/jszip) is used for reading zip files in the
web code (Live photos are zip files under the hood). Note that the desktop

View File

@ -0,0 +1,64 @@
import log from "@/base/log";
import piexif from "piexifjs";
export const updateFileCreationDateInEXIF = async (
fileBlob: Blob,
updatedDate: Date,
) => {
try {
let imageDataURL = await blobToDataURL(fileBlob);
// Since we pass a Blob without an associated type, we get back a
// generic data URL like "data:application/octet-stream;base64,...".
// Modify it to have a `image/jpeg` MIME type.
imageDataURL =
"data:image/jpeg;base64" +
imageDataURL.slice(imageDataURL.indexOf(","));
const exifObj = piexif.load(imageDataURL);
if (!exifObj["Exif"]) {
exifObj["Exif"] = {};
}
exifObj["Exif"][piexif.ExifIFD.DateTimeOriginal] =
convertToExifDateFormat(updatedDate);
log.debug(() => [
"updateFileCreationDateInEXIF",
{ updatedDate, exifObj },
]);
const exifBytes = piexif.dump(exifObj);
const exifInsertedFile = piexif.insert(exifBytes, imageDataURL);
return dataURLToBlob(exifInsertedFile);
} catch (e) {
log.error("updateFileModifyDateInEXIF failed", e);
return fileBlob;
}
};
/**
* Convert a blob to a `data:` URL.
*/
const blobToDataURL = (blob: Blob) =>
new Promise<string>((resolve) => {
const reader = new FileReader();
// We need to cast to a string here. This should be safe since MDN says:
//
// > the result attribute contains the data as a data: URL representing
// > the file's data as a base64 encoded string.
// >
// > https://developer.mozilla.org/en-US/docs/Web/API/FileReader/readAsDataURL
reader.onload = () => resolve(reader.result as string);
reader.readAsDataURL(blob);
});
/**
* Convert a `data:` URL to a blob.
*
* Requires `connect-src data:` in the CSP (since it internally uses `fetch` to
* perform the conversion).
*/
const dataURLToBlob = (dataURI: string) =>
fetch(dataURI).then((res) => res.blob());
function convertToExifDateFormat(date: Date) {
return `${date.getFullYear()}:${
date.getMonth() + 1
}:${date.getDate()} ${date.getHours()}:${date.getMinutes()}:${date.getSeconds()}`;
}