[英]Get Pixel Data out of Byte Array of Bitmap
我对以下问题problem之以鼻:
我在这里找到了一个类,可以使用SharpDX捕获屏幕。 它触发一个事件,并给我一个位图的字节数组。 以下类提供数组:
try
{
SharpDX.DXGI.Resource screenResource;
OutputDuplicateFrameInformation duplicateFrameInformation;
// Try to get duplicated frame within given time is ms
duplicatedOutput.AcquireNextFrame(5, out duplicateFrameInformation, out screenResource);
// copy resource into memory that can be accessed by the CPU
using (var screenTexture2D = screenResource.QueryInterface<Texture2D>())
device.ImmediateContext.CopyResource(screenTexture2D, screenTexture);
// Get the desktop capture texture
var mapSource = device.ImmediateContext.MapSubresource(screenTexture, 0, MapMode.Read, SharpDX.Direct3D11.MapFlags.None);
// Create Drawing.Bitmap
using (var bitmap = new Bitmap(width, height, PixelFormat.Format32bppArgb))
{
var boundsRect = new Rectangle(0, 0, width, height);
// Copy pixels from screen capture Texture to GDI bitmap
var mapDest = bitmap.LockBits(boundsRect, ImageLockMode.WriteOnly, bitmap.PixelFormat);
var sourcePtr = mapSource.DataPointer;
var destPtr = mapDest.Scan0;
for (int y = 0; y < height; y++)
{
// Copy a single line
Utilities.CopyMemory(destPtr, sourcePtr, width * 4);
// Advance pointers
sourcePtr = IntPtr.Add(sourcePtr, mapSource.RowPitch);
destPtr = IntPtr.Add(destPtr, mapDest.Stride);
}
// Release source and dest locks
bitmap.UnlockBits(mapDest);
device.ImmediateContext.UnmapSubresource(screenTexture, 0);
//bitmap.Save("sample.bmp"); // Das geht!
using (var ms = new MemoryStream())
{
bitmap.Save(ms, ImageFormat.Bmp);
ScreenRefreshed?.Invoke(this, ms.ToArray());
_init = true;
}
//_init = true; // Zsmhang: bitmap.Save
}
screenResource.Dispose();
duplicatedOutput.ReleaseFrame();
}
catch (SharpDXException e)
{
if (e.ResultCode.Code != SharpDX.DXGI.ResultCode.WaitTimeout.Result.Code)
{
logger.Error(e.Message);
logger.Error(e.StackTrace);
}
}
所以我得到了一个MemoryStream字节数组,我完全不确定如何从中获取像素数据。 我发现了许多类似的帖子,但似乎没人能正确地从线性数组中获取数据。 我尝试了多种变体,例如:
private void newFrameProcessing(object sender, byte[] data)
{
logger.Debug("Frame Tick! ");
Color clr = Color.Empty;
// Get color components count (BGRA)
int cCount = 4;
int y = 0;
// Get start index of the specified pixel
for (int x = 0; x <= 2; x++)
{
int f = ((y * 1280) + x) * cCount;
if (f > data.Length - cCount)
throw new IndexOutOfRangeException();
byte b = data[f];
byte g = data[f + 1];
byte r = data[f + 2];
byte a = data[f + 3]; // a
clr = Color.FromArgb(a, r, g, b);
logger.Debug("GetPixel("+x+","+y+") : index-f = " + f + " RGB: " + clr.R + " " + clr.G + " " + clr.B);
}
}
但这似乎是假设第一个像素在数组的开头。 我试图打印数组以查看其中的内容,而且数组中的第一个字节似乎是某种随机的东西(也许是位图标头之类的东西?),而不是正确的像素。 如果我将位图保存到.bmp文件中(事件触发前请参见注释行),我可以看到正确的屏幕截图,但是缺少文件夹名称之类的东西,这正常吗?
所以我的问题是:
提前致谢!
你可以做这样的事情
using (var bmp = new Bitmap(fromPath))
{
// lock the array for direct access int 32Bpp
var data = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppPArgb);
// store the max length so we don't have to recalculate it
var length = (int*)data.Scan0 + bmp.Height * bmp.Width;
for (var p = (int*)data.Scan0; p < length; p++)
{
//*p is your pixel as an int;
// change the color like this
*p = Color.Red.ToArgb();
Color = Color.FromArgb(*p);
}
// or if you want x/y
var p = (int*)data.Scan0;
for (int x = 0; x < bmp.Width; x++)
for (int y = 0; y < bmp.Height; y++)
*(p + x + y * bmp.Width) = Color.Red.ToArgb();
// if you want to copy the whole array
int[] managedArray = new int[bmp.Width * bmp.Height];
Marshal.Copy((int*)data.Scan0, managedArray, 0, bmp.Width * bmp.Height);
// unlock the bitmap
bmp.UnlockBits(data);
}
注意 :完全未经测试
最后,当将位图存储在1d数组中时,将存储第一行像素,然后紧接着是下一行像素。
因此,如果您想知道单个索引中任何时间的位置,则只需2个for循环
for (int x = 0; x < bmp.Width; x++)
for (int y = 0; y < bmp.Height; y++)
// your pixel is at array[x + y * width]
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.