アスペクト比を保ちながら画像の縮小を行うアルゴリズム


概要

ユーザから画像の投稿を受け付ける仕組みがある
ウェブサービスやスマートフォンアプリを作成するとき、
大きすぎる画像を圧縮する1つの考え方を記述します。

結論

アスペクト比を保ちながら、
画像のファイルサイズを1MB以下に抑えるためには、
以下のようなリサイズを行えば良い。

1. 圧縮係数Cを計算する。

w:画像の幅
h:画像の高さ

C = \frac{1024}{\sqrt{3wh}}

2. 元の画像の幅と高さに圧縮係数Cを掛ける。(任意)

h_{new} = h \times C \\
w_{new} = w \times C

問題

640 x 853 の Bmp画像を1MB以下にリサイズしたい。

解法1

C = \frac{1024}{\sqrt{3wh}} = \frac{1024}{\sqrt{3 \times 640 \times 853}} \approx 0.80

圧縮率80%の画像リサイズを行えば良い。

解法2

h_{new} = h \times 0.80 = 512\\
w_{new} = w \times 0.80 = 682

幅512, 高さ682となるようリサイズすると良い。

考え方

通常であれば、圧縮係数を計算してリサイズした後、
jpg、png、gifなどの形式に圧縮されることはあっても、
画像サイズが増えるようなことはないでしょう。
したがって、以上の計算式で
1MB以下の画像サイズという制約を守ることができると考えています。

ビットマップ形式の画像

ビットマップ形式は、各ピクセル、各RGB色ごとに256段階の色を指定する画像形式である。
各色は1バイト(8ビット)なので、ピクセルごとに3バイト(24ビット)必要になる。

つまり、フルカラーのビットマップ形式の画像は、
高さと幅が決まれば、以下の計算式で算出することができる。

Filesize = w \times h \times 3

640 x 853 のフルカラービットマップ形式のファイル容量は、

Filesize = w \times h \times 3 = 1,637,760Byte = 1637760 \div 2^{20} = 1.561MByte

圧縮係数Cの導出

ファイル容量が1MBになるとき、以下の計算式が成り立つ。

Cw \times Ch \times 3 = 2^{20} \\
C^2 = \frac{2^{20}}{3wh} \\
C = \frac{1024}{\sqrt{3wh}}

640 x 853 のフルカラービットマップ形式のファイル容量を1MB以下にリサイズする。

C = \frac{1024}{\sqrt{3 \times 640 \times 853}} \approx 0.80

リサイズ後の幅と高さを計算する。

h_{new} = h \times 0.80 = 512 \\
w_{new} = w \times 0.80 = 682

検算をする。(参考)

Filesize_{new} = 512 \times 682 \times 3 = 1,047,552Byte \approx 1MByte 

画像のサイズ縮小アルゴリズム

実用する場合は、jpgやpng、gifの画像を受け取って、
今回の計算でリサイズをすると思います。

1MB以上のファイルはリサイズするアルゴリズム

  1. アップロードされた画像のファイル形式を保存。
  2. ファイルサイズが1MB以上かどうかを判断。1MB以上の場合以下を実行。
  3. 画像の高さと幅から、圧縮係数Cを計算。
  4. リサイズ。