Fix HEIC photos not rendered

This commit is contained in:
MartinBraquet
2026-01-25 23:40:18 +01:00
parent d59961f6cc
commit 07bc32d781
4 changed files with 47 additions and 13 deletions

View File

@@ -58,14 +58,21 @@ export const AddPhotosWidget = (props: {
disabled={uploadingImages}
/>
<Row className="flex-wrap gap-2">
<label
className={clsx(
'bg-canvas-50 hover:bg-ink-300 text-ink-0 dark:text-ink-500 hover:dark:text-ink-600 flex h-[200px] w-[200px] cursor-pointer flex-col items-center rounded-md transition-colors'
)}
htmlFor="photo-upload"
>
<PlusIcon className=" mx-auto my-auto h-16 w-16 text-gray-500"/>
</label>
<div className="relative">
<label
className={clsx(
'bg-canvas-50 hover:bg-ink-300 text-ink-0 dark:text-ink-500 hover:dark:text-ink-600 flex h-[200px] w-[200px] cursor-pointer flex-col items-center rounded-md transition-colors',
uploadingImages && 'opacity-50 cursor-not-allowed'
)}
htmlFor="photo-upload"
>
{uploadingImages ? (
<div className="mx-auto my-auto h-16 w-16 animate-spin rounded-full border-b-2 border-gray-500"></div>
) : (
<PlusIcon className="mx-auto my-auto h-16 w-16 text-gray-500"/>
)}
</label>
</div>
{uniq(buildArray(pinned_url, photo_urls))?.map((url, index) => {
const isPinned = url === pinned_url
return (

View File

@@ -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, {

View File

@@ -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",

View File

@@ -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"