🖼

アップロードした画像の寸法を得る方法

2022/07/03に公開

概略

  • Image のインスタンスの src にデータを渡し、読み込まれた段階で寸法がわかる
  • その前の段階の読み込み方法に二通りの選択がある
    1. createObjectURL (Blog URL Scheme)
    2. FileReader (Data URL Scheme)
  • 寸法を知りたいだけならどちらでもよい
    • createObjectURL の方がややシンプルに書けるなどの利点はある
  • 同時にデータも欲しい場合(通常はこっち)は形式が異なるためどちらでもよくはない
  • 読み込みと寸法を得る処理を一緒に行おうとしているからややこしくなっているとも思える
  • とにかくめんどい

方法1. 寸法を知りたいだけ

<template lang="pug">
.App
  input(type="file" @change="change_handle" ref="input_files_el")
</template>

<script>
export default {
  methods: {
    change_handle() {
      const input_file = this.$refs["input_files_el"].files[0]
      const image = new Image()
      image.addEventListener("load", () => {
        console.log(image.naturalWidth)  // => 800
        console.log(image.naturalHeight) // => 600
        URL.revokeObjectURL(image.src)   // (寸法だけを知りたいので)破棄する
      })
      image.src = URL.createObjectURL(input_file)
      console.log(image.src)             // => blob:http://localhost:8080/231a3dc4-147d-4298-abad-1d9a5e4f530d
    },
  },
}
</script>
  • 常識的に考えて一瞬で取得できてよさそうな情報だけどこんなに書かないといけない
  • input タグを参照した時点でわかるようにしてほしい

方法2. Blob URL Scheme にしつつ寸法も知りたい

<template lang="pug">
.App
  input(type="file" @change="change_handle" ref="input_files_el")
  img(:src="new_image_url")
</template>

<script>
export default {
  data() {
    new_image_url: null,
  },
  methods: {
    change_handle() {
      const input_file = this.$refs["input_files_el"].files[0]
      this.new_image_url = URL.createObjectURL(input_file)
      console.log(this.new_image_url) // => blob:http://localhost:8080/231a3dc4-147d-4298-abad-1d9a5e4f530d
      if (true) {
        const image = new Image()
        image.addEventListener("load", () => {
          console.log(image.naturalWidth)  // => 800
          console.log(image.naturalHeight) // => 600
        })
        image.src = this.new_image_url
      }
    },
  },
}
</script>
  • createObjectURL で読んでいるので Blob URL Scheme になっている
  • Blob URL Scheme 形式を img タグの src に渡して表示できる
  • しかしサーバー側に渡してサーバーから読み込むことはできない(はず)

方法3. Data URL Scheme にしつつ寸法も知りたい

<template lang="pug">
.App
  input(type="file" @change="change_handle" ref="input_files_el")
  img(:src="new_image_url")
</template>

<script>
export default {
  data() {
    new_image_url: null,
  },
  methods: {
    change_handle() {
      const input_file = this.$refs["input_files_el"].files[0]

      const file_reader = new FileReader()
      file_reader.addEventListener("load", () => { // load: 成功したときのイベント
        console.log(file_reader.result)            // => data:image/jpeg;base64,/9j/4AAQSkZJ...
        this.new_image_url = file_reader.result
        if (true) {
          const image = new Image()
          image.addEventListener("load", () => {
            console.log(image.naturalWidth)   // => 800
            console.log(image.naturalHeight)  // => 600
          })
          image.src = this.new_image_url
        }
      }, false)
      file_reader.readAsDataURL(input_file)
    },
  },
}
</script>
  • FileReader で読んでいるので Data URL Scheme になっている
  • サーバー側に POST すれば読み取れる
    • Ruby なら base64, の後ろを Base64.decode64 に渡せばバイナリ化できる
    • データがでかすぎてログが大変なことになりがち

参考 🙏

https://gotohayato.com/content/519/
https://qiita.com/zenpou/items/4b1a0946b120fecd4494

Discussion