Bitmap(ビットマップ)完全解析その1


このセクションの概要:

前のセクションでは、Android の 13 種類の Drawable タイプについて説明しました。それらを自分のものに適用しましたか? プロジェクトについてはどうですか?このセクションでは、ビットマップのいくつかの使用法について説明します。このセクションの内容を始める前に、次のことを説明します。 まず、いくつかの名詞の概念を区別しましょう:

  • Drawable: 一般的なグラフィック オブジェクト。PNG や JPG などの一般的な形式の画像をロードするために使用されます。 これらは、以前に学習した 13 個の Drawable タイプのビジュアル オブジェクトでもあります。絵画を置く場所、つまり額縁として理解できます!
  • ビットマップ: イーゼルとして考えることができ、最初に絵を置きます。 画像ファイルの情報を取得したり、回転や切り取り、拡大や縮小などの加工を行います!
  • キャンバス: 名前が示すように、キャンバスには絵を描くことができ、ペイント(ブラシ)を使用することができます。 さまざまな図形を描いたり、文字を書いたりするには、パスを使用して複数の点を描画し、それらを接続してさまざまな図形を作成することもできます。
  • Matrix: グラフィックス特殊効果処理、カラーマトリックス (ColorMatrix)、および画像処理用のマトリックスに使用されます。 パン、ズーム、回転、チルトなど!

上記はすべて Android の基礎となるグラフィックス クラスであり、android.graphics によって提供されるインターフェイスです。 さて、さっそくこのセクションを始めましょう! PS: 公式ドキュメント: Bitmap


1. Bitmap、BitmapFactory、BitmapFacotry.Options を理解する

タイトルの通り、この 3 つの関係について直接話しても良かったのですが、ツンデレにしたいと思います。 、コード次第です! 1.gifBitmap クラスのソース コードを開くと、Bitmap の構築メソッドに次のようなものが表示されます:

2.png

私がおそらく言いたいのは、Bitmap の構築メソッドはプライベートであり、外部でインスタンス化することはできないということです。 . JNI 経由でインスタンス化します。 もちろん、ビットマップを作成するためのインターフェイスが必ず提供されます。このインターフェイス クラスは BitmapFactory! さあ、BitmapFactory クラスを開いて、左側の Structure をクリックして、BitmapFactory が提供していることを確認します。 これらのメソッドは、さまざまな形式のビットマップを作成するために提供されており、そのほとんどは decodeXxx です。

3.png

その後、各メソッドに Options タイプのパラメーターがあることがわかりました。それをクリックして確認してください。 そこで、これが静的内部クラスであることがわかりました: BitmapFacotry.Options! そして、彼はデコード中にオプションを設定するために使用されます。

4.png

ここでは、OOM (メモリ オーバーフロー) を回避するために inJustDecodeBounds を true に設定するなど、いくつかのパラメーターの値を設定します。 なんだ、OOMが分からない、大丈夫、後で説明するよ!ついにビットマップに戻りました!さて、ビットマップでは たくさんの方法があるので、一つずつ説明するのはやめます。よく使われる方法をいくつか選んで説明しましょう。 中国語のドキュメント: Android Chinese API (136) - Bitmap


2.ビットマップの共通メソッド

共通メソッド

  • public boolean compress (Bitmap.CompressFormat 形式、int 品質、OutputStream ストリーム) ビットマップを指定された OutputStream に圧縮することは、ビットマップをファイルに保存することと理解できます。 format: 形式、PNG、JPG など。 : 出力ストリーム 戻り値は、指定されたストリームへの圧縮が成功したかどうかを表します。 void recycle(): ビットマップが占有しているメモリ空間をリサイクルし、ビットマップを Dead としてマークします
  • boolean isRecycled(): ビットマップメモリ​​が解放されたかどうかを判断します
  • int getWidth(): Getビット 画像の幅
  • int getHeight(): ビットマップの高さを取得
  • boolean isMutable(): 画像が変更可能かどうか
  • int getScaledWidth(Canvas Canvas): を取得指定した濃度変換後の画像の幅
  • int getScaledHeight(Canvas Canvas): 指定した濃度変換後の画像の高さを取得
  • Staticメソッド
  • :

Bitmap createBitmap

(Bitmap src) : src を元の画像として使用して、不変の新しい画像を生成します 画像
  • Bitmap createScaledBitmap(Bitmap src, int dstWidth, int dstHeight, boolean filter): src を元の画像として使用して新しい画像を作成し、高さと新しい画像の幅とそれを変更するかどうか。
  • Bitmap createBitmap(int width, int height, Config config): 指定された形式とサイズのビットマップを作成します
  • Bitmap createBitmap(Bitmap source, int x, int y, int width, int height) は、ソースを元の画像として受け取り、新しい画像を作成し、開始座標と新しい画像の高さと幅を指定します。
  • public static Bitmap createBitmap(ビットマップソース, int x, int y, int width, int height, 行列 m、ブール フィルター)
  • BitmapFactory.Option
設定可能なパラメーター:
  • boolean inJustDecodeBounds——trueに設定すると、画像は取得されず、メモリも割り当てられませんが、画像の高さと幅の情報が返されます。
  • int in​​SampleSize——画像のスケーリングの倍数。 4 に設定すると、幅と高さは両方とも元のサイズの 1/4 になり、画像は元のサイズの 1/16 になります。
  • int outWidth——画像の幅の値を取得します
  • int outHeight——画像の高さの値を取得します
  • int in​​Density——ビットマップに使用されるピクセル圧縮率
  • int inTargetDensity—— ターゲット ビットマップ (生成するビットマップ) に使用するピクセル圧縮率
  • boolean inScaled - true に設定した場合の、inDensity から inTargetDensity までの画像圧縮。

それでは、ドキュメントを自分で確認する必要があります~


3. ビットマップ ビットマップを取得する

以下に示すように、BitmapDrawable または BitmapFactory を使用してビットマップを取得する 2 つの方法があります。 : まず、これを取得する必要があります

BitmapDrawable メソッド:

ストリームを通じて BitmapDrawable を構築するなど、BitmapDrawable オブジェクトを構築するコンストラクターを作成できます:

BitmapDrawable bmpMeizi = new BitmapDrawable(getAssets().open("pic_meizi.jpg"));
Bitmap mBitmap = bmpMeizi.getBitmap();
img_bg.setImageBitmap(mBitmap);

BitmapFactory メソッド:

はすべて静的メソッドです、リソース ID、パス、ファイル、データ ストリームなどを通じて直接呼び出して、ビットマップを取得できます。

//通过资源ID
private Bitmap getBitmapFromResource(Resources res, int resId) {
      return BitmapFactory.decodeResource(res, resId);
}

//文件
private Bitmap getBitmapFromFile(String pathName) {
      return BitmapFactory.decodeFile(pathName);
}

//字节数组
public Bitmap Bytes2Bimap(byte[] b) {
    if (b.length != 0) {
        return BitmapFactory.decodeByteArray(b, 0, b.length);
    } else {
        return null;
    }
}

//输入流
private Bitmap getBitmapFromStream(InputStream inputStream) {
      return BitmapFactory.decodeStream(inputStream);
}

4. ビットマップ関連情報の取得:

これにより、ビットマップ オブジェクトを取得する限り、関連するメソッドを呼び出して対応するパラメーターを取得し、getByteCount でサイズを取得できます。 getHeight と getWidth ~ ここでは書きません。ドキュメントを自分で確認してください。


5. 画像の特定の隅を抜き取る

場合によっては、Bitmap の createBitmap() を使用して直接クリックするだけで、画像の特定の隅を抜き取ることができます。 パラメータは次のとおりです: 処理されたビットマップ オブジェクト、開始 x、y 座標、インターセプトされた幅と高さ

Bitmap bitmap1 = BitmapFactory.decodeResource(getResources(), R.mipmap.pic_meizi);
Bitmap bitmap2 = Bitmap.createBitmap(bitmap1,100,100,200,200);
img_bg = (ImageView) findViewById(R.id.img_bg);
img_bg.setImageBitmap(bitmap2);

レンダリングの実行:

元の画像:

5.png

角を切り取る:

6.png


6. ビットマップのスケーリング

7.png

ここではビットマップのスケーリングにマトリックスを使用しませんが、ビットマップによって提供されるcreateScaledBitmapを直接使用してそれを実現します。 パラメータは次の順序です: 処理されたビットマップ オブジェクト、スケーリングされた幅と高さ、


7. ビットマップを使用してスクリーンショットを撮る

レンダリングの実行:

8.gif

実装コード:

public class MainActivity extends AppCompatActivity {
    static ByteArrayOutputStream byteOut = null;
    private Bitmap bitmap = null;
    private Button btn_cut;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        btn_cut = (Button) findViewById(R.id.btn_cut);
        btn_cut.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                captureScreen();
            }
        });
    }

    public void captureScreen() {
        Runnable action = new Runnable() {
            @Override
            public void run() {
                final View contentView = getWindow().getDecorView();
                try{
                    Log.e("HEHE",contentView.getHeight()+":"+contentView.getWidth());
                    bitmap = Bitmap.createBitmap(contentView.getWidth(),
                            contentView.getHeight(), Bitmap.Config.ARGB_4444);
                    contentView.draw(new Canvas(bitmap));
                    ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
                    bitmap.compress(Bitmap.CompressFormat.JPEG, 100, byteOut);
                    savePic(bitmap, "sdcard/short.png");
                }catch (Exception e){e.printStackTrace();}
                finally {
                    try{
                        if (null != byteOut)
                            byteOut.close();
                        if (null != bitmap && !bitmap.isRecycled()) {
//                            bitmap.recycle();
                            bitmap = null;
                        }
                    }catch (IOException e){e.printStackTrace();}

                }
            }
        };
        try {
            action.run();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void savePic(Bitmap b, String strFileName) {
        FileOutputStream fos = null;
        try {
            fos = new FileOutputStream(strFileName);
            if (null != fos) {
                boolean success= b.compress(Bitmap.CompressFormat.PNG, 100, fos);
                fos.flush();
                fos.close();
                if(success)
                    Toast.makeText(MainActivity.this, "截屏成功", Toast.LENGTH_SHORT).show();
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

コード分析:

コードは非常にシンプルで、最終的な View contentView = getWindow().getDecorView(); このコードは、現在の XML を取得するものです。 ルートノードのビュー!次に、スクリーンショットのサイズを設定し、contentView.draw(new Canvas(bitmap)) を呼び出します。 ビットマップはストリームに変換され、SD カードに書き込まれます。もちろん、スクリーンショットが変更された APP のコンテンツのみをキャプチャしていることも結果からわかります。 全画面をキャプチャしたい場合は、自分で Google してください~!


このセクションの概要:

このセクションでは、Bitmap、BitmapFactory とその静的内部クラス Options、および BitmapDrawable について説明します。 実際、基本的な使用のために必要なのは、ビットマップの作成方法を知ることだけです。その拡張機能は通常、Matrix と Canvas を通じて実装されます。 ビットマップの OOM 問題にさらに注目します。次のセクションでは、ビットマップの OOM 問題を回避する方法を学びます。 ありがとう〜9.gif