Search code examples
directx-11sharpdx

How to create bitmap from Surface (SharpDX)


I am new to DirectX and trying to use SharpDX to capture a screen shot using the Desktop Duplication API.

I am wondering if there is any easy way to create bitmap that I can use in CPU (i.e. save on file, etc.)

I am using the following code the get the desktop screen shot:

var factory = new SharpDX.DXGI.Factory1();
var adapter = factory.Adapters1[0];
var output = adapter.Outputs[0];

var device = new SharpDX.Direct3D11.Device(SharpDX.Direct3D.DriverType.Hardware,
                                                       DeviceCreationFlags.BgraSupport |
                                                       DeviceCreationFlags.Debug);

var dev1 = device.QueryInterface<SharpDX.DXGI.Device1>();

var output1 = output.QueryInterface<Output1>();
var duplication = output1.DuplicateOutput(dev1);
OutputDuplicateFrameInformation frameInfo;
SharpDX.DXGI.Resource desktopResource;
duplication.AcquireNextFrame(50, out frameInfo, out desktopResource);

var desktopSurface = desktopResource.QueryInterface<Surface>();

can anyone please give me some idea on how can I create a bitmap object from the desktopSurface (DXGI.Surface instance)?


Solution

  • The MSDN page for the Desktop Duplication API tells us the format of the image:

    DXGI provides a surface that contains a current desktop image through the new IDXGIOutputDuplication::AcquireNextFrame method. The format of the desktop image is always DXGI_FORMAT_B8G8R8A8_UNORM no matter what the current display mode is.

    You can use the Surface.Map(MapFlags, out DataStream) method get access to the data on the CPU.

    The code should look like* this:

    DataStream dataStream;
    desktopSurface.Map(MapFlags.Read, out dataStream);
    for(int y = 0; y < surface.Description.Width; y++) {
        for(int x = 0; x < surface.Description.Height; x++) {
            // read DXGI_FORMAT_B8G8R8A8_UNORM pixel:
            byte b = dataStream.Read<byte>();
            byte g = dataStream.Read<byte>();
            byte r = dataStream.Read<byte>();
            byte a = dataStream.Read<byte>();
            // color (r, g, b, a) and pixel position (x, y) are available
            // TODO: write to bitmap or process otherwise
        }
    }
    desktopSurface.Unmap();
    

    *Disclaimer: I don't have a Windows 8 installation at hand, I'm only following the documentation. I hope this works :)