|
| 1 | +import { MimeTypeImage } from '$lib/enums'; |
| 2 | +import { HEIC_JPEG_QUALITY } from '$lib/constants/image-size'; |
| 3 | + |
| 4 | +// heic requires a relatively large decoder, in order to reduce primary bundle size |
| 5 | +// we lazily load this decoder from a CDN when needed, and cache it for future conversions |
| 6 | +const HEIC_TO_CDN_URL = 'https://cdn.jsdelivr.net/npm/heic-to@1.5.2/dist/heic-to.js'; |
| 7 | + |
| 8 | +interface HeicToModule { |
| 9 | + heicTo(args: { blob: Blob; type: string; quality?: number }): Promise<Blob>; |
| 10 | +} |
| 11 | + |
| 12 | +let modulePromise: Promise<HeicToModule> | null = null; |
| 13 | + |
| 14 | +/** |
| 15 | + * Lazily load the heic-to decoder from the CDN and cache it |
| 16 | + * @returns Promise resolving to the heic-to module |
| 17 | + */ |
| 18 | +function getHeicTo(): Promise<HeicToModule> { |
| 19 | + if (!modulePromise) { |
| 20 | + modulePromise = import(/* @vite-ignore */ HEIC_TO_CDN_URL) as Promise<HeicToModule>; |
| 21 | + } |
| 22 | + |
| 23 | + return modulePromise; |
| 24 | +} |
| 25 | + |
| 26 | +/** |
| 27 | + * Convert a HEIC/HEIF file to a compressed JPEG data URL |
| 28 | + * @param file - The HEIC/HEIF file to convert |
| 29 | + * @returns Promise resolving to JPEG data URL |
| 30 | + */ |
| 31 | +export async function heicFileToJpegDataURL(file: File | Blob): Promise<string> { |
| 32 | + const { heicTo } = await getHeicTo(); |
| 33 | + const jpegBlob = await heicTo({ |
| 34 | + blob: file, |
| 35 | + type: MimeTypeImage.JPEG, |
| 36 | + quality: HEIC_JPEG_QUALITY |
| 37 | + }); |
| 38 | + |
| 39 | + return new Promise((resolve, reject) => { |
| 40 | + const reader = new FileReader(); |
| 41 | + reader.onload = () => resolve(reader.result as string); |
| 42 | + reader.onerror = () => reject(reader.error); |
| 43 | + reader.readAsDataURL(jpegBlob); |
| 44 | + }); |
| 45 | +} |
| 46 | + |
| 47 | +/** |
| 48 | + * Check if a MIME type represents a HEIC/HEIF image |
| 49 | + * @param mimeType - The MIME type to check |
| 50 | + * @returns True if the MIME type is image/heic or image/heif |
| 51 | + */ |
| 52 | +export function isHeicMimeType(mimeType: string): boolean { |
| 53 | + const normalized = mimeType.trim().toLowerCase(); |
| 54 | + |
| 55 | + return normalized === MimeTypeImage.HEIC || normalized === MimeTypeImage.HEIF; |
| 56 | +} |
0 commit comments