1. 程式人生 > >Bitmap類getPixels()詳解

Bitmap類getPixels()詳解

你也可以檢視我的其他同類文章,也會讓你有一定的收貨

getPixels()

void getPixels (int[] pixels, 
                int offset, 
                int stride, 
                int x, 
                int y, 
                int width, 
                int height)

Returns in pixels[] a copy of the data in the bitmap. Each value is a packed int representing a Color. The stride parameter allows the caller to allow for gaps in the returned pixels array between rows. For normal packed results, just pass width for the stride value. The returned colors are non-premultiplied ARGB values.

Parameters

引數名
pixels int: The array to receive the bitmap’s colors
offset int: The first index to write into pixels[]
stride int: The number of entries in pixels[] to skip between rows (must be >= bitmap’s width). Can be negative.
x int: The x coordinate of the first pixel to read from the bitmap
y int: The y coordinate of the first pixel to read from the bitmap
width int: The number of pixels to read from each row
height int: The number of rows to read

getPixels()函式把一張圖片,從指定的偏移位置(offset),指定的位置(x,y)擷取指定的寬高(width,height ),把所得影象的每個畫素顏色轉為int值,存入pixels。

stride 引數指定在行之間跳過的畫素的數目。圖片是二維的,存入一個一維陣列中,那麼就需要這個引數來指定多少個畫素換一行。

可能有的人有疑問了,直接使用引數中的width,不就可以了,幹嘛還要stride引數???

下面來看看stride引數的兩種用處,這個問題你就會明白

stride引數兩種用處

第一種:

可以擷取圖片中部分割槽域或者圖片拼接.

1.1、截圖:

假設讀取畫素值的原圖片寬為w,高為h,此時設定引數pixels[w* h], 引數stride為 w ,引數offset為0,引數x ,y為截圖的起點位置,引數width和height為截圖的寬度和高度,

則此方法執行後,返回的pixels[]陣列中從pixels[0]至pixels[width*height-1]裡儲存的是從圖片( x , y )處起讀取的截圖大小為width * height的畫素值.

示例:修改Android SDK自帶的AipDemo程式中BitmapDecode示例,更換影象為自制四角四色圖:

這裡寫圖片描述

影象大小為100*100,想擷取圖片右上1/4影象(圖上黃色部分)修改程式部分程式碼為:

//擷取圖片
mBitmap2.getPixels(pixels, 0, w, 50, 0, w/2, h/2);  

mBitmap3 = Bitmap.createBitmap(pixels, 0, w, w, h,  
                                           Bitmap.Config.ARGB_8888);  
mBitmap4 = Bitmap.createBitmap(pixels, 0, w, w, h,  
                                           Bitmap.Config.ARGB_4444);

這裡寫圖片描述

  • 生成的圖片尺寸大小是由Bitmap.createBitmap()中的第4、5個引數決定的。

1.2、改變offset

下面設定下getPixels()方法中offset,使得黃色部分截圖出現在它在原圖中的位置, offset = x + y*w ,本例程式碼如下:

顯示在右上角

offset = 50 + 0* 100

mBitmap2.getPixels(pixels, 50, w, 50, 0, w/2, h/2); 

這裡寫圖片描述

顯示在右下角

offset = 50 + 50* 100

mBitmap2.getPixels(pixels, 5050, w, 50, 0, w/2, h/2); 

這裡寫圖片描述

getPixels()是把二維的圖片的每一行畫素顏色值讀取到一個一維陣列中
offset指明瞭所擷取的圖片的第一個畫素的起始位置,如果顯示在右下角,起始座標是(50,50),這個點就是第50行,再移動50個畫素,每行100個畫素,所以在一維陣列中的位置就是50+50*100

1.3、改變stride

先給出stride的結論,

  • 在原圖上擷取的時候,需要讀取stride個畫素再去讀原圖的下一行
  • 如果一行的畫素個數足夠,就讀取stride個畫素再下一行讀
  • 如果一行的畫素個數不夠,用0(透明)來填充到 stride個
  • 得到的資料,依次存入pixels[]這個一維陣列中

stride 設定為寬度的1/2

mBitmap2.getPixels(pixels, 0, w/2, 50, 0, w/2, h/2); 

這裡寫圖片描述

stride 設為寬度的一半,上面的程式碼在擷取原圖的時候就是從(50,0)的位置讀取一半然後換行,一直這樣,直到讀取夠指定的寬高(w/2, h/2),把這些資料儲存到pixels[]中,所以在pixels[]的前2500個整數儲存的是黃色區塊的資訊。

stride 設定為寬度的2倍

mBitmap2.getPixels(pixels, 0, w/2, 50, 0, w/2, h/2); 

這裡寫圖片描述

stride 設為寬度的2倍,上面的程式碼在擷取原圖的時候就是從(50,0)的位置讀取2w個畫素然後換行,但是指定讀取的寬度為w/2,所以剩下的w3/2個值用0填充。一直這樣,直到讀取夠指定的寬高(w/2, h/2),把這些資料儲存到pixels[]中,所以在pixels[]中儲存的是{ w/2個黃色區塊資訊,w3/2個透明值 ,w/2個黃色區塊資訊,w3/2個透明值 ,……..}

所以看到左邊的黃色,感覺顏色變淡了,就是因為有透明顏色參雜進來

stride 設定為寬度的3/2倍

mBitmap2.getPixels(pixels, 0, w*3/2, 50, 0, w/2, h/2); 

這裡寫圖片描述

這個和上面的解釋一樣,下面來張大圖,讓你更好觀察

這裡寫圖片描述

stride 設定為寬度的3/2倍,起始位置為(0,0)

引數stride和width到底有什麼區別,看完下面這個例子,相信你會恍然大悟

擷取的是原圖左上角部分,stride = w*3/2;

mBitmap2.getPixels(pixels, 0, w*3/2, 0, 0, w/2, h/2); 

這裡寫圖片描述

另,pixels.length >= stride * height,否則會丟擲ArrayIndexOutOfBoundsException 異常

2: 圖片拼接

假設兩張圖片大小都為 w * h ,getPixels()方法中設定引數pixels[2*w*h],引數offset = 0,stride = 2*w讀取第一張圖片,再次執行getPixels()方法,設定引數offset = w,stride = 2*w,讀取第二張圖片,再將pixels[]繪製到畫布上就可以看到兩張圖片已經拼接起來了.

int w = mBitmap2.getWidth();  
            int h = mBitmap2.getHeight();  
            int n = 2*w;  
            Log.i(SampleView.VIEW_LOG_TAG,String.valueOf(w*h));  
            int[] pixels = new int[n*h];  
            for(int i=0; i < n*h; i++){  
                pixels[i] = -2578654;  
            }  
            mBitmap2.getPixels(pixels, 0, n, 0, 0, w, h);  
            mBitmap2.getPixels(pixels, w, n, 0, 0, w, h);  
            mBitmap3 = Bitmap.createBitmap(pixels, 0, n, n, h,  
                                           Bitmap.Config.ARGB_8888); 

執行結果如下 :

這裡寫圖片描述

第二種: 

stride表示陣列pixels[]中儲存的圖片每行的資料,在其中可以附加資訊,即
stride = width + padding,如下圖所示

這裡寫圖片描述

這樣可以不僅僅儲存圖片的畫素資訊,也可以儲存相應每行的其它附加資訊.

  • stride > width時,可以在pixels[]陣列中新增每行的附加資訊,可做它用.在使用Bitmap.createBitmap()建立新圖時,需要考慮新圖尺寸的大小

參考:
http://ranlic.iteye.com/blog/1313735 這篇部落格中,作者似乎沒有stride 的真正含義,在最後的結論一中,“用來表示pixels[]陣列中每行的畫素個數,用於行與行之間區分”,這句話理解是錯誤的。
getPixels()官方文件

關注我的公眾號,輕鬆瞭解和學習更多技術
這裡寫圖片描述