Bitmap 之 getPixels() 的 stride

學習Graphics中遇到位圖(Bitmap)中getPixels()方法,對該方法的用法大致理解,但對其中的stride參數卻不明白具體的用法以及用意,現記述過程以下:html

getPixels()方法的用處爲獲取位圖(Bitmap)中的像素值(顏色值),存入類型爲int的pixels數組中,至於從RGB轉換爲int數值的算法是什麼,暫時不知,存疑!! java


Android英文SDK中有關getPixels()方法的介紹以下: 
android

算法

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

Since: API Level 1數組

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.app

Parameters
pixels The array to receive the bitmap's colors
offset The first index to write into pixels[]
stride The number of entries in pixels[] to skip between rows (must be >= bitmap's width). Can be negative.
x The x coordinate of the first pixel to read from the bitmap
y The y coordinate of the first pixel to read from the bitmap
width The number of pixels to read from each row
height The number of rows to read
Throws
IllegalArgumentException if x, y, width, height exceed the bounds of the bitmap, or if abs(stride) < width.
ArrayIndexOutOfBoundsException if the pixels array is too small to receive the specified number of pixels. 



看完英文文檔仍然不甚明白,因而去搜了下中文Android文檔相應內容, getPixels()

ide

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

把位圖的數據拷貝到pixels[]中。每個都由一個表示顏色值的int值來表示。幅度參數(stride)代表調用者容許的像素數組行間距。對一般的填充結果,只要傳遞寬度值給幅度參數。ui

參數

pixels       接收位圖顏色值的數組

offset      寫入到pixels[]中的第一個像素索引值

stride       pixels[]中的行間距個數值(必須大於等於位圖寬度)。能夠爲負數

x             從位圖中讀取的第一個像素的x座標值。

                 y             從位圖中讀取的第一個像素的y座標值

                 width       從每一行中讀取的像素寬度

                 height   讀取的行數               

  異常

                   IllegalArgumentExcepiton                 若是xywidthheight越界或stride的絕對值小於位圖寬度時將被拋出。

                   ArrayIndexOutOfBoundsException          若是像素數組過小而沒法接收指定書目的像素值時將被拋出。


看完後仍然對Stride解釋中的"行間距"不太明白,去查了下Stride在英語中的原義,Stride在柯林斯中的英英釋義以下: 

1 If you stride somewhere, you walk there with quick, long steps. 
  stride意爲"大踏步快速前進" 
2 A stride is a long step which you take when you are walking or running. 
  stride在此作名詞,意爲"大步" 
3 Someone's stride is their way of walking with long steps. 
  指代某人具體邁大步的方式. 

因而能夠把stride理解爲人行走過程當中所邁大步的一段距離,而在此方法中能夠理解爲每行的像素數,至於用處是什麼,還要繼續尋找答案. 

而後去StackOverFlow去搜了搜"getPixels() stride"關鍵字,查找到以下信息: 

1 In most cases the stride is the same as the width. The stride is useful if you are trying to copy/draw a sub-region of a Bitmap. For instance, if you have a 100x100 bitmap and you want to draw the 50x50 top-right corner, you can use a width of 50px and a stride of 100px.(注:stride絕對值要大於等於位圖的寬度)

2 Stride is number of bytes used for storing one image row.

Stride can be different from the image width. 

Most of the images are 4 byte aligned.

For ex. a 24 bit (RGB) image with width of 50 pixels. The total bytes required will be 150 (3(RGB)*50). As image will be 4 byte aligned, in this case the byte required will become 154. 

So you will see stride as 154, width 50 and image alignment as 4 byte.

上面內容表示stride參數有兩種用處 

第一種
: 
能夠截取圖片中部分區域或者圖片拼接. 

截圖:假設讀取像素值的原圖片寬爲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圖像(圖上黃色部分)修改程序部分代碼爲: 

[java] view plaincopyprint?

  1. int[] pixels = new int[w*h];  

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

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

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

  5. String txt = String.valueOf(pixels[10]);  

  6. Log.i("myBitmapDecode""w = " + w + "; h = " + h);  

  7. Log.i("myBitmapDecode""pixels[0] = " + pixels[0] + "; pixels[1] = " + pixels[1] + "; pixels[10] = " + pixels[10]);  

  8. Log.i("myBitmapDecode""pixels[w] = " + pixels[w] + "; pixels[h] = " + pixels[h] + "; pixels[w*h-1] = " + pixels[w*h-1]);  

運行結果: 

I/myBitmapDecode(  660): w = 100; h = 100
I/myBitmapDecode(  660): pixels[0]-16777216; pixels[1] = -16777216; 
pixels[10] = -4352
I/myBitmapDecode(  660): pixels[w]-16777216; pixels[h] = -16777216; pixels[w*h-1] = 0

咱們看到右邊兩副ARGB_8888,ARGB_4444圖像隱約只在左上角顯示原圖右上的1/4黃色部分,其他部分爲背景色白色,那麼問題又來了,此時ARGB_8888,ARGB_4444圖像大小爲多少?仍是原圖的大小(100*100)嗎,或者是(50*50)了,否則背景色爲什麼是畫布的背景色呢(白色)?那麼把 pixels[100*100]數組設初始值看下狀況(經過Log.i()我查到了pixels中存儲的像素值爲百萬左右的負整數(-16777216),因此這裏胡亂取個數-2578654作爲初始值,顏色不太好,請見諒),修改後代碼以下: 

[java] view plaincopyprint?

  1. int[] pixels = new int[w*h];  

  2. for(int i=0; i<w*h; i++){  

  3.     pixels[i] = -2578654;   

  4. }  

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

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

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

  8. String txt = String.valueOf(pixels[10]);  

  9. Log.i("myBitmapDecode""w = " + w + "; h = " + h);  

  10. Log.i("myBitmapDecode""pixels[0] = " + pixels[0] + "; pixels[1] = " + pixels[1] + "; pixels[10] = " + pixels[10]);  

  11. Log.i("myBitmapDecode""pixels[w] = " + pixels[w] + "; pixels[h] = " + pixels[h] + "; pixels[w*h-1] = " + pixels[w*h-1]);  

運行結果: 


I/myBitmapDecode(  727): w = 100; h = 100
I/myBitmapDecode(  727): pixels[0] = -16777216; pixels[1] = -16777216; 
pixels[10] = -4352
I/myBitmapDecode(  727): pixels[w] = -16777216; pixels[h] = -16777216; pixels[w*h-1] = -2578654


咱們能夠看到結果了,若是pixels[]中的數值爲int默認值(0)的話,圖片相應的部分就爲背景色,若是設置爲別的初始值而在運行中沒有被修改的話,背景色就是修改值對應的RGB顏色. 

原圖位置(offset)
下面設置下getPixels[]方法中offset,使得黃色部分截圖出如今它在原圖中的位置, 

offset = x + y*w ,本例代碼以下: 

[java] view plaincopyprint?

  1. int[] pixels = new int[w*h];  

  2. for(int i=0; i<w*h; i++){  

  3.     pixels[i] = -2578654;   

  4. }  

  5. mBitmap2.getPixels(pixels, 50, w, 500, w/2, h/2;  

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

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

  8. String txt = String.valueOf(pixels[10]);  

  9. Log.i("myBitmapDecode""w = " + w + "; h = " + h);  

  10. Log.i("myBitmapDecode""pixels[0] = " + pixels[0] + "; pixels[1] = " + pixels[1] + "; pixels[10] = " + pixels[10]);  

  11. Log.i("myBitmapDecode""pixels[w] = " + pixels[w] + "; pixels[h] = " + pixels[h] + "; pixels[w*h-1] = " + pixels[w*h-1]);  

運行結果:
 
I/myBitmapDecode(  761): w = 100; h = 100
I/myBitmapDecode(  761): pixels[0] = -2578654; pixels[1] = -2578654; 
pixels[10] = -2578654
I/myBitmapDecode(  761): pixels[w] = -2578654; pixels[h] = -2578654; pixels[w*h-1] = -2578654

固然能夠用這個方法進行更復雜的運算,諸如截取素材圖片修改目標圖片(已存儲至pixels數組中)的指定區域!! 


背景色設置(pixels[])

背景顏色與pixels[]初始值一致,如紅色RED(-65536 0xffff0000),黃色YELLOW(-256 0xffffff00),具體詳見下面附註

[java] view plaincopyprint?

  1. int[] pixels = new int[w*h];  

  2. for(int i=0; i<w*h; i++){  

  3.     pixels[i] = -65536;     // Color.RED : -65536 (0xffff0000)  

  4. }  

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

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

  7. Log.i("myBitmapDecode""w = " + w + "; h = " + h);  

  8. Log.i("myBitmapDecode""pixels[0] = " + pixels[0] + "; pixels[1] = " + pixels[1] + "; pixels[10] = " + pixels[10] + "; pixels[50] = " + pixels[50]);  

  9. Log.i("myBitmapDecode""pixels[w] = " + pixels[w] + "; pixels[h] = " + pixels[h] + "; pixels[w*h-1] = " + pixels[w*h-1]);  

  10.   

  11. for(int i=0; i<w*h; i++){  

  12.     pixels[i] = -256;       // Color.YELLOW : -256 (0xffffff00)  

  13. }  

  14. mBitmap2.getPixels(pixels, 50*100 + 50, w, 5050, w/2, h/2);  

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

  16. Log.i("myBitmapDecode""w = " + w + "; h = " + h);  

  17. Log.i("myBitmapDecode""pixels[0] = " + pixels[0] + "; pixels[1] = " + pixels[1] + "; pixels[10] = " + pixels[10] + "; pixels[50] = " + pixels[50]);  

  18. Log.i("myBitmapDecode""pixels[w] = " + pixels[w] + "; pixels[h] = " + pixels[h] + "; pixels[w*h-1] = " + pixels[w*h-1]);  

運行結果:


I/myBitmapDecode( 1671): w = 100; h = 100
I/myBitmapDecode( 1671): pixels[0] = -65536; pixels[1] = -65536; pixels[10] = -65536; pixels[50] = -16777216
I/myBitmapDecode( 1671): pixels[w] = -65536; pixels[h] = -65536; pixels[w*h-1] = -65536
I/myBitmapDecode( 1671): w = 100; h = 100
I/myBitmapDecode( 1671): pixels[0] = -256; pixels[1] = -256; pixels[10] = -256; pixels[50] = -256
I/myBitmapDecode( 1671): pixels[w] = -256; pixels[h] = -256; pixels[w*h-1] = -16735513


圖片拼接

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

示例以下: 

[java] view plaincopyprint?

  1. int w = mBitmap2.getWidth();  

  2. int h = mBitmap2.getHeight();  

  3. int[] pixels = new int[2*w*h];  

  4. for(int i=0; i<2*w*h; i++){  

  5.     pixels[i] = -2578654;   

  6. }  

  7. mBitmap2.getPixels(pixels, 02*w, 00, w, h);  

  8. mBitmap2.getPixels(pixels, w, 2*w, 00, w, h);  

  9. mBitmap3 = Bitmap.createBitmap(pixels, 02*w, 2*w, h, Bitmap.Config.ARGB_8888);  

  10. String txt = String.valueOf(pixels[10]);  

  11. Log.i("myBitmapDecode""w = " + w + "; h = " + h);  

  12. Log.i("myBitmapDecode""pixels[0] = " + pixels[0] + "; pixels[1] = " + pixels[1] + "; pixels[10] = " + pixels[10]);  

  13. Log.i("myBitmapDecode""pixels[w] = " + pixels[w] + "; pixels[h] = " + pixels[h] + "; pixels[w*h-1] = " + pixels[w*h-1]);  

  14. Log.i("myBitmapDecode""pixels[2*w-1] = " + pixels[2*w-1] + "; pixels[2*w] = " + pixels[2*w] + "; pixels[2*w*h-1] = " + pixels[2*w*h-1]);  

運行結果: 

I/myBitmapDecode(  989): w = 100; h = 100
I/myBitmapDecode(  989): pixels[0] = -16777216; pixels[1] = -16777216; 
pixels[10] = -16777216
I/myBitmapDecode(  989): pixels[w] = -16777216; pixels[h] = -16777216; pixels[w*h-1] = -16777216
I/myBitmapDecode(  989): pixels[2*w-1] = -3328; pixels[2*w] = -16777216; pixels[2*w*h-1] = -16735513

第二種:  
stride表示數組pixels[]中存儲的圖片每行的數據,在其中能夠附加信息,即 
stride = width + padding,以下圖所示



這樣能夠不單單存儲圖片的像素信息,也能夠儲存相應每行的其它附加信息. 


最後,stride參數的意義及用處總結以下:


1 用來表示pixels[]數組中每行的像素個數,用於行與行之間區分,絕對值必須大於參數width,但沒必要大於所要讀取圖片的寬度w(在width < w 時成立).(stride負數有何做用不知,存疑).另,pixels.length >= stride * height,不然會拋出ArrayIndexOutOfBoundsException異常 

2 stride > width時,能夠在pixels[]數組中添加每行的附加信息,可作它用. 




附註(Color顏色對應值):

Constants

public static final int BLACK

Since: API Level 1

Constant Value: -16777216 (0xff000000)

public static final int BLUE

Since: API Level 1

Constant Value: -16776961 (0xff0000ff)

public static final int CYAN

Since: API Level 1

Constant Value: -16711681 (0xff00ffff)

public static final int DKGRAY

Since: API Level 1

Constant Value: -12303292 (0xff444444)

public static final int GRAY

Since: API Level 1

Constant Value: -7829368 (0xff888888)

public static final int GREEN

Since: API Level 1

Constant Value: -16711936 (0xff00ff00)

public static final int LTGRAY

Since: API Level 1

Constant Value: -3355444 (0xffcccccc)

public static final int MAGENTA

Since: API Level 1

Constant Value: -65281 (0xffff00ff)

public static final int RED

Since: API Level 1

Constant Value: -65536 (0xffff0000)

public static final int TRANSPARENT

Since: API Level 1

Constant Value: 0 (0x00000000)

public static final int WHITE

Since: API Level 1

Constant Value: -1 (0xffffffff)

public static final int YELLOW

Since: API Level 1

Constant Value: -256 (0xffffff00)



引用參考: 

1, int, int, int, int, int, int)]Android英文文檔getPixels()方法介紹

Android中文文檔getPixels()方法介紹

StackOverflow中關於getPixels()問答.

Using the LockBits method to access image data

本文引用參考

相關文章
相關標籤/搜索