2011-11-12 25 views
19

Tôi cố gắng lấy tất cả các giá trị byte từ một Bitmap (System.Drawing.Bitmap). Vì vậy, tôi khóa các byte và sao chép chúng:PixelFormat.Format32bppArgb dường như có thứ tự byte sai

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

Tôi đã thử hình ảnh này với một hình ảnh PNG 2x2 rất đơn giản với pixel (đỏ, lục, lam, trắng) mà tôi đã tạo trong Photoshop. Bởi vì định dạng, tôi mong đợi các giá trị sau trong argbData:

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

Nhưng tôi nhận:

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

Nhưng đây là một định dạng BGRA. Có ai biết tại sao các byte có vẻ hoán đổi? Nhân tiện, khi tôi sử dụng hình ảnh trực tiếp cho Image.Source như hình dưới đây, Hình ảnh được hiển thị chính xác. Vì vậy, lỗi của tôi là gì?

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

Trả lời

33

Pixel dữ liệu là ARGB, 1 byte cho alpha , 1 cho màu đỏ, 1 cho màu xanh lá cây, 1 cho màu xanh. Alpha là byte quan trọng nhất, màu xanh là ít quan trọng nhất. Trên một máy tính nhỏ, giống như máy của bạn và nhiều thứ khác, đầu nhỏ được lưu trữ đầu tiên để thứ tự byte là bb gg rr aa. Vì vậy, 0 0 255 255 bằng màu xanh = 0, xanh = 0, đỏ = 255, alpha = 255. Màu đỏ.

Chi tiết đơn đặt hàng cuối cùng này sẽ biến mất khi bạn truyền bd.Scan0 thành int * (con trỏ đến số nguyên) vì số nguyên cũng được lưu trữ ít người dùng cuối.

+4

Excelent! Tôi chỉ có thể thêm rằng bạn có thể kiểm tra thứ tự byte ("endianness") trong đó dữ liệu được lưu trữ trong kiến ​​trúc máy tính này thông qua [BitConverter.IsLittleEndian] (http://msdn.microsoft.com/en-us/library/system .bitconverter.islittleendian.aspx). – DmitryG

+1

Đó là một điểm tốt về 'BitConverter.IsLittleEndian', nhưng tôi nghĩ rằng nhận xét của HansPassant về endian-ness thực sự có giá trị - đây là một nơi mà người cuối cùng nên ** không được xem xét. [Đây] (http://commandcenter.blogspot.com.au/2012/04/byte-order-fallacy.html) một bài viết tuyệt vời về chủ đề này .. – Jonno

2

AFAIK nó là kỹ thuật dựa trên COLORREF (được sử dụng trong Windows GDI/GDI + ở khắp mọi nơi) và được lưu trữ trong bộ nhớ RGBA ... see http://msdn.microsoft.com/en-us/library/dd183449%28VS.85%29.aspx

+0

nếu tôi hiểu trang, điều đó có nghĩa là mỗi lần tôi sẵn sàng RGB, đó không phải là byte thực thực sự. Nó luôn luôn có nghĩa là BGR? Hay có một loại cờ chỉ ra điều này? – 0xBADF00D

+1

@hichaeretaqua Từ những gì tôi thu thập khi sử dụng GDI bạn luôn nhận được BGR/BGRA ... – Yahia

0

Ở định dạng pixel Bpp32Argb. Bạn không cần truy cập byte-by-byte.

Quét Quét 0 đến con trỏ Int32 trong ngữ cảnh không an toàn.

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

Bạn có thể thực hiện một số thao tác bit như dưới đây Để truy cập kênh màu của pixel đầu tiên.

Và không cần phải quan tâm đến thứ tự byte.

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

BTW bạn có thể làm việc với Color.ToArgb() trả lại int dễ dàng.

+0

Câu trả lời được chấp nhận đã đề cập đến điều này, nhưng tiếc là bạn không thể sử dụng mã không an toàn trong một số trường hợp. Đối với các trường hợp, tôi đã làm việc cho một số công ty không cho phép mã không an toàn. – 0xBADF00D

Các vấn đề liên quan