Image Rotation routines for 24/32 bit with optional AA

Share your advanced PureBasic knowledge/code with the community.
User avatar
Michael Vogel
Addict
Addict
Posts: 2797
Joined: Thu Feb 09, 2006 11:27 pm
Contact:

Re: Image Rotation routines for 24/32 bit with optional AA

Post by Michael Vogel »

djes wrote:We did a rotation some times ago. Maybe this code can help...

Here's the code:

Code: Select all

ProcedureDLL.l RotateImageEx2(ImageID, Angle.f)
  : 
  Protected CouleurFond = 0 
  :
What, if I don't want a black background? Thought, just a simple change would do it:
ProcedureDLL.l RotateImageEx2(ImageID, Angle.f, CouleurFond=#Black)
...but CouleurFond seems to be a fake :lol:
User avatar
djes
Addict
Addict
Posts: 1806
Joined: Sat Feb 19, 2005 2:46 pm
Location: Pas-de-Calais, France

Re: Image Rotation routines for 24/32 bit with optional AA

Post by djes »

:lol:
User avatar
Michael Vogel
Addict
Addict
Posts: 2797
Joined: Thu Feb 09, 2006 11:27 pm
Contact:

Re: Image Rotation routines for 24/32 bit with optional AA

Post by Michael Vogel »

djes wrote::lol:

Code: Select all

ProcedureDLL.l RotateImageEx2(ImageID, Angle.f,ColeurFond=#Black)

	ColeurFond=ColeurFond&$ff00 | ColeurFond>>16 | (ColeurFond&$FF)<<16
	:
	:
	Else
		!mov ebx,dword[p.v_Mem2Temp]
		;!xor eax,eax;							black background
		!mov eax,dword[p.v_ColeurFond];				user defined background
		!mov dword[ebx],eax
	EndIf
	:
EndProcedure
:mrgreen:
User avatar
djes
Addict
Addict
Posts: 1806
Joined: Sat Feb 19, 2005 2:46 pm
Location: Pas-de-Calais, France

Re: Image Rotation routines for 24/32 bit with optional AA

Post by djes »

Nice to see the AA 8)
c4s
Addict
Addict
Posts: 1981
Joined: Thu Nov 01, 2007 5:37 pm
Location: Germany

Re: Image Rotation routines for 24/32 bit with optional AA

Post by c4s »

I just noticed that the free rotation seems to remove a 1-2 pixel border depending on the angle if anti-aliasing is enabled: "0.0" removes it on all sides and others mostly on the top and right side. Also "90.0", "180" etc. look a little unexpected.

I'm using version 1.02 of the include provided in the second post of this thread. Here I slightly modified the first example by added a 1 pixel green and red border to show what I mean:

Code: Select all

Procedure.i CreateCheckers (iWidth, iHeight)
	Protected x, y
	Protected nImage, iSize = 12
	
	nImage = CreateImage(#PB_Any, iWidth, iHeight, 24)
	
	If nImage
		StartDrawing(ImageOutput(nImage))
		
		Box(0, 0, iWidth, iHeight, $FFFFFF)
		
		While y < iHeight + iSize
			While x < iWidth + iSize
				Box(x, y, iSize, iSize, $C0C0C0)
				Box(x + iSize, y + iSize, iSize, iSize, $C0C0C0)
				x + iSize*2           
			Wend
			x = 0
			y + iSize*2
		Wend
		
		StopDrawing()
	EndIf
	
	ProcedureReturn nImage
EndProcedure

Procedure.i MergeImages (nImgCheck, nImgOut)
	Protected nImage
	
	nImage = CreateImage(#PB_Any, ImageWidth(nImgCheck), ImageHeight(nImgCheck), 24)
	
	If nImage
		StartDrawing(ImageOutput(nImage))
		
		DrawImage(ImageID(nImgCheck), 0, 0)
		DrawAlphaImage(ImageID(nImgOut), 0, 0)
		
		StopDrawing()
	EndIf
	
	ProcedureReturn nImage
	
EndProcedure


#WIN = 1
#IMG = 1

#IW = 640
#IH = 480

Define iEvent, iTime1, k, nFont
Define nImgSrc, nImgOut
Define nImgCheck, nImgDisp


; ****************************************************************
; try to change these vars to check out the various combinations *
; ****************************************************************

Define iBitPlanes = 32                  ; test 24 or 32 bpp image
Define fRot = 90.0                      ; angle used for rotation
Define flgAntiAlias = 1                 ; Antialias (1) or simpler rotation (0)
Define iFillColor = RGB(255,255,255)    ; useful for transparent masking using GDI or simply to fill the background


nFont = LoadFont(#PB_Any, "Arial", 12, #PB_Font_Bold)

nImgSrc = CreateImage(#PB_Any, #IW, #IH, iBitPlanes)

StartDrawing(ImageOutput(nImgSrc))

For k = 0 To 100 Step 20
	Box(0 + k, 0 + k, #IW - k * 2, #IH - k * 2, RGB(k + 50, k + 100, k + 150))
Next

DrawingMode(#PB_2DDrawing_Transparent)
DrawingFont(FontID(nFont))

For k = 0 To #IH Step #IH / 10
	DrawText(20, k + 10, "TEXT - " + Str(iBitPlanes) + " BPP IMAGE - TEXT", RGB(k/3, k/2, k/2))
Next

If iBitPlanes = 24
	DrawingMode(#PB_2DDrawing_Default)
	Circle(#IW - 200, 100, 50, RGB(128,0,0))
	Circle(#IW - 200, #IH - 100, 50, RGB(0,128,0))   
	Circle(#IW - 80, #IH/2, 50, RGB(0,0,128))
Else
	iFillColor = 0
	
	; make 3 holes
	DrawingMode(#PB_2DDrawing_AlphaChannel)
	Circle(#IW - 200, 100, 50,  $00)
	Circle(#IW - 200, #IH - 100, 50, $00)
	Circle(#IW - 80, #IH/2, 50, $00)
	
	; fill them with semi-transparent circles
	DrawingMode(#PB_2DDrawing_AlphaBlend)
	Circle(#IW - 200, 100, 50, RGBA(128,0,0,100))
	Circle(#IW - 200, #IH - 100, 50, RGBA(0,128,0,100))
	Circle(#IW - 80, #IH/2, 50, RGBA(0,0,128,100))
EndIf

DrawingMode(#PB_2DDrawing_Outlined)
Box(0, 0, #IW, #IH, $00FF00)  ; Green
Box(1, 1, #IW - 2, #IH - 2, $0000FF)  ; Red

StopDrawing()



If OpenWindow(#WIN, 0, 0, 800, 800, "", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
	
	iTime1 = ElapsedMilliseconds()         
	nImgOut = RotateImageFree (nImgSrc, fRot, flgAntiAlias, iFillColor)
	iTime1 = ElapsedMilliseconds() - iTime1
	
	SetWindowTitle(#WIN, "Test " + Str(iBitPlanes) + " bit, AA = " + Str(flgAntiAlias) + ", msec = " + Str(iTime1) + ", deg = " + StrF(fRot,1))
	
	nImgCheck = CreateCheckers(ImageWidth(nImgOut), ImageHeight(nImgOut))
	nImgDisp = MergeImages(nImgCheck, nImgOut)
	
	FreeImage(nImgOut)
	FreeImage(nImgCheck)
	
	ImageGadget(#IMG, 0, 0, 0, 0, ImageID(nImgDisp), #PB_Image_Border)
	
	While iEvent <> #PB_Event_CloseWindow           
		iEvent = WaitWindowEvent()
	Wend
	
	FreeImage(nImgDisp)
	FreeImage(nImgSrc)
	FreeFont(nFont)
EndIf
Any ideas how to fix it?

Also would it be possible to anti-alias the image border as well?
If any of you native English speakers have any suggestions for the above text, please let me know (via PM). Thanks!
User avatar
luis
Addict
Addict
Posts: 3893
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

Re: Image Rotation routines for 24/32 bit with optional AA

Post by luis »

c4s wrote:Any ideas how to fix it?
I did this 2 years ago so I'm trying to remember looking at the code, and I believe I noticed the problem too but I didn't know how to fix it, 'cause it has something to do with some precision problem due to the use of sin/cos and floats to map one destination point to a source point in the original image.
That's why (performance aside) I decided to put a routine specifically for the multiples of 90 degrees. The best approach probably is to check the rotation angle in a wrapping proc, and use the specialized proc for 0/90/180/270 and the free one for any other angle.

I'll try to look into it but I don't guarantee I can find a perfect way, if someone else can enhance this to make it pixel-perfect for those cases too (without breaking it !) I would be very happy to hear it (edit: maybe it's ok now)
As I said I'm certainly not an expert on this topic.
c4s wrote: Also would it be possible to anti-alias the image border as well?
I would say no, because this should be done by the code drawing the image over the destination background. The proc included here can work only with the pixels available in the image, and to soften the perimeter it should know in advance what are the background colors of each pixel (or group of pixels) adjacent to a pixel in the perimeter to compute the appropriate color. So it's something it should be done by the code drawing the resulting rotated image on a specific background.

*code removed*

If this works for you too, I'll replace the original code with this one (1.05)

*updated*
Last edited by luis on Sun Nov 13, 2011 2:45 pm, edited 5 times in total.
"Have you tried turning it off and on again ?"
A little PureBasic review
c4s
Addict
Addict
Posts: 1981
Joined: Thu Nov 01, 2007 5:37 pm
Location: Germany

Re: Image Rotation routines for 24/32 bit with optional AA

Post by c4s »

Thanks luis!
Tommorrow I'll take a deeper look at the new code.
If any of you native English speakers have any suggestions for the above text, please let me know (via PM). Thanks!
c4s
Addict
Addict
Posts: 1981
Joined: Thu Nov 01, 2007 5:37 pm
Location: Germany

Re: Image Rotation routines for 24/32 bit with optional AA

Post by c4s »

OK, tested it and the issue with the 1 pixel border is more or less fixed now. Thanks luis!
luis wrote:I would say no, because this should be done by the code drawing the image over the destination background. The proc included here can work only with the pixels available in the image, and to soften the perimeter it should know in advance what are the background colors of each pixel (or group of pixels) adjacent to a pixel in the perimeter to compute the appropriate color. So it's something it should be done by the code drawing the resulting rotated image on a specific background.
I think I don't understand you. In my understanding we already have the background! It's iFillColor, isn't it?
If any of you native English speakers have any suggestions for the above text, please let me know (via PM). Thanks!
User avatar
luis
Addict
Addict
Posts: 3893
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

Re: Image Rotation routines for 24/32 bit with optional AA

Post by luis »

OK, I'll edit the original post and replace the code...
c4s wrote:I think I don't understand you. In my understanding we already have the background! It's iFillColor, isn't it?
For the 24 bit version yes, you are right, but for the 32 bit version with transparency it is not, iFillColor is ignored when alpha is used.

Something could be done probably for the 24 bit case, even if I find a little difficult to add "virtual pixels" (because out of the real image data) to the current algorithm. Uhm... it would be quite messy in fact.

I still think it's something it should be done by the code drawing the resulting image.
"Have you tried turning it off and on again ?"
A little PureBasic review
Little John
Addict
Addict
Posts: 4775
Joined: Thu Jun 07, 2007 3:25 pm
Location: Berlin, Germany

Re: Image Rotation routines for 24/32 bit with optional AA

Post by Little John »

Hello luis,

thank you for your image rotation routines, which come in handy for my current project!

I have 3 minor comments, and 2 serious problems:

a) In your main code, I think it's a bit better to write
XIncludeFile #PB_Compiler_FilePath + "RotateImage.pbi",
since your main code will be itself included in another source code file, which probably is in a different directory than your both files.

b) At the very beginning of your third post in this thread, it reads
INCLUDE FOR THE CODE ABOVE - "Image Direct Memory.pbi"
This name of the include file is not consistent with the name of the file used with the XIncludeFile command in your main file.
This is nitpicking, I know. Sorry. :-)

c) In your main code, there is a macro which starts with the line

Code: Select all

Macro JMP_IF_ZERO (var, label, exec=)
Did you deliberately write no default value after exec=? I didn't even know that this is valid syntax.



The reason for this post is, that I encountered 2 problems with the procedure RotateImageFree() (using PB 4.60 Windows XP SP3 x86). I managed to write a short code that demonstrates them:

Code: Select all

EnableExplicit

XIncludeFile <MyPath> + "RotateImage.pbi"

#Title$ = "Rotate test"

Procedure.i CreatePicture()
   Protected width.i, height.i, img.i, ret.i=0, rotate.f=6.0
   
   width = 515        ; no crash
   ; width = 516      ; crash in procedure RotateImageFree()
   height = 390
   
   img = CreateImage(#PB_Any, width, height, 32)
   If img And StartDrawing(ImageOutput(img))
      Box(0, 0, width, height, $FFFFFF)
      StopDrawing()
      ret = RotateImageFree(img, rotate, 1)
      FreeImage(img)
   EndIf
   
   ProcedureReturn ret
EndProcedure


Define pic.i, outFile$ = GetTemporaryDirectory() + "test.bmp"

pic = CreatePicture()
If pic = 0
   MessageRequester(#Title$, "Error creating the picture.")
   End
EndIf

If SaveImage(pic, outFile$) = 0
   MessageRequester(#Title$, "Error saving the picture.")
   End
EndIf
FreeImage(pic)
d) The edges of the rotated rectangle don't look smooth to me, even when I pass 1 as third parameter to RotateImageFree(), in order to use AntiAliasing. What can I do to make the edges more smooth? (I post a link to a PNG file here, becaue it's much smaller than the original BMP file. However, it looks the same.)

Image

e) After uncommenting the line

Code: Select all

; width = 516
in my above code, there will be a crash in RotateImageFree(). Am I doing something wrong, or is this due to a bug in your code?

Best regards, Little John
User avatar
luis
Addict
Addict
Posts: 3893
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

Re: Image Rotation routines for 24/32 bit with optional AA

Post by luis »

Little John wrote: a) In your main code, I think it's a bit better to write
XIncludeFile #PB_Compiler_FilePath + "RotateImage.pbi",
since your main code will be itself included in another source code file, which probably is in a different directory than your both files.
I have that in my copy, probably I added it at a later time when I actually used it somewhere.
Yes, it's better (we know a lot of us would like that to be the default behavior for every include ... sigh...). I'll edit the post.

Little John wrote: b) At the very beginning of your third post in this thread, it reads
INCLUDE FOR THE CODE ABOVE - "Image Direct Memory.pbi"
This name of the include file is not consistent with the name of the file used with the XIncludeFile command in your main file.
This is nitpicking, I know. Sorry. :-)
It was the name used in a previous version, I'll edit that too.
Little John wrote: c) In your main code, there is a macro which starts with the line

Code: Select all

Macro JMP_IF_ZERO (var, label, exec=)
Did you deliberately write no default value after exec=? I didn't even know that this is valid syntax.
It was on purpose but that macro was lifted from another code where I actually used that optional param. Not here, so you can safely remove that one and update the macro accordingly.
About the syntax, I agree is a little "dubious" but it worked and I used at that time.
Now I use another TRY / CATCH (sort of) approach and so it's only here now. Maybe I should update this code with that. Anyway for now I'll edit out the param.

About the border, this code will never do that.
The reason is explained more or less in this same thread:
http://www.purebasic.fr/english/viewtop ... 59#p366559

About the crash, it looks like a bug, I'll look into it ASAP (after dinner probably) and report back.
"Have you tried turning it off and on again ?"
A little PureBasic review
Little John
Addict
Addict
Posts: 4775
Joined: Thu Jun 07, 2007 3:25 pm
Location: Berlin, Germany

Re: Image Rotation routines for 24/32 bit with optional AA

Post by Little John »

luis wrote:About the border, this code will never do that.
The reason is explained more or less in this same thread:
http://www.purebasic.fr/english/viewtop ... 59#p366559
Ooops, sorry! I missed that piece of advice. I understand now, thanks.
luis wrote:About the crash, it looks like a bug, I'll look into it ASAP (after dinner probably) and report back.
Thank you.

Regards, Little John
User avatar
luis
Addict
Addict
Posts: 3893
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

Re: Image Rotation routines for 24/32 bit with optional AA

Post by luis »

The problem reported by c4s in the posts above made me introduce some quirky logic to make ends meet. Now I decided to remove the problem at its origin forcing the processing of the 0/90/180/270 angles by RotateImage() as intended and RotateImageFree() to take care of the rest as originally intended.
This should remove the rounding problems causing the bug you reported.

I changed only the main include (the .pb).
"Have you tried turning it off and on again ?"
A little PureBasic review
Little John
Addict
Addict
Posts: 4775
Joined: Thu Jun 07, 2007 3:25 pm
Location: Berlin, Germany

Re: Image Rotation routines for 24/32 bit with optional AA

Post by Little John »

Works fine now. Thanks!
chris319
Enthusiast
Enthusiast
Posts: 782
Joined: Mon Oct 24, 2005 1:05 pm

Re: Image Rotation routines for 24/32 bit with optional AA

Post by chris319 »

Very nice job!

Here is a modified version of RotateImageFree which allows the user to select a .bmp file and rotate the image interactively. Whenever I take pictures with my digital camera, the pressure of my finger on the shutter release tilts the camera and the horizon is no longer level. Here is a way to straighten those pictures out. Press the down arrow key to rotate the image clockwise; press the up arrow key to rotate the image counterclockwise; press the return/enter key to save the rotated image as a file (it now only works with .bmp images -- you can change this to suit).

Modifications:

- Notifies user if debugger is active.

- Added constant #ROT_INCREMENT, the image rotation increment.

- Defined variables fileName$ and result.

- Added input file requester allowing user to select a .bmp image, terminates program if user selects Cancel (null string).

- Variable iBitPlanes now gets its value from ImageDepth() after image is loaded.

- Message requester warns user if window cannot be opened, then terminates program.

- Added keyboard shortcuts.

- Moved two instances of FreeImage() to MergeImage(), just to get them out of the way.

- Reworked event loop. Program jumps to rotateAgain when user rotates image by means of up or down arrow keys.

- Changed variable fRot to float (single) to allow for rotation of image in fractional degrees.

- Call to RotateImageFree() passes fRot as negative value. Positive values give clockwise rotation; negative values give counterclockwise rotation.

Code: Select all

; TEST - RotateImageFree

    EnableExplicit

    IncludeFile "RotateImage.pb"

    Procedure.i CreateCheckers (iWidth, iHeight)
     Protected x, y
     Protected nImage, iSize = 12
     
     nImage = CreateImage(#PB_Any, iWidth, iHeight, 24)
     
     If nImage
        StartDrawing(ImageOutput(nImage))
       
         Box(0, 0, iWidth, iHeight, $FFFFFF)
         
         While y < iHeight + iSize
            While x < iWidth + iSize
                Box(x, y, iSize, iSize, $C0C0C0)
                Box(x + iSize, y + iSize, iSize, iSize, $C0C0C0)
                x + iSize*2           
            Wend
            x = 0
            y + iSize*2
         Wend
         
        StopDrawing()
     EndIf
     
     ProcedureReturn nImage
    EndProcedure

    Procedure.i MergeImages (nImgCheck, nImgOut)
     Protected nImage
     
     nImage = CreateImage(#PB_Any, ImageWidth(nImgCheck), ImageHeight(nImgCheck), 24)

     If nImage
        StartDrawing(ImageOutput(nImage))
       
         DrawImage(ImageID(nImgCheck), 0, 0)
         DrawAlphaImage(ImageID(nImgOut), 0, 0)
             
        StopDrawing()
     EndIf
     
        FreeImage(nImgOut)
        FreeImage(nImgCheck)

     ProcedureReturn nImage

    EndProcedure


    #WIN = 1
    #IMG = 1

    #IW = 640
    #IH = 480

    #ROT_INCREMENT = 0.5

    Define iEvent, iTime1, k, nFont
    Define nImgSrc, nImgOut
    Define nImgCheck, nImgDisp, fileName$, result


    ; ****************************************************************
    ; try to change these vars to check out the various combinations *
    ; ****************************************************************

    Define iBitPlanes ;= 32                  ; test 24 or 32 bpp image
    Define fRot.f = 0                         ; angle used for rotation
    Define flgAntiAlias = #True                 ; Antialias (1) or simpler rotation (0)
    Define iFillColor = RGB(255,255,255)    ; useful for transparent masking using GDI or simply to fill the background

Debug "Disable debugger for maximum performance."

    nFont = LoadFont(#PB_Any, "Arial", 12, #PB_Font_Bold)

;     nImgSrc = CreateImage(#PB_Any, #IW, #IH, iBitPlanes)
;            
;     StartDrawing(ImageOutput(nImgSrc))
;      
;      For k = 0 To 100 Step 20
;         Box(0 + k, 0 + k, #IW - k * 2, #IH - k * 2, RGB(k + 50, k + 100, k + 150))
;      Next
; 
;      DrawingMode(#PB_2DDrawing_Transparent)
;      DrawingFont(FontID(nFont))
;      
;      For k = 0 To #IH Step #IH / 10
;         DrawText(20, k + 10, "TEXT - " + Str(iBitPlanes) + " BPP IMAGE - TEXT", RGB(k/3, k/2, k/2))
;      Next
; 
;      If iBitPlanes = 24
;         DrawingMode(#PB_2DDrawing_Default)               
;         Circle(#IW - 200, 100, 50, RGB(128,0,0))
;         Circle(#IW - 200, #IH - 100, 50, RGB(0,128,0))   
;         Circle(#IW - 80, #IH/2, 50, RGB(0,0,128))       
;      Else
;         iFillColor = 0
;        
;         ; make 3 holes
;         DrawingMode(#PB_2DDrawing_AlphaChannel)       
;         Circle(#IW - 200, 100, 50,  $00)
;         Circle(#IW - 200, #IH - 100, 50, $00)
;         Circle(#IW - 80, #IH/2, 50, $00)
;        
;         ; fill them with semi-transparent circles
;         DrawingMode(#PB_2DDrawing_AlphaBlend)
;         Circle(#IW - 200, 100, 50, RGBA(128,0,0,100))
;         Circle(#IW - 200, #IH - 100, 50, RGBA(0,128,0,100))
;         Circle(#IW - 80, #IH/2, 50, RGBA(0,0,128,100))       
;      EndIf
;        
;     StopDrawing()

fileName$ = OpenFileRequester("Select a picture file", ".\", "bmp files| *.bmp", 0) ;MODIFY FOR DESIRED FILE TYPE
If fileName$ = "": End: EndIf

nImgSrc = LoadImage(#PB_Any, fileName$)
    ;;UsePNGImageDecoder()   
    ;;nImgSrc = LoadImage(#PB_Any, "test24.bmp")
    ;;nImgSrc = LoadImage(#PB_Any, "test32.png")
iBitPlanes = ImageDepth(nImgSrc)

result = OpenWindow(#WIN, 0, 0, 1024, 800, "", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
If result = 0: MessageRequester("Error", "Unable to open window."): End: EndIf
AddKeyboardShortcut(#WIN, #PB_Shortcut_Down, 1)
AddKeyboardShortcut(#WIN, #PB_Shortcut_Up, 2)
AddKeyboardShortcut(#WIN, #PB_Shortcut_Return, 3)

  
rotateAgain:
        iTime1 = ElapsedMilliseconds()         
        nImgOut = RotateImageFree (nImgSrc, -fRot, flgAntiAlias, iFillColor)
        iTime1 = ElapsedMilliseconds() - iTime1
       
        SetWindowTitle(#WIN, "Test " + Str(iBitPlanes) + " bit, AA = " + Str(flgAntiAlias) + ", msec = " + Str(iTime1) + ", deg = " + StrF(fRot,1))

        nImgCheck = CreateCheckers(ImageWidth(nImgOut), ImageHeight(nImgOut))
        nImgDisp = MergeImages(nImgCheck, nImgOut)
           
;         FreeImage(nImgOut) ;MOVED TO PROCEDURE MergeImages(), JUST BECAUSE
;         FreeImage(nImgCheck) ;MOVED TO PROCEDURE MergeImages(), JUST BECAUSE
           
        ImageGadget(#IMG, 0, 0, 0, 0, ImageID(nImgDisp))

Repeat

iEvent = WaitWindowEvent()

Select iEvent       

Case #PB_Event_Menu
  result = EventMenu()

  Select result

  Case 1 ;DOWN ARROW KEY PRESSED
    fRot + #ROT_INCREMENT
    Goto rotateAgain

  Case 2 ;UP ARROW KEY PRESSED
    fRot - #ROT_INCREMENT
    Goto rotateAgain

  Case 3 ;ENTER/RETURN KEY PRESSED
    SaveImage(nImgDisp, "Rotated.bmp")
    MessageRequester("", "Image saved.")

  EndSelect

Case #PB_Event_CloseWindow
        FreeImage(nImgDisp)
        FreeImage(nImgSrc)
        FreeFont(nFont)
        End

EndSelect

ForEver
Post Reply