画像のサイズを動的に指定する際の理屈を忘れがちなので備忘録
梅雨明け!バンザイ!nakamura です。
例えばユーザがアップロードした画像を決まったサイズのエリアに表示するような処理。よくあると思います。(画像を動的に生成するのではなく、img タグの height と width を動的に生成するやつです。)よくある割にいまいち理屈を忘れがちなので今日は個人的な備忘録も兼ねてエントリーします。
まぁよくよく考えてみれば何てことはないのですが、、、一応順を追って整理してみましょう。
いくつかのパターンで考えてみる
仮に横 320px、縦 240px の表示エリアがあるとして、色んなサイズの画像をその中にちょうどいい感じで表示する理屈を考えてみましょう。
縦も横も表示エリアより小さい場合
赤の点線が表示エリアで、黒の実線が実画像とします。
図のように横長の画像を表示エリア内にぴったりフィットさせる場合。直感的に分かると思いますが、横辺の長さが表示エリアと同じになるよう拡大率を計算して height と width を算出してあげれば良いはずです。この場合で言うと拡大率は 320/240 = 1.33333.... 倍ということになります。仮にですが、縦辺をもとに拡大率を計算すると 240/160 = 1.5 倍です。
縦も横も表示エリアより大きい場合
最初の例とは逆のパターンです。これも直感的に分かると思いますが、横辺にあわせて拡大率を計算してあげれば良いはず。縦辺にあわせるとどう考えても横辺が飛び出してしまいますね。拡大率は 320/480 = 0.66666.... 倍です。これも仮にですが縦辺にあわせたとすると拡大率は 240/320 = 0.75 倍です。
片方の辺だけが表示エリアより大きい場合
片方の辺が表示エリアより大きく、もう片方は表示エリア内に収まっているパターンです。言うまでもないですが、大きい方の辺が表示エリア内に収まるよう縮小するのが正解です。拡大率は 240/320 = 0.75 倍です。ここでも仮に横辺にあわせるとすると拡大率は 320/160 = 2 倍になります。
結局なんなの?
色々まわりくどい書き方をしましたが、そもそも拡大と縮小という 2 つのパターンで考えるからややこしくなるわけで、拡大率はいくつなのか?という視点で考えてあげると思いのほかシンプルだったりします。結論を言うと拡大だろうが縮小だろうが縦の拡大率と横の拡大率を比較してあげて小さい方の拡大率を採用するとうまくいきます!わざわざ使わない方の拡大率も例であげていたのはその為です。
コード例
例えば素の PHP で書くとこんな感じでしょうか。
<?php
/**
* 引数に与えられた画像の最適なサイズを計算し、imgタグを生成する。
* 表示エリアは縦 240px, 横 320px 。
*
* @param string $filename 画像ファイル名
* @return string heightとwidthを動的に生成したimgタグ
*/
function generateImgTag($filename) {
// 画像の絶対パス
$filepath = "/home/projects/c-brains.jp/htdocs/img/" . $filename;
// ファイルが存在するか、読み取り可能かチェック
if (!file_exists($filepath)
|| !is_readable($filepath)) {
return false;
}
// 画像サイズ取得
$size = getimagesize($filepath);
// 縦・横それぞれの拡大率を求める
if ($size) {
$width_rate = 320 / $size[0];
$height_rate = 240 / $size[1];
// 縦・横の拡大率を比較して少ない方を採用する
if ($height_rate <= $width_rate) {
$rate = $height_rate;
} else {
$rate = $width_rate;
}
// 計算
$width = $rate * $size[0];
$height = $rate * $size[1];
// imgタグ生成
return "<img src=\"/img/{$filename}\" alt=\"{$filename}\" height=\"{$height}\" width=\"{$width}\">";
}
return false;
}
?>
終わりに
割とよくある処理なのに忘れがちなので、個人的な整理も含めて書きました。理屈自体は言語関係なく通用するものなので『あれ、どうするんだっけ?』という事があればぜひ参考にしてみてください。