JS Client-Side Exif Orientation: Rotate and Mirror

2020-01-22 12:46发布

Digital camera photos are often saved as JPEG with an EXIF "orientation" tag. To display correctly, images need to be rotated/mirrored depending on which orientation is set, but browsers ignore this information rendering the image. Even in large commercial web apps, support for EXIF orientation can be spotty 1. The same source also provides a nice summary of the 8 different orientations a JPEG can have:

Summary of EXIF Orientations

Sample images are available at 4.

The question is how to rotate/mirror the image on the client side so that it displays correctly and can be further processed if necessary?

There are JS libraries available to parse EXIF data, including the orientation attribute 2. Flickr noted possible performance problem when parsing large images, requiring use of webworkers 3.

Console tools can correctly re-orient the images 5. A PHP script solving the problem is available at 6

10条回答
叼着烟拽天下
2楼-- · 2020-01-22 13:38

In addition to @fareed namrouti's answer,

This should be used if the image has to be browsed from a file input element

<input type="file" name="file" id="file-input"><br/>
image after transform: <br/>
<div id="container"></div>

<script>
    document.getElementById('file-input').onchange = function (e) {
        var image = e.target.files[0];
        window.loadImage(image, function (img) {
            if (img.type === "error") {
                console.log("couldn't load image:", img);
            } else {
                window.EXIF.getData(image, function () {
                    console.log("load image done!");
                    var orientation = window.EXIF.getTag(this, "Orientation");
                    var canvas = window.loadImage.scale(img,
                        {orientation: orientation || 0, canvas: true, maxWidth: 200});
                    document.getElementById("container").appendChild(canvas);
                    // or using jquery $("#container").append(canvas);
                });
            }
        });
    };
</script>
查看更多
可以哭但决不认输i
3楼-- · 2020-01-22 13:40

ok in addition to @user3096626 answer i think it will be more helpful if someone provided code example, the following example will show you how to fix image orientation comes from url (remote images):


Solution 1: using javascript (recommended)

  1. because load-image library doesn't extract exif tags from url images only (file/blob), we will use both exif-js and load-image javascript libraries, so first add these libraries to your page as the follow:

    <script src="https://cdnjs.cloudflare.com/ajax/libs/exif-js/2.1.0/exif.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/blueimp-load-image/2.12.2/load-image.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/blueimp-load-image/2.12.2/load-image-scale.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/blueimp-load-image/2.12.2/load-image-orientation.min.js"></script>
    

    Note the version 2.2 of exif-js seems has issues so we used 2.1

  2. then basically what we will do is

    a - load the image using window.loadImage()

    b - read exif tags using window.EXIF.getData()

    c - convert the image to canvas and fix the image orientation using window.loadImage.scale()

    d - place the canvas into the document

here you go :)

window.loadImage("/your-image.jpg", function (img) {
  if (img.type === "error") {
    console.log("couldn't load image:", img);
  } else {
    window.EXIF.getData(img, function () {
        var orientation = EXIF.getTag(this, "Orientation");
        var canvas = window.loadImage.scale(img, {orientation: orientation || 0, canvas: true});
        document.getElementById("container").appendChild(canvas); 
        // or using jquery $("#container").append(canvas);

    });
  }
});

of course also you can get the image as base64 from the canvas object and place it in the img src attribute, so using jQuery you can do ;)

$("#my-image").attr("src",canvas.toDataURL());

here is the full code on: github: https://github.com/digital-flowers/loadimage-exif-example


Solution 2: using html (browser hack)

there is a very quick and easy hack, most browsers display the image in the right orientation if the image is opened inside a new tab directly without any html (LOL i don't know why), so basically you can display your image using iframe by putting the iframe src attribute as the image url directly:

<iframe src="/my-image.jpg"></iframe>

Solution 3: using css (only firefox & safari on ios)

there is css3 attribute to fix image orientation but the problem it is only working on firefox and safari/ios it is still worth mention because soon it will be available for all browsers (Browser support info from caniuse)

img {
   image-orientation: from-image;
}
查看更多
Rolldiameter
4楼-- · 2020-01-22 13:41

One liner anyone?

I haven't seen anyone mention the browser-image-compression library. It's got a helper function perfect for this.

Usage: const orientation = await imageCompression.getExifOrientation(file)

Such a useful tool in many other ways too.

查看更多
男人必须洒脱
5楼-- · 2020-01-22 13:44

Mederr's context transform works perfectly. If you need to extract orientation only use this function - you don't need any EXIF-reading libs. Below is a function for re-setting orientation in base64 image. Here's a fiddle for it. I've also prepared a fiddle with orientation extraction demo.

function resetOrientation(srcBase64, srcOrientation, callback) {
  var img = new Image();    

  img.onload = function() {
    var width = img.width,
        height = img.height,
        canvas = document.createElement('canvas'),
        ctx = canvas.getContext("2d");

    // set proper canvas dimensions before transform & export
    if (4 < srcOrientation && srcOrientation < 9) {
      canvas.width = height;
      canvas.height = width;
    } else {
      canvas.width = width;
      canvas.height = height;
    }

    // transform context before drawing image
    switch (srcOrientation) {
      case 2: ctx.transform(-1, 0, 0, 1, width, 0); break;
      case 3: ctx.transform(-1, 0, 0, -1, width, height); break;
      case 4: ctx.transform(1, 0, 0, -1, 0, height); break;
      case 5: ctx.transform(0, 1, 1, 0, 0, 0); break;
      case 6: ctx.transform(0, 1, -1, 0, height, 0); break;
      case 7: ctx.transform(0, -1, -1, 0, height, width); break;
      case 8: ctx.transform(0, -1, 1, 0, 0, width); break;
      default: break;
    }

    // draw image
    ctx.drawImage(img, 0, 0);

    // export base64
    callback(canvas.toDataURL());
  };

  img.src = srcBase64;
};
查看更多
登录 后发表回答