onurzorluer / react-image-file-resizer

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

Base64 returning even when blob type is specified #9

Closed Riley-Brown closed 3 years ago

Riley-Brown commented 5 years ago

Describe the bug Base64 is being returned in memory as well as the blob uri, i'm concerned this may cause a memory leak in my application. chrome_s0ehbGP3gm

To Reproduce Steps to reproduce the behavior:

My code:

      const file = e.target.files ? e.target.files[0] : e.dataTransfer.files[0];
      Resizer.imageFileResizer(
        file,
        isLogo ? 512 : 1080, // maxHeight
        isLogo ? 512 : 1920, // maxWidth
        'PNG',
        100,
        0,
        blob => {
          // creates new converted PNG file using blob
          const convertedFile = new File([blob], 'convertedImage.png', {
            type: 'image/png',
            lastModified: Date.now()
          });
          const fileSizeMb = (convertedFile.size / 1024 / 1024).toFixed(4);
          if (fileSizeMb > 10) {
            return setFileError({
              hasError: true,
              error: 'Image size must be less than 10MB.'
            });
          }

          // creates blob reference in memory
          setImgPreview(window.URL.createObjectURL(blob));

          setFile(convertedFile);
        },
        'blob'
      );

Expected behavior A clear and concise description of what you expected to happen.

Should only return blob when blob type is specified

Screenshots If applicable, add screenshots to help explain your problem.

Desktop (please complete the following information):

Smartphone (please complete the following information):

Additional context Add any other context about the problem here.

andreaslorozco commented 4 years ago

I was casually digging through the code since I needed an image resizer from a file, and from what I can see:

The file is first transformed into a base64 string so that it can be resized and rotated. After that, the base64 string is transformed into a Blob and, depending on the outputType, the callback is called with either the base64 string or the Blob as the argument...

I haven't checked if there's a/an easy way to resize a Blob. That would make it easy to return a Blub without before transforming it into a base64 string.

However, I think the current code could be easily improved to not transform the image into a blob if the user wants a base64 string only.

Riley-Brown commented 4 years ago

Thanks for the info Andreas, I ended up making my own resizing logic using a canvas and blob data. Here's my code

  const resizeSvg = previewUrl => {
    // create image instance
    const img = new Image();
    img.src = previewUrl;

    img.onload = () => {
      // dimensions to maintain svg aspect ratio
      const width = 512;
      const scaleFactor = width / img.width;
      const height = img.height * scaleFactor;

      // create canvas element
      const canvas = document.createElement('canvas');
      canvas.width = width;
      canvas.height = height;

      const ctx = canvas.getContext('2d');
      ctx.drawImage(img, 0, 0, width, height); // draw img to canvas

      // use canvas toBlob method to convert svg to png
      ctx.canvas.toBlob(
        blob => {
          const convertedSvg = new File([blob], 'convertedSvg.png', {
            type: 'image/png',
            lastModified: Date.now()
          });
          setFile(convertedSvg);
        },
        'image/png',
        1
      );
    };
  };

This code was used to size up an SVG if it was below 512px width, but can be adjusted for other dimensions. It takes a preview URL param which is a blob I create from the image file data

 const previewUrl = window.URL.createObjectURL(file);