File tree Expand file tree Collapse file tree 3 files changed +41
-7
lines changed
Expand file tree Collapse file tree 3 files changed +41
-7
lines changed Original file line number Diff line number Diff line change 33 import { removeByUrl , upload } from " $lib/data/private/storage.remote" ;
44 import {
55 type AllowedFolder ,
6+ inferImageType ,
67 isAcceptedImageType ,
78 isAllowedFolder ,
89 } from " $lib/shared/logic/image" ;
3435 async function handleFile(file : File , fromPaste = false ) {
3536 error = null ;
3637
37- // Validate file type
38- if (! isAcceptedImageType (file .type )) {
38+ // Resolve MIME type: use file.type, or infer from extension as fallback
39+ // (some browsers report empty type for HEIC/HEIF)
40+ const resolvedType = isAcceptedImageType (file .type ) ? file .type : inferImageType (file .name );
41+ if (! resolvedType ) {
3942 error = " Unsupported image format" ;
4043 return ;
4144 }
6568 try {
6669 const arrayBuffer = await processedFile .arrayBuffer ();
6770 const base64 = arrayBufferToBase64 (arrayBuffer );
68- // Use the validated original type - server will re-compress to WebP anyway
69- const uploadType = isAcceptedImageType (processedFile .type ) ? processedFile .type : file . type ;
71+ // Use processed file's type if valid, otherwise fall back to resolved type
72+ const uploadType = isAcceptedImageType (processedFile .type ) ? processedFile .type : resolvedType ;
7073 const result = await upload ({
7174 data: base64 ,
7275 type: uploadType ,
Original file line number Diff line number Diff line change @@ -12,12 +12,14 @@ export function arrayBufferToBase64(buffer: ArrayBuffer): string {
1212}
1313
1414export async function compressImage ( file : File ) : Promise < File > {
15- // Skip if not an image that can be compressed
16- if ( ! file . type . startsWith ( "image/" ) || file . type === "image/gif" ) {
15+ const SERVER_LIMIT = 10 * 1024 * 1024 ; // 10MB DoS protection limit
16+
17+ // Skip if not an image that can be compressed via canvas,
18+ // or if already small enough (server handles format conversion anyway)
19+ if ( ! file . type . startsWith ( "image/" ) || file . type === "image/gif" || file . size <= SERVER_LIMIT ) {
1720 return file ;
1821 }
1922
20- const SERVER_LIMIT = 10 * 1024 * 1024 ; // 10MB DoS protection limit
2123 const QUALITY_STEPS = [ 0.9 , 0.7 , 0.5 , 0.3 ] ;
2224 const DIMENSION_STEPS = [ 1920 , 1440 , 1080 , 720 ] ;
2325
Original file line number Diff line number Diff line change @@ -24,6 +24,35 @@ export function isAcceptedImageType(type: string): type is AcceptedImageType {
2424 return ACCEPTED_IMAGE_TYPES . some ( ( t ) => t === type ) ;
2525}
2626
27+ /**
28+ * Extension-to-MIME mapping for when browsers don't report file.type
29+ * (common with HEIC/HEIF on desktop browsers)
30+ */
31+ const EXTENSION_TO_MIME : Record < string , AcceptedImageType > = {
32+ jpg : "image/jpeg" ,
33+ jpeg : "image/jpeg" ,
34+ png : "image/png" ,
35+ webp : "image/webp" ,
36+ avif : "image/avif" ,
37+ heic : "image/heic" ,
38+ heif : "image/heif" ,
39+ gif : "image/gif" ,
40+ tiff : "image/tiff" ,
41+ tif : "image/tiff" ,
42+ svg : "image/svg+xml" ,
43+ bmp : "image/bmp" ,
44+ } ;
45+
46+ /**
47+ * Infer MIME type from file extension (case-insensitive).
48+ * Returns undefined if extension is not recognized.
49+ */
50+ export function inferImageType ( filename : string ) : AcceptedImageType | undefined {
51+ const ext = filename . split ( "." ) . pop ( ) ?. toLowerCase ( ) ;
52+ if ( ! ext ) return undefined ;
53+ return EXTENSION_TO_MIME [ ext ] ;
54+ }
55+
2756/**
2857 * Allowed folder paths for uploads
2958 */
You can’t perform that action at this time.
0 commit comments