imageFormat.ts 1.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162
  1. const HEIC_MIME_TYPES = [
  2. 'image/heic',
  3. 'image/heif',
  4. 'image/heic-sequence',
  5. 'image/heif-sequence',
  6. ]
  7. export function isHeicOrHeif(file: File): boolean {
  8. const name = file.name.toLowerCase()
  9. const type = (file.type || '').toLowerCase()
  10. return (
  11. name.endsWith('.heic') ||
  12. name.endsWith('.heif') ||
  13. HEIC_MIME_TYPES.includes(type)
  14. )
  15. }
  16. function replaceExtension(fileName: string, extension: string): string {
  17. const lastDot = fileName.lastIndexOf('.')
  18. if (lastDot <= 0) return `${fileName}.${extension}`
  19. return `${fileName.slice(0, lastDot)}.${extension}`
  20. }
  21. export async function convertHeicHeifToWebp(file: File): Promise<File> {
  22. const type = (file.type || '').toLowerCase()
  23. // If the blob already has a browser-readable image MIME (and it's not a HEIC MIME),
  24. // skip conversion and return the original file.
  25. if (type && type.startsWith('image/') && !HEIC_MIME_TYPES.includes(type)) {
  26. return file
  27. }
  28. const { default: heic2any } = await import('heic2any')
  29. try {
  30. const result = await heic2any({
  31. blob: file,
  32. toType: 'image/webp',
  33. quality: 0.92,
  34. })
  35. const blob = Array.isArray(result) ? result[0] : result
  36. if (!(blob instanceof Blob)) {
  37. throw new Error('HEIC/HEIF 转换失败')
  38. }
  39. const targetFileName = replaceExtension(file.name, 'webp')
  40. return new File([blob], targetFileName, {
  41. type: 'image/webp',
  42. lastModified: Date.now(),
  43. })
  44. } catch (err: any) {
  45. // heic2any may throw when the provided blob is already browser-readable
  46. // (e.g. it contains image/jpeg despite .heic extension). In that case,
  47. // treat it as already-converted and return the original file.
  48. const msg = String(err?.message || '')
  49. if (err && (err.code === 1 || /already browser readable/i.test(msg))) {
  50. return file
  51. }
  52. throw err instanceof Error ? err : new Error('HEIC/HEIF 转换失败')
  53. }
  54. }