我尝试使用copyPixelsToBuffer
和copyPixelsFromBuffer
方法在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通道应用于每个副本(这似乎是它正在做的事情)。
copyPixelsToBuffer
和copyPixelsFromBuffer
应该如何运作?是否有任何方法来获取byte []中的原始数据?
在回答以下答案时添加:
在buffer.order(ByteOrder.nativeOrder());
之前加入copyPixelsToBuffer
会改变结果,但仍然不符合我的要求:
pixel before = ef234567
value before = ef614121
value after = ffffff41
pixel after = ff41ffff
似乎遭受了基本相同的问题(每个copyPixelsFrom/ToBuffer
都应用了alpha。)
答案 0 :(得分:1)
我的猜测是,这可能与你正在使用的ByteBuffer的字节顺序有关。 ByteBuffer默认使用big endian。 使用
在缓冲区上设置endianessbuffer.order(ByteOrder.nativeOrder());
看看它是否有帮助。
此外,copyPixelsFromBuffer / copyPixelsToBuffer不会以任何方式更改像素数据。它们是原始复制的。
答案 1 :(得分:1)
我意识到这是非常陈旧的,现在可能不会帮助你,但我最近遇到了这个问题,试图让copyPixelsFromBuffer
在我的应用中运行。 (感谢您提出这个问题,顺便说一下!您为调试节省了大量时间。)我希望能够帮助像我这样的其他人继续这个答案...
虽然我还没有使用它来确保它有效,但看起来,从API级别19开始,我们终于有办法指定不要"应用alpha& #34; ({1}}内的(a.k.a.preultiply)。他们正在添加一个setPremultiplied(boolean)
方法,通过允许我们指定Bitmap
来帮助处理此类情况。
我希望这有帮助!
答案 2 :(得分:1)
在Bitmap中访问数据的一种方法是使用getPixels()方法。下面你可以找到一个例子,我用来从argb数据中获取灰度图像,然后从字节数组返回到Bitmap(当然如果你需要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;
}
}
答案 3 :(得分:0)
这是一个老问题,但我遇到了同样的问题,并且发现位图字节是预乘的,你可以设置位图(从API 19开始)不预先乘以缓冲区,但是在API中,他们不保证。
来自the docs:
public final void setPremultiplied(boolean premultiplied)
设置位图是否应将其数据视为预乘。 出于性能原因,位图始终被视图系统和Canvas预先乘以。如果在框架中绘制,则在位图中存储未预先乘的数据(通过
setPixel
,setPixels
或BitmapFactory.Options.inPremultiplied
)会导致错误的混合。此方法不会影响没有Alpha通道的位图行为,或者
hasAlpha()
返回false。使用颜色未预乘的源位图调用
createBitmap
或createScaledBitmap
可能会产生RuntimeException
,因为这些函数需要绘制源,而un不支持 - 预乘的位图。