input filename is not needed

tested with sips
This commit is contained in:
Manav Rathi 2024-04-22 16:49:01 +05:30
parent 4461775283
commit 05cd0bcd2c
No known key found for this signature in database
7 changed files with 51 additions and 42 deletions

View file

@ -141,14 +141,18 @@ export const attachIPCHandlers = () => {
// - Conversion
ipcMain.handle("convertToJPEG", (_, fileName, imageData) =>
convertToJPEG(fileName, imageData),
ipcMain.handle("convertToJPEG", (_, imageData: Uint8Array) =>
convertToJPEG(imageData),
);
ipcMain.handle(
"generateImageThumbnail",
(_, inputFile, maxDimension, maxSize) =>
generateImageThumbnail(inputFile, maxDimension, maxSize),
(
_,
dataOrPath: Uint8Array | string,
maxDimension: number,
maxSize: number,
) => generateImageThumbnail(dataOrPath, maxDimension, maxSize),
);
ipcMain.handle(

View file

@ -3,20 +3,17 @@
import { existsSync } from "fs";
import fs from "node:fs/promises";
import path from "path";
import { CustomErrorMessage, ElectronFile } from "../../types/ipc";
import { CustomErrorMessage } from "../../types/ipc";
import log from "../log";
import { writeStream } from "../stream";
import { execAsync, isDev } from "../utils-electron";
import { deleteTempFile, makeTempFilePath } from "../utils-temp";
export const convertToJPEG = async (
fileName: string,
imageData: Uint8Array,
): Promise<Uint8Array> => {
const inputFilePath = await makeTempFilePath(fileName);
export const convertToJPEG = async (imageData: Uint8Array) => {
const inputFilePath = await makeTempFilePath();
const outputFilePath = await makeTempFilePath(".jpeg");
// Construct the command first, it may throw on NotAvailable on win32.
// Construct the command first, it may throw NotAvailable on win32.
const command = convertToJPEGCommand(inputFilePath, outputFilePath);
try {
@ -106,10 +103,28 @@ const IMAGE_MAGICK_THUMBNAIL_GENERATE_COMMAND_TEMPLATE = [
];
export async function generateImageThumbnail(
inputFile: File | ElectronFile,
dataOrPath: Uint8Array | string,
maxDimension: number,
maxSize: number,
): Promise<Uint8Array> {
const inputFilePath = await makeTempFilePath(fileName);
const outputFilePath = await makeTempFilePath(".jpeg");
// Construct the command first, it may throw NotAvailable on win32.
const command = convertToJPEGCommand(inputFilePath, outputFilePath);
try {
await fs.writeFile(inputFilePath, imageData);
await execAsync(command);
return new Uint8Array(await fs.readFile(outputFilePath));
} finally {
try {
deleteTempFile(outputFilePath);
deleteTempFile(inputFilePath);
} catch (e) {
log.error("Ignoring error when cleaning up temp files", e);
}
}
let inputFilePath = null;
let createdTempInputFile = null;
try {

View file

@ -124,20 +124,17 @@ const fsIsDir = (dirPath: string): Promise<boolean> =>
// - Conversion
const convertToJPEG = (
fileName: string,
imageData: Uint8Array,
): Promise<Uint8Array> =>
ipcRenderer.invoke("convertToJPEG", fileName, imageData);
const convertToJPEG = (imageData: Uint8Array): Promise<Uint8Array> =>
ipcRenderer.invoke("convertToJPEG", imageData);
const generateImageThumbnail = (
inputFile: File | ElectronFile,
dataOrPath: Uint8Array | string,
maxDimension: number,
maxSize: number,
): Promise<Uint8Array> =>
ipcRenderer.invoke(
"generateImageThumbnail",
inputFile,
dataOrPath,
maxDimension,
maxSize,
);

View file

@ -59,15 +59,12 @@ export const generateThumbnail = async (
const thumbnail =
fileTypeInfo.fileType === FILE_TYPE.IMAGE
? await generateImageThumbnail(blob, fileTypeInfo)
: await generateVideoThumbnail(blob, fileTypeInfo);
: await generateVideoThumbnail(blob);
if (thumbnail.length == 0) throw new Error("Empty thumbnail");
return { thumbnail, hasStaticThumbnail: false };
} catch (e) {
log.error(
`Failed to generate thumbnail for format ${fileTypeInfo.exactType}`,
e,
);
log.error(`Failed to generate ${fileTypeInfo.exactType} thumbnail`, e);
return { thumbnail: fallbackThumbnail(), hasStaticThumbnail: true };
}
};

View file

@ -292,14 +292,12 @@ export const getRenderableImage = async (fileName: string, imageBlob: Blob) => {
return imageBlob;
}
let jpegBlob: Blob | undefined;
const available = !moduleState.isNativeJPEGConversionNotAvailable;
if (isElectron() && available && isSupportedRawFormat(exactType)) {
// 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 {
jpegBlob = await nativeConvertToJPEG(fileName, imageBlob);
return await nativeConvertToJPEG(imageBlob);
} catch (e) {
if (e.message == CustomErrorMessage.NotAvailable) {
moduleState.isNativeJPEGConversionNotAvailable = true;
@ -309,12 +307,12 @@ export const getRenderableImage = async (fileName: string, imageBlob: Blob) => {
}
}
if (!jpegBlob && isFileHEIC(exactType)) {
if (!isFileHEIC(exactType)) {
// If it is an HEIC file, use our web HEIC converter.
jpegBlob = await heicToJPEG(imageBlob);
return await heicToJPEG(imageBlob);
}
return jpegBlob;
return undefined;
} catch (e) {
log.error(
`Failed to get renderable image for ${JSON.stringify(fileTypeInfo ?? fileName)}`,
@ -324,7 +322,7 @@ export const getRenderableImage = async (fileName: string, imageBlob: Blob) => {
}
};
const nativeConvertToJPEG = async (fileName: string, imageBlob: Blob) => {
const nativeConvertToJPEG = async (imageBlob: Blob) => {
const startTime = Date.now();
const imageData = new Uint8Array(await imageBlob.arrayBuffer());
const electron = globalThis.electron;
@ -332,8 +330,8 @@ const nativeConvertToJPEG = async (fileName: string, imageBlob: Blob) => {
// the main thread since workers don't have access to the `window` (and
// thus, to the `window.electron`) object.
const jpegData = electron
? await electron.convertToJPEG(fileName, imageData)
: await workerBridge.convertToJPEG(fileName, imageData);
? await electron.convertToJPEG(imageData)
: await workerBridge.convertToJPEG(imageData);
log.debug(() => `Native JPEG conversion took ${Date.now() - startTime} ms`);
return new Blob([jpegData]);
};

View file

@ -204,14 +204,10 @@ export interface Electron {
* yet possible, this function will throw an error with the
* {@link CustomErrorMessage.NotAvailable} message.
*
* @param fileName The name of the file whose data we're being given.
* @param imageData The raw image data (the contents of the image file).
* @returns JPEG data of the converted image.
*/
convertToJPEG: (
fileName: string,
imageData: Uint8Array,
) => Promise<Uint8Array>;
convertToJPEG: (imageData: Uint8Array) => Promise<Uint8Array>;
/**
* Generate a JPEG thumbnail for the given image.
@ -224,14 +220,16 @@ export interface Electron {
* not yet possible, this function will throw an error with the
* {@link CustomErrorMessage.NotAvailable} message.
*
* @param inputFile The file whose thumbnail we want.
* @param dataOrPath The data-of or path-to the image whose thumbnail we
* want.
* @param maxDimension The maximum width or height of the generated
* thumbnail.
* @param maxSize Maximum size (in bytes) of the generated thumbnail.
*
* @returns JPEG data of the generated thumbnail.
*/
generateImageThumbnail: (
inputFile: File | ElectronFile,
dataOrPath: Uint8Array | string,
maxDimension: number,
maxSize: number,
) => Promise<Uint8Array>;

View file

@ -44,8 +44,8 @@ const workerBridge = {
logToDisk,
// Needed by ML worker
getAuthToken: () => ensureLocalUser().then((user) => user.token),
convertToJPEG: (fileName: string, imageData: Uint8Array) =>
ensureElectron().convertToJPEG(fileName, imageData),
convertToJPEG: (imageData: Uint8Array) =>
ensureElectron().convertToJPEG(imageData),
detectFaces: (input: Float32Array) => ensureElectron().detectFaces(input),
faceEmbedding: (input: Float32Array) =>
ensureElectron().faceEmbedding(input),