2011-02-15 30 views
8

我試圖使用copyPixelsToBuffer和和copyPixelsFromBuffer方法訪問Android上ARGB_8888格式的位圖原始數據。但是,調用這些調用似乎總是將alpha通道應用於rgb通道。我需要一個byte []或類似的原始數據(通過JNI;是的,我知道Android 2.2中的bitmap.h,不能使用它)。訪問ARGB_8888中的原始數據Android位圖

下面是一個示例:

// Create 1x1 Bitmap with alpha channel, 8 bits per channel 
    Bitmap one = Bitmap.createBitmap(1,1,Bitmap.Config.ARGB_8888); 
    one.setPixel(0,0,0xef234567); 
    Log.v("?","hasAlpha() = "+Boolean.toString(one.hasAlpha())); 
    Log.v("?","pixel before = "+Integer.toHexString(one.getPixel(0,0))); 

    // Copy Bitmap to buffer 
    byte[] store = new byte[4]; 
    ByteBuffer buffer = ByteBuffer.wrap(store); 
    one.copyPixelsToBuffer(buffer); 

    // Change value of the pixel 
    int value=buffer.getInt(0); 
    Log.v("?", "value before = "+Integer.toHexString(value)); 
    value = (value >> 8) | 0xffffff00; 
    buffer.putInt(0, value); 
    value=buffer.getInt(0); 
    Log.v("?", "value after = "+Integer.toHexString(value)); 

    // Copy buffer back to Bitmap 
    buffer.position(0); 
    one.copyPixelsFromBuffer(buffer); 
    Log.v("?","pixel after = "+Integer.toHexString(one.getPixel(0,0))); 

日誌然後顯示

hasAlpha() = true 
pixel before = ef234567 
value before = 214161ef 
value after = ffffff61 
pixel after = 619e9e9e 

據我所知,ARGB信道的順序不同;沒關係。但我不想 希望alpha通道應用於每個副本(這是它似乎在做什麼)。

這是copyPixelsToBuffercopyPixelsFromBuffer應該如何工作?有沒有任何方式獲得一個字節[]中的原始數據?

添加響應如下回答:

copyPixelsToBufferbuffer.order(ByteOrder.nativeOrder());把不會改變結果,但仍然沒有在路上我希望它:

pixel before = ef234567 
value before = ef614121 
value after = ffffff41 
pixel after = ff41ffff 

似乎從本質上遭受同樣的問題(每個copyPixelsFrom/ToBuffer都應用了alpha)。

+0

嗨,我也遇到過這個問題。你找到了解決這個問題的方法嗎?也許將數據轉換回真RGB值的方法? – 2012-09-07 00:51:27

+0

您可能也想檢查``Bitmap.isPremultiplied()``。當alpha通道出現時,默認情況下它默認設置爲「true」。 – harism 2013-01-12 18:51:46

回答

1

我意識到這是非常陳舊,現在可能不會幫助你,但我最近碰到這個,試圖讓copyPixelsFromBuffer在我的應用程序中工作。 (謝謝你問這個問題,順便說一句,你節省了我噸調試時間。)我加入這個答案,希望它可以幫助像我這樣的人前進......

雖然我沒有用過但爲了確保它可以正常工作,看起來就像API Level 19一樣,我們終於有了一種方法來指定不在Bitmap內「應用alpha」(又稱預乘)。他們正在添加一個setPremultiplied(boolean)方法,通過允許我們指定false來幫助在這種情況下繼續前進。

我希望這有助於!

1

我的猜測是,這可能與您使用的ByteBuffer的字節順序有關。 ByteBuffer默認使用big endian。 在緩衝區上設置永久性

buffer.order(ByteOrder.nativeOrder()); 

看看是否有幫助。

此外,copyPixelsFromBuffer/copyPixelsToBuffer不以任何方式更改像素數據。他們被複制原始。

+0

這改變了結果,但不是主要問題:alpha通道仍然應用於每個副本(請參閱我的問題中添加的註釋)。 – 2011-02-15 23:42:49

1

在位圖中訪問數據的一種方法是使用getPixels()方法。下面你可以找到一個我用來從argb數據獲取灰度圖像然後從字節數組返回到位圖的例子(當然,如果你需要rgb你保留3x字節並保存它們...):

/*Free to use licence by Sami Varjo (but nice if you retain this line)*/ 

public final class BitmapConverter { 

    private BitmapConverter(){}; 

    /** 
    * Get grayscale data from argb image to byte array 
    */ 
    public static byte[] ARGB2Gray(Bitmap img) 
    { 

     int width = img.getWidth(); 
     int height = img.getHeight(); 

     int[] pixels = new int[height*width]; 
     byte grayIm[] = new byte[height*width]; 

     img.getPixels(pixels,0,width,0,0,width,height); 

     int pixel=0; 
     int count=width*height; 

     while(count-->0){ 
      int inVal = pixels[pixel]; 

      //Get the pixel channel values from int 
      double r = (double)((inVal & 0x00ff0000)>>16); 
      double g = (double)((inVal & 0x0000ff00)>>8 ); 
      double b = (double)( inVal & 0x000000ff)  ; 

      grayIm[pixel++] = (byte)(0.2989*r + 0.5870*g + 0.1140*b); 
     } 

     return grayIm; 
    } 

    /** 
    * Create a gray scale bitmap from byte array 
    */ 
    public static Bitmap gray2ARGB(byte[] data, int width, int height) 
    { 
     int count = height*width; 
     int[] outPix = new int[count]; 
     int pixel=0; 
     while(count-->0){ 
      int val = data[pixel] & 0xff; //convert byte to unsigned 
      outPix[pixel++] = 0xff000000 | val << 16 | val << 8 | val ; 
     } 

     Bitmap out = Bitmap.createBitmap(outPix,0,width,width, height, Bitmap.Config.ARGB_8888); 
     return out; 
    } 

} 
0

這是一個老問題,但我得到了同樣的問題,只是想通了,位圖字節是預相乘,可以設置位圖(如API 19),以不預 - 增加緩衝區,但在API中他們不保證。

the docs

public final void setPremultiplied(boolean premultiplied)

設置位圖是否應該把它的數據作爲預乘。 出於性能原因,位圖總是被視圖系統和Canvas預倍增。如果由框架繪製,將未預先倍增的數據存儲在位圖中(通過setPixelsetPixelsBitmapFactory.Options.inPremultiplied)可能會導致不正確的混合。

此方法不會影響沒有Alpha通道的位圖的行爲,或者hasAlpha()返回false。

調用createBitmapcreateScaledBitmap與源位圖,其顏色沒有預乘可能導致RuntimeException,因爲這些功能需要繪製源,其不支持非預乘以位圖。