PixelFormat.Format32bppArgb, кажется, имеет неправильный порядок байтов - PullRequest
22 голосов
/ 12 ноября 2011

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

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

Я протестировал это изображение с очень простым PNG-изображением 2x2 с пикселями (красный, зеленый, синий, белый), которое я создал в 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, как показано ниже, изображение отображается правильно. Так в чем моя вина?

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

Ответы [ 3 ]

38 голосов
/ 12 ноября 2011

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

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

2 голосов
/ 29 декабря 2016

В пиксельном формате 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);

Кстати, вы можете легко работать с Color.ToArgb(), возвращается int.

2 голосов
/ 12 ноября 2011

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

...