从位图的字节数组中获取像素数据

时间:2018-10-24 11:52:39

标签: c# screenshot sharpdx

我正在为以下问题而烦恼

我在这里发现了一个类,该类使用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文件中(事件触发前请参见注释行),我可以看到正确的屏幕截图,但是缺少文件夹名称之类的东西,是否正常?

所以我的问题是:

  1. 如何从线性阵列中获取正确的像素数据?也许我需要大步走吗?但我不知道这会在哪里帮助
  2. 我发现的代码不是使用Marshal.Copy的,这似乎是获得像素数据的广泛接受的方法。会更好吗?

谢谢!

1 个答案:

答案 0 :(得分:0)

您可以这样做

$(function(){
    var now = new Date();
    var mm = now.getMonth() + 1;
    $("#footer").html(`&copy; NekoLuka ${now.getFullYear()}/${mm}/${now.getDay()}`);
}

注意 :完全未经测试

最后,当将位图存储在1d数组中时,将存储第一行像素,然后紧接着是下一行像素。

因此,如果您想随时随地知道自己在单个索引中的位置,则只需两个for循环

py -3.7 -m pip install Shapely-1.6.4.post1-cp37-cp37m-win_amd64.whl