mirror of
https://github.com/Artemis-RGB/Artemis
synced 2026-11-11 11:26:27 +00:00
110 lines
4.1 KiB
C#
110 lines
4.1 KiB
C#
using System.Drawing;
|
|
using System.IO;
|
|
using SharpDX;
|
|
using SharpDX.Direct3D;
|
|
using SharpDX.Direct3D11;
|
|
using SharpDX.DXGI;
|
|
using Device = SharpDX.Direct3D11.Device;
|
|
using MapFlags = SharpDX.DXGI.MapFlags;
|
|
using Resource = SharpDX.DXGI.Resource;
|
|
using ResultCode = SharpDX.DXGI.ResultCode;
|
|
|
|
namespace Artemis.Utilities
|
|
{
|
|
internal class ScreenCapture
|
|
{
|
|
private readonly Device _device;
|
|
private readonly OutputDuplication _duplicatedOutput;
|
|
private readonly Texture2D _screenTexture;
|
|
private readonly uint numAdapter = 0; // # of graphics card adapter
|
|
private readonly uint numOutput = 0; // # of output device (i.e. monitor)
|
|
private DataStream _dataStream;
|
|
private Resource _screenResource;
|
|
private Surface _screenSurface;
|
|
|
|
public ScreenCapture()
|
|
{
|
|
// Create device and factory
|
|
_device = new Device(DriverType.Hardware);
|
|
var factory = new Factory1();
|
|
|
|
// Creating CPU-accessible texture resource
|
|
var texdes = new Texture2DDescription
|
|
{
|
|
CpuAccessFlags = CpuAccessFlags.Read,
|
|
BindFlags = BindFlags.None,
|
|
Format = Format.B8G8R8A8_UNorm,
|
|
Height = factory.Adapters1[numAdapter].Outputs[numOutput].Description.DesktopBounds.Bottom,
|
|
Width = factory.Adapters1[numAdapter].Outputs[numOutput].Description.DesktopBounds.Right,
|
|
OptionFlags = ResourceOptionFlags.None,
|
|
MipLevels = 1,
|
|
ArraySize = 1,
|
|
SampleDescription =
|
|
{
|
|
Count = 1,
|
|
Quality = 0
|
|
},
|
|
Usage = ResourceUsage.Staging
|
|
};
|
|
_screenTexture = new Texture2D(_device, texdes);
|
|
|
|
// duplicate output stuff
|
|
var output = new Output1(factory.Adapters1[numAdapter].Outputs[numOutput].NativePointer);
|
|
_duplicatedOutput = output.DuplicateOutput(_device);
|
|
_screenResource = null;
|
|
_dataStream = null;
|
|
}
|
|
|
|
public DataStream Capture()
|
|
{
|
|
try
|
|
{
|
|
OutputDuplicateFrameInformation duplicateFrameInformation;
|
|
_duplicatedOutput.AcquireNextFrame(1000, out duplicateFrameInformation, out _screenResource);
|
|
}
|
|
catch (SharpDXException e)
|
|
{
|
|
if (e.ResultCode.Code == ResultCode.WaitTimeout.Result.Code)
|
|
return Capture();
|
|
throw;
|
|
}
|
|
|
|
// copy resource into memory that can be accessed by the CPU
|
|
_device.ImmediateContext.CopyResource(_screenResource.QueryInterface<SharpDX.Direct3D11.Resource>(),
|
|
_screenTexture);
|
|
|
|
// cast from texture to surface, so we can access its bytes
|
|
_screenSurface = _screenTexture.QueryInterface<Surface>();
|
|
|
|
// map the resource to access it
|
|
_screenSurface.Map(MapFlags.Read, out _dataStream);
|
|
|
|
// seek within the stream and read one byte
|
|
_dataStream.Position = 4;
|
|
_dataStream.ReadByte();
|
|
|
|
// free resources
|
|
_dataStream.Close();
|
|
_screenSurface.Unmap();
|
|
_screenSurface.Dispose();
|
|
_screenResource.Dispose();
|
|
_duplicatedOutput.ReleaseFrame();
|
|
|
|
return _dataStream;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets a specific pixel out of the data stream.
|
|
/// </summary>
|
|
/// <param name="surfaceDataStream"></param>
|
|
/// <param name="position">Given point on the screen.</param>
|
|
/// <returns></returns>
|
|
public static Color GetColor(DataStream surfaceDataStream, Point position)
|
|
{
|
|
var data = new byte[4];
|
|
surfaceDataStream.Seek(position.Y*1920*4 + position.X*4, SeekOrigin.Begin);
|
|
surfaceDataStream.Read(data, 0, 4);
|
|
return Color.FromArgb(255, data[2], data[1], data[0]);
|
|
}
|
|
}
|
|
} |