Checkpoint
This commit is contained in:
parent
4a12774a3c
commit
1f5fbcae76
2 changed files with 46 additions and 44 deletions
|
@ -14,25 +14,26 @@ const maxThumbnailDimension = 720;
|
|||
const maxThumbnailSize = 100 * 1024; // 100 KB
|
||||
|
||||
/**
|
||||
* Generate a JPEG thumbnail for the given image or video data.
|
||||
* Generate a JPEG thumbnail for the given image or video blob.
|
||||
*
|
||||
* The thumbnail has a smaller file size so that is quick to load. But more
|
||||
* importantly, it uses a universal file format (JPEG in our case) so that the
|
||||
* thumbnail itself can be opened in all clients, even those like the web client
|
||||
* itself that might not yet have support for more exotic formats.
|
||||
*
|
||||
* @param blob The data (blob) of the file whose thumbnail we want to generate.
|
||||
* @param fileTypeInfo The type information for the file.
|
||||
* @param blob The image or video blob whose thumbnail we want to generate.
|
||||
*
|
||||
* @param fileTypeInfo The type information for the file this blob came from.
|
||||
*
|
||||
* @return The JPEG data of the generated thumbnail.
|
||||
*/
|
||||
export const generateThumbnail = async (
|
||||
export const generateThumbnailWeb = async (
|
||||
blob: Blob,
|
||||
fileTypeInfo: FileTypeInfo,
|
||||
): Promise<Uint8Array> =>
|
||||
fileTypeInfo.fileType === FILE_TYPE.IMAGE
|
||||
? await generateImageThumbnailUsingCanvas(blob, fileTypeInfo)
|
||||
: await generateVideoThumbnail(blob);
|
||||
: await generateVideoThumbnailWeb(blob);
|
||||
|
||||
const generateImageThumbnailUsingCanvas = async (
|
||||
blob: Blob,
|
||||
|
@ -74,12 +75,12 @@ const generateImageThumbnailUsingCanvas = async (
|
|||
return await compressedJPEGData(canvas);
|
||||
};
|
||||
|
||||
const generateVideoThumbnail = async (blob: Blob) => {
|
||||
const generateVideoThumbnailWeb = async (blob: Blob) => {
|
||||
try {
|
||||
return await ffmpeg.generateVideoThumbnail(blob);
|
||||
return await ffmpeg.generateVideoThumbnailWeb(blob);
|
||||
} catch (e) {
|
||||
log.error(
|
||||
`Failed to generate video thumbnail using FFmpeg, will fallback to canvas`,
|
||||
`Failed to generate video thumbnail using the wasm FFmpeg web worker, will fallback to canvas`,
|
||||
e,
|
||||
);
|
||||
return generateVideoThumbnailUsingCanvas(blob);
|
||||
|
@ -173,52 +174,35 @@ const percentageSizeDiff = (
|
|||
) => ((oldThumbnailSize - newThumbnailSize) * 100) / oldThumbnailSize;
|
||||
|
||||
/**
|
||||
* A fallback, black, thumbnail for use in cases where thumbnail generation
|
||||
* fails.
|
||||
*/
|
||||
export const fallbackThumbnail = () =>
|
||||
Uint8Array.from(atob(BLACK_THUMBNAIL_BASE64), (c) => c.charCodeAt(0));
|
||||
|
||||
/**
|
||||
* Generate a JPEG thumbnail for the given file using native tools.
|
||||
* Generate a JPEG thumbnail for the given file or path using native tools.
|
||||
*
|
||||
* This function only works when we're running in the context of our desktop
|
||||
* app, and this dependency is enforced by the need to pass the {@link electron}
|
||||
* object which we use to perform IPC with the Node.js side of our desktop app.
|
||||
*
|
||||
* @param fileOrPath Either the image or video File, or the path to the image or
|
||||
* video file on the user's local filesystem, whose thumbnail we want to
|
||||
* @param dataOrPath The image or video {@link File}, or the path to the image
|
||||
* or video file on the user's local filesystem, whose thumbnail we want to
|
||||
* generate.
|
||||
*
|
||||
* @param fileTypeInfo The type information for the file.
|
||||
* @param fileTypeInfo The type information for {@link fileOrPath}.
|
||||
*
|
||||
* @return The JPEG data of the generated thumbnail.
|
||||
*
|
||||
* @see {@link generateThumbnail}.
|
||||
* See also {@link generateThumbnailWeb}.
|
||||
*/
|
||||
export const generateThumbnailNative = async (
|
||||
electron: Electron,
|
||||
fileOrPath: File | string,
|
||||
fileTypeInfo: FileTypeInfo,
|
||||
): Promise<GeneratedThumbnail> => {
|
||||
try {
|
||||
const thumbnail =
|
||||
fileTypeInfo.fileType === FILE_TYPE.IMAGE
|
||||
? await generateImageThumbnailNative(electron, fileOrPath)
|
||||
: await generateVideoThumbnail(blob);
|
||||
|
||||
if (thumbnail.length == 0) throw new Error("Empty thumbnail");
|
||||
return { thumbnail, hasStaticThumbnail: false };
|
||||
} catch (e) {
|
||||
log.error(`Failed to generate ${fileTypeInfo.exactType} thumbnail`, e);
|
||||
return { thumbnail: fallbackThumbnail(), hasStaticThumbnail: true };
|
||||
}
|
||||
};
|
||||
): Promise<Uint8Array> =>
|
||||
fileTypeInfo.fileType === FILE_TYPE.IMAGE
|
||||
? await generateImageThumbnailNative(electron, fileOrPath)
|
||||
: await generateVideoThumbnailNative(blob);
|
||||
|
||||
const generateImageThumbnailNative = async (
|
||||
electron: Electron,
|
||||
fileOrPath: File | string,
|
||||
): Promise<Uint8Array> => {
|
||||
) => {
|
||||
const startTime = Date.now();
|
||||
const jpegData = await electron.generateImageThumbnail(
|
||||
fileOrPath instanceof File
|
||||
|
@ -232,3 +216,19 @@ const generateImageThumbnailNative = async (
|
|||
);
|
||||
return jpegData;
|
||||
};
|
||||
|
||||
const dataOrPath = (fileOrPath) => {
|
||||
fileOrPath
|
||||
}
|
||||
const generateVideoThumbnailNative = async (
|
||||
electron: Electron,
|
||||
fileOrPath: File | string,
|
||||
) => ffmpeg.generateVideoThumbnailNative(electron, )
|
||||
|
||||
|
||||
/**
|
||||
* A fallback, black, thumbnail for use in cases where thumbnail generation
|
||||
* fails.
|
||||
*/
|
||||
export const fallbackThumbnail = () =>
|
||||
Uint8Array.from(atob(BLACK_THUMBNAIL_BASE64), (c) => c.charCodeAt(0));
|
||||
|
|
|
@ -375,7 +375,6 @@ class ModuleState {
|
|||
|
||||
const moduleState = new ModuleState();
|
||||
|
||||
|
||||
/**
|
||||
* Read the given file or path into an in-memory representation.
|
||||
*
|
||||
|
@ -424,13 +423,19 @@ const moduleState = new ModuleState();
|
|||
* we can do all the rest of the IPC operations using the path itself, and for
|
||||
* the read during upload using a streaming IPC mechanism.
|
||||
*/
|
||||
async function readFile(
|
||||
const readFileOrPath = async (
|
||||
fileOrPath: File | string,
|
||||
fileTypeInfo: FileTypeInfo,
|
||||
): Promise<FileInMemory> {
|
||||
): Promise<FileInMemory> => {
|
||||
log.info(`Reading file ${fopLabel(fileOrPath)} `);
|
||||
|
||||
let thumbnail: Uint8Array
|
||||
// If it's a file, read it into data
|
||||
const dataOrPath =
|
||||
fileOrPath instanceof File
|
||||
? new Uint8Array(await fileOrPath.arrayBuffer())
|
||||
: fileOrPath;
|
||||
|
||||
let thumbnail: Uint8Array;
|
||||
|
||||
const electron = globalThis.electron;
|
||||
const available = !moduleState.isNativeThumbnailCreationNotAvailable;
|
||||
|
@ -462,7 +467,6 @@ async function readFile(
|
|||
filedata = await getUint8ArrayView(rawFile);
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
const thumbnail =
|
||||
fileTypeInfo.fileType === FILE_TYPE.IMAGE
|
||||
|
@ -476,11 +480,9 @@ async function readFile(
|
|||
return { thumbnail: fallbackThumbnail(), hasStaticThumbnail: true };
|
||||
}
|
||||
|
||||
|
||||
if (filedata instanceof Uint8Array) {
|
||||
|
||||
} else {
|
||||
filedata.stream
|
||||
filedata.stream;
|
||||
}
|
||||
|
||||
log.info(`read file data successfully ${getFileNameSize(rawFile)} `);
|
||||
|
@ -495,7 +497,7 @@ async function readFile(
|
|||
thumbnail,
|
||||
hasStaticThumbnail,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
async function readLivePhoto(
|
||||
fileTypeInfo: FileTypeInfo,
|
||||
|
|
Loading…
Add table
Reference in a new issue