chore: commit pending changes before custom services implementation
This commit is contained in:
@@ -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 */
|
||||
|
||||
Reference in New Issue
Block a user