Androidの基本ビットマップの基本

序文

この記事では、画像形式とAndroidビットマップ関連の知識ポイントを紹介します。詳細については、ネイティブレイヤーのソースコードを深く掘り下げる必要があります。
SKBitmap、Skiaイメージエンジン

1.画像フォーマット

  • GIF:インデックスカラー、ロスレス圧縮、サポートアニメーション、透明度に基づき、256色のみをサポート
  • JPG:不可逆圧縮、透明チャンネルなし、アニメーションなし、カラフルな写真に適しています
  • PNG:可逆圧縮、透過チャネル、アニメーションなし
  • WEBP:非可逆および可逆圧縮のサポート、透明性、アニメーションのサポート

PNGは、色が少ない単純な画像、同じような色の広い領域、または明らかな明るさの違いに適しています
。JPGは、高い忠実度を必要とするより複雑な画像に使用されます。PNGは可逆圧縮できますが、画像ファイルは比較的大きくなります。時間、JPGの画像圧縮アルゴリズムはPNGよりも多くの時間を消費します
。WEBP:サイズは小さいですが、エンコードとデコードが遅くなります

2.画像​​が占めるメモリのサイズ

  • 1ピクセルが占めるメモリの量
    //  表示一个像素,位数越高,那么可存储的颜色信息越多,图像也就越逼真。
    public enum Bitmap.Config {
        ALPHA_8; // 只有透明通道,1个字节
        RGB_565;  //  无透明通道,2个字节,表示不透明图片较好
        ARGB_4444; // Each channel(ARGB)分别用4个像素表示,2个字节
        ARGB_8888; // Each channel(ARGB)分别用8个像素表示,4个字节
        RGBA_F16;    //  ach channel(ARGB)分别用16个像素表示,8个字节
        HARDWARE; 
    }
  • densityDpiピクセル密度(dpi、1インチあたりのドット数、またはPPI、1インチあたり
    ピクセル数):1インチあたりピクセル数と画面サイズおよび画面解像度の組み合わせ5.0インチ携帯電話の画面解像度が1280x720の場合、ピクセル密度は192dpiです(計算プロセスでは、最初に対角線上のピクセル数を計算します)。

  • 密度画面密度:
    画面密度は、160dpi = 1.0に基づくピクセル密度の別の表現です。電話機が工場から出荷された後、X軸とY軸方向のピクセル密度を含む画面密度はすべて固定値です。
    Androidは、実際の画面密度(低、中、高、および超高、超超高)を分割します
    。通常の状況での通常の画面:ldpiは120dpi、mdpiは160dpi、hdpiは240dpi、xhdpiは320dpi、xxhdpiは480dpiです。Androidは、160dpiのピクセル密度に基づいて画面を分割します。ピクセル密度が160dpiの場合、画面密度は1.0、ピクセル密度が120dpiの場合、画面密度は0.75、ピクセル密度が320dpiの場合、画面密度は2.0。

密度 densityDpi フォルダ
1倍 〜160 mdpi
1.5倍 〜240 hdpi
2倍 〜320 xhdpi
3倍 〜480 xxhdpi
4倍 〜640 xxxhdpi
  • 480 * 300 png画像がxxhdpiの下に配置され、RGB_8888がロードされます。占有されるメモリサイズは次のとおりです。
        /*
           density如下图,在哪个文件下取哪个density
           targetDensity = resources.displayMetrics.densityDpi,
           scaledWidth = int( 图片的像素宽 *inTargetDensity / inDensity(float) + 0.5) 
           scaledHeight = int(图片的像素高 *inTargetDensity / inDensity(float) + 0.5)
           占用内存大小= scaledWidth * scaledHeight * 单个像素所占内存的大小 
        */
        // 一张 480*300 的png图片放在xxhdpi下,用RGB_8888加载,占用的内存大小为:
        val inTargetDensity: Int = resources.displayMetrics.densityDpi
        val inDensity = 480F // 在哪个文件夹下

        val scaledWidth: Int = (480 * inTargetDensity / inDensity + 0.5F).toInt()
        val scaledHeight: Int = (300 * inTargetDensity / inDensity + 0.5F).toInt()

        LogUtil.e("allocationByteCount: ${bitmap.allocationByteCount}")    
        LogUtil.e("allocate: ${scaledWidth * scaledHeight * 4}")
  • 480 * 300 png画像がアセットの下に配置され(スケーリングなし)、RGB_8888がロードされます。占有されるメモリサイズは次のとおりです。
        /*
            占用内存大小= imageWidth * imageHeight * 单个像素所占内存的大小
        */
        val bitmap = BitmapFactory.decodeStream(context.assets.open("test.png"))
        LogUtil.e("allocationByteCount: ${bitmap.allocationByteCount}")
        LogUtil.e("allocationByteCount: ${bitmap.byteCount}")

        LogUtil.e("config: ${bitmap.config}")
        LogUtil.e("hasAlpha: ${bitmap.hasAlpha()}")

        val imageWidth = 480
        val imageHeight = 300

        LogUtil.e("count: ${imageWidth * imageHeight * 4}")
  • アルファチャネルの画像が565を使用してロードされた
    場合はどうなりますか?解析できない場合、デコーダーはデコードに最適な構成を選択します。bitmap.getConfig実際の設定確認できます
      /**
         * If this is non-null, the decoder will try to decode into this
         * internal configuration. If it is null, or the request cannot be met,
         * the decoder will try to pick the best matching config based on the
         * system's screen depth, and characteristics of the original image such
         * as if it has per-pixel alpha (requiring a config that also does).
         * 
         * Image are loaded with the {@link Bitmap.Config#ARGB_8888} config by
         * default.
         */
        public Bitmap.Config inPreferredConfig = Bitmap.Config.ARGB_8888;
  • RGB_4444が廃止される理由
    通常、RGBには256レベルの明るさがあり、0、1、2 ...から255までの数字で表されます。最大の数値は255ですが、0も数値の1つであるため、合計256のレベルがあることに注意してください。
    計算によると、256レベルのRGBカラーは、合計で約1,678万色、つまり256×256×256 = 16777216を組み合わせることができます。多くの場合、1600万色または数千万色と呼ばれます。24ビットカラー(2の24乗)とも呼ばれます。
    4444は半分しか意味しないため、結果として得られる画質は低くなります。

3.ビットマップメモリ​​はどこにありますか?

Android 2.3.3(APIレベル10)以下では、ビットマップのバッキングピクセルデータはネイティブメモリに保存されます。これは、Dalvikヒープに格納されているビットマップ自体とは別のものです。ネイティブメモリ内のピクセルデータは予測可能な方法で解放されないため、アプリケーションがメモリ制限を一時的に超えてクラッシュする可能性があります。
Android 3.0(APIレベル11)からAndroid 7.1(APIレベル25)まで、ピクセルデータは関連するビットマップとともにDalvikヒープに保存されます。
Android 8.0(APIレベル26)以降では、ビットマップピクセルデータはネイティブヒープに保存されます。

2.3.3より前のネイティブヒープ、3.0から8.0までのJavaヒープ、8.0以降のネイティブヒープに格納されます。

4.bitmap.recycleメソッド

  • これは高度な呼び出しであり、このビットマップへの参照がなくなると通常のGCプロセスがこのメモリを解放するため、通常は呼び出す必要はありません。
    バージョン3.0より前に手動で呼び出す必要があり、呼び出す必要はありません。 3.o以降積極的にGCが処理します

  • このビットマップに関連付けられているネイティブオブジェクトを解放し、ピクセルデータへの参照をクリアします。これにより、ピクセルデータが同期的に解放されることはなく、他に参照がない場合はガベージコレクションが可能になります。
    ただし、メモリはアクティブコール、ただしすぐには収集されませんが、GCが収集するのを待機しています

  • ビットマップは「デッド」としてマークされます。つまり、getPixels()またはsetPixels()が呼び出されると例外がスローされ、何も描画されません。この操作は元に戻せないため、呼び出されない場合にのみ呼び出す必要があります。ビットマップのさらなる使用。
    再利用および元に戻すことができない操作。確認した場合にのみ、このメソッドを呼び出します。Glideは、処理中にバッファプールのBitmapPoolからtrimToSizesを実行した場合にのみ、このメソッドを呼び出します。

おすすめ

転載: blog.csdn.net/u014099894/article/details/105522016