官术网_书友最值得收藏!

4.8 使用位圖操作類Bitmap

類Bitmap的完整寫法是Android.Graphics.Bitmap,此類能夠對位圖實現基本操作。類Bitmap的功能最復雜,其中最為常用的是如下8個方法。

· boolean compress(Bitmap.CompressFormat format, int quality, OutputStream stream):壓縮一個Bitmap對象,根據相關的編碼、畫質保存到一個OutputStream中。其中第1個壓縮格式目前有JPG和PNG;

· void copyPixelsFromBuffer(Buffer src):從一個Buffer緩沖區復制位圖像素;

· void copyPixelsToBuffer(Buffer dst):將當前位圖像素內容復制到一個Buffer緩沖區;

· final int getHeight():獲取高度;

· final int getWidth():獲取寬度;

· final boolean hasAlpha():是否有透明通道;

· void setPixel(int x, int y, int color):設置某像素的顏色;

· int getPixel(int x, int y):獲取某像素的顏色。

4.8.1 Bitmap類的功能

1. 從資源中獲取位圖

可以使用BitmapDrawable或者BitmapFactory來獲取資源中的位圖。首先需要獲取資源:

Resources res=getResources();

(1)使用BitmapDrawable獲取位圖的基本流程如下。

step 1 使用BitmapDrawable (InputStream is)構造一個BitmapDrawable。

step 2 使用BitmapDrawable類的getBitmap()獲取得到位圖。

例如,通過下面的代碼讀取InputStream并得到位圖:

InputStream is=res.openRawResource(R.drawable.pic180);
BitmapDrawable bmpDraw=new BitmapDrawable(is);
Bitmap bmp=bmpDraw.getBitmap();

也可以采用下面的方式:

BitmapDrawable bmpDraw=(BitmapDrawable)res.getDrawable(R.drawable.pic180);
Bitmap bmp=bmpDraw.getBitmap();

(2)使用BitmapFactory獲取位圖。

使用BitmapFactory類decodeStream(InputStream is)解碼位圖資源,然后獲取位圖。

Bitmap bmp=BitmapFactory.decodeResource(res, R.drawable.pic180);

BitmapFactory的所有函數都是靜態的,這個輔助類可以通過資源ID、路徑、文件、數據流等方式來獲取位圖。

以上方法在編程的時候讀者可以自由選擇,在Android SDK說明中可以支持的圖片格式如下:png(preferred)、jpg(acceptable)、gif(discouraged)和bmp(Android SDK Support Media Format)。

2. 獲取位圖的信息

要獲取位圖信息,如獲取位圖大小、像素、密度、透明度、顏色格式等,得到Bitmap就迎刃而解了,這些信息在Bitmap的手冊中,這里需要說明以下兩點:

(1)在Bitmap中對RGB顏色格式使用Bitmap.Config定義,僅包括ALPHA_8、ARGB_4444、ARGB_8888、RGB_565,缺少了一些其他元素,如RGB_555,在開發中可能需要注意這個小問題;

(2)Bitmap還提供了compress()接口來壓縮圖片,不過Android SDK只支持PNG、JPG格式的壓縮,其他格式的需要Android開發人員自己補充。

3. 顯示位圖

可以使用核心類Canvas來顯示位圖,通過Canvas類的drawBitmap()顯示位圖,或者借助于BitmapDrawable來將Bitmap繪制到Canvas。當然,也可以通過BitmapDrawable將位圖顯示到View中。

(1)轉換為BitmapDrawable對象顯示位圖,代碼示例如下。

// 獲取位圖
Bitmap bmp=BitmapFactory.decodeResource(res, R.drawable.pic180);
// 轉換為BitmapDrawable對象
BitmapDrawable bmpDraw=new BitmapDrawable(bmp);
// 顯示位圖
ImageView iv2 = (ImageView)findViewById(R.id.ImageView02);
iv2.setImageDrawable(bmpDraw);

(2)使用Canvas類顯示位圖。

在此可以采用一個繼承自View的子類Panel,在子類的OnDraw中顯示,具體代碼如下所示。

public class MainActivity extends Activity {
@Override
  public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(new Panel(this));
  }
  class Panel extends View{
  public Panel(Context context) {
  super(context);
  }
  public void onDraw(Canvas canvas){
  Bitmap bmp = BitmapFactory.decodeResource(getResources(), R.drawable.pic180);
  canvas.drawColor(Color.BLACK);
  canvas.drawBitmap(bmp, 10, 10, null);
  }
  }
 }

4.8.2 Bitmap應用實例

實例4-6 使用Bitmap類模擬水紋效果(daima\4\BitmapCH1)。

本實例是Bitmap類的成名實例,實例文件BitmapCH1.java的主要代碼如下所示。

public class BitmapCH1 extends View implements Runnable
{
    int BACKWIDTH;
    int BACKHEIGHT;
    short[] buf2;
    short[] buf1;
    int[] Bitmap2;
    int[] Bitmap1;
      public BitmapCH1(Context context)
      {
          super(context);
          /* 裝載圖片 */
      Bitmap      image = BitmapFactory.decodeResource(this.getResources(),R.drawable.qq);
      BACKWIDTH = image.getWidth();
      BACKHEIGHT = image.getHeight();
        buf2 = new short[BACKWIDTH * BACKHEIGHT];
        buf1 = new short[BACKWIDTH * BACKHEIGHT];
        Bitmap2 = new int[BACKWIDTH * BACKHEIGHT];
        Bitmap1 = new int[BACKWIDTH * BACKHEIGHT];
        /* 加載圖片的像素到數組中 */
        image.getPixels(Bitmap1, 0, BACKWIDTH, 0, 0, BACKWIDTH, BACKHEIGHT);
          new Thread(this).start();
      }
    void DropStone(int x,// x坐標
                  int y,// y坐標
                  int stonesize,// 波源半徑
                  int stoneweight)// 波源能量
      {
          for (int posx = x - stonesize; posx < x + stonesize; posx++)
            for (int posy = y - stonesize; posy < y + stonesize; posy++)
                if ((posx - x) * (posx - x) + (posy - y) * (posy - y) < stonesize * stonesize)
                    buf1[BACKWIDTH * posy + posx] = (short) -stoneweight;
      }
    void RippleSpread()
      {
          for (int i = BACKWIDTH; i < BACKWIDTH * BACKHEIGHT - BACKWIDTH; i++)
          {
            // 波能擴散
            buf2[i]=(short)(((buf1[i-1]+buf1[i+1]+buf1[i-BACKWIDTH]+buf1[i+ BACKWIDTH]) >> 1) - buf2[i]);
            // 波能衰減
            buf2[i] -= buf2[i] >> 5;
          }
          // 交換波能數據緩沖區
          short[] ptmp = buf1;
          buf1 = buf2;
          buf2 = ptmp;
  }
 /* 渲染水紋效果 */
  void render()
  {
    int xoff, yoff;
    int k = BACKWIDTH;
    for (int i = 1; i < BACKHEIGHT - 1; i++)
    {
        for (int j = 0; j < BACKWIDTH; j++)
        {
            //計算偏移量
            xoff = buf1[k - 1] - buf1[k + 1];
            yoff = buf1[k - BACKWIDTH] - buf1[k + BACKWIDTH];
            //判斷坐標是否在窗口范圍內
            if ((i + yoff) < 0)
            {
                k++;
                continue;
            }
            if ((i + yoff) > BACKHEIGHT)
            {
                k++;
                continue;
            }
            if ((j + xoff) < 0)
            {
                k++;
                continue;
            }
            if ((j + xoff) > BACKWIDTH)
            {
                k++;
                continue;
            }
            //計算出偏移像素和原始像素的內存地址偏移量
            int pos1, pos2;
            pos1 = BACKWIDTH * (i + yoff) + (j + xoff);
            pos2 = BACKWIDTH * i + j;
            Bitmap2[pos2++] = Bitmap1[pos1++];
            k++;
        }
    }
  }
  public void onDraw(Canvas canvas)
  {
    super.onDraw(canvas);
    /* 繪制經過處理的圖片效果 */
    canvas.drawBitmap(Bitmap2, 0, BACKWIDTH, 0, 0, BACKWIDTH, BACKHEIGHT, false, null);
  }
  //觸筆事件
  public boolean onTouchEvent(MotionEvent event)
  {
    return true;
  }
  //按鍵按下事件
  public boolean onKeyDown(int keyCode, KeyEvent event)
  {
    return true;
  }
  //按鍵彈起事件
  public boolean onKeyUp(int keyCode, KeyEvent event)
  {
    DropStone(BACKWIDTH/2, BACKHEIGHT/2, 10, 30);
    return false;
  }
  public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event)
  {
    return true;
  }
  /*線程處理*/
  public void run()
  {
    while (!Thread.currentThread().isInterrupted())
    {
        try
        {
            Thread.sleep(50);
        }
        catch (InterruptedException e)
        {
            Thread.currentThread().interrupt();
        }
      RippleSpread();
      render();
        //使用postInvalidate可以直接在線程中更新界面
        postInvalidate();
    }
  }
}

執行后將通過對圖像像素的操作來模擬水紋效果,如圖4-6所示。

圖4-6 執行效果

實例 4-7 使用Bitmap類旋轉一幅圖片(daima\4\BitmapCH2)。

本實例是影響Bitmap類一生的實例,實現流程如下所示。

step 1 編寫布局文件main.xml,實現整體布局,主要代碼如下。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:background="@drawable/white"
  android:orientation="vertical"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"
  >
  <TextView
    android:id="@+id/myTextView1"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:text="@string/app_name"/>
  <LinearLayout
  android:orientation="horizontal"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
>
  <Button
    android:id="@+id/myButton1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/str_button1" />
  <ImageView
    android:id="@+id/myImageView1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center" />
  <Button
    android:id="@+id/myButton2"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/str_button2" />
  </LinearLayout>
</LinearLayout>

step 2 編寫處理文件BitmapCH2.java,分別實現左旋轉按鈕事件mButton1.setOnClickListener和右旋轉按鈕事件mButton2.setOnClickListener。文件BitmapCH2.java的主要實現代碼如下所示。

public class BitmapCH2 extends Activity
{
  private Button mButton1;
  private Button mButton2;
  private TextView mTextView1;
  private ImageView mImageView1;
  private int ScaleTimes;
  private int ScaleAngle;
  public void onCreate(Bundle savedInstanceState)
  {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    mButton1 =(Button) findViewById(R.id.myButton1);
    mButton2 =(Button) findViewById(R.id.myButton2);
    mTextView1 = (TextView) findViewById(R.id.myTextView1);
    mImageView1 = (ImageView) findViewById(R.id.myImageView1);
    ScaleTimes = 1;
    ScaleAngle = 1;
    final Bitmap mySourceBmp =
    BitmapFactory.decodeResource(getResources(), R.drawable.hippo);
    final int widthOrig = mySourceBmp.getWidth();
    final int heightOrig = mySourceBmp.getHeight();
    /* 程序剛運行,加載默認的Drawable */
    mImageView1.setImageBitmap(mySourceBmp);
    /* 向左旋轉按鈕 */
    mButton1.setOnClickListener(new Button.OnClickListener()
    {
@Override
public void onClick(View v)
{
    // TODO Auto-generated method stub
    ScaleAngle--;
    if(ScaleAngle<-5)
    {
      ScaleAngle = -5;
    }
    /* ScaleTimes=1,維持1:1的寬高比例*/
    int newWidth = widthOrig * ScaleTimes;
    int newHeight = heightOrig * ScaleTimes;
    float scaleWidth = ((float) newWidth) / widthOrig;
    float scaleHeight = ((float) newHeight) / heightOrig;
    Matrix matrix = new Matrix();
    /* 使用Matrix.postScale設置維度 */
    matrix.postScale(scaleWidth, scaleHeight);
    /* 使用Matrix.postRotate方法旋轉Bitmap*/
    //matrix.postRotate(5*ScaleAngle);
    matrix.setRotate(5*ScaleAngle);
    /* 創建新的Bitmap對象 */
    Bitmap resizedBitmap =
    Bitmap.createBitmap
    (mySourceBmp, 0, 0, widthOrig, heightOrig, matrix, true);
    BitmapDrawable myNewBitmapDrawable =
    new BitmapDrawable(resizedBitmap);
    mImageView1.setImageDrawable(myNewBitmapDrawable);
    mTextView1.setText(Integer.toString(5*ScaleAngle));
  }
});
/* 向右旋轉按鈕 */
mButton2.setOnClickListener(new Button.OnClickListener()
{
  @Override
  public void onClick(View v)
  {
    ScaleAngle++;
    if(ScaleAngle>5)
    {
      ScaleAngle = 5;
    }
    /* ScaleTimes=1,維持1:1的寬高比例*/
    int newWidth = widthOrig * ScaleTimes;
    int newHeight = heightOrig * ScaleTimes;
    /* 計算旋轉的Matrix比例 */
    float scaleWidth = ((float) newWidth) / widthOrig;
    float scaleHeight = ((float) newHeight) / heightOrig;
    Matrix matrix = new Matrix();
        /* 使用Matrix.postScale設置維度 */
        matrix.postScale(scaleWidth, scaleHeight);
        /* 使用Matrix.postRotate方法旋轉Bitmap*/
        //matrix.postRotate(5*ScaleAngle);
        matrix.setRotate(5*ScaleAngle);
        /* 創建新的Bitmap對象 */
        Bitmap resizedBitmap =
        Bitmap.createBitmap
        (mySourceBmp, 0, 0, widthOrig, heightOrig, matrix, true);
        BitmapDrawable myNewBitmapDrawable =
        new BitmapDrawable(resizedBitmap);
        mImageView1.setImageDrawable(myNewBitmapDrawable);
        mTextView1.setText(Integer.toString(5*ScaleAngle));
      }
    });
  }
}

執行后將顯示一幅圖片和兩個按鈕,單擊“左轉”和“右轉”按鈕,會實現對圖片的旋轉處理,如圖4-7所示。

圖4-7 執行效果

主站蜘蛛池模板: 福贡县| 朝阳市| 永吉县| 龙游县| 饶阳县| 四子王旗| 邢台市| 屯昌县| 新干县| 额敏县| 新蔡县| 周宁县| 城口县| 万全县| 成都市| 曲水县| 彝良县| 福泉市| 永修县| 潮安县| 田林县| 军事| 罗田县| 三江| 杨浦区| 普兰店市| 同德县| 宁化县| 庆云县| 荥阳市| 潮安县| 周宁县| 扶余县| 房产| 都安| 津市市| 赣州市| 平陆县| 县级市| 广安市| 卓资县|