JavaScript(jQuery)で画像のオリジナルサイズを取得したい

解決済

回答 5

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 1,498

agepan

score 61

現在Monacaを使ってアプリを開発しております。

アプリの中で画像のオリジナルサイズを取得したいと思い、以下のコードにて試していますが、正しい画像サイズを取得できません。

var array = ['image01.jpg''image02.jpg''image03.jpg'];

for (var i = 0; i < array.length; i++) {

  var path  = array[i];
  var image = new Image();

      image.onload = function () {
        var imageWidth  = image.width ;
        var imageHeight = image.height ;
      }

      image.src = path;

      alert(imageWidth + 'x' + imageHeight);
}


実際の画像サイズは2000x1500pxであるにもかかわらず、上記コードを用いて取得した結果は1124x1999pxとなり、画角も異なります(この値は画像によって異なります)。

iPhoneで動作確認を行っているのですが、iPhoneの画面画角に変形されているようにも思えますが、これも画像によって異なります。正しい画像サイズを取得できる方法お分かりの方いらっしゃいましたらよろしくお願いいたします。

コードを書くにあたって参考にしたページはこちらです。
https://lab.syncer.jp/Web/JavaScript/Snippet/35/

 追記

上記コードになる前に書いていたのが下記のコードです。

上記コードでは省いておりましたが、一連の画像を読み込む前に、別の画像(下記 画像A=「image_A.jpg」)を読み込んでおり、その次に上記コードと同じくfor文で画像(画像B=「image_B1〜B3.jpg」)を読み込んでいます。

画像Aは正しく読み込んで画像サイズを取得するのですが、その次の画像Bに関しては画像サイズが0となって正しく取得できません。

画像Bの方の変数名を変更しても同様で、同じようなコードなのになぜ画像Aが正しく読み込め、画像Bが正しく読めないのか分かりません。画像を何らか先に読み込む必要があるのか?と思い、調べて試してみたのが先に投稿しました上記のコードとなります。

// 画像Aの読み込み-----------------------------------------------------------------------

var image       = new Image();
    image.src   = 'image_A.jpg';
var imageWidth  = image.width;
var imageHeight = image.height;

alert(imageWidth + 'x' + imageHeight); // ←「2000x1500」など、正しい画像サイズを取得できる


// 画像B1〜B3の読み込み------------------------------------------------------------------

var array = ['image_B1.jpg', 'image_B2.jpg', 'image_B3.jpg'];

for (var j = 0; j < array.length; j++) {

  var image       = new Image(); // ←変数名を上と変えて「image2」としても「0」を取得します
      image.src   = array[j];
  var imageWidth  = image.width;
  var imageHeight = image.height;

  alert(imageWidth + 'x' + imageHeight); // ←結果は「0x0」と画像サイズを取得できない

} 

 追記2

先のコードを調整してみました。実際にはこれをfor文で囲み、複数画像を順繰りと舐めて画像サイズを取得したいと考えております。

var image = new Image();
    image.src = 'image.jpg';
    image.onload = function (){ // 引数に「image」を入れても同じ
      var imageWidth = image.naturalWidth;
      var imageHeight = image.naturalHeight;
      alert(imageWidth + 'x' + imageHeight);
    }
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • turbgraphics200

    2018/04/28 09:30

    全角になっているところを半角に修正して。

    キャンセル

  • kei344

    2018/04/28 12:19

    まだ質問が「受付中」になっていますが、「ベストアンサー」を選び「解決済」にされてはいかがでしょうか。

    キャンセル

回答 5

checkベストアンサー

+4

for (var i = 0; i < array.length; i++) {

  var path  = array[i];
  var image = new Image();
//...
}


↑ループの周回ごとにimage変数が書き換えられます。
もしonloadイベントが起きる前にループが終わるなら、

      image.onload = function () {
        var imageWidth  = image.width ;
        var imageHeight = image.height ;
      }


↑ここで参照しているimageは、想定しているものと異なっている可能性があります。
 
対策ですが、クロージャを作るか、letを使うなどしてブロックスコープを使うか、またはイベントターゲットの束縛を受けているthisを使ってみてください。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/04/28 13:44

    なるほどやはりそうですか、では別関数化させて続きの処理をさせてみようと思います。どうもありがとうございました!

    キャンセル

  • 2018/04/28 13:54

    あ、promise と async/await という方法がありましたね……
    IEで動作しないのが難点ですが、ご興味があれば。
    https://sbfl.net/blog/2016/07/13/simplifying-async-code-with-promise-and-async-await/

    キャンセル

  • 2018/05/10 21:39

    ありがとうございます、参考になります。
    Monacaの環境ですとiOSとAndroidで対応していれば大丈夫ですので、上記勉強させて頂きます!

    キャンセル

+2

naturalHeight、naturalWidthプロパティを使ってください。https://developer.mozilla.org/ja/docs/Web/API/HTMLImageElement

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/04/27 17:56

    ご回答ありがとうございます。最初naturalWidth、naturalHeightを用いていたのですが、結果が変わりませんでしたので、いろいろいじって現在のimage.widthとimage.height指定に行き着いております。

    キャンセル

  • 2018/04/27 17:59

    どういうコードを書いていたのでしょうか?
    提示コードではそもそもエラーになって動かないのでは?

    キャンセル

  • 2018/04/28 09:14

    コードを追記させていただきました。お目を通して頂けますと幸いです。

    キャンセル

+1

Promise.all() を使え」といわれそうですが。

'use strict';
const getImgNaturalSizeAll = (() => {
  function handleLoad (event) {
    const img = event.target,
          map = this.map;

    map.set(img.getAttribute('src'), {naturalWidth: img.naturalWidth, naturalHeight: img.naturalHeight});

    if (this.size === map.size) {
      this.resolve(map);
    }
  }

  return function getImgNaturalSizeAll (imgList, resolve) {
    const map = new Map,
          doc = document;

    for (let fileName of imgList) {
      const img = doc.createElement('img');

      img.src = fileName;
      img.addEventListener('load', {handleEvent: handleLoad,size: imgList.length, map: map, resolve: resolve}, false);
    }

  };
})();

function resolve (map) {
  console.log(JSON.stringify([...map]));
}

getImgNaturalSizeAll(['https://placehold.jp/4000x4000.png','https://placehold.jp/1000x1000.png', 'https://placehold.jp/150x150.png'],resolve);  // [["https://placehold.jp/4000x4000.png",{"naturalWidth":4000,"naturalHeight":4000}],["https://placehold.jp/1000x1000.png",{"naturalWidth":1000,"naturalHeight":1000}],["https://placehold.jp/150x150.png",{"naturalWidth":150,"naturalHeight":150}]]

※「ファイル名の配列」とMapの順序性保持はさぼりました。
上の結果ではたまたま一致していますが、保証しません。

※このコードは既存のdocumentにあるimg要素ノードに適用できない点で汎用性がありません。img要素ノードの配列を渡す設計にすると、NodeListも渡せるようになるのでそれなりに便利です。

Re: agepan さん

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/05/10 21:43

    回答遅れまして申し訳ございません。
    わざわざコードを書いて頂きましてありがとうございます!
    今回は今までに頂きました情報と、それをなんとかコードを弄くり回しまして実装することができました。たださらに優れたコードを取り入れたいと思いますので、頂きましたコードは今現在行っている作業が終わり次第、貴重な勉強材料として確認させて頂きます。ありがとうございました!

    キャンセル

0

Jquery未使用でも簡単に取得できます。

// オリジナル画像サイズを取得
const getOriginalSize = () => {
  const img = document.getElementsByClassName('fn-imageSize')[0];
  const imgSizeWidth = img.naturalWidth;
  const imgSizeHeight = img.naturalHeight;
  console.log(imgSizeWidth);
  console.log(imgSizeHeight);
}

window.addEventListener('load', getOriginalSize, false);


------ 複数要素取得したい時 ------

// オリジナル画像サイズを取得
const getOriginalSize = () => {
  const img = document.getElementsByClassName('fn-imageSize');
  // 取得したNodeListを配列化する
  const images = [].slice.call(img);
  images.forEach(function(item) {
    const imgSizeWidth = item.naturalWidth;
    const imgSizeHeight = item.naturalHeight;
    console.log(imgSizeWidth);
    console.log(imgSizeHeight);
  });
}

window.addEventListener('load', getOriginalSize, false);

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/04/28 12:55

    ご回答ありがとうございます!
    > const img = document.getElementsByClassName('fn-imageSize')[0];
    この部分はHTML上にある画像を差していると思いますが、画像をファイルパスで指定することでも可能でしょうか?

    キャンセル

0

このようなコードにすることで無事取得できました。

var image = new Image();
    image.src = 'image.jpg';    

    image.onload = function (){
      var imageWidth = this.width;
      var imageHeight = this.height;
      alert(imageWidth + 'x' + imageHeight);
    }

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.21%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる