2011-11-12 10 views
19

ビットマップ(System.Drawing.Bitmap)からすべてのバイト値を取得しようとしています。したがって、私はバイトをロックし、それらをコピーします。PixelFormat.Format32bppArgbのバイト順序が間違っているようです

public static byte[] GetPixels(Bitmap bitmap){ 
    if(bitmap-PixelFormat.Equals(PixelFormat.Format32.bppArgb)){ 
     var argbData = new byte[bitmap.Width*bitmap.Height*4]; 
     var bd = bitmap.LockBits(new Rectangle(0, 0, image.Width, image.Height), ImageLockMode.ReadOnly, bitmap.PixelFormat); 
     System.Runtime.InteropServices.Marshal.Copy(bd.Scan0, argbData, 0, bitmap.Width * bitmap.Height * 4); 
     bitmap.UnlockBits(bd); 
    } 
} 

私はPhotoshopで作成したピクセルと非常にシンプルな2x2のPNGの画像(赤、緑、青、白)を使って、このイメージをテストしました。

255 255 0 0 255 0 255 0 
255 0  0 255 255 255 255 255 

しかし、私は得た:そのためのフォーマットで、私はargbData内の以下の値を期待

0  0 255 255  0 255 0 255 
255 0 0 255 255 255 255 255 

をしかし、これはBGRAフォーマットです。バイトがスワップされたように見える理由は誰にも分かりますか? ところで、以下に示すようにImage.Sourceに直接画像を使用すると、画像が正しく表示されます。それで私のせいは何ですか?

<Image Source="D:/tmp/test2.png"/> 

答えて

33

画素データはARGB、アルファのための1つのバイトで見ます赤は1、緑は1、青は1です。アルファは最上位バイト、青は最下位バイトです。あなたと他の多くのようなリトルエンディアンのマシンでは、小さなものが最初に格納されるので、バイトオーダーはbb gg rr aaです。したがって、0 0 255 255は青色= 0、緑色= 0、赤色= 255、アルファ= 255です。これは赤です。

整数がリトルエンディアンにも格納されるため、bd.Scan0をint *(ポインタへのポインタ)にキャストすると、このエンディアン順序の詳細が消えます。

+4

Excelent!私はあなたが[BitConverter.IsLittleEndian](http://msdn.microsoft.com/en-us/library/system)を介して、このコンピュータアーキテクチャにデータが格納されているバイトオーダー(エンディアン)をチェックできることを追加することしかできません。 .bitconverter.islittleendian.aspx)フィールド。 – DmitryG

+1

これは 'BitConverter.IsLittleEndian'についての良い点ですが、@ HansPassantのエンディアンに関するコメントは本当に価値があると思います。これは、エンディアンが考慮されてはならない別の場所です**。 [Here's](http://commandcenter.blogspot.com.au/2012/04/byte-order-fallacy.html)このトピックに関する偉大な記事.. – Jonno

2

それは技術的に(+どこでもWindowsのGDI/GDIで使用されている)COLORREFに基づいており、それがメモリ内に保存されたRGBAです私の知る限り... http://msdn.microsoft.com/en-us/library/dd183449%28VS.85%29.aspx

+0

私がページを理解している場合、それは実際のバイトオーダーではないことを意味します。それは常にBGRを意味しますか?または、これを示すフラグがありますか? – 0xBADF00D

+1

@hichaeretaqua GDIを使うときに収集したものから、常にBGR/BGRAを取得します。 – Yahia

0

Bpp32Argbピクセル形式。 byte-by-byteアクセスは必要ありません。

安全ではないコンテキストでは、Scan0からInt32ポインタへのスキャン。

unsafe 
{ 
    var ptr=(int*)bmData.Scan0; 
} 

最初のピクセルのカラーチャネルにアクセスするには、次のようなビット操作を行うことができます。

バイトオーダーを気にする必要はありません。

var a=(ptr[0] & 0xFF000000)>>24; 
var r=(ptr[0] & 0x00FF0000)>>16; 
var g=(ptr[0] & 0x0000FF00)>>8; 
var b=(ptr[0] & 0x000000FF); 

ところであなたはColor.ToArgb()で作業することができ、簡単intを返しました。

+0

受け入れられた回答はすでにこれを言及していますが、残念ながらあなたは状況によっては安全でないコードを使用する。たとえば、安全でないコードをまったく許可しないいくつかの企業で働いていました。 – 0xBADF00D

関連する問題