我目前正在使用SharpDX.Direct3D11
NuGet包来捕获整个屏幕并将其转换为System.Drawing.Bitmap
对象,就像这样:
using SharpDX;
using SharpDX.Direct3D11;
using SharpDX.DXGI;
using System;
using System.Drawing;
using System.Drawing.Imaging;
using Device = SharpDX.Direct3D11.Device;
using MapFlags = SharpDX.Direct3D11.MapFlags;
using Resource = SharpDX.DXGI.Resource;
public class Direct3D11CaptureSource : SyncDisposable, ICaptureSource
{
public Direct3D11CaptureSource()
{
factory = new Factory1();
adapter = factory.GetAdapter1(0);
device = new Device(adapter);
output = adapter.GetOutput(0);
var desktopBounds = output.Description.DesktopBounds;
width = desktopBounds.Right - desktopBounds.Left;
height = desktopBounds.Bottom - desktopBounds.Top;
output1 = output.QueryInterface<Output1>();
copiedScreenTexture = new Texture2D(device, new Texture2DDescription
{
CpuAccessFlags = CpuAccessFlags.Read,
BindFlags = BindFlags.None,
Format = Format.B8G8R8A8_UNorm,
Width = width,
Height = height,
OptionFlags = ResourceOptionFlags.None,
MipLevels = 1,
ArraySize = 1,
SampleDescription = { Count = 1, Quality = 0 },
Usage = ResourceUsage.Staging
});
outputDuplication = output1.DuplicateOutput(device);
AcquireNextFrame();
ReleaseFrame();
}
readonly Adapter1 adapter;
readonly Texture2D copiedScreenTexture;
readonly Device device;
readonly Factory1 factory;
readonly int height;
readonly Output output;
readonly Output1 output1;
readonly OutputDuplication outputDuplication;
Resource screenResource;
readonly int width;
void AcquireNextFrame()
{
var result = outputDuplication.TryAcquireNextFrame(10000, out _, out screenResource);
if (result.Failure)
throw new Exception($"{nameof(outputDuplication.TryAcquireNextFrame)} failed");
if (!result.Success)
throw new Exception($"{nameof(outputDuplication.TryAcquireNextFrame)} did not succeed");
}
public Bitmap Capture()
{
try
{
AcquireNextFrame();
using (var screenTexture = screenResource.QueryInterface<Texture2D>())
device.ImmediateContext.CopyResource(screenTexture, copiedScreenTexture);
var map = device.ImmediateContext.MapSubresource(copiedScreenTexture, 0, MapMode.Read, MapFlags.None);
var bitmap = new Bitmap(width, height, PixelFormat.Format32bppArgb);
var bitmapAccess = bitmap.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, bitmap.PixelFormat);
var source = map.DataPointer;
var target = bitmapAccess.Scan0;
for (var y = 0; y < height; ++y)
{
Utilities.CopyMemory(target, source, width * 4);
source = IntPtr.Add(source, map.RowPitch);
target = IntPtr.Add(target, bitmapAccess.Stride);
}
bitmap.UnlockBits(bitmapAccess);
device.ImmediateContext.UnmapSubresource(copiedScreenTexture, 0);
return bitmap;
}
finally
{
ReleaseFrame();
}
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
ReleaseFrame();
outputDuplication.Dispose();
copiedScreenTexture.Dispose();
output1.Dispose();
output.Dispose();
device.Dispose();
adapter.Dispose();
factory.Dispose();
}
}
void ReleaseFrame()
{
screenResource?.Dispose();
screenResource = null;
}
}
我的目标虽然更具体。我正在尝试仅从特定过程(尤其是3D视频游戏)捕获快照。我可以通过其他方式使用此NuGet来实现这一目标吗?我应该使用其他工具吗?