diff --git a/web/apps/photos/src/utils/file/index.ts b/web/apps/photos/src/utils/file/index.ts index 17068c449..3e9c2d3d0 100644 --- a/web/apps/photos/src/utils/file/index.ts +++ b/web/apps/photos/src/utils/file/index.ts @@ -266,71 +266,53 @@ export function generateStreamFromArrayBuffer(data: Uint8Array) { }); } -export async function getRenderableImage(fileName: string, imageBlob: Blob) { +export const getRenderableImage = async (fileName: string, imageBlob: Blob) => { let fileTypeInfo: FileTypeInfo; try { const tempFile = new File([imageBlob], fileName); fileTypeInfo = await getFileType(tempFile); log.debug(() => `file type info: ${JSON.stringify(fileTypeInfo)}`); const { exactType } = fileTypeInfo; - let convertedImageBlob: Blob; - if (isRawFile(exactType)) { - try { - if (!isSupportedRawFormat(exactType)) { - throw Error(CustomError.UNSUPPORTED_RAW_FORMAT); - } - if (!isElectron()) { - throw new Error("not available on web"); - } - log.info( - `RawConverter called for ${fileName}-${convertBytesToHumanReadable( - imageBlob.size, - )}`, - ); - convertedImageBlob = await convertToJPEGInElectron( - imageBlob, - fileName, - ); - log.info(`${fileName} successfully converted`); - } catch (e) { - try { - if (!isFileHEIC(exactType)) { - throw e; - } - log.info( - `HEICConverter called for ${fileName}-${convertBytesToHumanReadable( - imageBlob.size, - )}`, - ); - convertedImageBlob = - await heicConversionService.convert(imageBlob); - log.info(`${fileName} successfully converted`); - } catch (e) { - throw Error(CustomError.NON_PREVIEWABLE_FILE); - } - } - return convertedImageBlob; - } else { + if (!isRawFile(exactType)) { + // Not something we know how to handle yet, give back the original. return imageBlob; } + + let jpegBlob: Blob | undefined; + + if (isElectron() && isSupportedRawFormat(exactType)) { + // If we're running in our desktop app, see if our Node.js layer can + // convert this into a JPEG for us. + jpegBlob = await tryConvertToJPEGInElectron(imageBlob, fileName); + } + + if (!jpegBlob && isFileHEIC(exactType)) { + // If it is an HEIC file, use our web HEIC converter. + jpegBlob = await heicConversionService.convert(imageBlob); + } + + return jpegBlob; } catch (e) { log.error( - `Failed to get renderable image for ${JSON.stringify(fileTypeInfo)}`, + `Failed to get renderable image for ${JSON.stringify(fileTypeInfo ?? fileName)}`, e, ); - return null; + return undefined; } -} +}; -const convertToJPEGInElectron = async ( +const tryConvertToJPEGInElectron = async ( fileBlob: Blob, filename: string, -): Promise => { +): Promise => { try { const startTime = Date.now(); const inputFileData = new Uint8Array(await fileBlob.arrayBuffer()); const electron = globalThis.electron; + // If we're running in a worker, we need to reroute the request back to + // the main thread since workers don't have access to the `window` (and + // thus, to the `window.electron`) object. const convertedFileData = electron ? await electron.convertToJPEG(inputFileData, filename) : await workerBridge.convertToJPEG(inputFileData, filename); diff --git a/web/packages/shared/error/index.ts b/web/packages/shared/error/index.ts index c91f21413..e9c9270b8 100644 --- a/web/packages/shared/error/index.ts +++ b/web/packages/shared/error/index.ts @@ -74,8 +74,6 @@ export const CustomError = { EXIF_DATA_NOT_FOUND: "exif data not found", SELECT_FOLDER_ABORTED: "select folder aborted", NON_MEDIA_FILE: "non media file", - UNSUPPORTED_RAW_FORMAT: "unsupported raw format", - NON_PREVIEWABLE_FILE: "non previewable file", PROCESSING_FAILED: "processing failed", EXPORT_RECORD_JSON_PARSING_FAILED: "export record json parsing failed", TWO_FACTOR_ENABLED: "two factor enabled",