浏览代码

HEIC convert

Manav Rathi 1 年之前
父节点
当前提交
ebb05e4bdf
共有 2 个文件被更改,包括 36 次插入5 次删除
  1. 35 4
      web/apps/cast/src/services/render.ts
  2. 1 1
      web/packages/media/worker/heic-convert.ts

+ 35 - 4
web/apps/cast/src/services/render.ts

@@ -2,8 +2,11 @@ import { FILE_TYPE } from "@/media/file-type";
 import { isNonWebImageFileExtension } from "@/media/formats";
 import { isNonWebImageFileExtension } from "@/media/formats";
 import { scaledImageDimensions } from "@/media/image";
 import { scaledImageDimensions } from "@/media/image";
 import { decodeLivePhoto } from "@/media/live-photo";
 import { decodeLivePhoto } from "@/media/live-photo";
+import { createHEICConvertComlinkWorker } from "@/media/worker/heic-convert";
+import type { DedicatedHEICConvertWorker } from "@/media/worker/heic-convert.worker";
 import { nameAndExtension } from "@/next/file";
 import { nameAndExtension } from "@/next/file";
 import log from "@/next/log";
 import log from "@/next/log";
+import type { ComlinkWorker } from "@/next/worker/comlink-worker";
 import { shuffled } from "@/utils/array";
 import { shuffled } from "@/utils/array";
 import { ensure } from "@/utils/ensure";
 import { ensure } from "@/utils/ensure";
 import { wait } from "@/utils/promise";
 import { wait } from "@/utils/promise";
@@ -51,6 +54,12 @@ type RenderableImageURLPair = [url: string, nextURL: string];
  */
  */
 let isChromecast = false;
 let isChromecast = false;
 
 
+/**
+ * If we're using HEIC conversion, then this variable caches the comlink web
+ * worker we're using to perform the actual conversion.
+ */
+let heicWorker: ComlinkWorker<typeof DedicatedHEICConvertWorker> | undefined;
+
 /**
 /**
  * An async generator function that loops through all the files in the
  * An async generator function that loops through all the files in the
  * collection, returning renderable URLs to each that can be displayed in a
  * collection, returning renderable URLs to each that can be displayed in a
@@ -285,8 +294,8 @@ const isFileEligible = (file: EnteFile) => {
     const [, extension] = nameAndExtension(file.metadata.title);
     const [, extension] = nameAndExtension(file.metadata.title);
     if (isNonWebImageFileExtension(extension)) {
     if (isNonWebImageFileExtension(extension)) {
         if (isChromecast) return false;
         if (isChromecast) return false;
-        // TODO(MR): HEIC support otherwise
-        return false;
+        // HEIC support otherwise.
+        return isHEIC(extension);
     }
     }
 
 
     return true;
     return true;
@@ -297,6 +306,17 @@ const isImageOrLivePhoto = (file: EnteFile) => {
     return fileType == FILE_TYPE.IMAGE || fileType == FILE_TYPE.LIVE_PHOTO;
     return fileType == FILE_TYPE.IMAGE || fileType == FILE_TYPE.LIVE_PHOTO;
 };
 };
 
 
+const isHEIC = (extension: string) => {
+    const ext = extension.toLowerCase();
+    return ext == "heic" || ext == "heif";
+};
+
+export const heicToJPEG = async (heicBlob: Blob) => {
+    let worker = heicWorker;
+    if (!worker) heicWorker = worker = createHEICConvertComlinkWorker();
+    return await (await worker.remote).heicToJPEG(heicBlob);
+};
+
 /**
 /**
  * Create and return a new data URL that can be used to show the given
  * Create and return a new data URL that can be used to show the given
  * {@link file} in our slideshow image viewer.
  * {@link file} in our slideshow image viewer.
@@ -311,12 +331,23 @@ const createRenderableURL = async (castToken: string, file: EnteFile) => {
 };
 };
 
 
 const renderableImageBlob = async (castToken: string, file: EnteFile) => {
 const renderableImageBlob = async (castToken: string, file: EnteFile) => {
-    const fileName = file.metadata.title;
+    let fileName = file.metadata.title;
     let blob = await downloadFile(castToken, file);
     let blob = await downloadFile(castToken, file);
+
     if (file.metadata.fileType === FILE_TYPE.LIVE_PHOTO) {
     if (file.metadata.fileType === FILE_TYPE.LIVE_PHOTO) {
-        const { imageData } = await decodeLivePhoto(fileName, blob);
+        const { imageData, imageFileName } = await decodeLivePhoto(
+            fileName,
+            blob,
+        );
+        fileName = imageFileName;
         blob = new Blob([imageData]);
         blob = new Blob([imageData]);
     }
     }
+
+    const [, ext] = nameAndExtension(fileName);
+    if (isHEIC(ext)) {
+        blob = await heicToJPEG(blob);
+    }
+
     const mimeType = await detectMediaMIMEType(new File([blob], fileName));
     const mimeType = await detectMediaMIMEType(new File([blob], fileName));
     if (!mimeType)
     if (!mimeType)
         throw new Error(`Could not detect MIME type for file ${fileName}`);
         throw new Error(`Could not detect MIME type for file ${fileName}`);

+ 1 - 1
web/packages/media/worker/heic-convert.ts

@@ -2,7 +2,7 @@ import { ComlinkWorker } from "@/next/worker/comlink-worker";
 import type { DedicatedHEICConvertWorker } from "./heic-convert.worker";
 import type { DedicatedHEICConvertWorker } from "./heic-convert.worker";
 
 
 export const createHEICConvertWebWorker = () =>
 export const createHEICConvertWebWorker = () =>
-    new Worker(new URL("worker/heic-convert.worker.ts", import.meta.url));
+    new Worker(new URL("heic-convert.worker.ts", import.meta.url));
 
 
 export const createHEICConvertComlinkWorker = () =>
 export const createHEICConvertComlinkWorker = () =>
     new ComlinkWorker<typeof DedicatedHEICConvertWorker>(
     new ComlinkWorker<typeof DedicatedHEICConvertWorker>(