Perf improvements for HEIC photos
This commit is contained in:
86
package-lock.json
generated
86
package-lock.json
generated
@@ -17,7 +17,7 @@
|
||||
"@types/google.accounts": "^0.0.17",
|
||||
"@types/uuid": "^10.0.0",
|
||||
"fontkit": "^2.0.4",
|
||||
"heic2any": "^0.0.4",
|
||||
"heic-convert": "^2.1.0",
|
||||
"idb": "^8.0.3",
|
||||
"pdf-lib": "^1.17.1",
|
||||
"uuid": "^11.1.0"
|
||||
@@ -1084,12 +1084,6 @@
|
||||
"tslib": "^2.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/helpers/node_modules/tslib": {
|
||||
"version": "2.8.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
|
||||
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
|
||||
"license": "0BSD"
|
||||
},
|
||||
"node_modules/@tailwindcss/node": {
|
||||
"version": "4.1.11",
|
||||
"resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.11.tgz",
|
||||
@@ -2256,11 +2250,31 @@
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/heic2any": {
|
||||
"version": "0.0.4",
|
||||
"resolved": "https://registry.npmjs.org/heic2any/-/heic2any-0.0.4.tgz",
|
||||
"integrity": "sha512-3lLnZiDELfabVH87htnRolZ2iehX9zwpRyGNz22GKXIu0fznlblf0/ftppXKNqS26dqFSeqfIBhAmAj/uSp0cA==",
|
||||
"license": "MIT"
|
||||
"node_modules/heic-convert": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/heic-convert/-/heic-convert-2.1.0.tgz",
|
||||
"integrity": "sha512-1qDuRvEHifTVAj3pFIgkqGgJIr0M3X7cxEPjEp0oG4mo8GFjq99DpCo8Eg3kg17Cy0MTjxpFdoBHOatj7ZVKtg==",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"heic-decode": "^2.0.0",
|
||||
"jpeg-js": "^0.4.4",
|
||||
"pngjs": "^6.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/heic-decode": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/heic-decode/-/heic-decode-2.1.0.tgz",
|
||||
"integrity": "sha512-0fB3O3WMk38+PScbHLVp66jcNhsZ/ErtQ6u2lMYu/YxXgbBtl+oKOhGQHa4RpvE68k8IzbWkABzHnyAIjR758A==",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"libheif-js": "^1.19.8"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/idb": {
|
||||
"version": "8.0.3",
|
||||
@@ -2320,6 +2334,12 @@
|
||||
"jiti": "lib/jiti-cli.mjs"
|
||||
}
|
||||
},
|
||||
"node_modules/jpeg-js": {
|
||||
"version": "0.4.4",
|
||||
"resolved": "https://registry.npmjs.org/jpeg-js/-/jpeg-js-0.4.4.tgz",
|
||||
"integrity": "sha512-WZzeDOEtTOBK4Mdsar0IqEU5sMr3vSV2RqkAIzUEV2BHnUfKGyswWFPFwK5EeDo93K3FohSHbLAjj0s1Wzd+dg==",
|
||||
"license": "BSD-3-Clause"
|
||||
},
|
||||
"node_modules/kleur": {
|
||||
"version": "4.1.5",
|
||||
"resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz",
|
||||
@@ -2330,6 +2350,15 @@
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/libheif-js": {
|
||||
"version": "1.19.8",
|
||||
"resolved": "https://registry.npmjs.org/libheif-js/-/libheif-js-1.19.8.tgz",
|
||||
"integrity": "sha512-vQJWusIxO7wavpON1dusciL8Go9jsIQ+EUrckauFYAiSTjcmLAsuJh3SszLpvkwPci3JcL41ek2n+LUZGFpPIQ==",
|
||||
"license": "LGPL-3.0",
|
||||
"engines": {
|
||||
"node": ">=8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/lightningcss": {
|
||||
"version": "1.30.1",
|
||||
"resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.1.tgz",
|
||||
@@ -2752,6 +2781,12 @@
|
||||
"tslib": "^1.11.1"
|
||||
}
|
||||
},
|
||||
"node_modules/pdf-lib/node_modules/tslib": {
|
||||
"version": "1.14.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
|
||||
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
|
||||
"license": "0BSD"
|
||||
},
|
||||
"node_modules/picocolors": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
|
||||
@@ -2772,6 +2807,15 @@
|
||||
"url": "https://github.com/sponsors/jonschlinkert"
|
||||
}
|
||||
},
|
||||
"node_modules/pngjs": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/pngjs/-/pngjs-6.0.0.tgz",
|
||||
"integrity": "sha512-TRzzuFRRmEoSW/p1KVAmiOgPco2Irlah+bGFCeNfJXxxYGwSw7YwAOAcd7X28K/m5bjBWKsC29KyoMfHbypayg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=12.13.0"
|
||||
}
|
||||
},
|
||||
"node_modules/postcss": {
|
||||
"version": "8.5.6",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz",
|
||||
@@ -3149,9 +3193,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/svelte": {
|
||||
"version": "5.36.6",
|
||||
"resolved": "https://registry.npmjs.org/svelte/-/svelte-5.36.6.tgz",
|
||||
"integrity": "sha512-THFCC4RzI45IHXVruiG/9RpyhapGdsMTm0lpd/1NEBkNUszGsuTET0ifiaYLfP2P6Y6Y4LRdrzloRhZGIIzphA==",
|
||||
"version": "5.36.7",
|
||||
"resolved": "https://registry.npmjs.org/svelte/-/svelte-5.36.7.tgz",
|
||||
"integrity": "sha512-QsaFAxL1PZvo9hwaN+x7Sq2U8oJARmsEuM8TEZVy98nx5D5IKzRi8FKkPvmOx9NXScSYnItDGLErBBn/ieIn2A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -3175,9 +3219,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/svelte-check": {
|
||||
"version": "4.2.2",
|
||||
"resolved": "https://registry.npmjs.org/svelte-check/-/svelte-check-4.2.2.tgz",
|
||||
"integrity": "sha512-1+31EOYZ7NKN0YDMKusav2hhEoA51GD9Ws6o//0SphMT0ve9mBTsTUEX7OmDMadUP3KjNHsSKtJrqdSaD8CrGQ==",
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/svelte-check/-/svelte-check-4.3.0.tgz",
|
||||
"integrity": "sha512-Iz8dFXzBNAM7XlEIsUjUGQhbEE+Pvv9odb9+0+ITTgFWZBGeJRRYqHUUglwe2EkLD5LIsQaAc4IUJyvtKuOO5w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -3283,9 +3327,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/tslib": {
|
||||
"version": "1.14.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
|
||||
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
|
||||
"version": "2.8.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
|
||||
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
|
||||
"license": "0BSD"
|
||||
},
|
||||
"node_modules/typescript": {
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
"@types/google.accounts": "^0.0.17",
|
||||
"@types/uuid": "^10.0.0",
|
||||
"fontkit": "^2.0.4",
|
||||
"heic2any": "^0.0.4",
|
||||
"heic-convert": "^2.1.0",
|
||||
"idb": "^8.0.3",
|
||||
"pdf-lib": "^1.17.1",
|
||||
"uuid": "^11.1.0"
|
||||
|
||||
@@ -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}
|
||||
|
||||
Reference in New Issue
Block a user