こんにちは。Androidエンジニアの宮本です。 マネーフォワード クラウド確定申告アプリの開発を担当しています。
本記事ではCamera Xライブラリの最新機能であるResolutionSelector APIを使った、既存APIの置き換えや高解像度撮影への対応方法について紹介します。
もしCamera Xライブラリについてまだご存知でない方は、私がDroidKaigi 2022で発表した「Camera Xライブラリの魅力と最新機能を紐解く」のセッションをぜひご覧ください。
はじめに
2023年4月19日にCamera Xライブラリのv1.3.0-alpha06がリリースされました。
このリリースでは新しくResolutionSelector APIというものが追加されており、カメラの解像度・アスペクト比の設定方法に関して変更が入っています。
また、以前のバージョンまででは実現できなかった一部端末での高解像度画像撮影が実現できるオプションが追加されています。
ResolutionSelector APIを使った解像度の設定
これまでカメラのプレビューや画像撮影の際にアプリケーション側で任意の解像度を設定するには、以下のように各UseCaseに対してsetTargetResolution()
を使用していました。
val imageCapture = ImageCapture.Builder() .setTargetResolution(Size(1920, 1080)) .build()
v1.3.0-alpha06ではこのAPIはdeprecatedになっています。
各UseCaseのBuilderにsetResolutionSelector()
が追加されているので、この引数にResolutionSelector
を設定することで代替することができます。
初めにResolutionSelector APIを使った解像度の設定について見てみましょう。以下のようにsetResolutionStrategy()
を使ってResolutionStrategy
を設定します。
val imageCapture = ImageCapture.Builder() .setResolutionSelector( ResolutionSelector.Builder() .setResolutionStrategy(ResolutionStrategy(Size(1080, 1920), ResolutionStrategy.FALLBACK_RULE_CLOSEST_HIGHER_THEN_LOWER)) .build() ) .build()
ResolutionStrategy
はboundSize
とfallbackRule
の2つのパラメータを持ちます。
boundSize
には使用したい解像度をSize型で指定します。
fallbackRule
はboundSize
で指定した解像度がデバイスでサポートされていない場合に、代替の解像度を設定するかどうかを決定できます。
fallbackRule
に指定できる定数はいくつかあり、例えばFALLBACK_RULE_CLOSEST_HIGHER_THEN_LOWER
は指定した解像度が利用できない場合にそれに最も近く、かつ高い解像度が設定しようとします。もしその解像度が存在しないなどの理由で利用できない場合は他の最も低い解像度を選択しようとします。
setResolutionStrategy()
を設定しない場合は、デフォルト値のResolutionStrategy.HIGHEST_AVAILABLE_STRATEGY
が設定され、デバイスが使用可能な最大解像度が設定されます。
また、fallbackRule
のデフォルト値のFALLBACK_RULE_NONE
では代替の解像度を設定することなく、UseCaseがbindされたときにIllegalArgumentExceptionがthrowされます。
基本的にはFALLBACK_RULE_NONE
以外の定数を指定してエラーが起きないようにするのが良いでしょう。
ResolutionSelector APIを使ったアスペクト比の設定
次にResolutionSelector APIを使ったアスペクト比の設定について見てみましょう。
これまでは以下のようにsetTargetAspectRatio()
を使用していましたが、こちらもdeprecatedになっています。
val preiview = Preview.Builder() .setTargetAspectRatio(AspectRatio.RATIO_16_9) .build()
v1.3.0-alpha06からは以下のようにsetAspectRatioStrategy()
を使ってAspectRatioStrategy
を設定します。
val preiview = Preview.Builder() .setResolutionSelector( ResolutionSelector.Builder() .setAspectRatioStrategy(AspectRatioStrategy(AspectRatio.RATIO_16_9, AspectRatioStrategy.FALLBACK_RULE_AUTO)) .build() ) .build()
AspectRatioStrategy
はpreferredAspectRatio
とfallbackRule
の2つのパラメータを持ちます。
preferredAspectRatio
には使用するアスペクト比をAspectRatio.RATIO_4_3
かAspectRatio.RATIO_16_9
で指定します。
fallbackRule
にはpreferredAspectRatio
で指定したアスペクト比の解像度が一つもデバイスでサポートされていない場合に、代替のアスペクト比を設定するかどうかを決定できます。
FALLBACK_RULE_AUTO
を指定すると別の最適なアスペクト比が設定されます。
FALLBACK_RULE_NONE
を指定すると代替のアスペクト比が設定されることなく、UseCaseがbindされたときにIllegalArgumentExceptionがthrowされます。
setAspectRatioStrategy()
を指定しない場合、デフォルトでAspectRatio.RATIO_4_3
とFALLBACK_RULE_AUTO
が適用されるRATIO_4_3_FALLBACK_AUTO_STRATEGY
が設定されます。
基本的にはRATIO_4_3_FALLBACK_AUTO_STRATEGY
もしくはRATIO_16_9_FALLBACK_AUTO_STRATEGY
を指定してエラーが起きないようにするのが良いでしょう。
デバイスが使用できる解像度の候補を制限する
setResolutionFilter()
を使用することで、デバイスがサポートしている解像度を取得して、使用できる解像度の候補を制限することができます。
以下は1920×1080以上の解像度のみ利用できるように制限する例です。
val imageCapture = ImageCapture.Builder() .setResolutionSelector( ResolutionSelector.Builder() .setResolutionFilter { supportedSizes, rotationDegrees -> supportedSizes.filter { it.width >= 1080 && it.height >= 1920} } .build() ) .build()
一部デバイスで実現できなかった高解像度画像撮影が可能になった
これまでCamera Xライブラリを使ったカメラアプリにおいて、一部のデバイスで撮影した画像の解像度が、プリインストールされているカメラアプリやCamera 2 APIで撮影された画像よりも低い事象が起きていました。
以下はとあるデバイスにてStreamConfigurationMap.getOutputSizes()
とStreamConfigurationmap.getHighResolutionOutputSizes()
で出力した、サポートされている解像度のListです。
getHighResolutionOutputSizes : [4208x2368, 4208x2048, 4160x3120, 3120x3120] getOutputSizes : [1920x1080, 1480x720, 1280x720, 1080x1080, 960x720, 720x720, 720x480, 640x480, 352x288, 320x240, 176x144]
このように特定の高解像度がgetHighResolutionOutputSize()
でのみ取得できます。
これまでこれらの高解像度はCamera Xでは使用することができず、issue trackerにも起票されていましたが、setAllowedResolutionMode()
が追加されたことで使用できるようになりました。
※ v1.3.0-alpha07でsetHighResolutionEnabledFlag()
からsetAllowedResolutionMode()
に名前が変更されています。
val imageCapture = ImageCapture.Builder() .setResolutionSelector( ResolutionSelector.Builder() .setAllowedResolutionMode(ALLOWED_RESOLUTIONS_SLOW) .build() ) .build()
このようにALLOWED_RESOLUTIONS_SLOW
を指定することでCamera Xが利用可能な解像度の候補にgetHighResolutionOutputSizes()
で取得できる解像度が含まれるようになります。
デフォルトではALLOWED_RESOLUTIONS_NORMAL
が設定されています。
このフラグを有効にすることで撮影に時間がかかる場合があるため、ProgressIndicatorなどを表示して処理中であることをユーザーに伝えるなどすると良いでしょう。
おわりに
Camera X v1.3.0-alpha06で追加されたResolutionSelector APIについて調べたことをまとめました。
個人的にはDroidKaigi 2022で発表した時点ではできなかった高解像度撮影のサポートがようやく実現されて嬉しく感じています。
Camera XライブラリはCamera 2 APIと比較してとても使いやすいものになっているので可能なら乗り換えることをおすすめします。
GihHubでJetpack ComposeでCamera Xライブラリを使用したサンプルプロジェクトを公開していますので、参考になれば幸いです。