Enhance canvas functionality by adding media preview capabilities and image upload handling. Introduce compressed image previews during uploads, improve media library integration, and implement retry logic for bridge edge creation. Update dashboard to display media previews and optimize image node handling.

This commit is contained in:
Matthias
2026-04-08 20:44:31 +02:00
parent a7eb2bc99c
commit b7f24223f2
43 changed files with 4064 additions and 148 deletions

View File

@@ -1,6 +1,74 @@
export async function getImageDimensions(
file: File,
): Promise<{ width: number; height: number }> {
const image = await decodeImageFile(file);
return { width: image.naturalWidth, height: image.naturalHeight };
}
export type ImagePreviewOptions = {
maxEdge?: number;
format?: string;
quality?: number;
};
export type CompressedImagePreview = {
blob: Blob;
width: number;
height: number;
};
export async function createCompressedImagePreview(
file: File,
options: ImagePreviewOptions = {},
): Promise<CompressedImagePreview> {
const maxEdge = options.maxEdge ?? 640;
const format = options.format ?? "image/webp";
const quality = options.quality ?? 0.75;
const image = await decodeImageFile(file);
const sourceWidth = image.naturalWidth;
const sourceHeight = image.naturalHeight;
if (!sourceWidth || !sourceHeight) {
throw new Error("Could not read image dimensions");
}
const scale = Math.min(1, maxEdge / Math.max(sourceWidth, sourceHeight));
const targetWidth = Math.max(1, Math.round(sourceWidth * scale));
const targetHeight = Math.max(1, Math.round(sourceHeight * scale));
const canvas = document.createElement("canvas");
canvas.width = targetWidth;
canvas.height = targetHeight;
const context = canvas.getContext("2d");
if (!context) {
throw new Error("Could not create canvas context");
}
context.drawImage(image, 0, 0, targetWidth, targetHeight);
const blob = await new Promise<Blob>((resolve, reject) => {
canvas.toBlob(
(result) => {
if (!result) {
reject(new Error("Could not encode preview image"));
return;
}
resolve(result);
},
format,
quality,
);
});
return {
blob,
width: targetWidth,
height: targetHeight,
};
}
async function decodeImageFile(file: File): Promise<HTMLImageElement> {
return new Promise((resolve, reject) => {
const objectUrl = URL.createObjectURL(file);
const image = new window.Image();
@@ -15,7 +83,7 @@ export async function getImageDimensions(
return;
}
resolve({ width, height });
resolve(image);
};
image.onerror = () => {