Help us understand the problem. What is going on with this article?

スマホでカメラ撮影した画像をcanvasに描画すると、横表示されてしまう問題

More than 3 years have passed since last update.

基本的には、EXIF情報のorientationを参考にビューワーが画像を自動回転してくれるのだが、 canvasにもってくるとEXIF情報が失われてしまう。結果、すべての画像が横表示されてしまうバグが発生。

そこでcanvasを作成する前にorientationを取得し、そのデータを元にcanvasを強制的に回転。回転させたcanvasから取得したbase64を使用すると、横向きにならない。

index.js
import Exif from './lib/Exif';

const exif = new Exif();

// file api
let file    = document.querySelector('input[type=file]').files[0];
let reader  = new FileReader();

reader.onloadend = function () {
    let inputbase64data = reader.result; // 入力したいbase64データ
    exif.clearOrientation(inputbase64data, function(outputbase64data) {
        // outputbase64data: 横向きが直った画像base64データ
        // これを使って改めてcanvasを描画
    })
};
// fileを読み込んだらonloadendが走る
if (file) { reader.readAsDataURL(file); }
Exif.js
export default class Exif {

    constructor (opts = {}) {}

    clearOrientation(imgDataURL, callBack) {
        var byteString = atob(imgDataURL.split(',')[1]);
        var orientaion = byteStringToOrientation(byteString);

        var img = new Image();
        img.onload = function() {

            var canvas = document.createElement('canvas');
            var ctx = canvas.getContext('2d');
            switch (orientaion) {
                case 3: //画像が180度回転している時
                    canvas.width = img.width;
                    canvas.height = img.height;
                    ctx.rotate(Math.PI);
                    ctx.drawImage(img, -img.width, -img.height);
                    ctx.rotate(-Math.PI);
                    break;
                case 6: //画像が時計回りに90度回っている時
                    canvas.width = img.height;
                    canvas.height = img.width;
                    ctx.rotate(Math.PI * 0.5);
                    ctx.drawImage(img, 0, -img.height);
                    ctx.rotate(-Math.PI * 0.5);
                    break;
                case 8: //画像が反時計回りに90度回っている時
                    canvas.width = img.height;
                    canvas.height = img.width;
                    ctx.rotate(-Math.PI * 0.5);
                    ctx.drawImage(img, -img.width, 0);
                    ctx.rotate(Math.PI * 0.5);
                    break;
                default:
                    canvas.width = img.width;
                    canvas.height = img.height;
                    ctx.drawImage(img, 0, 0);
            }
            callBack(canvas.toDataURL("image/jpeg"));
        }
        img.src = imgDataURL;

        // exif情報のorientationを取得
        function byteStringToOrientation(img) {
            var head = 0;
            var orientation;
            while (1) {
                if (img.charCodeAt(head) == 255 & img.charCodeAt(head + 1) == 218) {
                    break;
                }
                if (img.charCodeAt(head) == 255 & img.charCodeAt(head + 1) == 216) {
                    head += 2;
                } else {
                    var length = img.charCodeAt(head + 2) * 256 + img.charCodeAt(head + 3);
                    var endPoint = head + length + 2;
                    if (img.charCodeAt(head) == 255 & img.charCodeAt(head + 1) == 225) {
                        var segment = img.slice(head, endPoint);
                        var bigEndian = segment.charCodeAt(10) == 77;
                        if (bigEndian) {
                            var count = segment.charCodeAt(18) * 256 + segment.charCodeAt(19);
                        } else {
                            var count = segment.charCodeAt(18) + segment.charCodeAt(19) * 256;
                        }
                        for (var i = 0; i < count; i++) {
                            var field = segment.slice(20 + 12 * i, 32 + 12 * i);
                            if ((bigEndian && field.charCodeAt(1) == 18) || (!bigEndian && field.charCodeAt(0) == 18)) {
                                orientation = bigEndian ? field.charCodeAt(9) : field.charCodeAt(8);
                            }
                        }
                        break;
                    }
                    head = endPoint;
                }
                if (head > img.length) {
                    break;
                }
            }
            return orientation;
        }
    }

}

base64が空で返ってくるバグ

※大きい画像を回転させるのには負担がかかる。iPhone5で画像が描画されない(base64が空で返ってきてしまう)バグがあったので、リサイズ後に回転させた。正しい処理の仕方は以下のようになる。

fileAPI(base64取得)

exif(orientation取得)

resize / trimming

rotate


参考
JPEGからJavascriptでEXIFのOrientation情報のみを取得する
[JavaScript] 画像リサイズ&回転
ExifのOrientationを見て画像を回転させる
↓既存のライブラリ
ExifのOrientationを見たうえでcanvasに画像を表示できるJSライブラリ
JavaScript-Load-Image

mo49
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした