2011-11-12 9 views
19

trato de obtener todos los valores de byte de un mapa de bits (System.Drawing.Bitmap). Por lo tanto cierro los bytes y copiarlos:PixelFormat.Format32bppArgb parece tener orden de bytes mal

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); 
    } 
} 

He probado esta imagen como una imagen PNG 2x2 muy simple con con píxeles (rojo, verde, azul, blanco) que he creado en Photoshop. Debido al formato, que esperaba los siguientes valores dentro del argbData:

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

Pero tengo:

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

Pero este es un formato BGRA. ¿Alguien sabe por qué los bytes parecen intercambiados? Por cierto, cuando uso la imagen directamente para Image.Source como se muestra a continuación, la imagen se muestra correctamente. Entonces, ¿cuál es mi culpa?

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

Respuesta

33

datos de píxeles es ARGB, 1 byte para la alfa , 1 para rojo, 1 para verde, 1 para azul. Alpha es el byte más significativo, el azul es el menos significativo. En una máquina little-endian, como la suya y muchas otras, el extremo más pequeño se almacena primero, por lo que el orden de bytes es bb gg rr aa. Entonces 0 0 255 255 es igual a azul = 0, verde = 0, rojo = 255, alfa = 255. Eso es rojo.

Este detalle de orden de endianidad desaparece cuando convierte bd.Scan0 en un int * (puntero-a-entero) ya que los enteros también se almacenan en little-endian.

+4

¡Excelente! Solo puedo agregar que puede verificar el orden de bytes ("endianness") en el que se almacenan los datos en esta arquitectura de computadora a través de [BitConverter.IsLittleEndian] (http://msdn.microsoft.com/en-us/library/system) .bitconverter.islittleendian.aspx) campo. – DmitryG

+1

Ese es un buen punto sobre 'BitConverter.IsLittleEndian', pero creo que el comentario de @ HansPassant sobre endian-dad es muy valiosa - este es otro lugar donde el endian-dad debería ** ** no ser considerado. [Aquí está] (http://commandcenter.blogspot.com.au/2012/04/byte-order-fallacy.html) un excelente artículo sobre este tema. – Jonno

2

yo sepa que se basa técnicamente en COLORREF (que se utiliza en Windows GDI/GDI + en todas partes) y que se almacena en la memoria RGBA ... ver http://msdn.microsoft.com/en-us/library/dd183449%28VS.85%29.aspx

+0

si entiendo la página, eso significa que cada vez que preparo RGB, no es un byteorder real. ¿Siempre significa BGR? ¿O hay un tipo de bandera que indique esto? – 0xBADF00D

+1

@hichaeretaqua Por lo que deduzco cuando uso GDI siempre obtienes BGR/BGRA ... – Yahia

0

En formato de píxel Bpp32Argb. No necesita acceso byte a byte.

Trun scan0 a un puntero Int32 en el contexto inseguro.

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

Usted puede hacer alguna operación poco como abajo para acceder a los canales de color de primer pixel.

Y no necesita preocuparse de orden de bytes.

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

Por cierto se puede trabajar con Color.ToArgb() regresaron int fácilmente.

+0

La respuesta aceptada ya lo menciona, pero lamentablemente no se puede use código inseguro en algunas circunstancias. Por ejemplo, trabajé para varias compañías que no permiten ningún código inseguro. – 0xBADF00D

Cuestiones relacionadas