@@ -70,7 +70,7 @@ class ImageCropElement extends ReactAdapterElement {
7070 height
7171 )
7272 setCrop ( newcrop ) ;
73- this . _updateCroppedImage ( newcrop ) ;
73+ this . _updateCroppedImage ( newcrop ) . catch ( console . error ) ;
7474 }
7575 }
7676 } ;
@@ -123,7 +123,7 @@ class ImageCropElement extends ReactAdapterElement {
123123 } ;
124124
125125 const onComplete = ( c : PixelCrop ) => {
126- this . _updateCroppedImage ( c ) ;
126+ this . _updateCroppedImage ( c ) . catch ( console . error ) ;
127127 } ;
128128
129129 return (
@@ -160,11 +160,56 @@ class ImageCropElement extends ReactAdapterElement {
160160 } )
161161 ) ;
162162 }
163+
164+ /**
165+ * Attempts to detect the MIME type of given HTMLImageElement.
166+ *
167+ * Resolution order:
168+ * 1. If the image is a data URL, extracts the MIME type directly.
169+ * 2. Otherwise, sends a HEAD request to the image URL to read
170+ * the Content-Type header (faster, no body download).
171+ * 3. If the HEAD request does not provide Content-Type, falls back
172+ * to fetching the full image as a Blob and using `blob.type`.
173+ *
174+ * @param img The HTMLImageElement whose MIME type should be detected.
175+ * @returns A Promise resolving to the MIME type string (e.g. "image/png"),
176+ * or null if it cannot be determined.
177+ */
178+ async #getImageMimeType( img : HTMLImageElement ) : Promise < string | null > {
179+ if ( ! img . src ) {
180+ return null ;
181+ }
182+
183+ // Case 1: data URL (e.g., data:image/png;base64,...)
184+ if ( img . src . startsWith ( "data:" ) ) {
185+ const semiIndex = img . src . indexOf ( ";" ) ;
186+ if ( semiIndex > 5 ) {
187+ return img . src . substring ( 5 , semiIndex ) ;
188+ }
189+ return null ;
190+ }
191+
192+ try {
193+ // Case 2: try a HEAD request (fast, no body)
194+ const headRes = await fetch ( img . src , { method : "HEAD" } ) ;
195+ const mime = headRes . headers . get ( "Content-Type" ) ;
196+ if ( mime ) {
197+ return mime ;
198+ }
199+
200+ // Case 3: fallback — fetch full blob
201+ const blobRes = await fetch ( img . src ) ;
202+ const blob = await blobRes . blob ( ) ;
203+ return blob . type || null ;
204+ } catch ( err ) {
205+ console . error ( "Error fetching image MIME type:" , err ) ;
206+ return null ;
207+ }
208+ }
163209
164- public _updateCroppedImage ( crop : PixelCrop | PercentCrop ) {
210+ public async _updateCroppedImage ( crop : PixelCrop | PercentCrop ) {
165211 const image = this . querySelector ( "img" ) ;
166212 if ( crop && image ) {
167-
168213 crop = convertToPixelCrop ( crop , image . width , image . height ) ;
169214
170215 // create a canvas element to draw the cropped image
@@ -207,8 +252,10 @@ class ImageCropElement extends ReactAdapterElement {
207252
208253 ctx . restore ( ) ;
209254
255+ const imgMimeType = await this . #getImageMimeType( image ) || 'image/png' ;
256+
210257 // get the cropped image
211- let croppedImageDataUri = canvas . toDataURL ( "image/png" , 1.0 ) ;
258+ let croppedImageDataUri = canvas . toDataURL ( imgMimeType , 1.0 ) ;
212259
213260 // dispatch the event containing cropped image
214261 this . fireCroppedImageEvent ( croppedImageDataUri ) ;
0 commit comments