我正在使用此代码将位图另存为二进制数据。
Bitmap bmp = new Bitmap(screenWidth, position);
Graphics g = Graphics.FromImage(bmp);
g.CopyFromScreen(screenLeft, screenTop, 0, 0, bmp.Size);
Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
System.Drawing.Imaging.BitmapData bmpData = bmp.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadOnly, bmp.PixelFormat);
IntPtr ptr = bmpData.Scan0;
int bytes = bmpData.Stride * bmp.Height;
byte[] rgbValues = new byte[bytes];
System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, bytes);
bmp.UnlockBits(bmpData);
File.WriteAllBytes(filename, bmp);
g.Dispose();
由于我只需要第一个通道的值,是否可以从位图中检索到它?性能至关重要。
答案 0 :(得分:0)
您快到了,但是缺少一些关键细节:
bmp.PixelFormat
,而是将BitmapData
对象的像素格式强制为PixelFormat.Format32BppArgb
,那么您将100%确定将获得哪种结构,并处于32位模式,步幅将始终与可预测的width * 4
完全匹配。如果不这样做,如果读取的图像恰好是调色板或某种16bpp格式,其中每个像素不能分为简单的颜色分量字节,则可能会得到意外的结果。Uint32
值,这意味着颜色分量字节的实际顺序是相反的: { BB, GG, RR, AA }
。因此,要提取您的频道:
// Channels are: B=0, G=1, R=2, A=3
Int32 channel = 1 // for this example, extract the Green channel.
Int32 width;
Int32 height;
Byte[] rgbaValues;
using (Bitmap bmp = new Bitmap(screenWidth, position))
using (Graphics g = Graphics.FromImage(bmp))
{
width = bmp.Width
height = bmp.Height;
g.CopyFromScreen(screenLeft, screenTop, 0, 0, bmp.Size);
Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
BitmapData bmpData = bmp.LockBits(rect, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
Int32 bytes = bmpData.Stride * bmp.Height;
rgbaValues = new byte[bytes];
Marshal.Copy(bmpData.Scan0, rgbValues, 0, bytes);
bmp.UnlockBits(bmpData);
g.Dispose();
}
Byte[] channelValues = new byte[width * height];
Int32 lineStart = 0;
Int32 lineStartChannel = 0;
for (Int32 y = 0; y < height; ++y)
{
Int32 offset = lineStart;
Int32 offsetChannel = lineStartChannel;
for (Int32 x = 0; x < width; ++x)
{
// For reference:
//Byte blue = rgbaValues[offset + 0];
//Byte green = rgbaValues[offset + 1];
//Byte red = rgbaValues[offset + 2];
//Byte alpha = rgbaValues[offset + 3];
channelValues[offsetChannel] = rgbaValues[offset + channel];
offset += 4;
offsetChannel++;
}
lineStart += stride;
lineStartChannel += width;
}
File.WriteAllBytes(filename, channelValues);
这只是将数据保存为字节数组。如果要将其写为图像,最简单的方法可能是制作一个8位的位图,在其上打开一个BitmapData对象,然后一行一行地写入其中,然后将其调色板设置为从0,0,0到255,255,255。
我发布了一个函数,该函数采用字节数组,图像尺寸和调色板,并在this answer中将其制成图像。