GDI+ FAQ: Calculating Best-Fit Drawing Using
A Transform
Often, an image
needs to be displayed in a rectangle that is not the same size or aspect
ratio as the original image. One solution is to make a temporary copy of
an image, perhaps a thumbnail, and use this to display the image. Another
method often used is to simply stretch the image into the rectangle and
hope for the best. This is the PictureBox controls best-fit method.
However, in cases where the aspect ratio of the image is important
stretching is a poor choice.
My favourite method
employs the power of GDI+ transforms to draw the image directly without
making a copy. A transform can be calculated that fits the longest
dimension of the image into the shortest dimension of the destination
rectangle, An offset can also be calculated that moves the image into the
horizontal or vertical center of the destination rectangle. The resulting
transform is then used to draw the image directly into the destination
without having to copy the image.
The images in Figure
1 show how the image is displayed on a form after
transformation.
Figure
1
The code that
performs this is shown in listing 1. The work is all handled in the
Form1_Paint routine.
using
System;
using
System.Drawing;
using
System.Drawing.Drawing2D;
using
System.Collections;
using
System.ComponentModel;
using
System.Windows.Forms;
using
System.Data;
namespace
bestfit
{
/// <summary>
/// Summary
description for Form1.
/// </summary>
public class
Form1 : System.Windows.Forms.Form
{
public Image _image=null;
/// <summary>
/// Required
designer variable.
/// </summary>
private System.ComponentModel.Container
components = null;
public Form1()
{
//
// Required for Windows Form Designer
support
//
InitializeComponent();
SetStyle(
ControlStyles.ResizeRedraw |
ControlStyles.AllPaintingInWmPaint |
ControlStyles.DoubleBuffer,
true);
}
/// <summary>
/// Clean up any
resources being used.
/// </summary>
protected override void
Dispose( bool disposing
)
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing
);
}
#region
Windows Form Designer generated code
/// <summary>
/// Required method
for Designer support - do not modify
/// the contents of
this method with the code editor.
/// </summary>
private void
InitializeComponent()
{
//
// Form1
//
this.AutoScaleBaseSize = new System.Drawing.Size(5,
13);
this.ClientSize = new System.Drawing.Size(464,
261);
this.Name = "Form1";
this.Text = "Form1";
this.Load += new System.EventHandler(this.Form1_Load);
this.Paint += new
System.Windows.Forms.PaintEventHandler(this.Form1_Paint);
}
#endregion
/// <summary>
/// The main entry
point for the application.
/// </summary>
[STAThread]
static void
Main()
{
Application.Run(new
Form1());
}
private void
Form1_Load(object sender,
System.EventArgs e)
{
OpenFileDialog dlg= new
OpenFileDialog();
dlg.Filter="Image files (*.bmp, *.jpg,
*.gif)|*.BMP;*.JPG;*.GIF";
if(dlg.ShowDialog()==DialogResult.OK)
{
this._image=Image.FromFile(dlg.FileName);
Invalidate();
}
}
private void
Form1_Paint(object sender,
System.Windows.Forms.PaintEventArgs e)
{
if(_image==null)
return;
double largestRatio=Math.Max((double)_image.Width/this.ClientSize.Width,(double)_image.Height/this.ClientSize.Height);
float posX=(float)(this.ClientSize.Width*largestRatio/2-_image.Width/2);
float posY=(float)(this.ClientSize.Height*largestRatio/2-_image.Height/2);
Matrix mx=new Matrix(1.0f/(float)largestRatio,0,0,1.0f/(float)largestRatio,0,0);
mx.Translate(posX,posY);
e.Graphics.Transform=mx;
e.Graphics.DrawImageUnscaled(_image,0,0);
}
}
}
Back to the GDI+
FAQ
|