I am writing a program that displays a map, and on top of it another layer where position of cameras and their viewing direction is shown. The map itself can be zoomed and panned. The problem is that the map files are of significant size and zooming does not go smoothly.
I created class ZoomablePictureBox : PictureBox
to add zooming and panning ability. I tried different methods, from this and other forums, for zooming and panning and ended up with the following, firing on the OnPaint
event of ZoomablePictureBox
:
private void DrawImgZoomed(PaintEventArgs e)
{
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
if (imgZoomed != null)
e.Graphics.DrawImage(imgZoomed, new Rectangle(-ShiftX, -ShiftY, imgZoomed.Width, imgZoomed.Height), 0, 0, imgZoomed.Width, imgZoomed.Height, GraphicsUnit.Pixel);
}
Where ShiftX and ShiftY provide proper map panning (calculation irrelevant for this problem).
imgZoomed
is zoomed version of original map calculated in BackgroundWorker everytime the zoom changes:
private void bgWorker_DoWork(object sender, DoWorkEventArgs e)
{
Bitmap workerImage = e.Argument as Bitmap;
Bitmap result;
result = new Bitmap(workerImage, new Size((int)(workerImage.Width * Zoom), (int)(workerImage.Height * Zoom)));
e.Result = result;
}
So current approach is, that everytime user scrolls mousewheel, the new imgZoomed
is calculated based on current Zoom. With map size of ~30 MB this can take up to 0,5 second which is annoying, but panning runs smoothly.
I realize that this may not be the best idea. In previous approach i did not create zoomed image copy everytime mouse is scrolled but did this instead:
e.Graphics.DrawImage(Image, new Rectangle(-ShiftX, -ShiftY, (int)(this._image.Width * Zoom), (int)(this._image.Height * Zoom)), 0, 0, Image.Width, Image.Height, GraphicsUnit.Pixel);
Zoom was much smoother, because from what i understand, it just stretched original image. On the other hand panning was skipping heavily.
I wast thinking of:
- creating copies of orignial map for each zoom in memory/on hard drive - it will take up too much memory/hdd space
- creating copies of orignial map for next/actual/previous zooms so i have more time to calculate next step - it will not help if user scrolls more than one step at a time
I also tried matrix transformations - no real performance gain, and calculating pan was a real pain in the arse.
I'm running in circles here and don't know how to do it. If i open the map in default Windows picture viewer zooming and panning is smooth. How do they do that?
In what way do I achieve smooth zooming and panning at the same time?
StretchBlt
with cachedGraphics
andHBitmap
objects. This helped me achieve super smooth display even on 7000X7000 images. – Rotem