Perf improvements for HEIC photos
All checks were successful
Build Docker image / build (push) Successful in 1m57s
Build Docker image / verify (push) Successful in 27s
Build Docker image / deploy (push) Successful in 3s

This commit is contained in:
Roman Krček
2025-07-18 11:11:20 +02:00
parent 94e34fbc75
commit fa6b8312c6
3 changed files with 114 additions and 41 deletions

View File

@@ -129,28 +129,59 @@
blob = await response.blob();
}
// Check for HEIC/HEIF format and convert if necessary
// Check for HEIC/HEIF format. If so, start conversion but don't block.
if (
blob.type === 'image/heic' ||
blob.type === 'image/heif' ||
photo.url.toLowerCase().endsWith('.heic')
) {
console.log(`Converting HEIC image for ${photo.name}...`);
try {
const { default: heic2any } = await import('heic2any');
const conversionResult = await heic2any({
blob,
toType: 'image/jpeg',
quality: 0.9
});
blob = Array.isArray(conversionResult) ? conversionResult[0] : conversionResult;
console.log(`Successfully converted HEIC for ${photo.name}`);
} catch (e) {
console.error(`Failed to convert HEIC image for ${photo.name}:`, e);
throw new Error('HEIC conversion failed');
}
console.log(`HEIC detected for ${photo.name}. Starting conversion in background.`);
photo.status = 'loading'; // Visually indicate something is happening
// Don't await this, let it run in the background
convertHeicPhoto(index, blob);
return; // End loadPhoto here for HEIC, conversion will handle the rest
}
// For non-HEIC images, proceed as normal
await processLoadedBlob(index, blob);
} catch (error) {
console.error(`Failed to load photo for ${photo.name}:`, error);
photo.status = 'error';
}
}
async function convertHeicPhoto(index: number, blob: Blob) {
const photo = photos[index];
try {
console.log(`Converting HEIC with heic-convert for ${photo.name}...`);
// Dynamically import the browser-specific version of the library
const { default: convert } = await import('heic-convert/browser');
const inputBuffer = await blob.arrayBuffer();
const outputBuffer = await convert({
buffer: new Uint8Array(inputBuffer), // heic-convert expects a Uint8Array
format: 'JPEG',
quality: 0.9
});
const convertedBlob = new Blob([outputBuffer], { type: 'image/jpeg' });
console.log(`Successfully converted HEIC for ${photo.name}`);
// Now that it's converted, process it like any other image
await processLoadedBlob(index, convertedBlob);
} catch (e) {
console.error(`Failed to convert HEIC image for ${photo.name}:`, e);
photo.status = 'error';
}
}
async function processLoadedBlob(index: number, blob: Blob) {
const photo = photos[index];
try {
const objectUrl = createImageObjectUrl(blob);
// Test if image loads properly
@@ -184,11 +215,9 @@
// Automatically run face detection to generate crop
await detectFaceForPhoto(index);
} catch (error) {
console.error(`Failed to load photo for ${photo.name}:`, error);
console.error(`Failed to process blob for ${photo.name}:`, error);
photo.status = 'error';
}
// No need to reassign photos array with $state reactivity
}
async function detectFaceForPhoto(index: number) {
@@ -441,7 +470,7 @@
</p>
</div>
{:else}
<div class="p-6 grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6">
<div class="p-6 grid grid-cols-1 md:grid-cols-2 lg:grid-cols-2 xl:grid-cols-3 gap-6">
{#each photos as photo, index}
<PhotoCard
{photo}