ホーム > カテゴリ > HTML5・JavaScript >

アスペクト比(縦横比)を維持して画像を縮小・拡大する

画像を「縮小」または「拡大」する際にアスペクト比(縦横比)を維持しないと画像が潰れてしまいます。今回はアスペクト比を維持しながら、画像を縮小、拡大する方法をご紹介します。サンプルコードはJavaScriptですが、他の言語でも流用できます。

[元のイメージ]

[アスペクト比を維持しないリサイズ]

[アスペクト比を維持したリサイズ]

サンプルの実行例

操作方法は最初に画像を読み込んで、「幅」または「高さ」を適当に入力すると、もう片方にアスペクト比を維持したサイズが自動入力されます。

実行ボタンを押すと「幅」「高さ」のサイズで画像がリサイズされます。

※上記は実行例の画像となっております。

サンプルコード

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<script>

// キャンバス
var src_canvas; 
var src_ctx;
var dst_canvas; 
var dst_ctx;

// イメージ
var image;

window.onload = function(){   
  
  src_canvas = document.getElementById("SrcCanvas");
  src_ctx = src_canvas.getContext("2d");    
  dst_canvas = document.getElementById("DstCanvas");
  dst_ctx = dst_canvas.getContext("2d");    
  
  image = document.getElementById("img_source");
}

function run(){  

  // エラーチェック
  // ※明示的にブラウザのValidation機能(HTML5)を発動させています。
  if (!document.getElementById("num_width").checkValidity()){
    return true;
  } 
    
  if (!document.getElementById("num_height").checkValidity()){
    return true;
  } 

  // リサイズ後のサイズ
  var width  = parseInt(document.getElementById("num_width").value,10);
  var height = parseInt(document.getElementById("num_height").value,10);
  
  // エラーチェック
  if (width < 1){
     alert('この設定では画像の幅が0ピクセルになる為、実行できません。');
     return false;
  }
  
  if (height< 1){
     alert('この設定では画像の高さが0ピクセルになる為、実行できません。');
     return false;
  }    
  
  dst_canvas.width  = width;
  dst_canvas.height = height;    

  // 低品質(ブラウザの機能でリサイズ)
  dst_ctx.drawImage(image,0,0,dst_canvas.width,dst_canvas.height);  
  
  document.getElementById("msg_destination").innerHTML = 
     '[リサイズ後] ' + dst_canvas.width + ' x '  + dst_canvas.height;
  
  return false;                                
}

function setAspectRatio(option) {

  // 幅が入力された
  if (option == 1){
    if (!document.getElementById("num_width").checkValidity()) return;
    
    // 幅を基準にアスペクト比を調整する
    var size = parseInt(document.getElementById("num_width").value,10);
    var aspectratio = image.width / size;
    var another = Math.round(image.height / aspectratio);
    
    document.getElementById("num_height").value = another;
    
  // 高さが入力された  
  }else if (option == 2){
    if (!document.getElementById("num_height").checkValidity()) return;

    // 高さを基準にアスペクト比を調整する
    var size = parseInt(document.getElementById("num_height").value,10);    
    var aspectratio = image.height / size;
    var another = Math.round(image.width / aspectratio);
    
    document.getElementById("num_width").value = another;  
  } 
}

// ユーザーによりファイルが追加された  
function onAddFile(event) {
  var files;
  var reader = new FileReader();
  
  if(event.target.files){
    files = event.target.files;
  }else{ 
    files = event.dataTransfer.files;   
  }    

  // ファイルが読み込まれた
  reader.onload = function (event) {
    
    // イメージが読み込まれた
    image.onload = function (){  

      document.getElementById("num_width").value  = src_canvas.width  = image.width;
      document.getElementById("num_height").value = src_canvas.height = image.height;
        
      // キャンバスに画像を描画
      src_ctx.drawImage(image,0,0);           
      
      document.getElementById("msg_source").innerHTML =  
        '[元の画像] ' + image.width + ' x '  + image.height;      
    };      
       
    // イメージが読み込めない
    image.onerror  = function (){           
      alert('このファイルは読み込めません。');  
    };

    image.src = reader.result;       
  };
  
  if (files[0]){    
    reader.readAsDataURL(files[0]); 
  }
  document.getElementById("inputfile").value = '';
}      

</script>
</head>
<body> 
<h4>画像の読み込み</h4>
<p></p>
<form>
  <input type="file" id="inputfile" accept="image/jpeg,image/png,image/gif" onchange="onAddFile(event);">
  <p></p> 
  <table>
    <tr>
      <td>幅</td><td><input type="number" id="num_width" style="width:80px;text-align:right;" min="1" max="10000" required onkeyup="setAspectRatio(1);"> px</td>
    </tr>
    <tr>
      <td>高さ</td><td><input type="number" id="num_height" style="width:80px;text-align:right;" min="1" max="10000" required onkeyup="setAspectRatio(2);"> px</td>
    </tr>   
  </table>
  <p></p>                  
  <input type="submit" onclick="return run();" value="実行">
</form>
<p></p>

<h3 id="msg_destination">[変換後]</h3>
<p></p>    
<canvas id="DstCanvas"></canvas>
<p></p>
      
<h3 id="msg_source">[元の画像]</h3>
<p></p>  
<img id="img_source" style="display:none;">
<canvas id="SrcCanvas"></canvas>
<p></p>    

</body>
</html> 

特に解説は要らないと思いますが、setAspectRatio()でアスクペクト比を算出しています。また、リサイズはブラウザの機能でリサイズしていますので、低品質です。高品質のリサンプリングを使用したリサイズは「画像の縮小」「画像の拡大」で試せます。

高品質バイキュービック法(双三次補間)のリサンプリングによるリサイズのコードは現在は再利用、再配布不可ですが、将来的には画像エフェクトライブラリの一部としてオープンソースで公開するかも知れません。





関連記事



公開日:2016年05月18日
記事NO:01962