12

我正在尝试使用copyPixelsToBufferandcopyPixelsFromBuffer方法在 Android 上访问 ARGB_8888 格式的位图的原始数据。然而,这些调用的调用似乎总是将 alpha 通道应用于 rgb 通道。我需要 byte[] 或类似的原始数据(通过 JNI;是的,我知道 Android 2.2 中的 bitmap.h,不能使用它)。

这是一个示例:

    // 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应该工作的?有什么方法可以获取字节 [] 中的原始数据吗?

为响应以下答案而添加:

buffer.order(ByteOrder.nativeOrder());在确实改变结果之前放入copyPixelsToBuffer,但仍然不是我想要的方式:

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

似乎遇到了基本相同的问题(每个都应用了 alpha copyPixelsFrom/ToBuffer)。

4

4 回答 4

3

在 Bitmap 中访问数据的一种方法是使用 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;
   }

}
于 2014-10-23T15:50:18.353 回答
1

我的猜测是,这可能与您使用的 ByteBuffer 的字节顺序有关。ByteBuffer 默认使用大端。在缓冲区上设置字节序

buffer.order(ByteOrder.nativeOrder());

看看有没有帮助。

此外,copyPixelsFromBuffer/copyPixelsToBuffer 不会以任何方式更改像素数据。它们是原始复制的。

于 2011-02-15T23:17:12.393 回答
1

我意识到这是非常陈旧的,现在可能对您没有帮助,但是我最近在尝试copyPixelsFromBuffer在我的应用程序中工作时遇到了这个问题。(顺便说一句,谢谢您提出这个问题!您为我节省了大量的调试时间。)我添加了这个答案,希望它能帮助像我这样的其他人继续前进......

虽然我还没有使用它来确保它有效,但看起来,从 API 级别 19 开始,我们最终将有一种方法来指定不在Bitmap. 他们正在添加一种setPremultiplied(boolean)方法,通过允许我们指定false.

我希望这有帮助!

于 2014-03-15T20:21:26.027 回答
0

这是一个老问题,但我遇到了同样的问题,只是发现位图字节是预乘的,您可以将位图(从 API 19 开始)设置为不预乘缓冲区,但在 API他们不保证。

文档

public final void setPremultiplied(boolean premultiplied)

设置位图是否应将其数据视为预乘。出于性能原因,位图总是被视图系统和画布预乘。如果由框架绘制,将未预乘的数据存储在位图中(通过setPixelsetPixelsBitmapFactory.Options.inPremultiplied)可能会导致不正确的混合。

此方法不会影响没有 Alpha 通道的位图的行为,或者如果hasAlpha()返回 false。

调用createBitmapcreateScaledBitmap使用未预乘颜色的源位图可能会导致 a RuntimeException,因为这些函数需要绘制源,而未预乘位图不支持该源位图。

于 2016-08-19T11:58:17.873 回答