chore: commit pending changes before custom services implementation

This commit is contained in:
2026-06-13 11:27:47 +01:00
parent 45814a4040
commit d77f330bda
4 changed files with 77 additions and 53 deletions
@@ -4,6 +4,7 @@
import FileDropZone from '$lib/components/ui/file-drop-zone.svelte';
import { authStore } from '$lib/stores/auth.svelte';
import * as AlertDialog from '$lib/components/ui/alert-dialog';
import heic2any from 'heic2any';
// =============== Image Upload ===============
let uploading = $state(false);
@@ -28,9 +29,60 @@
let hasOversizedFiles = $derived(uploadFiles.some(isFileTooBig));
function handleFilesDropped(files: File[]) {
uploadFiles = files;
generatePreviews(files);
function isHeicFile(file: File): boolean {
const name = file.name.toLowerCase();
return name.endsWith('.heic') || name.endsWith('.heif');
}
/**
* Check if the browser can natively decode a HEIC file.
* Safari (macOS/iOS) and Chrome-on-Android have native HEIC support,
* which preserves HDR metadata and color profiles better than any conversion.
*/
function supportsNativeHeicDecode(file: File): Promise<boolean> {
return new Promise((resolve) => {
const img = new Image();
const url = URL.createObjectURL(file);
img.onload = () => { URL.revokeObjectURL(url); resolve(true); };
img.onerror = () => { URL.revokeObjectURL(url); resolve(false); };
img.src = url;
});
}
async function convertHeicToPng(file: File): Promise<File> {
const result = await heic2any({ blob: file, toType: 'image/png' });
const blob = Array.isArray(result) ? result[0] : result;
const pngName = file.name.replace(/\.(heic|heif)$/i, '.png');
return new File([blob], pngName, { type: 'image/png' });
}
async function handleFilesDropped(files: File[]) {
const converted = await Promise.all(
files.map(async (file) => {
if (!isHeicFile(file)) return file;
// Try native browser HEIC decode first (Safari, Chrome w/ HEVC)
// This preserves HDR metadata & color profiles at full quality
try {
const nativeOk = await supportsNativeHeicDecode(file);
if (nativeOk) return file;
} catch {
// Fall through to heic2any
}
// Fallback: convert to PNG via heic2any (libheif WASM)
// PNG is lossless, libheif handles ICC profiles correctly,
// and the downstream canvas pipeline is 8-bit anyway.
try {
return await convertHeicToPng(file);
} catch (e) {
console.error('HEIC conversion failed for', file.name, e);
return file;
}
})
);
uploadFiles = converted;
generatePreviews(converted);
}
/** Generate scaled previews for each file */