onurzorluer / react-image-file-resizer

Resize Local Images with React 🌄 🌅
MIT License
320 stars 41 forks source link

No response (success nor error) with HEIC format. #59

Open scott-schibli opened 3 years ago

scott-schibli commented 3 years ago

Hello, I am running into problems with compressing a .heic image. It seems that all other image formats work perfectly, but when I use a .heic image, I do not get a response - neither a success or error in my catch.

I guess my question is, I don't seem to find anywhere how to specifically reject the returned promise from the 'resizeFile' method from the Resizer.imageFileResizer() method, how can I do that? Does this package even support heic (I cant find anything online about .heic files relating to this package at all -- curious).

This is my resizeFile method:

const resizeFile = (file: File) => { return new Promise((resolve) => { Resizer.imageFileResizer( file, 1080, 1080, 'JPEG', 80, 0, (uri) => { resolve(uri); }, 'base64', ); }); };

And this is my try catch which I am calling it from:

files.forEach(async (file, i) => { try { const image = await resizeFile(file); const newFile = dataURIToBlob(image); formData.append(file.name, newFile); } catch (err) { console.log(err); } });

Expected behavior I expect a response, either an error or success from passing any type of image.

Desktop (please complete the following information):

boythan commented 3 years ago

I have same problem.

dylancrockett commented 2 years ago

I believe it might have something to do with these two lines in the library https://github.com/onurzorluer/react-image-file-resizer/blob/8a979bc30e76324c03e0e69aef47c42d0096126b/src/index.js#L95 https://github.com/onurzorluer/react-image-file-resizer/blob/8a979bc30e76324c03e0e69aef47c42d0096126b/src/index.js#L169

As I have looked into this further it is also due to the fact that pretty much no browser apart from Safari supports HEIC as a valid image format (so if you are using Chromium based browsers the fix I mention below wont work). If you are not on safari it looks like you would need some other method for converting from HEIC to something like png, jpeg, or webp first before resizing.

Possible Solution (For Browsers which support HEIC)

I believe I came up with a solution which fixes this problem, which not only applies to heic files but any other image file which is not a png, jpeg, or webp (such as svg).

Change line 95 to be: b64Data.toString().replace(/^data:image\/(.*);base64,/, "")

Then line 169 to be: let fileNameWithoutFormat = fileName.toString().replace(/\.[^.]*$/, "").concat(".");

And it should now be able to handle any file which has a mime type like image/*, I wouldn't say this guarantees the file is resized correctly, the file still needs to be able to be displayed on a canvas object to be manipulated (at least I believe this is how the file manipulation is done from looking through the code).

I made these changes to my local version of the library and it is now working with file types like heic and svg. I am not sure what other impacts this might have or what errors may come of this but I think the changes I mentioned are worth looking into.

mbyrne00 commented 1 year ago

Hey @onurzorluer - any chance of incorporating this suggested fix? Would be nice to support heic in this great simple-to-use lib.

mbyrne00 commented 1 year ago

This has become less urgent for me, as I forgot that when you don't explicitly accept heic files with your file input and you do accept jpg, then iOS converts them first.

jovana commented 1 year ago

I have also a workaround, which is very easy to use. Using the heic2any script: https://www.npmjs.com/package/heic2any

Before running the resizer check the image type and convert:

if (file.type === 'image/heic') {
        // file conversion takes a bit.
        file = await heic2any({
            blob: file,
            quality: 0.5
        });
    }
Andriy-Kulak commented 10 months ago

This has become less urgent for me, as I forgot that when you don't explicitly accept heic files with your file input and you do accept jpg, then iOS converts them first.

Can you explain what you mean by this? I don't get it. iOS on phones converts HEIC to JPEG on the fly? that doesn't make sense

Andriy-Kulak commented 10 months ago

I have also a workaround, which is very easy to use. Using the heic2any script: https://www.npmjs.com/package/heic2any

Before running the resizer check the image type and convert:

if (file.type === 'image/heic') {
        // file conversion takes a bit.
        file = await heic2any({
            blob: file,
            quality: 0.5
        });
    }

When I try to resize the result of this I get the same error as the original Post on here. Do you do anything specific afterwards?

mbyrne00 commented 10 months ago

This has become less urgent for me, as I forgot that when you don't explicitly accept heic files with your file input and you do accept jpg, then iOS converts them first.

Can you explain what you mean by this? I don't get it. iOS on phones converts HEIC to JPEG on the fly? that doesn't make sense

Asking for help and telling someone their comment "doesn't make sense" isn't always the best strategy ;-).

Anyway, I don't have the code at hand but if you search around you will see there are various scenarios where iOS devices will automatically convert HEIC to JPG if it's for image requests that do not accept HEIC. For example comments like the one below. I can't remember in the context of this component, but I had a similar experience from memory. For my use cases, this was enough. There may still be valid reasons others want to do it explicitly, however.

Tried a standard input tag with the proper accept attribute <input type="file" accept="image/jpeg,image/png" /> Selected a HEIC file from Photos in Safari, the selected image was automatically converted to JPEG.

Andriy-Kulak commented 10 months ago

This has become less urgent for me, as I forgot that when you don't explicitly accept heic files with your file input and you do accept jpg, then iOS converts them first.

Can you explain what you mean by this? I don't get it. iOS on phones converts HEIC to JPEG on the fly? that doesn't make sense

Asking for help and telling someone their comment "doesn't make sense" isn't always the best strategy ;-).

Anyway, I don't have the code at hand but if you search around you will see there are various scenarios where iOS devices will automatically convert HEIC to JPG if it's for image requests that do not accept HEIC. For example comments like the one below. I can't remember in the context of this component, but I had a similar experience from memory. For my use cases, this was enough. There may still be valid reasons others want to do it explicitly, however.

Tried a standard input tag with the proper accept attribute <input type="file" accept="image/jpeg,image/png" /> Selected a HEIC file from Photos in Safari, the selected image was automatically converted to JPEG.

You're right. sorry wasn't in the best headspace yesterday. thanks for calling my attitude out and quick response/tip to help me resolve this. The solution that seems to work is specifically defining accept image file types to png jpeg, example below.

  const {
    ...
    acceptedFiles,
  } = useDropzone({
    accept: {
      "image/jpeg": [],
      "image/png": [],
    }
  });

<input type="file" accept="image/jpeg,image/png" /> as you suggested will probably work just as well.

just tested and seems to work on mobile iphones well. if the desire is to add ability for people to upload HEIC images from desktop, then something like heic2any will likely be needed although it's not a priority for me either.

Cheers!