Page 1 of 3

Rotate Image

Posted: Sat Oct 21, 2006 6:36 pm
by MikeB
I need to be able to rotate an image by 90° clockwise and anti-clockwise. It is for a picture viewer for occasions when the picture was taken with the camera rotated.

I fully expected to find this was a command in PB4 but apparently not! I have done a search, but all I have found is a library that dates back a couple of years and produces linker errors.

I feel sure someone must have done this, any pointers to where would be appreciated.

Posted: Sat Oct 21, 2006 9:32 pm
by MikeB
I have written a routine for doing this,

Code: Select all

LoadImage(0,piccy$)
x = ImageWidth(0)
y = ImageHeight(0)
Dim spotty.l(x,y)
If OpenWindow(0,0,0,x,y,"Original")
	If CreateGadgetList(WindowID(0))
		ImageGadget(0,0,0,x,y,ImageID(0))
	EndIf
EndIf
CreateImage(1,y,x)
;
StartDrawing(ImageOutput(0))
For column = 0 To y-1
	For strip = 0 To x-1
		spotty(strip,column) = Point(strip,column)
	Next
Next
StopDrawing()
;
StartDrawing(ImageOutput(1))
For column = 0 To y-1
	For strip = 0 To x-1
		Plot(column,x-strip,spotty(strip,column))
	Next
Next
StopDrawing()
;

If OpenWindow(1,x+10,0,y,x,"copy")
	If CreateGadgetList(WindowID(1))
		ImageGadget(1,0,0,y,x,ImageID(1))
	EndIf
EndIf
Repeat
	ev = WaitWindowEvent()
Until ev = #PB_Event_CloseWindow
It works but is a bit slow, what it needs is writing in ASM or using API or both. If anyone knows how, it would be a help to have a routine to rotate the other way as well.
With my PB method the other way is just a case of starting top right and going down instead of bottom left and going up, with the columns going R>L instead of L>R.
At the moment I am about to write the clockwise bit and put them in the program, it will do until/if something faster comes up!

Posted: Mon Oct 23, 2006 9:29 am
by netmaestro
I made a lib for that very purpose a while back. It's coded in API and will be quite a bit faster than what you've got there. You are welcome to use it. It has one command, you call it like this:

Code: Select all

OpenLibrary(0,"Quarters.dll")
MyImage = CallFunction(0,"TurnByQuarters",ImageID(#image), 1)
CloseLibrary(0)
where the last parameter is 1=90 degrees clockwise, 2=180 degrees, 3=90 degrees counterclockwise. If it succeeds, the dll returns an image handle with the rotated image, if it fails the return value is 0. You must pass 1, 2, or 3 as rotation parameters, anything else returns failed.

As a new image is created each time you call the function, you must remember to:

Code: Select all

DeleteObject_(MyImage)
when you're finished with it or you'll have a memory leak.

http://www.networkmaestro.com/Quarters.dll

Posted: Mon Oct 23, 2006 4:33 pm
by Paul
Having to carry along extra DLL's with your app is such a pain ;)

Here is some code I threw together...

Code: Select all

; Image Rotating Code
; by Paul Leischow
; Compiler: PB 3.94

Procedure Image_Rotate(Image.l)
  height=ImageHeight()
  width=ImageWidth()
  If height>width
    temp=CreateImage(#PB_Any,height,height)
    Else
    temp=CreateImage(#PB_Any,width,width)
  EndIf
  
  Dim rect.Point(2)
  rect(0)\x=height
  rect(0)\y=0
  rect(1)\x=height
  rect(1)\y=width
  rect(2)\x=0
  rect(2)\y=0
  dc=StartDrawing(ImageOutput())
    DrawImage(UseImage(Image),0,0)
    PlgBlt_(dc,@rect(),dc,0,0,width,height,0,0,0)
  StopDrawing()
  GrabImage(temp,image,0,0,height,width)
  FreeImage(temp)
EndProcedure



LoadImage(1,"picture1.bmp")
Image_Rotate(1) ;rotates image 90 degrees clockwise everytime you call procedure

If OpenWindow(0,0,0,600,500,#PB_Window_ScreenCentered|#PB_Window_SystemMenu,"")
  If CreateGadgetList(WindowID(0))
    ImageGadget(0,0,0,10,10,UseImage(1))
    Repeat:Until WaitWindowEvent()=#PB_Event_CloseWindow
  EndIf
EndIf

Posted: Mon Oct 23, 2006 4:35 pm
by Paul
and for those who still have problems converting to PB 4.00 ....

Code: Select all

; Image Rotating Code
; by Paul Leischow
; Compiler: PB 4.00

Procedure Image_Rotate(Image.l)
  height=ImageHeight(Image)
  width=ImageWidth(Image)
  If height>width
    temp=CreateImage(#PB_Any,height,height)
    Else
    temp=CreateImage(#PB_Any,width,width)
  EndIf
  
  Dim rect.Point(2)
  rect(0)\x=height
  rect(0)\y=0
  rect(1)\x=height
  rect(1)\y=width
  rect(2)\x=0
  rect(2)\y=0
  dc=StartDrawing(ImageOutput(temp))
    DrawImage(ImageID(Image),0,0)
    PlgBlt_(dc,@rect(),dc,0,0,width,height,0,0,0)
  StopDrawing()
  GrabImage(temp,image,0,0,height,width)
  FreeImage(temp)
EndProcedure



LoadImage(1,"picture1.bmp")
Image_Rotate(1) ;rotates image 90 degrees clockwise everytime you call procedure

If OpenWindow(0,0,0,600,500,"",#PB_Window_ScreenCentered|#PB_Window_SystemMenu)
  If CreateGadgetList(WindowID(0))
    ImageGadget(0,0,0,10,10,ImageID(1))
    Repeat:Until WaitWindowEvent()=#PB_Event_CloseWindow
  EndIf
EndIf

Posted: Mon Oct 23, 2006 4:59 pm
by Thorsten1867

Code: Select all

Procedure RotateImg(Image$,opt.b)
  
  hnd1.l = LoadImage(#ImageRotate1,Image$)
  
  bitmap_w = ImageWidth(#ImageRotate1)
  bitmap_h = ImageHeight(#ImageRotate1)
  
  hnd2 = CreateImage(#ImageRotate2,bitmap_h, bitmap_w)
  
  source_dc = CreateCompatibleDC_(main_dc) : SelectObject_(source_dc,hnd1) 
  dest_dc = CreateCompatibleDC_(main_dc) : SelectObject_(dest_dc,hnd2)
  
  ia = bitmap_h
  If opt = 1
    While ia > 0 ;{ 90° nach rechts
      i = 0 
      While i < bitmap_w
        BitBlt_(dest_dc,bitmap_h-ia,i,1,1,source_dc,i,ia,#SRCCOPY)
        i + 1 
      Wend 
      ia - 1 
    Wend ;}
  Else
    While ia > 0 ;{ 90° nach links
      i = 0 
      While i < bitmap_w
        BitBlt_(dest_dc,ia,bitmap_w-i,1,1,source_dc,i,ia,#SRCCOPY)
        i + 1 
      Wend 
      ia - 1 
    Wend ;}
  EndIf
  deletedc_(source_dc) 
  deletedc_(dest_dc) 
  
  SaveImage(#ImageRotate2,Image$,#PB_ImagePlugin_JPEG)
  
EndProcedure

Posted: Mon Oct 23, 2006 7:29 pm
by MikeB
Thanks for the help chaps, I have tried each of the them and they all work well.

I think that the one that is best for my purpose is the one by Thorsten as I have modified it slightly to rotate an already loaded image. I also did not want to save the new (rotated) version.

I can now pass the image number and option, the procedure creates the new rotated image then copies the new one to the original and frees the new one.

Posted: Mon Oct 23, 2006 10:54 pm
by MikeB
After inclusion in my program, I found a slight bug in the routines as the positions on the bitmap go from 0 to x-1 and 0 to y-1, not 1 to x and 1 to y, where x and y are the Image width and Image height. This caused a single pixel black line on the rotated image.

Corrected as follows

Code: Select all

	If opt = 1  ; 90° clockwise
		While ia >= 0
			i = 0 
			While i < bitmap_w 
				BitBlt_(dest_dc, bitmap_h-ia-1, i, 1, 1,source_dc, i, ia, #SRCCOPY)
				i + 1 
			Wend 
			ia - 1 
		Wend
	Else ; 90° anticlockwise 
		While ia >= 0 
			i = 0 
			While i < bitmap_w 
				BitBlt_(dest_dc, ia, bitmap_w-i-1, 1, 1, source_dc, i, ia, #SRCCOPY) 
				i + 1 
			Wend 
			ia - 1 
		Wend 
	EndIf 
Added the '=' on the two occurences of 'While ia >= 0' and the -1 in the 'BitBlt_(dest_dc, bitmap_h-ia-1, i, 1, 1,source_dc, i, ia, #SRCCOPY)' and 'BitBlt_(dest_dc, ia, bitmap_w-i-1, 1, 1, source_dc, i, ia, #SRCCOPY)'

Posted: Fri Nov 24, 2006 11:39 pm
by TerryHough
[quote="netmaestro"]I made a lib for that very purpose a while back. It's coded in API...

@netmaestro
Does this routine use PlgBLT API? I'm looking for something useable on Win32 (Win98SE).

I'm not getting a failure, just not getting an image back. A sligthly extended example would probably help me :oops:

Terry

Posted: Sat Nov 25, 2006 7:00 am
by netmaestro
The code for that dll is buried on a cd somewhere, I can probably come up with it if necessary but I'm pretty sure it's going to need Win2000/XP. If I were you I'd use gdiplus.dll for this and distribute it with your app. If you need a sample (or the whole thing it's pretty short) I can post it tomorrow. I'm not sure what your non-gdiplus 9x alternatives are, but if you do it this way it'll work on W9x and go blazing fast.

Posted: Sat Nov 25, 2006 4:06 pm
by TerryHough
I was trying to use it on WinXPPro. I think I am confused between handles and image ID.

So, if you have a more complete example available I would appreciate it.

Posted: Sat Nov 25, 2006 5:05 pm
by netmaestro

Code: Select all

OpenLibrary(0,"Quarters.dll") 
MyImage = CallFunction(0,"TurnByQuarters",ImageID(#image), 1) 
CloseLibrary(0)

SetGadgetState(#img, MyImage)

; later when you're finished with it
DeleteObject_(MyImage)

Posted: Sat Nov 25, 2006 5:46 pm
by TerryHough
@netmaestro

Thanks, but I'm still failing. Here is my code, maybe you see the error.

[edited: Code now works - :oops: ]

Code: Select all

Pgm$ = "Image rotation test"
ExamineDesktops()
#Window=0
If OpenWindow(#Window,0,0,DesktopWidth(0),DesktopHeight(0) - 33,Pgm$,#PB_Window_SystemMenu)
  CreateGadgetList(WindowID(#Window))
  dc = StartDrawing(WindowOutput(0)) ; Change to the desired output
  Box(0,0, WindowWidth(0), WindowHeight(0),#White) ; Set the image to background color
  
  Image = LoadImage(#PB_Any,"\purebasic_4\purebasic.bmp")
  ImageGadget(2, 0, 0,ImageWidth(Image), ImageHeight(Image), ImageID(Image))	; show the image
  ImageGadget(3, 200, 200, 200, 200, ImageID(Image))	; show the image
  While WindowEvent():Wend
  Delay(2000) ; wait 2 seconds then rotate the image
  
  If OpenLibrary(0,"Quarters.dll")
    MyImage = CallFunction(0,"TurnByQuarters",ImageID(Image), 1)
    SetGadgetState(3, MyImage)
    While WindowEvent():Wend
  
    DeleteObject_(MyImage)
    CloseLibrary(0)
  Else
    MessageRequester("Debug","Could not open the library",#MB_ICONERROR)
  EndIf
  Repeat
    event = WaitWindowEvent()
  Until event = #PB_Event_CloseWindow
EndIf
End


Posted: Sat Nov 25, 2006 6:04 pm
by netmaestro
Try this test prog:

Code: Select all

Image = LoadImage(#PB_Any,"\purebasic_4\purebasic.bmp") 
OpenWindow(0,0,0,320,240,"",$CF0001)
CreateGadgetList(WindowID(0))
ImageGadget(0,50,20,0,0,ImageID(image))
ButtonGadget(1,100,210,80,20,"flip")
Repeat
  ev = WaitWindowEvent()
  If ev=#PB_Event_Gadget
    If EventGadget()=1
      OpenLibrary(0,"quarters.dll")
      MyImage = CallFunction(0,"TurnByQuarters",ImageID(image),1)
      SetGadgetState(0, MyImage)
      CloseLibrary(0)
    EndIf
  EndIf 
Until ev= #WM_CLOSE

If MyImage
  DeleteObject_(MyImage)
EndIf

Posted: Sun Nov 26, 2006 3:08 am
by TerryHough
Thanks netmaestro,

If the library is closed, the image is lost.

Laughing at myself. :lol:
Terry