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

前端 未结 12 1112
花落未央
花落未央 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: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 = 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;
    }
    

提交回复
热议问题