アスペクト比(縦横比)を維持して画像を縮小・拡大する
画像を「縮小」または「拡大」する際にアスペクト比(縦横比)を維持しないと画像が潰れてしまいます。今回はアスペクト比を維持しながら、画像を縮小、拡大する方法をご紹介します。サンプルコードは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