ARGB_8888Androidビットマップの生データへのアクセス
-
14-11-2019 - |
質問
私はAndroid上でARGB_8888形式のビットマップの生データにアクセスしようとしています copyPixelsToBuffer
と copyPixelsFromBuffer
メソッド。ただし、これらの呼び出しを呼び出すと、常にアルファチャネルがrgbチャネルに適用されるようです。私はbyte[]または類似の生データが必要です(JNIを通過するために;はい、私はビットマップについて知っています。Android2.2では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チャネルの順序が異なることを理解しています;いいんだよしかし、私はしません アルファチャンネルをすべてのコピーに適用する必要があります(これは実行しているようです)。
これはどうですか copyPixelsToBuffer
と copyPixelsFromBuffer
働くことになっていますか?そこにありますか 任意の byte[]で生データを取得する方法は?
以下の回答に応じて追加されました:
入れて buffer.order(ByteOrder.nativeOrder());
前に copyPixelsToBuffer
結果は変わりますが、それでも私が望む方法ではありません:
pixel before = ef234567
value before = ef614121
value after = ffffff41
pixel after = ff41ffff
本質的に同じ問題に苦しんでいるようです(アルファはそれぞれに適用されます copyPixelsFrom/ToBuffer
).
解決
私はこれが非常に古く、おそらく今あなたを助けないことを認識していますが、私は最近これを取得しようとしています copyPixelsFromBuffer
私のアプリで動作するように。(この質問をしてくれてありがとう、btw!あなたはデバッグで私に多くの時間を節約しました。)私はそれが私のような他の人が前進するのを助けることを期待してこの答えを追加しています。..
私はまだこれを使用していませんが、APIレベル19の時点で、最終的に「アルファを適用しない」(別名)を指定する方法があるように見えます。プレマルチ)内 Bitmap
.彼らは追加している setPremultiplied(boolean)
私たちが指定することを可能にすることによって、このような状況で役立つはずの方法 false
.
私はこれが役立つことを願っています!
他のヒント
ビットマップ内のデータにアクセスする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;
}
}
私の推測では、これはあなたが使用しているByteBufferのバイトオーダーと関係があるかもしれないということです。ByteBufferはデフォルトでビッグエンディアンを使用します。バッファにendianessを設定するには、次のようにします
buffer.order(ByteOrder.nativeOrder());
それが役立つかどうかを確認してください。
さらに、copyPixelsFromBuffer/copyPixelsToBufferはピクセルデータを変更しません。それらは生でコピーされます。
これは古い質問ですが、私は同じ問題に遭遇し、ビットマップバイトが事前に乗算されていることを理解しただけで、ビットマップ(API19の時点)をバッ
から のドキュメントです。:
public final void setPremultiplied(boolean premultiplied)
ビットマップがそのデータを事前に乗算したものとして扱うかどうかを設定します。ビットマップは、パフォーマンス上の理由から、常にビューシステムとキャンバスによって事前に乗算されたものとして扱われます。ビットマップに未乗算のデータを格納する(
setPixel
,setPixels
, 、またはBitmapFactory.Options.inPremultiplied
)フレームワークによって描画された場合、誤ったブレンドにつながる可能性があります。このメソッドは、アルファチャンネルのないビットマップの動作には影響しません。
hasAlpha()
falseを返します。呼び出し
createBitmap
またはcreateScaledBitmap
色が事前に乗算されていないソースビットマップでは、次の結果が発生する可能性がありますRuntimeException
, これらの関数はソースを描画する必要があるため、事前に乗算されていないビットマップではサポートされていません。