I want to create an image from a win32 control (ie WindowsFormsHost, Hwndhost , webview2) being displayed in a WPF window.
- Am I correct that RenderTargetBitmap will not work for these kinds of controls?
Assuming I am correct, I am looking at the methods used in this GitHub project to make the image. The project wraps the webbrowser control in a ContenControl. It then gets the position of this content control on the screen and uses the Graphics class method CopyFromScreen.
private void CreateScreenshotFromContent()
{
Point upperLeftPoint = _airspaceContent.PointToScreen(new Point(0, 0));
var bounds = new System.Drawing.Rectangle((int)(upperLeftPoint.X * _scalingFactor),
(int)(upperLeftPoint.Y * _scalingFactor),
(int)(_airspaceContent.RenderSize.Width * _scalingFactor),
(int)(_airspaceContent.RenderSize.Height * _scalingFactor));
using (var bitmap = new System.Drawing.Bitmap((int)bounds.Width, (int)bounds.Height))
{
using (var g = System.Drawing.Graphics.FromImage(bitmap))
{
g.CopyFromScreen(new System.Drawing.Point(bounds.Left, bounds.Top),
System.Drawing.Point.Empty,
new System.Drawing.Size((int)bounds.Width, (int)bounds.Height));
}
_airspaceScreenshot.Source = GetImageSourceFromBitmap(bitmap);
}
}
// https://stackoverflow.com/questions/5977445/how-to-get-windows-display-settings
[DllImport("gdi32.dll")]
static extern int GetDeviceCaps(IntPtr hdc, int nIndex);
private void GetScalingFactor()
{
var g = System.Drawing.Graphics.FromHwnd(IntPtr.Zero);
IntPtr desktop = g.GetHdc();
int LogicalScreenHeight = GetDeviceCaps(desktop, 10);
int PhysicalScreenHeight = GetDeviceCaps(desktop, 117);
float ScreenScalingFactor = (float)PhysicalScreenHeight / (float)LogicalScreenHeight;
_scalingFactor = ScreenScalingFactor; // 1.25 = 125%
}
public ImageSource GetImageSourceFromBitmap(System.Drawing.Bitmap bitmap)
{
using (var memory = new MemoryStream())
{
bitmap.Save(memory, ImageFormat.Png);
memory.Position = 0;
BitmapImage bitmapImage = new BitmapImage();
bitmapImage.BeginInit();
bitmapImage.StreamSource = memory;
bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
bitmapImage.EndInit();
return bitmapImage;
}
}
The GitHub project uses the WebBrowser control. One small complication is I am updating this to the WebView2 control which is newer but is also just a win32 control in WPF.
All works fine if the PC's scaling is 100%. The resulting image almost perfectly matches what the control displays. Unfortunately this does not if scaling is changed.
This is how the window looks with the Webbrowser control with 200% scaling.
The image however is considerable enlarged when the scaling is 200%.
My project now targets 4.7.2 .Net Framework which if I understand correctly means it is now DPI aware thus I understand I do not need to do anything extra with the app config or manifest. Am I correct Manifest changes like below are no longer needed?
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2</dpiAwareness>
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true/pm</dpiAware>
</windowsSettings>
</application>