I have a form that prints correctly on my machine but when I deploy the application on another machine, the form does not fit on the page and the desktop background appears on the printed document. The primary differences between the two machines is that one has the DPI setting at 150%. I have changed auto scaling many times but nothing changes. The form looks ok on screen but just does not print correctly. Below is the code I am using.
private void btnPrint_Click(object sender, EventArgs e)
{
CaptureScreen();
printPreviewDialog1.Document = printDocument1;
printPreviewDialog1.ShowDialog();
}
Bitmap memoryImage;
private void CaptureScreen()
{
Graphics myGraphics = this.CreateGraphics();
Size s = this.Size;
memoryImage = new Bitmap(s.Width, s.Height, myGraphics);
Graphics memoryGraphics = Graphics.FromImage(memoryImage);
memoryGraphics.CopyFromScreen(this.Location.X, this.Location.Y, 0, 0, s);
}
private void printDocument1_PrintPage(System.Object sender,
System.Drawing.Printing.PrintPageEventArgs e)
{
e.Graphics.DrawImage(memoryImage, 0, 0);
}
The higher dpi scaling is not (like the old 125% scaling) made by increasing the Windows font size and having the application handle the scaling, but by having the operating system do the scaling for you. In this mode, the operating system lies to the application about the actual dpi settings and does by itself scale the application when drawing its surface.
The result is that inside your application, the pixel positions and sizes are not the real ones used on the screen. But the CopyFromScreen()
method requires the actual pixel coordinates and sizes. You need to find out the pixel scaling your application undergoes and then apply this scaling to the coordinates you use.
Here is the working code (The getScalingFactor()
method was stolen from this answer).
[DllImport("gdi32.dll")]
static extern int GetDeviceCaps(IntPtr hdc, int nIndex);
public enum DeviceCap
{
VERTRES = 10,
DESKTOPVERTRES = 117,
}
private float getScalingFactor()
{
using (Graphics g = Graphics.FromHwnd(IntPtr.Zero))
{
IntPtr desktop = g.GetHdc();
try
{
int LogicalScreenHeight = GetDeviceCaps(desktop, (int)DeviceCap.VERTRES);
int PhysicalScreenHeight = GetDeviceCaps(desktop, (int)DeviceCap.DESKTOPVERTRES);
float ScreenScalingFactor = (float)PhysicalScreenHeight / (float)LogicalScreenHeight;
return ScreenScalingFactor;
}
finally
{
g.ReleaseHdc();
}
}
}
private void button1_Click(object sender, EventArgs e)
{
using (Graphics myGraphics = this.CreateGraphics())
{
var factor = getScalingFactor();
Size s = new Size((int)(this.Size.Width * factor), (int)(this.Size.Height * factor));
using (Bitmap memoryImage = new Bitmap(s.Width, s.Height, myGraphics))
{
using (Graphics memoryGraphics = Graphics.FromImage(memoryImage))
{
memoryGraphics.CopyFromScreen((int)(Location.X * factor), (int)(Location.Y * factor), 0, 0, s);
memoryImage.Save(@"D:\x.png", ImageFormat.Png);
}
}
}
}