基本的には、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