位圖:Bitmap
在上一節(jié)學(xué)習(xí) Drawable 圖像資源的時(shí)候我們?cè)诤芏嗟胤接玫搅?bitmap,bitmap 其實(shí)就是真實(shí)圖片在 Android 中最直接的表現(xiàn)形式,這一節(jié)我們來仔細(xì)學(xué)習(xí)一下 Bitmap 的使用。
1. 什么是 Bitmap
Bitmap 在 Android 中對(duì)應(yīng)一張圖片文件,它是一個(gè)二位系統(tǒng),通過編碼記錄了一張圖片的完整形式。以左上角為原點(diǎn),向右和向下建立一個(gè)(X , Y)坐標(biāo)系,坐標(biāo)系中的每一個(gè)點(diǎn)都成為一個(gè)“像素”。在不同編碼格式的 Bitmap 里一個(gè)像素占的 bit 數(shù)有所不同,這些 bit 共同表征了當(dāng)前像素的色值,可能是8 bit、16 bit 或者 24 bit 等等,最后將這些所有的色值組合起來就成了一張完整的原始圖片。
我們?cè)?Android 中繪制的一切圖像都是一個(gè) Bitmap,我們可以創(chuàng)建一個(gè) Bitmap 示例或者使用 Bitamp 工具來修改、優(yōu)化一個(gè)圖像資源。
2. Bitmap 的常用 API
- createBitmap(int width, int height, Bitmap.Config config):
根據(jù)傳入的寬高、創(chuàng)建一個(gè)可修改的 Bitmap 對(duì)象 - createBitmap(DisplayMetrics display, int width, int height, Bitmap.Config config):
相比上一個(gè)接口,這個(gè)可以在創(chuàng)建的時(shí)候傳入一些參數(shù) - createBitmap(Bitmap src):
根據(jù)傳入的 Bitamp 創(chuàng)建一個(gè)新的 Bitamp - copy(Bitmap.Config config, boolean isMutable):
將 Bitamp 對(duì)象的所有像素復(fù)制到一個(gè)新的 Bitmap 當(dāng)中 - extractAlpha():
提取原始 Bitmap 的透明度并返回一個(gè)新的 Bitamp - getConfig():
獲取 Bitamp 的配置信息 - getDensity():
返回 Bitamp 的圖片像素密度 - getRowBytes():
返回 Bitamp 圖片的像素字節(jié)數(shù)組 - setPixel(int x, int y, int color):
設(shè)置圖片的(x, y)坐標(biāo)點(diǎn)上的色值 - setDensity(int density):
設(shè)置圖片像素密度
3. 獲取 Bitamp 實(shí)例
Android 提供了多種方法獲取 Bitamp 實(shí)例,我們可以直接從 ImageView 上拿到當(dāng)前設(shè)置的圖片的 Bitamp 對(duì)象:
private Bitmap bmp;
private ImageView img;
img = (ImageView)findViewById(R.id.imageView);
BitmapDrawable drawable = (BitmapDrawable)img.getDrawable();
bmp = drawable.getBitmap();
從上面的代碼中也可以看到我們可以通過 Drawable 的getBitmap()
方法從 Drawable 對(duì)象中提取出 Bitamp。
Android 還提供了一個(gè) BitampFractory 工廠對(duì)象,專門讓我們?nèi)カ@取 Bitmap 實(shí)例,主要有以下幾種常用方法:
// 從資源文件中解碼出 Bitmap
private Bitmap getBitmapFromResource(Resources res, int resId) {
return BitmapFactory.decodeResource(res, resId);
}
// 從圖片文件中獲取
private Bitmap getBitmapFromFile(String pathName) {
return BitmapFactory.decodeFile(pathName);
}
// 從像素?cái)?shù)組中獲取
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. Bitmap 使用示例
通過這兩節(jié)的學(xué)習(xí),我們知道 Drawable 和 Bitmap 可以相互轉(zhuǎn)換,接下來編寫一個(gè)示例完成將 ImageView 中的 Drawable 對(duì)象保存到本地的示例程序。
4.1 MainActivity 截圖功能
package com.emercy.myapplication;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class MainActivity extends Activity {
static ByteArrayOutputStream byteOut = null;
private Bitmap bitmap = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button btn_cut = (Button) findViewById(R.id.button);
btn_cut.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
capture();
}
});
}
public void capture() {
Runnable action = new Runnable() {
@Override
public void run() {
final View contentView = getWindow().getDecorView();
try {
bitmap = Bitmap.createBitmap(contentView.getWidth(),
contentView.getHeight(), Bitmap.Config.ALPHA_8);
contentView.draw(new Canvas(bitmap));
ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, byteOut);
save(bitmap);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (null != byteOut)
byteOut.close();
if (null != bitmap && !bitmap.isRecycled()) {
bitmap = null;
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
};
try {
action.run();
} catch (Exception e) {
e.printStackTrace();
}
}
private void save(Bitmap b) {
FileOutputStream fos;
try {
fos = new FileOutputStream("sdcard/short.png");
boolean success = b.compress(Bitmap.CompressFormat.PNG, 80, fos);
fos.flush();
fos.close();
if (success) {
Toast.makeText(MainActivity.this, "截圖完成", Toast.LENGTH_SHORT).show();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
在capture()
方法中,我們獲取當(dāng)前 Activity 的“DecorView”(Activtiy 的頂層 View,我們?cè)O(shè)置的 CotentView 是其子 View),然后獲取 DecorView 的輸入流并會(huì)轉(zhuǎn)化成 Bitmap,最后直接輸出到文件中即可。
4.2 布局文件
這一節(jié)的布局文件可以任意,你可以嘗試寫出各種復(fù)雜的 UI 樣式,因?yàn)樯厦娴?code>capture()方法是從“DecorView”中獲取 Bitmap,所以無論你寫了多少 View,最終都會(huì)通過setContentView()
設(shè)置到“ContentView”中,而 ContentView 也是在 DecorView 中的,所以無論怎么寫都逃離不開截圖范圍,最后記得加一個(gè) Button 用于觸發(fā)截屏。
5. 小結(jié)
本節(jié)進(jìn)一步講述了 Andorid 圖像相關(guān)的內(nèi)容,相比 Drawable,Bitmap 直接對(duì)應(yīng)一張圖片,更加具體。它可以與 Drawable 相互轉(zhuǎn)化,并提供了多種 API 來直接操作一張圖片,在做圖片裁剪和修改的場(chǎng)景非常適用。