I have an image viewer application which I want to apply a magnifying glass effect on certain area of the image. The problem I've run into is that when I slowly dragged the magnifying glass across (when left mouse down) the magnifying glass window didn't move smoothly. I believe it has something to do with drawing the graphics of the original image on the background. May someone please help me solve this issue Thanks.

Help in implementation of a magnifying glass
Brandon Bloom
LoveWinXP
SLV
If that doesn't get you anywhere, email me your project so I'll have half an idea what is really going on. Email address is in my profile, |Monkeytail| = @
cgirolami
using System;
using System.Drawing;
using System.Windows.Forms;
public class NoBlinkPanel2 : Panel {
private Image mImage;
public NoBlinkPanel2() {
SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint, true);
}
public Image Image {
get { return mImage; }
set {
mImage = value;
Invalidate();
}
}
protected override void OnPaintBackground(PaintEventArgs e) {
// Do *not* erase background
}
protected override void OnPaint(PaintEventArgs e) {
// Render bitmap to panel
Rectangle srce = new Rectangle(0, 0, mImage.Width, mImage.Height);
Rectangle dest = new Rectangle(0, 0, Width, Height);
if (mImage == null) e.Graphics.FillRectangle(new SolidBrush(this.BackColor), dest);
else e.Graphics.DrawImage(mImage, dest, srce, GraphicsUnit.Pixel);
base.OnPaint(e);
}
}
Bland
First off, you get flicker (the white shimmer around the rectangle) because the panel isn't double-buffered. Check out this thread for a custom panel that avoids this. Secondly, you stretch the image to fit the size of the panel. That's expensive due to the required interpolation. Drawing the image at its original size gives you an immediate speed-up of 500% or better. The scrollbars in the custom panel would allow you to do this. You will however need to change your magnifier glass position logic.
Lastly, use the PaintEventArgs.ClipRectangle property. It tells you what portion of the image needs to be redrawn. That ought to give you a significant speed boost too although I haven't tried it.
Codigo47
MA2005
In the MyMagnifyGlass class, I have the following code to move the magnifying window to center to the mouse location:
public void MoveTo(Point location) {
this.mouseX = location.X;
this.mouseY = location.Y;
this.Location = new Point(this.mouseX - this.Size.Width/2, this.mouseY - this.Size.Height/2);
this.Invalidate();
}
and then draw the portion of the image in its original size:
private void magnifyGlass_Paint(object sender, PaintEventArgs e) {
int x = (int)(this.mouseX * (float)this.image.Width/this.Parent.ClientSize.Width) - this.Size.Width/2;
int y = (int)(this.mouseY * (float)this.image.Height/this.Parent.ClientSize.Height) - this.Size.Height/2;
e.Graphics.DrawImage(this.image, new Rectangle(new Point(), this.Size), x, y, this.Size.Width, this.Size.Height, GraphicsUnit.Pixel);
}
In the MyImageViewer class, I use Panel to be my drawing board and have the following code to show the magnified area when the mouse is down:
private void picPanel_MouseDown(object sender, MouseEventArgs e) {
if (this.image != null && e.Button == MouseButtons.Left) {
this.isMagnified = true;
this.magnifier.MoveTo(new Point(e.X, e.Y));
this.magnifier.Show();
}
}
private void picPanel_Paint(object sender, PaintEventArgs e) {
if (this.image != null) {
e.Graphics.InterpolationMode = InterpolationMode.HighQualityBilinear;
e.Graphics.DrawImage(this.image, new Rectangle(0, 0, this.picPanel.Size.Width, this.picPanel.Size.Height),0,0,this.image.Width,this.image.Height,GraphicsUnit.Pixel);
}
}
So far so good, but when I move the mouse, the image flicks and the magnifying glass window jumps. The code is as followed:
private void picPanel_MouseMove(object sender, MouseEventArgs e) {
if (this.image != null && this.isMagnified) {
this.magnifier.MoveTo(new Point(e.X, e.Y));
this.Update();
}
}
I hope to avoid DirectX and I believe this magnifying glass can be implemented smoothly without using DirectX. I have used an off-the-self component that has this feature, and DirectX was not needed.
Thanks.
Hristo Atanasov
My problem seems to be on drawing the image in the viewer, not the portion within the magnify glass panel. If I don't re-draw the image in the viewer, dragging the magnify glass panel across the viewer's surface will leave a white path along its way, but the magnified portion within the panel shows up pretty fast, and the panel itself moves across the viewer's surface smoothly.
On the other hand, if I re-draw the image in the viewer (I have even tried using Region to limit the amount of invalidated area), dragging the magnify glass panel across the viewer will cause the panel to jump and its content flicker.
I have tried searching in this forum and the Internet to see if someone else has written code to implement a magnifying glass feature in .NET, but it came up nothing. I am not sure if my algorithm (have a panel as a magnifying glass over the image viewer panel) is the right way to go.
Any pointers/comments will be appreciated. Thanks.
user32
Thanks.
RtMahi
Hmm. Possibly do the drawing on a different thread. The window is jumping because of the drawing most likely.
Perhaps use DirectX
aliassce
On the other hand, I turn off the interpolation during magnifying, and that helped a lot.
I can't really use the referenced NoBlinkPanel class simply because I need the image to completely fit inside the viewer, hence, autoscroll doesn't help.
So, I need to cheat a little bit, re-draw the image without interpolation when mouse-down and then re-draw with interpolation when mouse-up.
Thanks.
frappy666
Now, the only issue left is with the interpolation. Any suggestions
Duane Douglas
I have just emailed you a sample project that implements the magnifying glass feature. Thanks for your help.
You are amazingly fast and helpful. Keep up the great work!.
Regards.
-
J
chaza
private Bitmap mBuffer;
...
mBuffer = new Bitmap(this.image.Width, this.image.Height, System.Drawing.Imaging.PixelFormat.Format32bppPArgb);
Graphics gr = Graphics.FromImage(mBuffer);
gr.DrawImage(this.image, 0, 0);
gr.Dispose();
...
private void magnifyGlass_Paint(object sender, PaintEventArgs e) {
int x = (int)(this.mouseX * (float)mBuffer.Width/this.Parent.ClientSize.Width) - this.Size.Width/2;
int y = (int)(this.mouseY * (float)mBuffer.Height/this.Parent.ClientSize.Height) - this.Size.Height/2;
e.Graphics.DrawImage(mBuffer, new Rectangle(new Point(), this.Size), x, y, this.Size.Width, this.Size.Height, GraphicsUnit.Pixel);
}