blueimp / JavaScript-Load-Image

Load images provided as File or Blob objects or via URL. Retrieve an optionally scaled, cropped or rotated HTML img or canvas element. Use methods to parse image metadata to extract IPTC and Exif tags as well as embedded thumbnail images, to overwrite the Exif Orientation value and to restore the complete image header after resizing.
https://blueimp.github.io/JavaScript-Load-Image/
MIT License
4.46k stars 923 forks source link

Breaking change in prev release #134

Closed BrodaNoel closed 3 years ago

BrodaNoel commented 3 years ago

Hi everyone. I can't find in which commit you had it, but... check this out:

During... I guess years, we have been using this code in my company's project:

  fixImageRotation = file => {
    return new Promise(resolve => {
      loadImage(
        file,
        img => {
          img.toBlob(blob => {
            resolve(blob);
          }, 'image/jpeg');
        },
        { orientation: true }
      );
    });
  };

Seems like some weeks/months ago, this feature stoped working (it's a feature we don't frecuently use, so, we are not sure when it got broken).

The bug was simple: img.toBlob is undefined. I had to dig a lot inside your code (forked, and running tests), where I realized that in this test, you ALSO have it undefined:

    it('Load image url as img element', function (done) {
      expect(
        loadImage(imageUrlGIF, function (img) {
          console.log('$$ img.toBlob', img.toBlob); // <<< Here is undefined
          expect(img.nodeName.toLowerCase()).to.equal('img')
          expect(img.width).to.equal(60)
          expect(img.height).to.equal(40)
          done()
        })
      ).to.be.ok
    })

So, after 3 millon console.log, I realized that here, you do have it defined:

    it('Write EXIF Orientation tag and replace image head', function (done) {
      loadImage(
        blobJPEG,
        function (img, data) {
          console.log('$$ what img.toBlob', img.toBlob); // <<< Here it's defined.
          expect(data.imageHead).to.be.ok
          expect(data.exif).to.be.ok
          expect(data.exif.get('Orientation')).to.equal(6)
          expect(data.iptc).to.be.ok
          expect(data.iptc.get('ObjectName')).to.equal('blueimp.net')
          // Reset EXIF Orientation data:
          var buffer = loadImage.writeExifData(
            data.imageHead,
            data,
            'Orientation',
            1
          )
          // Check if Orientation writer changes image head buffer in place:
          expect(buffer).to.equal(data.imageHead)
          img.toBlob(function (blob) {
            loadImage.replaceHead(blob, data.imageHead, function (newBlob) {
              loadImage(
                newBlob,
                function (img, data) {
                  expect(img.width).to.equal(40)
                  expect(img.height).to.equal(60)
                  expect(data.imageHead).to.be.ok
                  expect(data.exif).to.be.ok
                  expect(data.exif.get('Orientation')).to.equal(1)
                  expect(data.iptc).to.be.ok
                  expect(data.iptc.get('ObjectName')).to.equal('blueimp.net')
                  done()
                },
                { meta: true }
              )
            })
          }, 'image/jpeg')
        },
        { meta: true, orientation: true, canvas: true, minWidth: 40 }
      )
    })

Soooo, I added the { canvas: true } option, and now it's fixed in the project.

The problem, is that it is a breaking change. Which is probably the root of the problem of https://github.com/blueimp/JavaScript-Canvas-to-Blob/issues/35. That's just another dev that didn't add the canvas: true, so .toBlob is undefined.

As you may image, I fixed it doing this:

  fixImageRotation = file => {
    return new Promise(resolve => {
      loadImage(
        file,
        img => {
          img.toBlob(blob => {
            resolve(blob);
          }, 'image/jpeg');
        },
        {
           orientation: true,
           canvas: true, // <<< Here the fix
         }
      );
    });
  };
blueimp commented 3 years ago

Hi @BrodaNoel and sorry for the late reply. I think what you are referring to is a breaking change that happened in browsers - browsers updated their logic on the auto-orientation of images, now doing it automatically. As a result, images that had to be returned as canvas objects to be able to adjust their orientation now could be returned as is, without converting them into canvas elements first. The possibility that the library might return and img element was always there and documented: https://github.com/blueimp/JavaScript-Load-Image#callback-arguments