画像のダウンロード サイズの縮小

ダウンロード トラフィックのほとんどは画像です。そのため、ダウンロード可能な画像を小さくするほど、ネットワークの使い心地が良くなります。このページは、画像ファイルを小さくし、ネットワークへの負荷を少なくするためのガイダンスとなっています。

画像形式について

Android アプリでは通常、AVIF、PNG、JPG、WebP のうち 1 つ以上のファイル形式の画像を使用します。各形式で、画像サイズを縮小する手順があります。

AVIF

Android 12(API レベル 31)以降は、AV1 画像ファイル形式(AVIF)を使用する画像をサポートしています。AVIF は、AV1 でエンコードされた画像と画像シーケンス用のコンテナ形式です。AVIF は動画圧縮からのフレーム内エンコード済みコンテンツを活用します。これにより、JPEG などの古い画像形式と比べて、同じファイルサイズでの画質が大幅に向上します。この形式のメリットについては、Jake Archibald のブログ投稿で詳しく説明されています。

PNG

PNG ファイルの縮小で重要なのは、画像を構成するピクセルの各行で使用する色数を減らすことです。色数を減らすことで、パイプラインの他のすべての段階で圧縮性が高まります。

使用する色数を減らすことには大きな効果があります。これは、PNG の圧縮効率が、部分的に、水平方向に隣接するピクセルの色が変化する度合いの関数になっているためです。したがって、PNG 画像の各行で使用する色数を減らすと、ファイルサイズが小さくなります。

この方法を採用するにあたって、色数を減らすことは、実質的に非可逆エンコードを適用することになるので、その点に注意してください。しかし、表面上の小さな誤差が人間の目にどのように映るかを、エンコード ツールが正しく判断できるとは限りません。したがって、圧縮効率と許容可能な画質との間で適切なバランスをとるために、この作業を手動で行う必要があります。

特に有用なアプローチが 2 つあります。インデックス付き形式を取り入れることと、ベクトル量子化を適用することです。

インデックス付き形式の使用

減色の手順は、画像をインデックス付きの PNG 形式でエクスポートできるように、使用する色を最適化するところから始まります。インデックス カラーモードを使用できるようにするには、最適な 256 色を選び、そのカラーパレットへのインデックスで全ピクセル値を置き換えます。その結果、最大 1,600 万色から 256 色に減色され、透過なしの場合は 1 ピクセル当たり 3 バイトから 1 バイトに、透過ありの場合は 4 バイトから 1 バイトになります。ファイルサイズ縮小のためには、最初にこの変更を行うことが重要です。

図 1 に、元の画像とインデックス付きの画像を示します。

図 1. インデックス付き形式に変換する前後の画像

図 2 に、図 1 の画像のカラーパレットを示します。

図 2. 図 1 の画像のカラーパレット

画像をパレット付き画像として表現すると、ファイルサイズを大幅に改善できるため、画像の大部分を変換できるかどうか調査する価値があります。

もちろん、すべての画像が 256 色だけで正確に表現できるとは限りません。 たとえば、正しく表示するために 257、310、512、または 912 色が必要な場合があります。このような場合、ベクトル量子化も有効です。

ベクトル量子化

インデックス付き画像の処理は、ベクトル量子化(VQ)として説明するとより明確になります。VQ は多次元数の丸め処理を行います。この処理では、画像のすべての色が類似度に基づいてグループ化されます。そのグループ内のすべての色が、1 つの中心点の値で置き換えられます。ここで、中心点は、そのセル(ボロノイの用語ではサイト)内の色に対する偏差が最小になる点です。図 3 では、緑の点が入力の色を示し、赤の点は入力の色を置き換える中心点を示しています。各セルは青い線で区切られています。

図 3. ベクトル量子化を画像の色に適用する

VQ を画像に適用すると、固有の色数が減少し、各色のグループが視覚的品質が「かなり近い」単色に置き換えられます。

この方法を使用して、画像内の最大色数を求めることもできます。たとえば、図 4 は、1,670 万色(1 ピクセル当たり 24 ビット、すなわち 24 bpp)を使ったオウムの頭の画像と、16 色(3 bpp)だけを使った画像です。

図 4. ベクトル定量化の適用前後の画像

すぐに品質の劣化があるとわかります。グラデーションがほとんどなくなり、バンディング効果が発生しています。この画像には 16 色よりも多くの色数が必要です。

パイプラインに VQ のステップを入れると、画像で実際に使用されている色の数をより正確に把握でき、色数を大幅に削減できます。この手法を実装するのにすぐ使用できるツールがいくつかあります。

JPG

JPG 画像を使用している場合、小さな変更によりファイルサイズを大幅に縮小できる可能性があります。これには以下が含まれます。

  • さまざまなエンコード方法で、品質に影響を与えずにファイルサイズを小さくする。
  • 品質をわずかに調整して圧縮率を高める。

このような方法で、多くの場合、ファイルサイズを最大 25% 削減できます。

ツールを選択する際は、写真のエクスポート ツールで GPS 情報などの不要なメタデータを画像に挿入する可能性があるのでご注意ください。最低でも、既存のツールを活用して、ファイルからこの情報を取り除くようにしてください。

WebP

WebP は、Android 4.2.1(API レベル 17)からサポートされている新しい画像形式です。この形式では、ウェブ上の画像に対する高品質な可逆圧縮と非可逆圧縮が可能です。デベロッパーは、WebP を使用して、より小さく、より高品質な画像を作成できます。WebP 非可逆圧縮画像ファイルは、PNG よりも平均で 26% 小さくなります。この画像ファイルは、透明度(アルファ チャネル)もサポートしますが、22% 大きくなるだけです。

WebP の非可逆圧縮画像は、SSIM 画質指標が同等の JPG 画像よりも、25%~34% 小さくなります。非可逆 RGB 圧縮が許容される場合、非可逆 WebP では透明度もサポートされ、通常、PNG の 3 分の 1 のファイルサイズになります。

WebP の詳細については、WebP のサイトをご覧ください。

既存の BMP、JPG、PNG、静的 GIF 画像は、Android Studio を使用して WebP 形式に変換できます。詳しくは、Android Studio を使用した WebP 画像の作成をご覧ください。

形式の選択

画像の種類によって、適した画像形式は異なります。JPG と PNG の圧縮処理は非常に異なっており、結果も大きく異なります。

PNG と JPG のどちらを選ぶかは、多くの場合、画像自体の複雑さによって決まります。図 5 は、デベロッパーが適用する圧縮方式によって大きな違いが生じる 2 つの画像を示しています。左の画像には細かな部分が多く、JPG の方が効率的に圧縮されます。右の画像は同じ色が連続するため、PNG の方が効率的に圧縮されます。

図 5. JPG が適切な場合と、PNG が適切な場合

WebP は、非可逆モードと非可逆モードの両方をサポートしているため、PNG と JPG の両方を置き換えるのに理想的です。ただし、ネイティブ サポートがあるのは、Android 4.2.1(API レベル 17)以降を搭載するデバイスのみです。幸いなことに、ほとんどのデバイスがこの要件を満たしています。

図 6 は、使用する圧縮方式を決めるのに役立つ簡単な可視化を示しています。

図 6. 圧縮方式の決定

最適な品質値を決定する

圧縮と画質の適切なバランスを実現するために使用できる手法はいくつかあります。1 つはスカラー値を使用するもので、そのため JPG と WebP にのみ使用できます。別の手法は、Butteraugli ライブラリを利用するもので、すべての画像形式に使用できます。

スカラー値(JPG と WebP のみ)

JPG と WebP の優れた性質は、スカラー値を使用してファイルサイズと品質のバランスをとれるという点に由来します。つまり、画像に適した品質値が見つかるということです。品質レベルが低すぎると、画質を犠牲にして小さなファイルが作成されます。品質レベルが高すぎると、ファイルサイズが大きくなるだけで、ユーザーにとってはあまりメリットがありません。

最も簡単な解決策は、最大でない値を使用することです。ただし、品質値の影響は画像によって異なります。たとえば、75% の品質で、ほとんどの画像はきれいに見えるかもしれませんが、うまくいかない場合もあります。必ず、選択した最大値を代表的な画像サンプルに対してテストしてください。また、すべてのテストを、圧縮されたバージョンではなく、元のイメージに対して実行してください。

1 日に数百万もの JPG をアップロードして再送信する大規模なメディア アプリケーションでは、各アセットの手動調整は実用的ではありません。この問題には、画像カテゴリに応じて異なる画質レベルを指定することで対処できます。たとえば、サムネイルの品質設定に 35% を設定しても、画像が小さいため圧縮アーティファクトは隠れてしまいます。

Butteraugli

Butteraugli プロジェクトは、画像の視覚心理的誤り上限(人間が画像の劣化に気づき始めるポイント)をテストするライブラリです。つまり、圧縮画像の劣化を定量化しようとするものです。

Butteraugli では、画質の目標を定めて、PNG、JPG、WebP 非可逆圧縮、WebP 可逆圧縮を実行できます。その後、ファイルサイズと Butteraugli レベルのバランスが最適な画像を選択できます。図 7 は、ユーザーが問題を認識できるほど視覚的な劣化が大きくならない、最低限の JPG 品質レベルを見つけるために、Butteraugli を使用する例です。その結果、ファイルサイズが約 65% 削減されます。

図 7. Butteraugli 技術を適用する前後の画像

Butteraugli では、出力または入力のどちらに基づいて進めることもできます。つまり、ユーザーが顕著な劣化を感じない最低の品質設定を探すことも、あるいはいろいろな劣化レベルを試してその品質レベルを確認することもできます。

さまざまなサイズを配信する

サーバーから配信する画像の解像度は、1 つの画像に 1 種類の解像度だけで済ませたいと考えるでしょう。デバイスが画像にアクセスすると、サーバーはその 1 種類の解像度で画像を送り返し、ダウンスケーリングはデバイスに任せます。

この方法は、デベロッパーにとっては便利ですが、必要以上に多くのデータをダウンロードする必要があるため、ユーザー側の負担が重くなります。そうではなく、複数サイズの画像を保存しておき、用途に最適なサイズを選べるようにしてください。たとえば、サムネイルでは、フルサイズの画像を配信して、それをダウンスケーリングしてもらうよりも、実際のサムネイル画像を配信する方が使用するネットワーク帯域幅が大幅に少なくなります。

この方法で、ダウンロードが高速になり、制限付きまたは従量制のデータプランを使っている場合、コストを低く抑えられます。このように処理すると、デバイスとメインメモリで画像に使用するスペースも小さくなります。4K などの大きな画像の場合、デバイスで画像を読み込む前にサイズを変更する必要もなくなります。

この方法を実装するには、適切にキャッシュを使い、異なる解像度で画像を配信するバックエンド画像サービスが必要です。この目的に利用できるサービスはすでにあります。たとえば、App Engine には画像のサイズ変更機能があらかじめインストールされています。