JS Client-Side Exif Orientation: Rotate and Mirror JPEG Images

前端 未结 12 896
花落未央
花落未央 2020-11-22 11:59

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 se

相关标签:
12条回答
  • 2020-11-22 12:17

    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.

    0 讨论(0)
  • 2020-11-22 12:18

    I've written a little php script which rotates the image. Be sure to store the image in favour of just recalculate it each request.

    <?php
    
    header("Content-type: image/jpeg");
    $img = 'IMG URL';
    
    $exif = @exif_read_data($img,0,true);
    $orientation = @$exif['IFD0']['Orientation'];
    if($orientation == 7 || $orientation == 8) {
        $degrees = 90;
    } elseif($orientation == 5 || $orientation == 6) {
        $degrees = 270;
    } elseif($orientation == 3 || $orientation == 4) {
        $degrees = 180;
    } else {
        $degrees = 0;
    }
    $rotate = imagerotate(imagecreatefromjpeg($img), $degrees, 0);
    imagejpeg($rotate);
    imagedestroy($rotate);
    
    ?>
    

    Cheers

    0 讨论(0)
  • 2020-11-22 12:19

    The github project JavaScript-Load-Image provides a complete solution to the EXIF orientation problem, correctly rotating/mirroring images for all 8 exif orientations. See the online demo of javascript exif orientation

    The image is drawn onto an HTML5 canvas. Its correct rendering is implemented in js/load-image-orientation.js through canvas operations.

    Hope this saves somebody else some time, and teaches the search engines about this open source gem :)

    0 讨论(0)
  • 2020-11-22 12:23

    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;
    }
    
    0 讨论(0)
  • 2020-11-22 12:24

    If

    width = img.width;
    height = img.height;
    var ctx = canvas.getContext('2d');
    

    Then you can use these transformations to turn the image to orientation 1

    From orientation:

    1. ctx.transform(1, 0, 0, 1, 0, 0);
    2. ctx.transform(-1, 0, 0, 1, width, 0);
    3. ctx.transform(-1, 0, 0, -1, width, height);
    4. ctx.transform(1, 0, 0, -1, 0, height);
    5. ctx.transform(0, 1, 1, 0, 0, 0);
    6. ctx.transform(0, 1, -1, 0, height, 0);
    7. ctx.transform(0, -1, -1, 0, height, width);
    8. ctx.transform(0, -1, 1, 0, 0, width);

    Before drawing the image on ctx

    0 讨论(0)
  • 2020-11-22 12:26

    WunderBart's answer was the best for me. Note that you can speed it up a lot if your images are often the right way around, simply by testing the orientation first and bypassing the rest of the code if no rotation is required.

    Putting all of the info from wunderbart together, something like this;

    var handleTakePhoto = function () {
        let fileInput: HTMLInputElement = <HTMLInputElement>document.getElementById('photoInput');
        fileInput.addEventListener('change', (e: any) => handleInputUpdated(fileInput, e.target.files));
        fileInput.click();
    }
    
    var handleInputUpdated = function (fileInput: HTMLInputElement, fileList) {
        let file = null;
    
        if (fileList.length > 0 && fileList[0].type.match(/^image\//)) {
            isLoading(true);
            file = fileList[0];
            getOrientation(file, function (orientation) {
                if (orientation == 1) {
                    imageBinary(URL.createObjectURL(file));
                    isLoading(false);
                }
                else 
                {
                    resetOrientation(URL.createObjectURL(file), orientation, function (resetBase64Image) {
                        imageBinary(resetBase64Image);
                        isLoading(false);
                    });
                }
            });
        }
    
        fileInput.removeEventListener('change');
    }
    
    
    // from http://stackoverflow.com/a/32490603
    export function getOrientation(file, callback) {
        var reader = new FileReader();
    
        reader.onload = function (event: any) {
            var view = new DataView(event.target.result);
    
            if (view.getUint16(0, false) != 0xFFD8) return callback(-2);
    
            var length = view.byteLength,
                offset = 2;
    
            while (offset < length) {
                var marker = view.getUint16(offset, false);
                offset += 2;
    
                if (marker == 0xFFE1) {
                    if (view.getUint32(offset += 2, false) != 0x45786966) {
                        return callback(-1);
                    }
                    var little = view.getUint16(offset += 6, false) == 0x4949;
                    offset += view.getUint32(offset + 4, little);
                    var tags = view.getUint16(offset, little);
                    offset += 2;
    
                    for (var i = 0; i < tags; i++)
                        if (view.getUint16(offset + (i * 12), little) == 0x0112)
                            return callback(view.getUint16(offset + (i * 12) + 8, little));
                }
                else if ((marker & 0xFF00) != 0xFF00) break;
                else offset += view.getUint16(offset, false);
            }
            return callback(-1);
        };
    
        reader.readAsArrayBuffer(file.slice(0, 64 * 1024));
    };
    
    export 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;
    }
    
    0 讨论(0)
提交回复
热议问题