PixelFormat.Format32bppArgb кажется неправильным порядком байтов

Я пытаюсь получить все значения байтов из растрового изображения (System.Рисунок.Растровый.) Поэтому я блокирую байты и копирую их:

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

я протестировал это изображение с очень простым изображением 2x2 PNG с пикселями (красный, зеленый, синий, белый), которые я создал в Photoshop. Из-за формата я ожидал следующие значения в argbData:

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

А я:

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

но это формат BGRA. Кто-нибудь знает, почему байты меняются местами? Кстати, когда я использую изображение непосредственно для изображения.Источник, как показано ниже, изображение отображается правильно. Так в чем же моя вина?

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

3 ответов


пиксельные данные формате ARGB, 1 байт для альфа, 1 красный, 1 зеленый, 1 синий. Альфа-самый значимый байт, синий-наименее значимый. На машине little-endian, как ваша и многие другие, маленький конец хранится первым, поэтому порядок байтов-bb gg rr aa. Таким образом, 0 0 255 255 равно blue = 0, green = 0, red = 255, alpha = 255. Это красный.

эта деталь заказа endian-ness исчезает, когда вы бросаете bd.Scan0 в int* (указатель на целое число), так как целые числа хранятся прямым порядком байтов, а также.


AFAIK он технически основан на COLORREF (который используется в Windows GDI/GDI+ везде) и который хранится RGBA в памяти... см.http://msdn.microsoft.com/en-us/library/dd183449%28VS.85%29.aspx


в формате пикселей Bpp32Argb. Вам не нужен байтовый доступ.

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

BTW вы можете работать с Color.ToArgb() вернулся int легко.