exactType => extension

This commit is contained in:
Manav Rathi 2024-04-24 22:02:12 +05:30
parent e03a0a09d4
commit 7f3d9690c0
No known key found for this signature in database
9 changed files with 50 additions and 66 deletions

View file

@ -24,5 +24,5 @@ export const detectMediaMIMEType = async (file: File): Promise<string> => {
const ext = lowercaseExtension(file.name);
if (!ext) return undefined;
return KnownFileTypeInfos.find((f) => f.exactType == ext)?.mimeType;
return KnownFileTypeInfos.find((f) => f.extension == ext)?.mimeType;
};

View file

@ -15,11 +15,3 @@ export interface Metadata {
version?: number;
deviceFolder?: string;
}
export interface FileTypeInfo {
fileType: FILE_TYPE;
exactType: string;
mimeType?: string;
imageType?: string;
videoType?: string;
}

View file

@ -36,16 +36,15 @@ type RawEXIFData = Record<string, any> &
export async function getParsedExifData(
receivedFile: File,
{ exactType }: FileTypeInfo,
{ extension }: FileTypeInfo,
tags?: string[],
): Promise<ParsedEXIFData> {
const exifLessFormats = ["gif", "bmp"];
const exifrUnsupportedFileFormatMessage = "Unknown file format";
try {
if (exifLessFormats.includes(exactType)) {
return null;
}
if (exifLessFormats.includes(extension)) return null;
const exifData: RawEXIFData = await exifr.parse(receivedFile, {
reviveValues: false,
tiff: true,
@ -68,10 +67,10 @@ export async function getParsedExifData(
return parseExifData(filteredExifData);
} catch (e) {
if (e.message == exifrUnsupportedFileFormatMessage) {
log.error(`EXIFR does not support format ${exactType}`, e);
log.error(`EXIFR does not support ${extension} files`, e);
return undefined;
} else {
log.error(`Failed to parse EXIF data of ${exactType} file`, e);
log.error(`Failed to parse EXIF data for a ${extension} file`, e);
throw e;
}
}

View file

@ -59,12 +59,12 @@ export const detectFileTypeInfo = async (
}
return {
fileType,
exactType: typeResult.ext,
extension: typeResult.ext,
mimeType: typeResult.mime,
};
} catch (e) {
const extension = lowercaseExtension(fileOrPath.name);
const known = KnownFileTypeInfos.find((f) => f.exactType == extension);
const known = KnownFileTypeInfos.find((f) => f.extension == extension);
if (known) return known;
if (KnownNonMediaFileExtensions.includes(extension))
@ -91,8 +91,8 @@ async function extractElectronFileType(file: ElectronFile) {
async function getFileTypeFromBuffer(buffer: Uint8Array) {
const result = await FileType.fromBuffer(buffer);
if (!result?.mime) {
throw Error(`Could not deduce MIME type from buffer`);
if (!result?.ext || !result?.mime) {
throw Error(`Could not deduce file type from buffer`);
}
return result;
}

View file

@ -246,7 +246,7 @@ async function extractLivePhotoMetadata(
): Promise<ExtractMetadataResult> {
const imageFileTypeInfo: FileTypeInfo = {
fileType: FILE_TYPE.IMAGE,
exactType: fileTypeInfo.imageType,
extension: fileTypeInfo.imageType,
};
const {
metadata: imageMetadata,

View file

@ -5,7 +5,6 @@ import { withTimeout } from "@ente/shared/utils";
import { BLACK_THUMBNAIL_BASE64 } from "constants/upload";
import * as ffmpeg from "services/ffmpeg";
import { heicToJPEG } from "services/heic-convert";
import { isFileHEIC } from "utils/file";
/** Maximum width or height of the generated thumbnail */
const maxThumbnailDimension = 720;
@ -36,9 +35,9 @@ export const generateThumbnailWeb = async (
const generateImageThumbnailUsingCanvas = async (
blob: Blob,
fileTypeInfo: FileTypeInfo,
{ extension }: FileTypeInfo,
) => {
if (isFileHEIC(fileTypeInfo.exactType)) {
if (extension == "heic" || extension == "heif") {
log.debug(() => `Pre-converting HEIC to JPEG for thumbnail generation`);
blob = await heicToJPEG(blob);
}

View file

@ -341,9 +341,9 @@ const getLivePhotoFileType = async (
const videoFileTypeInfo = await detectFileTypeInfo(livePhotoAssets.video);
return {
fileType: FILE_TYPE.LIVE_PHOTO,
exactType: `${imageFileTypeInfo.exactType}+${videoFileTypeInfo.exactType}`,
imageType: imageFileTypeInfo.exactType,
videoType: videoFileTypeInfo.exactType,
extension: `${imageFileTypeInfo.extension}+${videoFileTypeInfo.extension}`,
imageType: imageFileTypeInfo.extension,
videoType: videoFileTypeInfo.extension,
};
};
@ -588,7 +588,7 @@ const readLivePhoto = async (
} = await withThumbnail(
livePhotoAssets.image,
{
exactType: fileTypeInfo.imageType,
extension: fileTypeInfo.imageType,
fileType: FILE_TYPE.IMAGE,
},
readImage.dataOrStream,

View file

@ -1,4 +1,4 @@
import { FILE_TYPE, type FileTypeInfo } from "@/media/file-type";
import { FILE_TYPE } from "@/media/file-type";
import { decodeLivePhoto } from "@/media/live-photo";
import { lowercaseExtension } from "@/next/file";
import log from "@/next/log";
@ -40,9 +40,6 @@ import { isArchivedFile, updateMagicMetadata } from "utils/magicMetadata";
import { safeFileName } from "utils/native-fs";
import { writeStream } from "utils/native-stream";
const TYPE_HEIC = "heic";
const TYPE_HEIF = "heif";
const RAW_FORMATS = [
"heic",
"rw2",
@ -287,23 +284,22 @@ export function generateStreamFromArrayBuffer(data: Uint8Array) {
}
export const getRenderableImage = async (fileName: string, imageBlob: Blob) => {
let fileTypeInfo: FileTypeInfo;
try {
const tempFile = new File([imageBlob], fileName);
fileTypeInfo = await detectFileTypeInfo(tempFile);
const fileTypeInfo = await detectFileTypeInfo(tempFile);
log.debug(
() =>
`Obtaining renderable image for ${JSON.stringify(fileTypeInfo)}`,
() => `Need renderable image for ${JSON.stringify(fileTypeInfo)}`,
);
const { exactType } = fileTypeInfo;
const { extension } = fileTypeInfo;
if (!isRawFile(exactType)) {
// Not something we know how to handle yet, give back the original.
if (!isRawFile(extension)) {
// Either it is not something we know how to handle yet, or
// something that the browser already knows how to render.
return imageBlob;
}
const available = !moduleState.isNativeJPEGConversionNotAvailable;
if (isElectron() && available && isSupportedRawFormat(exactType)) {
if (isElectron() && available && isSupportedRawFormat(extension)) {
// If we're running in our desktop app, see if our Node.js layer can
// convert this into a JPEG using native tools for us.
try {
@ -317,17 +313,14 @@ export const getRenderableImage = async (fileName: string, imageBlob: Blob) => {
}
}
if (isFileHEIC(exactType)) {
// If it is an HEIC file, use our web HEIC converter.
if (extension == "heic" || extension == "heif") {
// For HEIC/HEIF files we can use our web HEIC converter.
return await heicToJPEG(imageBlob);
}
return undefined;
} catch (e) {
log.error(
`Failed to get renderable image for ${JSON.stringify(fileTypeInfo ?? fileName)}`,
e,
);
log.error(`Failed to get renderable image for ${fileName}`, e);
return undefined;
}
};
@ -346,13 +339,6 @@ const nativeConvertToJPEG = async (imageBlob: Blob) => {
return new Blob([jpegData]);
};
export function isFileHEIC(exactType: string) {
return (
exactType.toLowerCase().endsWith(TYPE_HEIC) ||
exactType.toLowerCase().endsWith(TYPE_HEIF)
);
}
export function isRawFile(exactType: string) {
return RAW_FORMATS.includes(exactType.toLowerCase());
}

View file

@ -7,7 +7,15 @@ export enum FILE_TYPE {
export interface FileTypeInfo {
fileType: FILE_TYPE;
exactType: string;
/**
* A lowercased, standardized extension for files of the current type.
*
* TODO(MR): This in not valid for LIVE_PHOTO.
*
* See https://github.com/sindresorhus/file-type/blob/main/core.d.ts for the
* full list of values this property can have.
*/
extension: string;
mimeType?: string;
imageType?: string;
videoType?: string;
@ -15,42 +23,42 @@ export interface FileTypeInfo {
// list of format that were missed by type-detection for some files.
export const KnownFileTypeInfos: FileTypeInfo[] = [
{ fileType: FILE_TYPE.IMAGE, exactType: "jpeg", mimeType: "image/jpeg" },
{ fileType: FILE_TYPE.IMAGE, exactType: "jpg", mimeType: "image/jpeg" },
{ fileType: FILE_TYPE.VIDEO, exactType: "webm", mimeType: "video/webm" },
{ fileType: FILE_TYPE.VIDEO, exactType: "mod", mimeType: "video/mpeg" },
{ fileType: FILE_TYPE.VIDEO, exactType: "mp4", mimeType: "video/mp4" },
{ fileType: FILE_TYPE.IMAGE, exactType: "gif", mimeType: "image/gif" },
{ fileType: FILE_TYPE.VIDEO, exactType: "dv", mimeType: "video/x-dv" },
{ fileType: FILE_TYPE.IMAGE, extension: "jpeg", mimeType: "image/jpeg" },
{ fileType: FILE_TYPE.IMAGE, extension: "jpg", mimeType: "image/jpeg" },
{ fileType: FILE_TYPE.VIDEO, extension: "webm", mimeType: "video/webm" },
{ fileType: FILE_TYPE.VIDEO, extension: "mod", mimeType: "video/mpeg" },
{ fileType: FILE_TYPE.VIDEO, extension: "mp4", mimeType: "video/mp4" },
{ fileType: FILE_TYPE.IMAGE, extension: "gif", mimeType: "image/gif" },
{ fileType: FILE_TYPE.VIDEO, extension: "dv", mimeType: "video/x-dv" },
{
fileType: FILE_TYPE.VIDEO,
exactType: "wmv",
extension: "wmv",
mimeType: "video/x-ms-asf",
},
{
fileType: FILE_TYPE.VIDEO,
exactType: "hevc",
extension: "hevc",
mimeType: "video/hevc",
},
{
fileType: FILE_TYPE.IMAGE,
exactType: "raf",
extension: "raf",
mimeType: "image/x-fuji-raf",
},
{
fileType: FILE_TYPE.IMAGE,
exactType: "orf",
extension: "orf",
mimeType: "image/x-olympus-orf",
},
{
fileType: FILE_TYPE.IMAGE,
exactType: "crw",
extension: "crw",
mimeType: "image/x-canon-crw",
},
{
fileType: FILE_TYPE.VIDEO,
exactType: "mov",
extension: "mov",
mimeType: "video/quicktime",
},
];