この記事について
画像をアップロードして、表示するものをつくったところ、「あ、iPhoneでアップしたら横向きになっちゃった」っていうのは割とアルアルだと思います。対応方法としては、
- クライアント側(JS)で回転処理してからアップロードする
- バックエンド側で回転処理をして保存する
の2パターンかと思いますが、Firebase,Nuxt(+Vuetify),TypeScriptだったときの、両方についての対応サンプルとなります。
クライアント側対応版
blueimp-load-image
を使いました。こちら
<v-img
:src="previewImageSrc"
aspect-ratio="1"
class="previewImg"
></v-img>
<v-file-input
@change="onChangeFileInput"
label="画像の変更"
></v-file-input>
onChangeFileInput(file: any) {
if (file) {
BlueimpLoader.parseMetaData(file, (data: any) => {
const options = {
maxHeight: 500,
maxWidth: 500,
canvas: true,
orientation: 1
}
if (data.exif) {
options.orientation = data.exif.get('Orientation')
}
BlueimpLoader(
file,
(canvas: HTMLCanvasElement) => {
this.previewImageSrc = canvas.toDataURL(file.type)
canvas.toBlob((blob) => {
this.imageBlob = blob
})
},
options
)
})
} else {
this.previewImageSrc = ''
this.imageBlob = null
}
}
全コード
これでプレビュー表示も回転しますし、this.imageBlob
をFirebase StorageにアップすればOKだね。という話になります。
Firebase側対応版
Firebase Functions を使います。Storageに画像がアップロードされたら起動する感じにしておきます。
基本的には、Firebase公式ドキュメントにサムネを生成するコードがのっているので、ほぼほぼそれを参考にしました。
await spawn('convert', [
tempDownloadFilePath,
'-auto-orient',
'-thumbnail',
'600x600>',
tempConvertedFilePath
])
やる前はメタデータのExifでOrientationを取得して。。。みたいなのを想定していたのですが、
まさかのパラメータに-auto-orient
追加だけで、できてしまいました。感動!!!
注意すべきは
exports.convertImage = functions.storage.object().onFinalize(async (object) => {
onFinalize
のイベントで実行されるので、変換した画像をStorageに保存するときに、またこのスクリプトが実行されます。なので、下手したら無限ループするやんってことでしょうか(公式サンプルも今回のもファイル名判定してループを止めています)。
なもんで、実際に導入するときはemulatorとかしっかりつかって検証した上でやりましょう。
また、Databaseに変換後のパスを保存したりとか、このFunctionsの変換処理が終わったタイミングってどうやって判断すんだっけとか、色々考えないと、実際のサービスなどでは使えないでしょうね。
最後に
どっちがいいかはその時々で違うと思います。クライアント側でやるほうが楽だし、アップロードの通信量を削減できるというメリットもあると思います。
でもバックエンド側でやれば、ゆーてもバリデーション的な位置づけで、変な画像は許可させないぞ、という立ち位置もとれるというのはGoodかなぁと。
ではでは、みなさまメリクリ〜