diff --git a/web/components/widgets/add-photos.tsx b/web/components/widgets/add-photos.tsx index 52130b4..ac4610f 100644 --- a/web/components/widgets/add-photos.tsx +++ b/web/components/widgets/add-photos.tsx @@ -58,14 +58,21 @@ export const AddPhotosWidget = (props: { disabled={uploadingImages} /> - +
+ +
{uniq(buildArray(pinned_url, photo_urls))?.map((url, index) => { const isPinned = url === pinned_url return ( diff --git a/web/lib/firebase/storage.ts b/web/lib/firebase/storage.ts index 1f0d7b1..550e7c8 100644 --- a/web/lib/firebase/storage.ts +++ b/web/lib/firebase/storage.ts @@ -1,10 +1,15 @@ -import { ref, uploadBytesResumable, getDownloadURL } from 'firebase/storage' -import { nanoid } from 'nanoid' -import { storage } from './init' +import {getDownloadURL, ref, uploadBytesResumable} from 'firebase/storage' +import {nanoid} from 'nanoid' +import {storage} from './init' import Compressor from 'compressorjs' const ONE_YEAR_SECS = 60 * 60 * 24 * 365 +const isHeic = (file: File) => + file.type === 'image/heic' || + file.type === 'image/heif' || + /\.heic$/i.test(file.name) + export const uploadImage = async ( username: string, file: File, @@ -13,7 +18,8 @@ export const uploadImage = async ( ) => { // Replace filename with a nanoid to avoid collisions const [, ext] = file.name.split('.') - const filename = `${nanoid(10)}.${ext}` + const stem = nanoid(10); + const filename = `${stem}.${ext}` const storageRef = ref( storage, `user-images/${username}${prefix ? '/' + prefix : ''}/${filename}` @@ -23,7 +29,22 @@ export const uploadImage = async ( return Promise.reject('File is over 20 MB') } - // if >1MB compress + // Convert HEIC → JPEG immediately (as HEIC not rendered) + if (isHeic(file) && typeof window !== 'undefined') { + // heic2any available in client only + const {default: heic2any} = await import('heic2any') + const converted = await heic2any({ + blob: file, + toType: 'image/jpeg', + quality: 0.9, + }) + + file = new File([converted as Blob], `${stem}.jpg`, { + type: 'image/jpeg', + }) + } + + // 2️⃣ Compress if > 1MB if (file.size > 1024 ** 2) { file = await new Promise((resolve, reject) => { new Compressor(file, { diff --git a/web/package.json b/web/package.json index be3457c..a93db55 100644 --- a/web/package.json +++ b/web/package.json @@ -46,6 +46,7 @@ "csstype": "3.0.10", "dayjs": "1.11.10", "firebase": "11.1.0", + "heic2any": "0.0.4", "link-preview-js": "3.0.4", "lodash": "4.17.21", "nanoid": "5.0.9", diff --git a/yarn.lock b/yarn.lock index 6ec533b..26b070f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9306,6 +9306,11 @@ heap-js@^2.6.0: resolved "https://registry.yarnpkg.com/heap-js/-/heap-js-2.7.1.tgz#3f152279e42214725cac405257554b000b178cc4" integrity sha512-EQfezRg0NCZGNlhlDR3Evrw1FVL2G3LhU7EgPoxufQKruNBSYA8MiRPHeWbU+36o+Fhel0wMwM+sLEiBAlNLJA== +heic2any@0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/heic2any/-/heic2any-0.0.4.tgz#eddb8e6fec53c8583a6e18b65069bb5e8d19028a" + integrity sha512-3lLnZiDELfabVH87htnRolZ2iehX9zwpRyGNz22GKXIu0fznlblf0/ftppXKNqS26dqFSeqfIBhAmAj/uSp0cA== + hex-rgb@^4.1.0: version "4.3.0" resolved "https://registry.yarnpkg.com/hex-rgb/-/hex-rgb-4.3.0.tgz#af5e974e83bb2fefe44d55182b004ec818c07776"