みなさんの環境では、以下の画像はどのように見えますか?
タイトルの通りですが、Chrome 81、Safari 13.1からjpegのExif、Orientationの値を考慮して画像が表示されるようになったようです
See the Pen exif orientation by megos (@megos) on CodePen.
各ブラウザの動き
ブラウザに関わらず画像の向きを正しく表示する
blueimp-load-imageの2.29.0以上を使うことでExifのOrientationを考慮して画像を読み込むことができます
2.29.0未満の場合、
画像読み込み → blueimp-load-image(回転1回目) → htmlに表示(回転2回目)と二重に回転した画像が表示されます…
issue報告からすぐ対応してくださった作者様に感謝…!
以下は駄文です。私がいろいろとハマったことを書いていきます
2020/03/31
携わっているWebアプリで画像が回転するという報告が上がる(iOS13系)
2020/04/01
自分のiPhone(iOS13.4)で試す。再現しない(回転しない)
iPhoneシミュレータ12.4、13.4でそれぞれ試す
12.4 → 回転する
13.4 → 回転しない
ここまでで、jpegのExif orientationが影響していることがわかる
orientationを考慮して画像を読み込むことができるblueimp-load-imageを入れる
すると、iOS13.4で画像が二重に回転することがわかる
2020/04/02
いろいろ試してみる
全て失敗
- blueimp-load-imageから渡ってきた
HTMLCanvasElement
をtoDataURL('image/png')
としてpngとしてbase64化する - blueimp-load-imageのオプションに
canvas: false
を渡す →orientation
を指定するとcanvas
がtrue
になるので意味無し https://github.com/blueimp/JavaScript-Load-Image/blob/v2.28.0/README.mdSetting the orientation also enables the canvas option.
Exifの情報が残っているのでは?という推論から、
orientationの値を取得 → orientationを0でクリア → 先程取得した値をblueimp-load-imageに投げる
という方法を考える
Exifの情報を読み込むライブラリはあっても、書き込むものは無さそうだった
今回はorientationだけでいいので、Exifの仕様を読んで理解するという謎の時間が発生
qiita.com http://www.cipa.jp/std/documents/j/DC-008-2012_J.pdf dsas.blog.klab.org hp.vector.co.jp
Qiitaの記事を元にバイナリを書き換えるコードを作成
const getAndRemoveOrientation = buffer => { const dataView = new DataView(buffer) let app1Start = 2 if (dataView.getUint16(app1Start) === 0xffe0) { // Have APP0 app1Start += dataView.getUint16(4) + 2 } if (dataView.getUint16(app1Start) !== 0xffe1) { // Noting APP1 return { orientation: 0, buffer } } const littleEndian = dataView.getUint16(app1Start + 10) === 0x4949 const fieldSizeStart = 18 + app1Start const fieldEntrySize = 12 const ORIENTATION = 0x0112 const valueOffset = 8 const fieldSize = dataView.getUint16(fieldSizeStart, littleEndian) for (let i = 0; i < fieldSize; i++) { const start = fieldSizeStart + 2 + i * fieldEntrySize const tag = dataView.getUint16(start, littleEndian) if (tag === ORIENTATION) { const orientation = dataView.getUint16(start + valueOffset, littleEndian) // NOTE: Clear orientation tag because it rotation twice in Safari 13.1 dataView.setUint16(start + valueOffset, 0, littleEndian) return { orientation, buffer: dataView.buffer } } } return { orientation: 0, buffer } }
バイナリを書き換えることで二重回転することなく表示することができた!
(´-`).。oO(本当にこんな対応でいいのか?)
2020/04/03
Safariの13.1のみで発生しているかも?と思ってWebKit Bugzillaへ。ビンゴなissueを発見
ということはバイナリを書き換えるような大掛かりなことをしなくても if (safari version => 13.1)
みたいな分岐だけ入れたほうがいいのか悩む…
2020/04/08
blueimp-load-imageにissueが上がっているのを見かける
WebKit Bugzillaを見ていたので、ライブラリのバグじゃないしなぁと思ってissue作るのをためらっていたんですよね
これをみて、よさそうなワークアラウンドと、Chrome 81でも同じ動きをするということがわかる
ここまで調べて方針が決まったので、残りは明日やろうと一旦離れる
{ orientation: getComputedStyle(document.body).imageOrientation !== 'from-image' }
2020/04/09
続きをしようと思って再びissueを見たら二重回転しないようにライブラリが更新されていた
yarn
してあっけなく終了。お疲れさまでした。時間かかりすぎた。