-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
undersampling / bitmap zoom implementation #41
Comments
I think bitmap zoom can be achieved efficiently enough by using a nearest neighbor image resize function. The reason I implemented bitmap zoom by creating a large bitmap with the zoomed pixels is that I had a bad experience with image scaling. The windows API has a StretchBlt function which I have found to be way (and I mean way) too slow when the HALFTONE stretch mode is used. It was used in the first version of the program that was published here at github: ExploreFractals/ExploreFractals.cpp Line 1156 in 91df77a
But that was too slow because I was trying to achieve the effect of oversampling by using stretching. 4×4 oversampling meant that the resolution of the bitmap was 16 times larger than the image on screen and the bitmap was stretched (well, shrunk) every time the screen refreshed. For such large bitmaps and with a good looking stretch method (HALFTONE) it was too slow, but what I want with bitmap zoom is to stretch a small bitmap and with a simpler method. To get an idea of the difference in speed: a benchmark by using nana (which I assume calls the windows API): The GUI_main function starts like this: int GUI_main(FractalParameters& defaultParameters, uint number_of_threads, FractalParameters& firstTabParameters)
{
paint::image_process::selector().stretch("proximal interpolation"); It first sets the stretching algorithm. Proximal interpolation is nearest neighbor: https://qpcr4vir.github.io/nana-doxy/html/d1/d81/stretch_image_8cpp-example.html I placed timers around the code where stretching occurs: paint::graphics viewport_copy;
API::window_graphics(viewport, viewport_copy);
paint::graphics& bitmap_graphics = fp->bitmapManager->graph;
if (zoomIn) {
rectangle fromPart(
nana::point(xPos - xPos / 4 - fp->offsetX, yPos - yPos / 4 - fp->offsetY)
,nana::size(bitmapWidth / 4, bitmapHeight / 4)
);
rectangle toPart(nana::point(0, 0), nana::size(bitmapWidth, bitmapHeight));
timerstart
viewport_copy.stretch(fromPart, bitmap_graphics, toPart);
timerend("zoom in stretch")
}
else {
rectangle fromPart(
nana::point(0 - fp->offsetX, 0 - fp->offsetY)
,nana::size(bitmapWidth, bitmapHeight)
);
rectangle toPart(
nana::point(xPos - xPos / 4, yPos - yPos / 4)
,nana::size(bitmapWidth / 4, bitmapHeight / 4)
);
timerstart
viewport_copy.stretch(fromPart, bitmap_graphics, toPart);
timerend("zoom out stretch")
} Results using a maximized ExploreFractals on my computer: zoom in stretch: 0,019 seconds With bilinear interoplation: zoom in stretch: 0,065 seconds For bitmap zoom, it's the zoom in stretch performance that matters. Nearest neigbor is 3,4 times faster which is not as much as I expected. comparing stretch and bitblt performanceWhat really matters is how much slower stretch is compared to copying an existing bitmap to the screen for every refresh. A timer around the code that copies (bitblt) timerstart
graph.bitblt(draw_area, g, nana::point(offsetX, offsetY));
timerend("bitblt time") shows that it takes 0,0033 seconds, so stretching is 5,75 times slower than copying pixels. |
When using undersampling / bitmap zoom, the zoomed bitmap is created in memory, even if it's not displayed in full. That makes it impossible to create, for example, a 3000×3000 image with 10×10 undersampling. The program would create a bitmap of size 30000×30000, which is larger than the limit on windows api bitmaps, even though probably only a small part of it has to be viewed at once (at most the size of the screen can be seen).
I started to reconsider this implementation because of what image viewers do. Image viewers allow the user to zoom in on an image. If they would create a bitmap for the complete zoomed image, they would reach the bitmap limit very quickly and run out of memory, yet they exist and work well, so there's probably a better way to do this.
I'm not sure if it's a good idea to spend time on this because it's not very important and maybe there's a good reason why it works for image viewers and not a fractal program. For example, image viewer only have to show a not changing image. My program needs to show render progress, which leads to things like scaling an image for every frame, which is slow. It may be possible to avoid duplicate work by keeping track of which pixels need to be changed but that's much more work to design and implement.
The text was updated successfully, but these errors were encountered: