Page 1 of 2
Speed of Image manipulation
Posted: Fri Oct 24, 2003 10:29 pm
by fsw
Hi all,
I have a image with the size of 2048 x 1536 pixel.
Now I like to rotate it 90 degrees and I use this function:
Code: Select all
Image2DC = StartDrawing(ImageOutput())
For y = 0 To Image\bmHeight
For x = 0 To Image\bmWidth
BitBlt_(Image2DC,y,Image\bmWidth-x-1,1,1,Image1DC,x,y,#SRCCOPY)
Next
Next
StopDrawing()
All works fine but what I find interesting is the fact that this loop takes about 5 seconds from start to the end (CPU 100%), and
IrfanView takes for the same function (rotate left/right) approximatly
1 second (CPU 66%).
How is that possible
Is the double FOR/NEXT loop so slow under PureBasic
(I suppose that Irfan also uses the BitBlt API function for the rotation...)
How can I accellerate the rotation ?
BTW:
For now I start 3 threads (Rotate Original Right / Rotate Original Left / Rotate Original Twice - each one waits for the prior started one) right when a image is chosen by the user.
When the user after 5 seconds clicks the function Rotate Original Right OR after 10 seconds Rotate Original Left OR after 15 seconds Rotate Original Twice, the pictures show up
immediately after a mouse click (way faster as IrfanView hint, hint, hint... - supposed the user looks at a image at least for a few seconds before he decides to do something...).
But if he clicks right after choosing one, it takes 5 seconds for Right + 5 for Left and + 5 for Twice (rotate 180 degrees) which ends up to 15 seconds.
I can't use the 3 threads on the same time because of some PB functions used (StartDrawing, StopDrawing, CreateImage, UseImage) and on the other hand I don't know if it would speed up a bit (1 CPU anyway)...
Posted: Sat Oct 25, 2003 12:24 am
by Blade
BitBlt perhaps is meant for large screen area...
For single pixel I'd use peeks/pokes.
Posted: Sun Oct 26, 2003 5:00 am
by fsw
Found out what's misleading my measurements:
IrfanView always resizes the Image the way you can see it to the full.
So my 2048 x 1536 image was always resized to 840x630 (for a 1024x768 desktop resolution) and then rotated.
And I didn't. I always rotated with the original size.
If I do it with my routine the image (resized to 840x630 first) needs also 1 second to do it.
So it seems all is OK.
But if anybody has a faster way to do it, please let me know.
Posted: Sun Oct 26, 2003 9:10 am
by blueznl
have you had a look at PlgBlt_() ?
Posted: Sun Oct 26, 2003 2:41 pm
by freak
Yes, PlgBlt_() is very fast. In my test, was about 12x faster than BitBlt_()
with the For/Next.
Unfortunately PlgBlt_() is only supported on Windows NT/2K/XP.
Some code:
Code: Select all
Image2DC = StartDrawing(ImageOutput())
; These 3 points represent 3 points of the old image, and the values you assign
; to them are their positions in the new image.
;
; first: top/left corner of old image
; second: top/right corner of old image
; third: bottom/left corner of old image
Dim Points.Point(2)
Points(0)\x = 0
Points(0)\y = Image\bmWidth
Points(1)\x = 0
Points(1)\y = 0
Points(2)\x = Image\bmHeight
Points(2)\y = Image\bmWidth
PlgBlt_(Image2DC, @Points(), Image1DC, 0, 0, Image\bmWidth, Image\bmHeight, 0, 0, 0)
StopDrawing()
My test was 12 seconds with BitBlt_() and not even 1 second with this
code. (2560x1024 image)
btw: rotating by any angle and any rotation point is possible like this.
You just have to write a routine to calculate the corner points.
Timo
Posted: Mon Oct 27, 2003 4:14 am
by fsw
Thank you all.
Will try it out.
Posted: Fri Oct 31, 2003 2:40 am
by blueznl
damn, i must be stupid or what, but i can't get plgblt_ to work, anybody who can see what's wrong with the following code?
Code: Select all
main_whnd = OpenWindow(0,0,0,660,500,#PB_Window_ScreenCentered|#PB_Window_SystemMenu,"Test")
main_dc = GetDC_(main_whnd)
;
bitmap_hnd.l = LoadImage(0,"c:\software\purebasic\_projects\1.bmp")
bitmap_w = ImageWidth()
bitmap_h = ImageHeight()
;
Structure corners
x1.l ; left upper corner
y1.l
x2.l ; right upper corner
y2.l
x3.l ; left lower corner
y3.l
EndStructure
new.corners
new\x1 = 0
new\y1 = 0
new\x2 = bitmap_w
new\y2 = 0
new\x3 = 0
new\y3 = bitmap_h
StartDrawing(WindowOutput())
source_dc = CreateCompatibleDC_(main_dc)
SelectObject_(source_dc,bitmap_hnd)
PlgBlt_(main_dc,@new\x1,source_dc,0,0,bitmap_w,bitmap_h,0,0,0)
; BitBlt_(main_dc,0,0,bitmap_w,bitmap_h,source_dc,0,0,#SRCCOPY)
StopDrawing()
;
DeleteDc_(source_dc)
ReleaseDC_(main_whnd,main_dc)
;
Posted: Fri Oct 31, 2003 12:31 pm
by Fred
StartDrawing() returns the DC, may be it could help you..
Posted: Fri Oct 31, 2003 2:56 pm
by blueznl
fred, i think it's a bug (sorry)
if i comment out any of the last three lines (that have nothing to do with the rest of this code) it doesn't display the image
is there something of a cache in the compiler that isn't cleared?
Code: Select all
main_whnd = OpenWindow(0,0,0,660,500,#PB_Window_ScreenCentered|#PB_Window_SystemMenu,"Test")
main_dc = GetDC_(WindowID(0))
;
bitmap_hnd.l = LoadImage(0,"..\_projects\1.bmp")
bitmap_w = ImageWidth()
bitmap_h = ImageHeight()
;
Structure corners
x1.l ; left upper corner
y1.l
x2.l ; right upper corner
y2.l
x3.l ; left lower corner
y3.l
EndStructure
;
new.corners
new\x1 = bitmap_w
new\y1 = 0
new\x2 = bitmap_w
new\y2 = bitmap_h
new\x3 = 0
new\y3 = 0
;
source_dc = CreateCompatibleDC_(main_dc)
SelectObject_(source_dc,bitmap_hnd)
;
StartDrawing(WindowOutput())
PlgBlt_(main_dc,@new\x1,source_dc,-10,10,bitmap_w,bitmap_h,0,0,0)
StopDrawing()
;
Repeat
Until WaitWindowEvent() = #PB_Event_CloseWindow
;
Debug bitmap1_hnd
Debug main_nr
bitmap2_hnd.l = LoadImage(1,"..\_projects\2.bmp")
Posted: Fri Oct 31, 2003 4:20 pm
by Fred
There is something wrong for sure. I will take a closer look.
Posted: Fri Oct 31, 2003 4:37 pm
by fsw
I was not able to get plgblt_ to work either.
But I said nothing because I thought: It's me again

Posted: Fri Oct 31, 2003 4:40 pm
by Fred
Try to disable the debugger to see if the problem is gone..
Posted: Fri Oct 31, 2003 4:47 pm
by fsw
Fred wrote:Try to disable the debugger to see if the problem is gone..
YES, IT'S GONE...
Posted: Fri Oct 31, 2003 4:58 pm
by Fred
Ok, as pointed by Danilo on IRC, painting directly on the Window is bad as the debugger erase it... Use an ImageGadget() to get a refresh persistent image...
Posted: Fri Oct 31, 2003 6:28 pm
by blueznl
following works...
*** edit *** but only with the debugger off
Code: Select all
main_whnd = OpenWindow(0,200,100,660,500,#PB_Window_SystemMenu,"Test")
main_dc = GetDC_(WindowID(0))
;
bitmap1_hnd.l = LoadImage(0,"..\_projects\1.bmp")
bitmap_w = ImageWidth()
bitmap_h = ImageHeight()bitmap_h = ImageHeight()
;
bitmap2_hnd = CreateImage(1,bitmap_w,bitmap_h)
;
Structure corners
x1.l ; left upper corner
y1.l
x2.l ; right upper corner
y2.l
x3.l ; left lower corner
y3.l
EndStructure
;
new.corners
new\x1 = bitmap_w
new\y1 = 0
new\x2 = bitmap_w
new\y2 = bitmap_h
new\x3 = 0
new\y3 = 0
;
source_dc = CreateCompatibleDC_(main_dc)
SelectObject_(source_dc,bitmap1_hnd)
dest_dc = CreateCompatibleDC_(main_dc)
SelectObject_(dest_dc,bitmap2_hnd)
PlgBlt_(dest_dc,@new\x1,source_dc,0,0,bitmap_w,bitmap_h,0,0,0)
deletedc_(source_dc)
deletedc_(dest_dc)
;
UseWindow(0)
StartDrawing(WindowOutput())
DrawImage(bitmap2_hnd,10,10)
StopDrawing()
;
Repeat
Until WaitWindowEvent() = #PB_Event_CloseWindow
;