如何访问位图图像中的每个字节

Posted

技术标签:

【中文标题】如何访问位图图像中的每个字节【英文标题】:How to access each byte in a bitmap image 【发布时间】:2008-12-03 15:58:53 【问题描述】:

假设我有一个位图图像,是否可以遍历图像中的所有单个字节?如果是,怎么做?

【问题讨论】:

是的,我猜 1 像素 = 1 字节? 1 像素 = x 位(其中 x 是图像的颜色深度) 【参考方案1】:

我发现了这个:http://channel9.msdn.com/forums/TechOff/108813-Bitmap-to-byte-array/

说你可以使用 Memorystream 和 .Save 方法,它看起来像这样:

System.Drawing.Bitmap bmp = GetTheBitmap();
System.IO.MemoryStream stream = new System.IO.MemoryStream();
bmp.Save(stream, System.Drawing.Imaging.ImageFormat.Bmp);
stream.Position = 0;
byte[] data = new byte[stream.Length];
stream.Read(data, 0, stream.Length);

【讨论】:

【参考方案2】:

如果您需要访问像素信息,超级慢但超级简单的方法是在您的 Bitmap 对象上调用 GetPixel 和 SetPixel 方法。

超快速且不那么难的方法是调用Bitmap的LockBits方法,并使用从它返回的BitmapData对象直接读写Bitmap的字节数据。您可以像 Ilya 的示例那样使用 Marshal 类来完成后一部分,或者您可以像这样跳过 Marshal 开销:

    BitmapData data;
    int x = 0; //or whatever
    int y = 0;
    unsafe
    
        byte* row = (byte*)data.Scan0 + (y * data.Stride);
        int columnOffset = x * 4;
        byte B = row[columnOffset];
        byte G = row[columnOffset + 1];
        byte R = row[columnOffset + 2];
        byte A = row[columnOffset + 3];
    

【讨论】:

感谢您的回答。我建议这个答案的读者也阅读docs.microsoft.com/en-us/dotnet/csharp/language-reference/…。这对我也很有帮助。【参考方案3】:

使用 Bitmap 类的 LockBits 成员获取 BitmapData,然后使用 Scan0 和 Marshal.ReadByte 读取字节。这是一个小例子(虽然它不是关于正确的亮度调整):

    public static void AdjustBrightness(Bitmap image, int brightness)
    
        int offset = 0;
        brightness = (brightness * 255) / 100;
        // GDI+ still lies to us - the return format is BGR, NOT RGB.
        BitmapData bmData = image.LockBits(new Rectangle(0, 0, image.Width, image.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);

        int stride = bmData.Stride;
        IntPtr Scan0 = bmData.Scan0;

        int nVal = 0;
        int nOffset = stride - image.Width * 3;
        int nWidth = image.Width * 3;

        for (int y = 0; y < image.Height; ++y)
        
            for (int x = 0; x < nWidth; ++x)
            
                nVal = Marshal.ReadByte(Scan0, offset) + brightness;

                if (nVal < 0)
                    nVal = 0;
                if (nVal > 255)
                    nVal = 255;

                Marshal.WriteByte(Scan0, offset, (byte)nVal);
                ++offset;
            
            offset += nOffset;
        
        image.UnlockBits(bmData);
    

【讨论】:

【参考方案4】:

另一种解决方案是使用 LockBits 和 Marshal.Copy 将您的位图转换为数组。我需要这个解决方案,因为我有两张仅颜色深度不同的图像,而其他提供的解决方案处理得不好(或太慢)。

using (Bitmap bmp = new Bitmap(fname)) 
    // Convert image to int32 array with each int being one pixel
    int cnt = bmp.Width * bmp.Height * 4 / 4;
    BitmapData bmData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height),
                            ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
    Int32[] rgbValues = new Int32[cnt];

    // Copy the RGB values into the array.
    System.Runtime.InteropServices.Marshal.Copy(bmData.Scan0, rgbValues, 0, cnt);
    bmp.UnlockBits(bmData);
    for (int i = 0; i < cnt; ++i) 
        if (rgbValues[i] == 0xFFFF0000)
            Console.WriteLine ("Red byte");
    

【讨论】:

以上是关于如何访问位图图像中的每个字节的主要内容,如果未能解决你的问题,请参考以下文章

如何从 android 中的 sdcard 图像创建位图?

如何将组成文件的原始位显示为位图图像? [关闭]

位图存储图像数据每行字节数为4的倍数

C# 位图图像、字节数组和流!

将位图保存到位置

设备无关位图字节数组到图像:参数无效