UIImageViewとアンチエイリアス

UIImageViewで巨大な画像を表示する話です。

■■■■■■■■■■■■■■■

【初めに】

UIImageView.frame.sizeと、UIImageView.image.sizeが異なるとき、画像はUIImageView.contentModeに応じて拡大縮小されて表示されます。
このときの拡大縮小にはアンチエイリアス処理が施されるものと思っていました。

■■■■■■■■■■■■■■■

【経験したこと】

iPadで全画面表示する可能性もあれば小さなボタン程度の寸法で表示する可能性もある、そんな画像が必要になりました。
UIImageView.imageはcontentModeに応じて拡大縮小されて表示されるので、考え得る最も大きな寸法で表示したときに充分な解像度を持つ画像1枚があればよいと考えました。
ところが、そのような過剰に高解像度な画像を、単にUIImageView.imageに入れるだけではアンチエイリアス処理がかかっていないことに気付きました。

■■■■■■■■■■■■■■■

【検証】

①検証には下図の画像を使用します。
ブログ用に縮小した1枚を掲載しますが、実際には様々な画素数の画像を使用します。

f:id:b131:20210412170901j:plain

②UIImageView.frame.sizeに対する画像寸法が様々に異なるとき、どのように表示されるのかを比較します。

■■■■■■■■■■■■■■■

【結果】

①UIImageView.frame.sizeに対して画像寸法がn%の寸法のとき、それぞれの表示は下図のとおりでした。

f:id:b131:20210412171025j:plain


②「墾」の部分を拡大表示すると下図のようになります。

f:id:b131:20210412171058j:plain


■■■■■■■■■■■■■■■

【考察】

①UIImageViewの拡大縮小にアンチエイリアス処理は、施されています。

②ただし、画像寸法が極端に大きいとき、即ち画像を極端に縮小して表示するとき、アンチエイリアスの効果が小さくなります。

③UIImageView.frame.sizeに対する画像が500%以上、つまり画像を1/5以下に縮小して表示するとき、ほぼアンチエイリアスはかからないようです。

アンチエイリアス処理された自然な画像に見えるのは、200%程度までです。250%以上は違和感がある画像、500%以上は明らかにジャギーが目立ちます。

⑤UIImageView.frame.sizeに対する画像寸法は200%程度、つまり画像の縮小は1/2程度までを想定し、適切な寸法の画像を使うべきです。

■■■■■■■■■■■■■■■

【対策】

使用する機種やアプリの使い方によってUIImageView.frame.sizeの変動量が大きいとき、つまり画像を1/2より更に縮小して表示する可能性があるときは、単にUIImageをUIImageView.imageに入れるとジャギーが目立つ表示になるので対策が必要です。

①UIImageViewによる縮小ではなく、UIKitのDrawing機能でUIImageを縮小すれば、縮小量が大きい場合でも適切なアンチエイリアス処理が施されます。

②具体的なコードの例は下記のとおりです。

let resizedSize:CGSize = CGSize(width: imageView.frame.size.width), height: imageView.frame.size.height)
UIGraphicsBeginImageContextWithOptions(resizedSize, false, 0)
uiImage.draw(in: CGRect(origin: .zero, size: resizedSize))
let resizedImage:UIImage? = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
imageView.image = outputImage

・Point 1
UIGraphicsBeginImageContextWithOptionsの引数scaleを「0」にすると、Retinaディスプレイの倍率を考慮したUIImageが出力されます。

・Point 2
UIImage以外、例えばUILabelを縮小表示するなどにも応用できます。

・Point 3
機種や画像寸法にもよりますが、大きな計算コストを要することに注意が必要です。

■■■■■■■■■■■■■■■

【その他】

iOS純正「写真」アプリでは、巨大な画像でも適切にアンチエイリアス処理された表示がされているように見えます。
単に表示用のキャッシュ画像を内部で作成しているだけではないと思います。なぜならピンチインorアウト操作して画像の表示を拡大縮小しても、問題なく綺麗に表示されるからです。しかもピンチ操作にはひっかかりがなく滑らかに操作できます。
だから単にUIImageView.imageにUIImageを入れるだけでもなければ、ユーザの操作の都度Drawingしているわけでもないような気がします。
どういう仕組みなのでしょう。

■■■■■■■■■■■■■■■

この記事を作成したのは2021-4/12です。
環境は、Xcode Ver.12.4 (12D4e)、iOS 14.4です。