Rotate images +/- 90 deg. using native code only

Share your advanced PureBasic knowledge/code with the community.
User avatar
BasicallyPure
Enthusiast
Enthusiast
Posts: 536
Joined: Thu Mar 24, 2011 12:40 am
Location: Iowa, USA

Rotate images +/- 90 deg. using native code only

Post by BasicallyPure »

I wanted to rotate an image left or right by 90 degrees.
There are other examples here on the forum that will do that but they were either too complex for my liking or not cross platform.

I have written a procedure that uses only native PureBasic code.
The code is simple and reasonably fast.
The image is rotated in place once it is copied into a square temporary image.
After rotation if the original image was not square there will be empty space either on top or along the left side of the temporary image.
GrabImage() is used to recover the relevant portion of the rotated image.

2.17.2014
edit: now supports 32 bit as well as 24 bit images.

Code: Select all

; Rotate image +/- 90 degrees
; by BasicallyPure
; 2.18.2014
; supports 24 and 32 bit depth
; cross platform

EnableExplicit

Procedure ROTATE_90(image, dir)
   ; rotate image +/- 90 deg.
   ; 'image' is the number of the image to rotate
   ; if 'dir' <> 0 then rotate right else rotate left
   
   Protected a,b,c,e,f,h,s,w,x,y,ym,xm,tempImg,depth
   
   If IsImage(image) = 0 : ProcedureReturn 0 : EndIf
   
   StartDrawing(ImageOutput(image))
      w = OutputWidth()
      h = OutputHeight()
      f = DrawingBufferPixelFormat() & $7F
   StopDrawing()
      
      If f = #PB_PixelFormat_32Bits_RGB Or f = #PB_PixelFormat_32Bits_BGR
         depth = 32
      ElseIf f = #PB_PixelFormat_24Bits_RGB Or f = #PB_PixelFormat_24Bits_BGR
         depth = 24
      Else
         ProcedureReturn 0
      EndIf

   If w > h : s = w : Else : s = h : EndIf ; find the largest dimension
   
   tempImg = CreateImage(#PB_Any,s,s,depth) ; make a square working area
   
   StartDrawing(ImageOutput(tempImg))
      If depth = 32 : DrawingMode(#PB_2DDrawing_AllChannels) : EndIf
      
      DrawImage(ImageID(image),0,0)
      
      ym = s/2-1 ; max y loop value
      xm = s/2-(s!1&1) ; max x value, subtract 1 if 's' is even
      s-1
      
      If dir <> 0 ; rotate right
         For y = 0 To ym
            For x = 0 To xm
               e = Point(x,y)
               a = s-x : Plot(x,y,Point(y,a))
               b = s-y : Plot(y,a,Point(a,b))
               c = s-a : Plot(a,b,Point(b,c))
               Plot(b,c,e)
            Next x
         Next y
      Else ; rotate left
         For y = 0 To ym
            For x = 0 To xm
               e = Point(x,y)
               a = s-y : Plot(x,y,Point(a,x))
               b = s-x : Plot(a,x,Point(b,a))
               c = s-a : Plot(b,a,Point(c,b))
               Plot(c,b,e)
            Next x
         Next y
      EndIf
      
   StopDrawing()
   
   If dir <> 0
      GrabImage(tempImg,image,s-h+1,0,h,w) ; right
   Else
      GrabImage(tempImg,image,0,s-w+1,h,w) ; left
   EndIf
   
   FreeImage(tempImg)
   ProcedureReturn 1
EndProcedure


; Demo
UseJPEGImageDecoder() : UsePNGImageDecoder()

If OpenWindow(0,0,0,800,600,"",#PB_Window_MaximizeGadget|#PB_Window_ScreenCentered)
   
   Define Pattern$ = "image (*.png, *.jpg, *.bmp)|*.png;*.jpg;*.bmp|image *.*|*.*"
   Define F$, T$, Path$ = GetHomeDirectory() + "My Pictures\"
   
   CompilerIf #PB_Compiler_OS = #PB_OS_Linux
      Path$ = GetHomeDirectory() + "Pictures/"
   CompilerEndIf
   
   CreateStatusBar(0,WindowID(0))
   AddStatusBarField(#PB_Ignore)
   ImageGadget(0,110,10,1,1,0)
   ButtonGadget(1,10,010,90,25,"Load Image")
   ButtonGadget(2,10,070,90,25,"Rotate Right")
   ButtonGadget(3,10,100,90,25,"Rotate left")
   ButtonGadget(4,10,150,90,25,"Quit")
   
   Repeat
      Select WaitWindowEvent()
         Case #PB_Event_CloseWindow : Break
         Case #PB_Event_Gadget
            Select EventGadget()
               Case 1 : F$ = OpenFileRequester("Select image", Path$, Pattern$, 0)
                  If F$ : LoadImage(0,F$)
                     If IsImage(0)
                        T$ = F$ + "  |  (" + ImageWidth(0)
                        T$ + " x " + ImageHeight(0) + ")"
                        StatusBarText(0, 0, T$)
                        SetGadgetState(0,ImageID(0))
                     EndIf
                  EndIf
               Case 2 : If ROTATE_90(0,1) : SetGadgetState(0,ImageID(0)) : EndIf
               Case 3 : If ROTATE_90(0,0) : SetGadgetState(0,ImageID(0)) : EndIf
               Case 4 : Break
            EndSelect
      EndSelect
   ForEver
   
EndIf
Last edited by BasicallyPure on Sun Feb 23, 2014 7:20 pm, edited 7 times in total.
BasicallyPure
Until you know everything you know nothing, all you have is what you believe.
davido
Addict
Addict
Posts: 1890
Joined: Fri Nov 09, 2012 11:04 pm
Location: Uttoxeter, UK

Re: Rotate images +/- 90 deg. using native code only

Post by davido »

@BasicallyPure

Tried it with some scanned text documents.

Works perfectly.
Thank you for sharing. :D
DE AA EB
User avatar
majikeyric
Enthusiast
Enthusiast
Posts: 181
Joined: Mon Oct 21, 2013 5:21 pm
Location: France
Contact:

Re: Rotate images +/- 90 deg. using native code only

Post by majikeyric »

Thanks! It's fast even with big images.
User avatar
Kwai chang caine
Always Here
Always Here
Posts: 5345
Joined: Sun Nov 05, 2006 11:42 pm
Location: Lyon - France

Re: Rotate images +/- 90 deg. using native code only

Post by Kwai chang caine »

Works great, quick and very usefull
Thanks for sharing 8)
ImageThe happiness is a road...
Not a destination
RichardL
Enthusiast
Enthusiast
Posts: 532
Joined: Sat Sep 11, 2004 11:54 am
Location: UK

Re: Rotate images +/- 90 deg. using native code only

Post by RichardL »

Good morning,

I dug this out of my archives, it should be much faster than using Point() and Plot() which are traditionally very slow functions and not good news when used intensively to remap images.

(It does a flip as well... but the method can be modified to produce any combination of rotate +-90 and flip XY)

RichardL

Code: Select all

; Simple image rotate by 90 degrees using direct access to
; image buffers. Should be cross platform... no API tricks.

; Define libraries
UseJPEGImageDecoder()
UseJPEGImageEncoder()
UsePNGImageDecoder()

SourceFile$ = "c:\temp\90DegreeClamp.jpg"
DestFile$   = "c:\temp\DestFile.jpg"

If LoadImage(1,SourceFile$) ; Load Image
  Iw = ImageWidth(1) : Ih = ImageHeight(1) ; Get image size
  Debug File$+"  W="+Str(Iw)+"  H="+Str(Ih)
  
  If StartDrawing(ImageOutput(1))
      
      ; Get information for source image
      *SBuf = DrawingBuffer()
      SPitch = DrawingBufferPitch()
      Select DrawingBufferPixelFormat() & $7FFF
        Case #PB_PixelFormat_24Bits_RGB : SBpp = 3 : Depth = 24 ; 3 Bytes per pixel (RRGGBB)
        Case #PB_PixelFormat_24Bits_BGR : SBpp = 3 : Depth = 24 ; 3 Bytes per pixel (BBGGRR)
        Case #PB_PixelFormat_32Bits_RGB : SBpp = 4 : Depth = 32 ; 4 Bytes per pixel (RRGGBB)
        Case #PB_PixelFormat_32Bits_BGR : SBpp = 4 : Depth = 32 ; 4 Bytes per pixel (BBGGRR)
        Default : MessageRequester("Sorry...","24 and 32 bit depths only")  : End
      EndSelect
    StopDrawing()
    
    ; Create new image with axes swapped and get it's info
    CreateImage(2,Ih,Iw,8*SBpp)
    If StartDrawing(ImageOutput(2))
        *DBuf = DrawingBuffer()
        DPitch = DrawingBufferPitch()
      StopDrawing()
      
      ; Copy image 1 to image 2 with rotation
      For Y = 0 To Ih - 2
        *S = *SBuf + (Y * SPitch)
        *D = *DBuf + (Y * SBpp)
        For X = 0 To Iw -1
          Pix = PeekL(*S)
          PokeL(*D,Pix)
          *D + DPitch
          *S + SBpp
        Next
      Next Y
      
    EndIf
  EndIf
  
  SaveImage(2,DestFile$)
  
  ; VERY crude demo of result
  h = Ih : If Iw>Ih : h = Iw : EndIf
  OpenWindow(1,100,100,Iw+Ih,h,"Test")
  StartDrawing(WindowOutput(1))
    DrawImage(ImageID(1),0,0)
    DrawImage(ImageID(2),Iw,0)
  StopDrawing()
  
  FreeImage(1)
  FreeImage(2)
  
  While WaitWindowEvent() <> #PB_Event_CloseWindow
  Wend    
   
EndIf
davido
Addict
Addict
Posts: 1890
Joined: Fri Nov 09, 2012 11:04 pm
Location: Uttoxeter, UK

Re: Rotate images +/- 90 deg. using native code only

Post by davido »

@RichardL
Another nice example.

Thank you for sharing.
DE AA EB
User avatar
Kwai chang caine
Always Here
Always Here
Posts: 5345
Joined: Sun Nov 05, 2006 11:42 pm
Location: Lyon - France

Re: Rotate images +/- 90 deg. using native code only

Post by Kwai chang caine »

@RichardL
Yes !!! nice too :D
Thanks !!! 8)
ImageThe happiness is a road...
Not a destination
User avatar
em_uk
Enthusiast
Enthusiast
Posts: 366
Joined: Sun Aug 08, 2010 3:32 pm
Location: Manchester UK

Re: Rotate images +/- 90 deg. using native code only

Post by em_uk »

Yummy, direct to drawbuffer :)

why is using direct access much quicker than point?
----

R Tape loading error, 0:1
User avatar
BasicallyPure
Enthusiast
Enthusiast
Posts: 536
Joined: Thu Mar 24, 2011 12:40 am
Location: Iowa, USA

Re: Rotate images +/- 90 deg. using native code only

Post by BasicallyPure »

@RichardL
Is there any way to prevent your code from doing a flip (mirror) as the rotation is the only effect I would like?

I spent quite a bit of time trying to do a counter-clockwise rotation with your code with only partial success.
After I made a better GUI that allows consecutive rotations I noticed the mirror problem with the original code.

I have modified your code to allow both CW and CCW rotation.
My testing has shown a problem with my CCW rotation on some images.
It perform the rotation ok but the colors are wrong on some images.
All of my test images have been 24 bit BGR as far as I can tell.

The code below has a variable named 'padding' that can fix the color problem
on the images that show wrong colors when rotated CCW if it set to equal 1.
On other images that do not show the wrong color problem there will be an IMA error if 'padding' is equal to 1.
I don't know how to determine when this variable needs to be set to 1.

I suspect but do not know if this is caused by the 'padding' that is mentioned in the help entry for DrawingBufferPitch().
I really don't know what is going on here so a solution escapes me.
If anyone knows what this 'padding' is and could explain it, that would be great.

After I noticed the mirror problem with the original code I decided to stop further work on this and I hope someone can provide some help.

What I do here for the CCW rotation is to set *DBuff to point to the end of the buffer, not the beginning.
Then the loop iterates backward thru the buffer.

Here is the code that I have so far. (Warning! This code is buggy)

Edit: I have solved the color problem. Now all images maintain the proper color when rotated.
Unfortunately I have discovered another problem with one particular image I have.
I have determined the problem (an IMA error) only occurs with an image that is 1024 x 768 in size.

(Warning! This code is still buggy but not as much. :shock: )

Code: Select all

; Simple image rotate by 90 degrees using direct access to
; image buffers. Should be cross platform... no API tricks.

EnableExplicit

; Define libraries
UseJPEGImageDecoder()
UseJPEGImageEncoder()
UsePNGImageDecoder()

Procedure ROTATE(image, flag = 0)
   ;if flag <> 0 image rotates left else image rotates right
   
   Protected Iw, Ih, SBpp, DBpp, Depth, SPitch, DPitch, X, Y
   Protected result, padding, imgTemp, *SBuf, *DBuf, *D, *S
   
   If IsImage(image) = 0 : ProcedureReturn result : EndIf
   
   StartDrawing(ImageOutput(image))
      
      ; Get information for source image
      Iw = OutputWidth() : Ih = OutputHeight() ; Get image size
      *SBuf = DrawingBuffer()
      SPitch = DrawingBufferPitch()
      Select DrawingBufferPixelFormat() & $7FFF
         Case #PB_PixelFormat_24Bits_RGB : SBpp = 3 : Depth = 24 ; 3 Bytes per pixel (RRGGBB)
         Case #PB_PixelFormat_24Bits_BGR : SBpp = 3 : Depth = 24 ; 3 Bytes per pixel (BBGGRR)
         Case #PB_PixelFormat_32Bits_RGB : SBpp = 4 : Depth = 32 ; 4 Bytes per pixel (RRGGBB)
         Case #PB_PixelFormat_32Bits_BGR : SBpp = 4 : Depth = 32 ; 4 Bytes per pixel (BBGGRR)
         Default
            MessageRequester("Sorry...","24 and 32 bit depths only")
            StopDrawing()
            ProcedureReturn result
      EndSelect
   StopDrawing()
   
   ; Create temporary image with axes swapped and get it's info
   imgTemp = CreateImage(#PB_Any, Ih, Iw, 8*SBpp)
   
   If imgTemp
      StartDrawing(ImageOutput(imgTemp))
         *DBuf = DrawingBuffer()
         DPitch = DrawingBufferPitch()
         
         If flag ; rotate left
            ; DPitch is padded to multiples of 4 bytes.
            ; (Ih * SBpp) is the actual ammount of data per row.
            ; so the adjustment is as follows:
            padding = DPitch - (Ih * SBpp)
            
            ; set pointer to the last pixel data
            *DBuf = *DBuf + (Iw * DPitch) - (SBpp + padding)
            
            ; reverse the direction of data iteration
            DPitch = -DPitch
            DBpp = -SBpp
         Else
            DBpp = SBpp
         EndIf
         
         Iw - 1 : Ih - 1
         
         ; Copy image to imgTemp with rotation
         For Y = 0 To Ih
            ;fixes IMA error when image is 1024 x 768
            ;If y = Ih : Iw-1 : EndIf
            
            *S = *SBuf + (Y * SPitch)
            *D = *DBuf + (Y * DBpp)
            For X = 0 To Iw
               PokeL(*D, PeekL(*S))
               *D + DPitch
               *S + SBpp
            Next
         Next Y
      StopDrawing()
      
      CopyImage(imgTemp,image)
      FreeImage(imgTemp)
      result = 1
   EndIf
   
   ProcedureReturn result
EndProcedure

; demo
Define Path$ = GetHomeDirectory() + "My Pictures\"
Define Pattern$ = "image (*.png, *.jpg, *.bmp)|*.png;*.jpg;*.bmp|image *.*|*.*"
Define F$

OpenWindow(0, 0, 0, 910, 610, "Test",#PB_Window_MaximizeGadget)
CreateImage(1,800,600,24)
ImageGadget(0,100,5,800,600,ImageID(1))
ButtonGadget(1,5,5,90,25,"Load")
ButtonGadget(2,5,35,90,25,"Right")
ButtonGadget(3,5,65,90,25,"Left")
ButtonGadget(4,5,95,90,25,"Quit")

Repeat
   Select WaitWindowEvent()
      Case #PB_Event_CloseWindow : Break
      Case #PB_Event_Gadget
         Select EventGadget()
            Case 1 : F$ = OpenFileRequester("Select image", Path$, Pattern$, 0)
               If F$ : LoadImage(1,F$)
                  If IsImage(1) : SetGadgetState(0,ImageID(1)) : EndIf
               EndIf
            Case 2 : ROTATE(1,0) : SetGadgetState(0,ImageID(1))
            Case 3 : ROTATE(1,1) : SetGadgetState(0,ImageID(1))
            Case 4 : Break
         EndSelect
   EndSelect
ForEver
Last edited by BasicallyPure on Sun Feb 16, 2014 2:22 am, edited 2 times in total.
BasicallyPure
Until you know everything you know nothing, all you have is what you believe.
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3870
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: Rotate images +/- 90 deg. using native code only

Post by wilbert »

You might be careful with this latest approach.
As far as I know there's no guarantee the returned value from DrawingBuffer() is still valid after StopDrawing() is called.
It seems to work fine but in theory it's possible to have only a temporary buffer that is not accessible anymore after StopDrawing().
If the return value from DrawingBuffer() is guaranteed to be available even after StopDrawing() is called, it would be nice if Fred could add that to the documentation since it would be a nice feature.
Windows (x64)
Raspberry Pi OS (Arm64)
User avatar
BasicallyPure
Enthusiast
Enthusiast
Posts: 536
Joined: Thu Mar 24, 2011 12:40 am
Location: Iowa, USA

Re: Rotate images +/- 90 deg. using native code only

Post by BasicallyPure »

You make a good point.

Thanks,
BP
BasicallyPure
Until you know everything you know nothing, all you have is what you believe.
User avatar
BasicallyPure
Enthusiast
Enthusiast
Posts: 536
Joined: Thu Mar 24, 2011 12:40 am
Location: Iowa, USA

Re: Rotate images +/- 90 deg. using native code only

Post by BasicallyPure »

The code from the first post has been updated to support 32 bit as well as 24 bit images.

I now have fixed all of the known problems with the direct buffer access method.
Keep in mind Wilbert's warning as stated above.
Now that I have two different working methods I performed some speed test comparisons.

The code from the first post I will refer to as method 1.
The code in this post I will refer to as method 2.

Here are the results using a 24 bit test image of dimensions 3008 x 2000.
all times are in milliseconds. Each rotation was perform 4 times then averaged.

Method 1 : uses Plot() and Point() to move pixels around.
rotate right, 330, 333, 340, 344, average = 337
rotate left, 329, 333, 332, 337, average = 333

Method 2: uses Poke() and Peek() with direct buffer access.
rotate right, 233, 234, 241, 236, average = 236
rotate left, 228, 229, 233, 237, average 232

Method 2 is about 30% faster.

This has been tested with Windows and Linux.

Code: Select all

; rotate image by 90 degrees using direct access to image buffers.
; Should be cross platform... no API tricks.
; 2.17.2014
; PureBasic 5.21
; supports 24 and 32 bit images

EnableExplicit

Procedure ROTATE(image, flag)
   ;if flag <> 0 image rotates left else image rotates right
   
   Protected A, B, result, padding, imgTemp, format
   Protected *SBuf  ; pointer to first memory byte of source buffer
   Protected *DBuf  ; pointer to first memory byte of destination buffer
   Protected *FPix  ; points to where first pixel is peeked in source buffer
   Protected *S,*D  ; source and destination pointers
   Protected Iw     ; image width
   Protected Ih     ; image height
   Protected Depth  ; image color depth, 24 or 32
   Protected SBpp   ; SourceBytesPerPixel
   Protected DBpp   ; DestinationBytesPerPixel
   Protected SPitch ; source image number of bytes per row (x)
   Protected DPitch ; destination image number of bytes per row (x)
   
   Macro Copy3Bytes(Source, Destination)
      PokeA(Destination, PeekA(Source))
      PokeW(Destination+1, PeekW(Source+1))
   EndMacro
   
   Macro Copy4Bytes(Source, Destination)
      PokeL(Destination, PeekL(Source))
   EndMacro
   
   If IsImage(image) = 0 : ProcedureReturn result : EndIf
   
   StartDrawing(ImageOutput(image))
      ; Get information for source image
      Iw = OutputWidth() : Ih = OutputHeight() ; Get image size
      *SBuf  = DrawingBuffer()
      SPitch = DrawingBufferPitch()
      format = DrawingBufferPixelFormat()
      
      Select  format & $7FFF
         Case #PB_PixelFormat_24Bits_RGB : SBpp = 3 : Depth = 24 ; 3 Bytes per pixel (RRGGBB)
         Case #PB_PixelFormat_24Bits_BGR : SBpp = 3 : Depth = 24 ; 3 Bytes per pixel (BBGGRR)
         Case #PB_PixelFormat_32Bits_RGB : SBpp = 4 : Depth = 32 ; 4 Bytes per pixel (RRGGBB)
         Case #PB_PixelFormat_32Bits_BGR : SBpp = 4 : Depth = 32 ; 4 Bytes per pixel (BBGGRR)
         Default
            MessageRequester("Sorry...","24 and 32 bit depths only")
            StopDrawing()
            ProcedureReturn result
      EndSelect
      
      If format & #PB_PixelFormat_ReversedY = 0 ; this is for Linux
         flag = flag ! 1 & 1
      EndIf
   StopDrawing()
   
   ; Create temporary image with axis swapped
   Swap Ih,Iw
   imgTemp = CreateImage(#PB_Any, Iw, Ih, 8*SBpp)
   
   ; perform the rotation
   If imgTemp
      StartDrawing(ImageOutput(imgTemp))
         *DBuf = DrawingBuffer()
         DPitch = DrawingBufferPitch()
         DBpp = SBpp
         
         If flag = 0 ; configure to rotate right
            *FPix = *SBuf + (Ih-1) * SBpp ; point to last pixel in first row
            SBpp = -SBpp ; reverse X iteration direction
         Else ; configure to rotate left
            *FPix = *SBuf + (Iw-1) * SPitch ; point to first pixel in last row
            SPitch = -SPitch ; reverse Y iteration direction
         EndIf
         
         ; time to fly
         If Depth = 24
            A = 0 : While A < Ih
               *S = *FPix + (A * SBpp)   ; set source pointer X position
               *D = *DBuf + (A * DPitch) ; set destination pointer Y position
               B = 0 : While B < Iw
                  Copy3Bytes(*S, *D)
                  *S + SPitch ; increment source pointer Y position
                  *D + DBpp   ; increment destination pointer X position
               B + 1 : Wend
            A + 1 : Wend
         ElseIf Depth = 32
            A = 0 : While A < Ih
               *S = *FPix + (A * SBpp)   ; set source pointer X position
               *D = *DBuf + (A * DPitch) ; set destination pointer Y position
               B = 0 : While B < Iw
                  Copy4Bytes(*S, *D)
                  *S + SPitch ; increment source pointer Y position
                  *D + DBpp   ; increment destination pointer X position
               B + 1 : Wend
            A + 1 : Wend
         EndIf
      
      StopDrawing()
      
      CopyImage(imgTemp,image)
      FreeImage(imgTemp)
      result = 1
   EndIf
   
   ProcedureReturn result
EndProcedure

; demo
UseJPEGImageDecoder()
UsePNGImageDecoder()

CompilerIf #PB_Compiler_OS = #PB_OS_Linux
   Define Path$ = GetHomeDirectory() + "Pictures/"
CompilerElse
   Define Path$ = GetHomeDirectory() + "My Pictures\"
CompilerEndIf

Define Pattern$ = "image (*.png, *.jpg, *.bmp)|*.png;*.jpg;*.bmp|image *.*|*.*"
Define flags = #PB_Window_MaximizeGadget | #PB_Window_ScreenCentered
Define F$

OpenWindow(0, 0, 0, 910, 610, "Test", flags)
SetWindowColor(0,$A0A0A0)
CreateImage(1,800,600,24)
ImageGadget(0,100,5,800,600,ImageID(1))
ButtonGadget(1,5,5,90,25,"Load")
ButtonGadget(2,5,60,90,25,"Right")
ButtonGadget(3,5,90,90,25,"Left")
ButtonGadget(4,5,145,90,25,"Quit")

Repeat
   Select WaitWindowEvent()
      Case #PB_Event_CloseWindow : Break
      Case #PB_Event_Gadget
         Select EventGadget()
            Case 1 : F$ = OpenFileRequester("Select image", Path$, Pattern$, 0)
               If F$ : LoadImage(1,F$)
                  If IsImage(1) : SetGadgetState(0,ImageID(1)) : EndIf
               EndIf
            Case 2 : ROTATE(1,0) : SetGadgetState(0,ImageID(1))
            Case 3 : ROTATE(1,1) : SetGadgetState(0,ImageID(1))
            Case 4 : Break
         EndSelect
   EndSelect
ForEver
BasicallyPure
Until you know everything you know nothing, all you have is what you believe.
davido
Addict
Addict
Posts: 1890
Joined: Fri Nov 09, 2012 11:04 pm
Location: Uttoxeter, UK

Re: Rotate images +/- 90 deg. using native code only

Post by davido »

@BasicallyPure

Looks great. Some very nice improvements.

Rotating images used to be a pain. It has just got very much easier.

Thank you for sharing. :D :D
DE AA EB
User avatar
electrochrisso
Addict
Addict
Posts: 980
Joined: Mon May 14, 2007 2:13 am
Location: Darling River

Re: Rotate images +/- 90 deg. using native code only

Post by electrochrisso »

Very nice BP, thanks for sharing. :)
PureBasic! Purely one of the best 8)
Post Reply