Drawing, images and printing with GDI+
Graphics, Pen and Brush basics, drawing to a control versus a bitmap, DPI-aware scaling, and printing through PrintDocument with a preview.
The drawing model
protected override void OnPaint(PaintEventArgs e)
{
var g = e.Graphics;
g.SmoothingMode = SmoothingMode.AntiAlias;
g.PixelOffsetMode = PixelOffsetMode.HighQuality;
using var pen = new Pen(Color.FromArgb(200, 60, 60), 2f);
using var fill = new SolidBrush(Color.FromArgb(40, 200, 60, 60));
var rect = new Rectangle(10, 10, 200, 120);
g.FillRectangle(fill, rect);
g.DrawRectangle(pen, rect);
g.DrawLine(pen, rect.Left, rect.Bottom, rect.Right, rect.Top);
g.DrawString("Sample", Font, Brushes.Black, rect.Location);
}- Everything created with
new- pens, brushes, fonts, bitmaps, graphics contexts on images - must be disposed. Wrap them inusing. - Static
BrushesandPensentries are shared and must not be disposed. DrawStringrenders with GDI+ text layout;TextRenderer.DrawTextuses GDI and matches the rest of the UI. PreferTextRendererfor labels,DrawStringfor rotated or transformed text.- Coordinates are in device pixels; at 150 percent scaling a 200 px rectangle is physically smaller than the designer suggested.
Drawing to a bitmap
static Bitmap RenderChart(IReadOnlyList<double> values, int width, int height)
{
var bmp = new Bitmap(width, height, PixelFormat.Format32bppPArgb);
using var g = Graphics.FromImage(bmp);
g.Clear(Color.White);
g.SmoothingMode = SmoothingMode.AntiAlias;
var max = values.Max();
using var pen = new Pen(Color.SteelBlue, 2f);
for (var i = 1; i < values.Count; i++)
{
var x1 = (i - 1) * width / (float)values.Count;
var x2 = i * width / (float)values.Count;
g.DrawLine(pen, x1, height - (float)(values[i - 1] / max * height),
x2, height - (float)(values[i] / max * height));
}
return bmp;
}
// on a control: a 500 x 300 bitmap shown in a 250 x 150 box
pictureBox.Image?.Dispose();
pictureBox.Image = RenderChart(values, 500, 300);
pictureBox.SizeMode = PictureBoxSizeMode.Zoom;| Target | Create with | Remember |
|---|---|---|
| A control | e.Graphics in OnPaint | Never store it; it is only valid during the paint |
| An image | Graphics.FromImage(bmp) | Dispose the Graphics, keep the Bitmap |
| The printer | e.Graphics in PrintPage | Units are hundredths of an inch by default |
| A screen capture | Graphics.CopyFromScreen | Multi-monitor coordinates can be negative |
Render behind-the-scenes images at the pixel size they will be displayed, multiplied by the current DPI scale, then draw them with InterpolationMode.HighQualityBicubic. Scaling up a low-resolution bitmap in the paint handler is the usual cause of blurry charts.
Printing and print preview
var doc = new PrintDocument { DocumentName = "Invoice 1042" };
doc.DefaultPageSettings.Landscape = false;
doc.DefaultPageSettings.Margins = new Margins(60, 60, 60, 60);
var page = 0;
doc.PrintPage += (s, e) =>
{
var g = e.Graphics;
g.DrawString($"Invoice 1042 - page {page + 1}", Font, Brushes.Black, 60, 60);
// print the same visual the screen shows, scaled to the printable area
var area = e.MarginBounds;
var chart = RenderChart(values, area.Width, area.Height / 2);
g.DrawImage(chart, area.Left, area.Top + 40, area.Width, area.Height / 2);
chart.Dispose();
page++;
e.HasMorePages = page * 2 < values.Count; // decide inside the handler
};
using var preview = new PrintPreviewDialog { Document = doc, Width = 1000, Height = 700 };
preview.ShowDialog(this);⚠️
Print output is in hundredths of an inch, not pixels, and the printable area is smaller than the page because of unprintable margins. Always lay out from
e.MarginBounds and test on a real printer - a preview can look correct while the physical page clips the last column.FAQ
Why is my drawing blurry at 150 percent scaling?
Either the bitmap was rendered at 100 percent sizes and then stretched, or
AutoScaleMode is wrong for the container. Render at device size and let the DPI scaling handle the rest.Print to PDF without a printer driver?
Use the Microsoft Print to PDF queue, or generate the document with a PDF library and skip
PrintDocument entirely when you need precise pagination.Related
Custom controls and owner-drawn rendering High DPI, accessibility and theming
Last refreshed 2026-09-18.