画像デコーダー

NDK の ImageDecoder API は、画像を直接デコードするための Android C / C++ アプリ用の標準 API を提供します。これにより、アプリ デベロッパーは Java API(JNI 経由)やサードパーティの画像デコード ライブラリを使用する必要がなくなりました。この API と Bitmap モジュール内のエンコード関数により、次のことが可能になります。

  • 独自のデコード ライブラリをリンクする必要がないため、ネイティブ アプリとライブラリのサイズを小さくすることができます。
  • アプリとライブラリは、デコード ライブラリに対するプラットフォームのセキュリティ アップデートを自動的に利用できます。
  • アプリは自身が提供する画像を直接メモリにデコードできます。さらに、アプリは(必要であれば)画像データを後処理して、OpenGL や描画コードに渡すことができます。

このページでは、API を使用して画像をデコードする方法について説明します。

可用性と機能

ImageDecoder API は、Android 11(API レベル「R」)以上をターゲットとするアプリで使用できます。実装は次のファイル内にあります。

  • imagedecoder.h(デコーダー用)
  • bitmap.h(エンコーダ用)
  • libjnigraphics.so

API は次の画像形式をサポートします。

  • JPEG
  • PNG
  • GIF
  • WebP
  • BMP

  • ICO

  • WBMP

  • HEIF

  • デジタルネガ(DNG SDK を使用)

この API は、デコードされた RAW 画像のすべての使用を処理できるようにするため、次のような高レベルのオブジェクト(Java フレームワーク内のデコード済み画像の上部に作成されたオブジェクトを含む)は提供しません。

  • Drawable オブジェクト
  • NinePatch: エンコードされた画像内に存在する場合、NinePatch のチャンクは無視されます。
  • ビットマップ密度: AImageDecoder は画面の密度に基づく自動サイズ調整は行いませんが、AImageDecoder_setTargetSize() を介して別のサイズへのデコードを行うことができます。
  • アニメーション: アニメーション GIF または WebP ファイルの最初のフレームのみをデコードします。

画像のデコード

デコードは、エンコードされた画像を表現する、なんらかの形式の入力から始まります。AImageDecoder は複数のタイプの入力を受け入れます。

  • AAsset(下記参照)
  • ファイル ディスクリプタ
  • バッファ

次のコードは、ファイルから画像 Asset を開いてデコードし、デコーダーとアセットを適切に処分する方法を示しています。デコードされた画像をレンダリングする方法の例については、Teapot サンプルをご覧ください。

AAssetManager* nativeManager = AAssetManager_fromJava(env, jAssets);
    const char* file = // Filename
    AAsset* asset = AAssetManager_open(nativeManager, file, AASSET_MODE_STREAMING);
    AImageDecoder* decoder;
    int result = AImageDecoder_createFromAAsset(asset, &decoder);
    if (result != ANDROID_IMAGE_DECODER_SUCCESS) {
      // An error occurred, and the file could not be decoded.
    }

    const AImageDecoderHeaderInfo* info = AImageDecoder_getHeaderInfo(decoder);
    int32_t width = AImageDecoderHeaderInfo_getWidth(info);
    int32_t height = AImageDecoderHeaderInfo_getHeight(info);
    AndroidBitmapFormat format =
           (AndroidBitmapFormat) AImageDecoderHeaderInfo_getAndroidBitmapFormat(info);
    size_t stride = AImageDecoder_getMinimumStride(decoder);  // Image decoder does not
                                                              // use padding by default
    size_t size = height * stride;
    void* pixels = malloc(size);

    result = AImageDecoder_decodeImage(decoder, pixels, stride, size);
    if (result != ANDROID_IMAGE_DECODER_SUCCESS) {
      // An error occurred, and the file could not be decoded.
    }

    // We’re done with the decoder, so now it’s safe to delete it.
    AImageDecoder_delete(decoder);

    // The decoder is no longer accessing the AAsset, so it is safe to
    // close it.
    AAsset_close(asset);

    // Draw the pixels somewhere

    // Free the pixels when done drawing with them
    free(pixels);