WinForm 中漂亮的放大镜图像效果
使用通用面板和 GDI+ 在 winform 中实现图像的放大镜效果。
引言
在某些情况下,图像放大非常有用。但实现一个精美的放大效果并不容易,尤其是在使用 C# 的 winform 中。现在我做到了,虽然可能并不完美。希望你喜欢。
背景
我一直在从事使用工业相机进行图像采集的工作,并且有很多图片需要用户浏览。
目的是为了查看图像的细节。我尝试使用 WinForm 来方便用户实现这个目的。
简单原理
创建两个自定义控件,一个用于显示完整图像,另一个用于显示部分放大后的图像。
使用 Gdi 实现一个圆形控件。
private void PartialMagPicPanel_Load(object sender, EventArgs e)
{
IntPtr dc;
IntPtr region;
IntPtr hpen2;
IntPtr holdpen;
dc = GetDC(this.Handle);
BeginPath(dc);
hpen2 = CreatePen(5, 5, ColorTranslator.ToWin32(Color.Red));
holdpen = (IntPtr)SelectObject(dc, hpen2);
Ellipse(dc, 0, 0, this.Width, this.Height);
DeleteObject(hpen2);
EndPath(dc);
region = PathToRegion(dc);
SetWindowRgn(this.Handle, region, true);
}
[System.Runtime.InteropServices.DllImport("gdi32")]
private static extern IntPtr BeginPath(IntPtr hdc);
[System.Runtime.InteropServices.DllImport("gdi32")]
private static extern int SetBkMode(IntPtr hdc,int nBkMode);
const int TRANSPARENT = 1;
...
当鼠标位于放大图像面板中时,控件会跟随鼠标位置移动。并将当前的鼠标位置转换为原始图像中的位置。预先设置放大区域的大小,计算原始图像中新区域的位置。
将新的区域绘制到放大图像面板上。
使用代码
A
在完整图像面板中创建放大图像面板。
public partial class PicDataPanel : UserControl
{
private PartialMagPicPanel partailMagImageView = null;
public PartialMagPicPanel PartailMagImageView
{
get { return partailMagImageView; }
set { partailMagImageView = value; }
}
public PicDataPanel()
{
InitializeComponent();
partailMagImageView = new PartialMagPicPanel();
partailMagImageView.Location = new Point(2, 2);
partailMagImageView.Size = new Size(this.Width / 2, this.Width / 2);
partailMagImageView.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.Controls.Add(partailMagImageView);
}
}
B
为两个面板控件创建事件方法。
...
private System.Windows.Forms.PaintEventHandler Full_Paint_Handler = null;
private System.Windows.Forms.PaintEventHandler PartialMag_Paint_Handler = null;
private System.Windows.Forms.MouseEventHandler PartialMag_MouseMove_Handler = null;
private System.Windows.Forms.MouseEventHandler PartialMag_MouseWheel_Handler = null
private void Full_Paint(object sender, PaintEventArgs e)
{
...
private void PartialMag_Paint(object sender, PaintEventArgs e)
{
...
}
private void PartialMag_MouseMove(object sender, MouseEventArgs e)
{
...
}
private void PartialMag_MouseWheel(object sender, MouseEventArgs e)
{
...
}
...
B1
Full_Paint 方法是将完整图像绘制到完整图像面板上。
private void Full_Paint(object sender, PaintEventArgs e)
{
e.Graphics.DrawImage(orignalimh
, new Rectangle(0, 0, pdp.Width, pdp .Height)
, new Rectangle(0, 0, orignalimh.Width, orignalimh.Height), GraphicsUnit.Pixel);
}
B2
PartialMag_Paint 方法是将放大图像绘制到放大面板上。它包含三个部分。
第一部分:鼠标点在完整图像面板中的原始图像位置。
int srcx = (pdp.PartailMagImageView.Location.X + pdp.PartailMagImageView.Width / 2)
* orignalimh.Width / pdp.Width;
int srcy = (pdp.PartailMagImageView.Location.Y + pdp.PartailMagImageView.Height / 2)
* orignalimh.Height / pdp.Height;
第二部分:将放大图像绘制到面板上。
e.Graphics.DrawImage(orignalimh
, new Rectangle(0, 0, pdp.PartailMagImageView.Width, pdp.PartailMagImageView.Height)
, new Rectangle(srcx - ZoomOutRate / 2, srcy - ZoomOutRate / 2, ZoomOutRate, ZoomOutRate)
, GraphicsUnit.Pixel);
第三部分:绘制放大镜的边缘。
Pen mypen = new Pen(Color.CornflowerBlue, 7);
e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
e.Graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
e.Graphics.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
e.Graphics.DrawEllipse(mypen, 0, 0, pdp.PartailMagImageView.Width-7, pdp.PartailMagImageView.Height-7);
B3
PartialMag_MouseMove 方法使放大镜控件跟随鼠标。
curMoPo = e.Location;
if (curMoPo.X != pdp.PartailMagImageView.Width / 2 && curMoPo.Y != pdp.PartailMagImageView.Height / 2)
{
int offsetx = pdp.PartailMagImageView.Width / 2 - curMoPo.X;
int offsety = pdp.PartailMagImageView.Height / 2 - curMoPo.Y;
pdp.PartailMagImageView.Location = new Point(
pdp.PartailMagImageView.Location.X - offsetx,
pdp.PartailMagImageView.Location.Y - offsety);
}
pdp.PartailMagImageView.Invalidate(false);
pdp.PartailMagImageView.Update();
pdp.Update();
B4
PartialMag_MouseWheel 方法用于更改缩放比例。
if (e.Delta > 0)
{
ZoomOutRate -= 20;
}
else
{
ZoomOutRate += 20;
}
ZoomOutRate = ZoomOutRate < 20 ? 20 : ZoomOutRate;
ZoomOutRate = ZoomOutRate > orignalimh.Width ? orignalimh.Width : ZoomOutRate;
toolStripStatusLabel_ZOOM.Text = String.Format("Zoom:{0}", ZoomOutRate);
pdp.PartailMagImageView.Invalidate(false);
pdp.PartailMagImageView.Update();
pdp.Update();
C
创建面板控件并绑定事件。
PicDataPanel pdp = null;
Full_Paint_Handler = new PaintEventHandler(Full_Paint);
PartialMag_Paint_Handler = new PaintEventHandler(PartialMag_Paint);
PartialMag_MouseMove_Handler = new MouseEventHandler(PartialMag_MouseMove);
PartialMag_MouseWheel_Handler = new MouseEventHandler(PartialMag_MouseWheel);
pdp = new PicDataPanel();
pdp.Dock = DockStyle.Fill;
pdp.Paint += Full_Paint_Handler;
pdp.PartailMagImageView.Paint += PartialMag_Paint_Handler;
pdp.PartailMagImageView.MouseMove += PartialMag_MouseMove_Handler;
pdp.PartailMagImageView.MouseWheel += PartialMag_MouseWheel_Handler;
this.panel1.Controls.Add(pdp);
关注点
我困惑于如何提高加载大图像时的性能。