我正在尝试保存第二个监视器的屏幕截图,该监视器的分辨率/ DPI与主监视器不同(我对这些术语并不完全熟悉,所以我不太确定),这是我正在使用的代码:
public void SaveScreenshot(Screen screen)
{
using (Bitmap bitmap = new Bitmap(screen.Bounds.Width, screen.Bounds.Height))
{
using (Graphics g = Graphics.FromImage(bitmap))
{
int x = screen.Bounds.Left;
int y = screen.Bounds.Top;
int w = screen.Bounds.Width;
int h = screen.Bounds.Height;
g.CopyFromScreen(x, y, 0, 0, new Size(w, h));
}
bitmap.Save("screenshot.bmp");
}
}
问题在于,生成的图像没有完整的图片,而是具有较大且裁剪的图片。
我不知道我在做什么错。
答案 0 :(得分:0)
我设法使用EnumDisplaySettings解决了这个问题:
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace ScreenResolution
{
class ScreenResolutionHandler
{
const int ENUM_CURRENT_SETTINGS = -1;
public static Rectangle GetRealRectangle(Screen screen)
{
DEVMODE dm = new DEVMODE();
dm.dmSize = (short)Marshal.SizeOf(typeof(DEVMODE));
EnumDisplaySettings(screen.DeviceName, ENUM_CURRENT_SETTINGS, ref dm);
return new Rectangle(dm.dmPositionX, dm.dmPositionY, dm.dmPelsWidth, dm.dmPelsHeight);
}
[DllImport("user32.dll")]
public static extern bool EnumDisplaySettings(string lpszDeviceName, int iModeNum, ref DEVMODE lpDevMode);
[StructLayout(LayoutKind.Sequential)]
public struct DEVMODE
{
private const int CCHDEVICENAME = 0x20;
private const int CCHFORMNAME = 0x20;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 0x20)]
public string dmDeviceName;
public short dmSpecVersion;
public short dmDriverVersion;
public short dmSize;
public short dmDriverExtra;
public int dmFields;
public int dmPositionX;
public int dmPositionY;
public ScreenOrientation dmDisplayOrientation;
public int dmDisplayFixedOutput;
public short dmColor;
public short dmDuplex;
public short dmYResolution;
public short dmTTOption;
public short dmCollate;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 0x20)]
public string dmFormName;
public short dmLogPixels;
public int dmBitsPerPel;
public int dmPelsWidth;
public int dmPelsHeight;
public int dmDisplayFlags;
public int dmDisplayFrequency;
public int dmICMMethod;
public int dmICMIntent;
public int dmMediaType;
public int dmDitherType;
public int dmReserved1;
public int dmReserved2;
public int dmPanningWidth;
public int dmPanningHeight;
}
}
}
并将原始代码编辑为
public void SaveScreenshot(Screen screen)
{
Rectangle rect = ScreenResolutionHandler.GetRealRectangle(screen);
int x = rect.X;
int y = rect.Y;
int w = rect.Width;
int h = rect.Height;
using (Bitmap bitmap = new Bitmap(w, h))
{
using (Graphics g = Graphics.FromImage(bitmap))
{
g.CopyFromScreen(x,y, 0, 0, new Size(w, h));
}
bitmap.Save("screenshot.bmp");
}
}
更新:
如@Jimi所建议的,最终我必须启用每个显示器的dpi意识,才能在将其放在窗体上时保持图像的质量
app.manifest
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- A list of the Windows versions that this application has been tested on
and is designed to work with. Uncomment the appropriate elements
and Windows will automatically select the most compatible environment. -->
<!-- Windows Vista -->
<!--<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}" />-->
<!-- Windows 7 -->
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}" />
<!-- Windows 8 -->
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}" />
<!-- Windows 8.1 -->
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}" />
<!-- Windows 10 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
</application>
</compatibility>
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true/pm</dpiAware> <!-- legacy -->
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">permonitorv2,permonitor</dpiAwareness> <!-- falls back to pm if pmv2 is not available -->
</windowsSettings>
</application>