Update UI components in +page.svelte and HomeWithDialog.svelte to disable certain buttons with a "Coming soon" label, enhancing user experience by indicating future functionality. Adjust server internal options to reflect a new version hash.
This commit is contained in:
@@ -11,6 +11,13 @@ function isHeicFile(file: File): boolean {
|
||||
);
|
||||
}
|
||||
|
||||
/** True if the file is an image we can process (image/* or HEIC by type/extension). */
|
||||
export function isAcceptableImageFile(file: File | null): boolean {
|
||||
if (!file) return false;
|
||||
const type = (file.type ?? "").toLowerCase();
|
||||
return type.startsWith("image/") || isHeicFile(file);
|
||||
}
|
||||
|
||||
function makeOutputFile(blob: Blob, baseName: string, ext: string): File {
|
||||
return new File([blob], `${baseName}.${ext}`, {
|
||||
type: blob.type,
|
||||
@@ -18,78 +25,93 @@ function makeOutputFile(blob: Blob, baseName: string, ext: string): File {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an image File to WebP (or JPEG on Safari where WebP isn't supported).
|
||||
* HEIC from iPhone is handled: if the image fails to load, we decode with heic2any first.
|
||||
*/
|
||||
export function convertImageToWebP(file: File, quality = 0.85): Promise<File> {
|
||||
function isSafari(): boolean {
|
||||
if (typeof navigator === "undefined") return false;
|
||||
const ua = navigator.userAgent;
|
||||
return ua.includes("Safari") && !ua.includes("Chrome");
|
||||
}
|
||||
|
||||
/** Load blob in Image, draw to canvas, encode as WebP or JPEG. Rejects if image fails to load or encode. */
|
||||
function tryCanvas(sourceBlob: Blob, baseName: string, quality: number): Promise<File> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const baseName = file.name.replace(/\.[^.]+$/i, "") || "image";
|
||||
|
||||
const tryCanvas = (sourceBlob: Blob) => {
|
||||
const url = URL.createObjectURL(sourceBlob);
|
||||
const img = new Image();
|
||||
img.onload = () => {
|
||||
URL.revokeObjectURL(url);
|
||||
const canvas = document.createElement("canvas");
|
||||
canvas.width = img.naturalWidth;
|
||||
canvas.height = img.naturalHeight;
|
||||
const ctx = canvas.getContext("2d");
|
||||
if (!ctx) {
|
||||
reject(new Error("Could not get canvas context"));
|
||||
return;
|
||||
}
|
||||
ctx.drawImage(img, 0, 0);
|
||||
// Safari doesn't support WebP in toBlob; try WebP first, fall back to JPEG
|
||||
canvas.toBlob(
|
||||
(blob) => {
|
||||
if (blob && blob.type === "image/webp") {
|
||||
resolve(makeOutputFile(blob, baseName, "webp"));
|
||||
return;
|
||||
}
|
||||
canvas.toBlob(
|
||||
(jpegBlob) => {
|
||||
if (!jpegBlob) {
|
||||
reject(new Error("Failed to encode image"));
|
||||
return;
|
||||
}
|
||||
resolve(makeOutputFile(jpegBlob, baseName, "jpg"));
|
||||
},
|
||||
"image/jpeg",
|
||||
quality
|
||||
);
|
||||
},
|
||||
"image/webp",
|
||||
quality
|
||||
);
|
||||
};
|
||||
img.onerror = () => {
|
||||
URL.revokeObjectURL(url);
|
||||
reject(new Error("Failed to load image"));
|
||||
};
|
||||
img.src = url;
|
||||
};
|
||||
|
||||
const url = URL.createObjectURL(file);
|
||||
const url = URL.createObjectURL(sourceBlob);
|
||||
const img = new Image();
|
||||
img.onload = () => {
|
||||
URL.revokeObjectURL(url);
|
||||
tryCanvas(file);
|
||||
};
|
||||
img.onerror = async () => {
|
||||
URL.revokeObjectURL(url);
|
||||
// HEIC often fails to load in Image() on iOS; decode with heic2any then run canvas
|
||||
if (isHeicFile(file)) {
|
||||
try {
|
||||
const jpegBlob = await convertHeicBlobToJpeg(file);
|
||||
tryCanvas(jpegBlob);
|
||||
} catch (e) {
|
||||
reject(e instanceof Error ? e : new Error("Failed to convert HEIC"));
|
||||
}
|
||||
} else {
|
||||
reject(new Error("Failed to load image"));
|
||||
const canvas = document.createElement("canvas");
|
||||
canvas.width = img.naturalWidth;
|
||||
canvas.height = img.naturalHeight;
|
||||
const ctx = canvas.getContext("2d");
|
||||
if (!ctx) {
|
||||
reject(new Error("Could not get canvas context"));
|
||||
return;
|
||||
}
|
||||
ctx.drawImage(img, 0, 0);
|
||||
// Safari doesn't support WebP in toBlob; try WebP first, fall back to JPEG
|
||||
canvas.toBlob(
|
||||
(blob) => {
|
||||
if (blob && blob.type === "image/webp") {
|
||||
resolve(makeOutputFile(blob, baseName, "webp"));
|
||||
return;
|
||||
}
|
||||
canvas.toBlob(
|
||||
(jpegBlob) => {
|
||||
if (!jpegBlob) {
|
||||
reject(new Error("Failed to encode image"));
|
||||
return;
|
||||
}
|
||||
resolve(makeOutputFile(jpegBlob, baseName, "jpg"));
|
||||
},
|
||||
"image/jpeg",
|
||||
quality
|
||||
);
|
||||
},
|
||||
"image/webp",
|
||||
quality
|
||||
);
|
||||
};
|
||||
img.onerror = () => {
|
||||
URL.revokeObjectURL(url);
|
||||
reject(new Error("Failed to load image"));
|
||||
};
|
||||
img.src = url;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an image File to WebP (or JPEG on Safari where WebP isn't supported).
|
||||
* HEIC: Safari uses native Image() first, then heic2any fallback; other browsers use heic2any first, then Image() fallback.
|
||||
*/
|
||||
export async function convertImageToWebP(file: File, quality = 0.85): Promise<File> {
|
||||
const baseName = file.name.replace(/\.[^.]+$/i, "") || "image";
|
||||
|
||||
if (isHeicFile(file)) {
|
||||
const safari = isSafari();
|
||||
if (safari) {
|
||||
// Safari can decode HEIC in Image(); heic2any is unreliable on Safari (e.g. transparent output)
|
||||
try {
|
||||
return await tryCanvas(file, baseName, quality);
|
||||
} catch {
|
||||
try {
|
||||
const jpegBlob = await convertHeicBlobToJpeg(file);
|
||||
return await tryCanvas(jpegBlob, baseName, quality);
|
||||
} catch (e) {
|
||||
throw e instanceof Error ? e : new Error("Failed to convert HEIC");
|
||||
}
|
||||
}
|
||||
}
|
||||
// Non-Safari: Image() usually can't decode HEIC; use heic2any first
|
||||
try {
|
||||
const jpegBlob = await convertHeicBlobToJpeg(file);
|
||||
return await tryCanvas(jpegBlob, baseName, quality);
|
||||
} catch {
|
||||
try {
|
||||
return await tryCanvas(file, baseName, quality);
|
||||
} catch (e) {
|
||||
throw e instanceof Error ? e : new Error("Failed to convert HEIC");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return await tryCanvas(file, baseName, quality);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user