Symfoware

Symfowareについての考察blog

JavaScriptで選択されたjpgのサイズ(高さ、幅)をSOFマーカーから取得する

ファイルダイアログで選択されたjpegファイルの高さと幅をJavaScriptで取得できないか。


Imageオブジェクト



調べてみると、よくある手法としてはFileReader#readAsDataURLで
選択された画像を読み込みDataURLに変換。

Imageオブジェクトのソースに設定して、画像としてロードできた後にサイズを取得する。


  1. <!doctype html>
  2. <html lang="ja">
  3. <head>
  4.     <meta charset="utf-8">
  5.     <title>Sample</title>
  6. <script type='text/javascript'>
  7. function test_click() {
  8.     var file_input = document.querySelector('#file-input');
  9.     var file = file_input.files[0];
  10.     
  11.     var fileReader = new FileReader();
  12.     fileReader.onload = function(e) {
  13.         var img = new Image();
  14.         // DataURLとして読み込んだ内容をImageに設定
  15.         // 画像として読み込めた後に幅と高さを取得
  16.         img.onload = function() {
  17.             var result = '';
  18.             result += 'width:' + img.width;
  19.             result += "\n";
  20.             result += 'height:' + img.height;
  21.             
  22.             document.querySelector('#result').innerText = result;
  23.             
  24.         };
  25.         img.src = e.target.result;
  26.     };
  27.     fileReader.readAsDataURL(file);
  28.     
  29. };
  30. </script>
  31. </head>
  32. <body>
  33.     <h3>jpegテスト</h3>
  34.     <input id="file-input" type="file" />
  35.     <div>
  36.         <input type="button" id="test" onclick="test_click()" value="実行" />
  37.     </div>
  38.     <div id="result"></div>
  39. </body>
  40. </html>




765_01.png

765_02.png


これでもやりたいことは実現出来たのですが、画像サイズが大きくなると
値の取得に時間がかかるんですよ。




SOFマーカー




※2017/8/11追記

うまくサイズが取得できないjpegがあったので修正しました。
(修正版)JavaScriptで選択されたjpgのサイズ(高さ、幅)をSOFマーカーから取得する



jpegのファイルフォーマットの仕様として、幅や高さを持っているはず。
その領域を直接読み込んでやれば良いのでは?

こちらが参考になりました。
JPG 画像を開かずに縦横サイズを得る

やはり、データ内に高さと幅を持っているそうです。

JPG ファイルフォーマットをもう少し調べてみると、
JPG ファイルフォーマット
JPG セグメント(SOF0)

SOFと呼ばれる領域に画像の高さと幅を持っているようです。

このキーワードで調べてみると、そのものズバリのソースを見つけました。
jpeg_sof_finder.html


こちらを参考に、SOF領域から画像サイズを取得してみます。


  1. <!doctype html>
  2. <html lang="ja">
  3. <head>
  4.     <meta charset="utf-8">
  5.     <title>Sample</title>
  6. <script type='text/javascript'>
  7. function test_click() {
  8.     var file_input = document.querySelector('#file-input');
  9.     var file = file_input.files[0];
  10.     
  11.     var fileReader = new FileReader();
  12.     fileReader.onload = function(e) {
  13.         // https://gist.github.com/lucianogiuseppe/b9e6d1ede2671405fcf3680e96dda84e
  14.         var bytes = e.target.result;
  15.         var int32View = new Uint8Array(bytes);
  16.         
  17.         if ((int32View[0] != 0xff) || (int32View[1] != 0xd8)) {
  18.             console.log('Not a valid JPEG');
  19.             return false;
  20.         }
  21.         if((int32View[2] !== 0xff) || (int32View[3] < 0xe0) || (int32View[3] > 0xef) ) { //check APP0..APP15 marker
  22.             console.log('Bad APPX');
  23.             return false;
  24.         }
  25.         
  26.         var sizeSeg = 0, offset=0;
  27.         sizeSeg = (int32View[4]*256) + int32View[5]; //segment size
  28.         offset = 4 + sizeSeg;
  29.         //while EOF
  30.         while(offset < int32View.length ) {
  31.             if(int32View[offset] != 0xff) {
  32.                 console.log('bad segment');
  33.                 break;
  34.             }
  35.             if(int32View[offset+1] == 0xd9) {
  36.                 console.log('JPEG EOI!');
  37.                 break;
  38.             }
  39.         
  40.             //check SOF0...SOF15 segment marker
  41.             if(int32View[offset+1] >= 0xc0 && int32View[offset+1] <= 0xcf) {
  42.                 //get image information
  43.                 var imgH = (int32View[offset+5]*256) + int32View[offset+6];
  44.                 var imgW = (int32View[offset+7]*256) + int32View[offset+8];
  45.                 var result = '';
  46.                 result += 'width:' + imgW;
  47.                 result += "\n";
  48.                 result += 'height:' + imgH;
  49.                 
  50.                 document.querySelector('#result').innerText = result;
  51.                 return true;
  52.             } else {
  53.                 //go to next segment
  54.                 sizeSeg = (int32View[offset+2]*256) + int32View[offset+3];
  55.                 offset += 2 + sizeSeg;
  56.             }
  57.         }
  58.         console.log('End of File');
  59.         return false;
  60.     };
  61.     fileReader.readAsArrayBuffer(file);
  62.     
  63. };
  64. </script>
  65. </head>
  66. <body>
  67.     <h3>jpegテスト</h3>
  68.     <input id="file-input" type="file" />
  69.     <div>
  70.         <input type="button" id="test" onclick="test_click()" value="実行" />
  71.     </div>
  72.     <div id="result"></div>
  73. </body>
  74. </html>



高速に画像サイズを取得することができました。




サンプルはこちらにおいておきます。
画像サイズ取得(Image使用)
画像サイズ取得(SOF領域読み取り)
関連記事

テーマ:プログラミング - ジャンル:コンピュータ

  1. 2017/08/07(月) 22:52:46|
  2. Java
  3. | トラックバック:0
  4. | コメント:0
  5. | 編集
<<Android ListViewを使用してリストを表示する | ホーム | JavaScriptでjpeg画像のexif情報を取得する(exif-js使用)>>

コメント

コメントの投稿


管理者にだけ表示を許可する

トラックバック

トラックバック URL
http://symfoware.blog68.fc2.com/tb.php/2014-b9abd571
この記事にトラックバックする(FC2ブログユーザー)