exactType => extension
This commit is contained in:
parent
e03a0a09d4
commit
7f3d9690c0
9 changed files with 50 additions and 66 deletions
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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",
|
||||
},
|
||||
];
|
||||
|
|
Loading…
Add table
Reference in a new issue