Quick scaling/dragging in a canvas

I am capturing high resolution images with a frame grabber. Processing of these images will take place on the high res version, but for display purposes I want to show something a little more lightweight. On capture, I need to be able to scale the image in the canvas to fit, but I also need to drag it around the canvas and zoom in on parts of it up to 100% of its original size.

Right now I’m doing this using the MouseWheel and MouseDrag events and handling scaling in the paint event, and it works. But on a 16bit 14,000 x 10,000 pixel image, so it’s incredibly slow. …As you might expect.

I need to be able to view the image at 100% sometimes, so I can’t simply scale the image down and then blow it back up, because I need to be able to do some pixel peeking on this in my application, look at focus, etc. I need a way to quickly manipulate the original high resolution image, quickly, within this canvas.

My thought was to reduce the bit depth to something like 8 bit, which should get me partway there without too much compromise. A 14k image is still going to be pretty slow to move around though even at 8 bits. I can’t seem to find a Xojo way to do this.

Any other suggestions for reducing the size of the image in the canvas so that I can manipulate it in a quicker way? I’m not 100% opposed to compression but it would have to be super light, because I need to be able to look at something as close as possible to the original image.

I am looking for a platform independent way to do this. We’re making the app for Windows, but may eventually use it on the mac as well.

I’ve done this before by caching scaled versions at different resolutions on load, then drawing the version with the dimensions that most closely matches the zoom level. I also draw to an off-screen buffer (just a Picture object) the size and scale factor of the viewport, then draw that buffer to the Canvas. Either of these should get you a more responsive app when you’re working with any size image.

You, of course, are working with a massively large image. Will take a lot of work to get blazing fast speed.

2 Likes

haha. I don’t need blazing fast, I just need it to be faster. Right now, on a pretty quick i9 10900 10-core @ 3.7GHz, it takes over a second for each click of the mouse wheel to scale the image down.

We are waiting for the code to arrive later this week, but we’re paying someone to create a Plain C library for openCV, so we can declare into it directly. That’s probably going to be pretty quick, and it’s possible it may solve our problem, but in the mean time I’d like to find a way to get close in Xojo.

The off-screen buffer idea sounds interesting. I remember learning about that in the early 90s when I worked for a company that made a high end video editing application. that was how they were able to make the preview video play back in real time, on whopping 640x480 pixel images on a Mac Quadra 840AV.

Do you have code you can share that shows how you do this in Xojo?

Not ready that I can just toss up. Basically you’d create a Canvas subclass with properties for image offset X and Y, your zoom level, and a Picture property. In the Paint event you check to make sure that the Picture property isn’t Nil. If it is, initialize it something like this:

if picBuffer = nil or picBuffer.Width <> g.Width or picBuffer.Height <> g.Height then
  picBuffer = new Picture( g.Width, g.Height )
end if

Repaint

g.DrawPicture( picBuffer, 0, 0 )

Then have a method that repaints the buffer, I typically call this something like Repaint which will draw the large image to the picture and perform any other operations that may be needed:

Private Sub Repaint()
  #pragma DisableBackgroundTasks
  #pragma DisableBoundsChecking
  #pragma NilObjectChecking False
  #pragma StackOverflowChecking False

  var g as Graphics = picBuffer.Graphics
  g.DrawPicture( SuperLargePicture, 0, 0, g.Width, g.Height, offsetX * ZoomLevel, offsetY * ZoomLevel, g.Width * ZoomLevel, g.Height * ZoomLevel )
End Sub

Note that this is untested browser code and may need some work.

There also some image plugins out there that may be able to speed up this work.

1 Like

cool. thanks. I’ll give this a go.

Hello Perry,
in xojo it is easy to display pictures quickly
you just have to minimize your typing and display
here is a canvas solution with a background image
in different resolutions
Only the current position is shown in the canvas.paint
and after the background processing just in
display canvas.backdrop

A simple example without registers, only with Xojo functions

https://www.dropbox.com/s/ax464bmcbxt4m5f/showlargepictures.xojo_binary_project?dl=1

Thanks. I wound up going with this post, or at least a variation of it. The performance is much better, but still not very smooth. I think this is mostly to do with the time it takes to do the scaling operation, so I’m hoping that once we can do that in OpenCV, it’ll be a bit quicker.