
Image Rotation routines for 24/32 bit with optional AA
Re: Image Rotation routines for 24/32 bit with optional AA
Badly, it's not my own routine, even if I optimised it, and I really have no time by now... But yours "does the job", and is clean 

Re: Image Rotation routines for 24/32 bit with optional AA
Optimized a little for speed.
1) Splitted the code and macros for 24 / 32 bit to remove the select/case branch (2% gain)
2) Removed the clipping test (RGB_Clamp macro) using a little trick (the - 0.000005 in the code) to eliminate the rounding problems who caused sometimes the overflow/underflow in the 0/255 range. This way a lot of if were removed (around 1% gain probably less).
3) Eliminated the copy of the data from the image to the structure in the main loop. It wasn't needed. My bad. Now I simply move a pointer in memory and read the data directly without copy it to the temp structure until the moment I need to write it to the destination (changed the ReadPixel?? macro). This is where the gain is (big error, big gain I guess). 10% maybe a little more.
So, at the end should be around 15% faster for the heavier scenario (32 bit and antialias enabled).
Hope I don't broke something in the process, but it seem working !
Bye!
1) Splitted the code and macros for 24 / 32 bit to remove the select/case branch (2% gain)
2) Removed the clipping test (RGB_Clamp macro) using a little trick (the - 0.000005 in the code) to eliminate the rounding problems who caused sometimes the overflow/underflow in the 0/255 range. This way a lot of if were removed (around 1% gain probably less).
3) Eliminated the copy of the data from the image to the structure in the main loop. It wasn't needed. My bad. Now I simply move a pointer in memory and read the data directly without copy it to the temp structure until the moment I need to write it to the destination (changed the ReadPixel?? macro). This is where the gain is (big error, big gain I guess). 10% maybe a little more.
So, at the end should be around 15% faster for the heavier scenario (32 bit and antialias enabled).
Hope I don't broke something in the process, but it seem working !
Bye!
"Have you tried turning it off and on again ?"
A little PureBasic review
A little PureBasic review
Re: Image Rotation routines for 24/32 bit with optional AA
Nice code, clean and nice to read! Just for info, to optimise (not useful in my opinion as it's not designed to be realtime), you could use lines routines as x and y have a linear progression. Then you only have to compute the four source corners (not the dest). The second optimisation (harder), is to have a linear progression along the memory, as you could somehow add the x and y components of the source image. The third optimisation is to transform the source image to something more manageable by the processor. All of this could benefit from assembler, but will be not as portable.
However, as dest is memory and fully linear, you can speed up things a bit by removing some computations in the main loop, as in this topic : http://www.purebasic.fr/english/viewtop ... 13&t=39036
But honestly I prefer this code like it is now, as it is convenient
However, as dest is memory and fully linear, you can speed up things a bit by removing some computations in the main loop, as in this topic : http://www.purebasic.fr/english/viewtop ... 13&t=39036
But honestly I prefer this code like it is now, as it is convenient

Re: Image Rotation routines for 24/32 bit with optional AA
Your points are very interesting djes! I'm not quite sure how to implement them, especially the first one.
Probably I don't have the concept very clear in my mind and should I give it some thought... a little over my head I believe
If you have time and the will, could you explain a little more in detail the first suggestion you make ?
In any case thank you and thank you for the link too, I'll read it this afternoon!
EDIT: I lied, I din't resist and read it now!
AHHH! I see what you mean, yes I thought about that but I skipped it because it would have meant to loose my nice ReadPixel WritePixel macros and have them diluted along the main loop. It will be faster (very little I think) but I will be less easy to read and to derive maybe other routines from the same code. Well it's often that way when optimize for speed, you loose something else. But I understand your point. Maybe I'll try it just for fun!
djes wrote:you could use lines routines as x and y have a linear progression. Then you only have to compute the four source corners (not the dest).
Probably I don't have the concept very clear in my mind and should I give it some thought... a little over my head I believe

If you have time and the will, could you explain a little more in detail the first suggestion you make ?
In any case thank you and thank you for the link too, I'll read it this afternoon!
EDIT: I lied, I din't resist and read it now!
AHHH! I see what you mean, yes I thought about that but I skipped it because it would have meant to loose my nice ReadPixel WritePixel macros and have them diluted along the main loop. It will be faster (very little I think) but I will be less easy to read and to derive maybe other routines from the same code. Well it's often that way when optimize for speed, you loose something else. But I understand your point. Maybe I'll try it just for fun!
"Have you tried turning it off and on again ?"
A little PureBasic review
A little PureBasic review
Re: Image Rotation routines for 24/32 bit with optional AA
In any case, keep your original code 

- Le Soldat Inconnu
- Enthusiast
- Posts: 306
- Joined: Wed Jul 09, 2003 11:33 am
- Location: France
Re: Image Rotation routines for 24/32 bit with optional AA
hi,
i do code to rotate image with AA
i just adapt for alpha channel
so let go
Full librairie is here
http://www.lsi-dev.com/index.php?mod=do ... erid&id=40
Image symetry, rotation, and some effect about color
i do code to rotate image with AA
i just adapt for alpha channel
so let go

Code: Select all
ProcedureDLL.l RotateImageEx2(ImageID, Angle.f, Mode.l) ; Rotation d'une image d'un angle en °
Protected bmi.BITMAPINFO, bmi2.BITMAPINFO, hdc.l, NewImageID, Mem, n, nn, bm.BITMAP
Angle = Angle * #PI / 180 ; On convertit en radian
Cos.f = Cos(Angle)
Sin.f = Sin(Angle)
CouleurFond = 0
GetObject_(ImageID, SizeOf(BITMAP), @bm.BITMAP)
bmi\bmiHeader\biSize = SizeOf(BITMAPINFOHEADER)
bmi\bmiHeader\biWidth = bm\bmWidth
bmi\bmiHeader\biHeight = bm\bmHeight
bmi\bmiHeader\biPlanes = 1
bmi\bmiHeader\biBitCount = 32
bmi2\bmiHeader\biSize = SizeOf(BITMAPINFOHEADER)
Select Mode
Case 1
bmi2\bmiHeader\biWidth = bm\bmWidth
bmi2\bmiHeader\biHeight = bm\bmHeight
Case 2
bmi2\bmiHeader\biWidth = Round(Sqr(bm\bmWidth * bm\bmWidth + bm\bmHeight * bm\bmHeight), 1)
bmi2\bmiHeader\biHeight = bmi2\bmiHeader\biWidth
Default
bmi2\bmiHeader\biWidth = Round(bm\bmWidth * Abs(Cos) + bm\bmHeight * Abs(Sin), 1)
bmi2\bmiHeader\biHeight = Round(bm\bmHeight * Abs(Cos) + bm\bmWidth * Abs(Sin), 1)
EndSelect
bmi2\bmiHeader\biPlanes = 1
bmi2\bmiHeader\biBitCount = 32
Mem = AllocateMemory(bm\bmWidth * bm\bmHeight * 4)
If Mem
Mem2 = AllocateMemory(bmi2\bmiHeader\biWidth * bmi2\bmiHeader\biHeight * 4)
If Mem2
hdc = CreateCompatibleDC_(GetDC_(ImageID))
If hdc
GetDIBits_(hdc, ImageID, 0, bm\bmHeight, Mem, @bmi, #DIB_RGB_COLORS) ; on envoie la liste dans l'image
DeleteDC_(hdc)
EndIf
CX1 = bm\bmWidth - 1
CY1 = bm\bmHeight - 1
CX2 = bmi2\bmiHeader\biWidth - 1
CY2 = bmi2\bmiHeader\biHeight - 1
Mem01 = Mem + bm\bmWidth * 4
Mem10 = Mem + 4
Mem11 = Mem01 + 4
Mem2Temp = Mem2
For nn = 0 To CY2
y1b.l = nn * 2 - CY2
Temp1.f = CX1 - y1b * Sin
Temp2.f = CY1 + y1b * Cos
For n = 0 To CX2
x1b.l = n * 2 - CX2
x1.f = (Temp1 + x1b * Cos) / 2
y1.f = (Temp2 + x1b * Sin) / 2
x2.l = x1
y2.l = y1
If x1 < x2
DEC x2
EndIf
If y1 < y2
DEC y2
EndIf
x2b = x2 + 1
y2b = y2 + 1
If x2b >= 0 And x2 <= CX1 And y2b >= 0 And y2 <= CY1 ; On filtre si on est completement en dehors de l'image
fx.f = x1 - x2
fy.f = y1 - y2
f00.f = (1 - fx) * (1 - fy)
f01.f = (1 - fx) * fy
f10.f = fx * (1 - fy)
f11.f = fx * fy
MemTemp = (x2 + y2 * bm\bmWidth) * 4
If x2 >= 0 And x2 <= CX1
If y2 >= 0 And y2 <= CY1
c00 = PeekL(Mem + MemTemp)
Else
c00 = 0
EndIf
If y2b >= 0 And y2b <= CY1
c01 = PeekL(Mem01 + MemTemp)
Else
c01 = 0
EndIf
Else
c00 = 0
c01 = 0
EndIf
If x2b >= 0 And x2b <= CX1
If y2 >= 0 And y2 <= CY1
c10 = PeekL(Mem10 + MemTemp)
Else
c10 = 0
EndIf
If y2b >= 0 And y2b <= CY1
c11 = PeekL(Mem11 + MemTemp)
Else
c11 = 0
EndIf
Else
c10 = 0
c11 = 0
EndIf
Channel00 = c00 >> 24 & $FF
Channel01 = c01 >> 24 & $FF
Channel10 = c10 >> 24 & $FF
Channel11 = c11 >> 24 & $FF
Alpha = Channel00 * f00 + Channel01 * f01 + Channel10 * f10 + Channel11 * f11
Channel00 = c00 >> 16 & $FF
Channel01 = c01 >> 16 & $FF
Channel10 = c10 >> 16 & $FF
Channel11 = c11 >> 16 & $FF
Rouge = Channel00 * f00 + Channel01 * f01 + Channel10 * f10 + Channel11 * f11
Channel00 = c00 >> 8 & $FF
Channel01 = c01 >> 8 & $FF
Channel10 = c10 >> 8 & $FF
Channel11 = c11 >> 8 & $FF
Vert = Channel00 * f00 + Channel01 * f01 + Channel10 * f10 + Channel11 * f11
Channel00 = c00 & $FF
Channel01 = c01 & $FF
Channel10 = c10 & $FF
Channel11 = c11 & $FF
Bleu = Channel00 * f00 + Channel01 * f01 + Channel10 * f10 + Channel11 * f11
PokeL(Mem2Temp, Rouge | Vert << 8 | Bleu << 16 | Alpha << 24)
Else
PokeL(Mem2Temp, 0)
EndIf
Mem2Temp + 4
Next
Next
; On crée la nouvelle image
NewImageID = CreateImage(#PB_Any, bmi2\bmiHeader\biWidth, bmi2\bmiHeader\biHeight, 32)
hdc = CreateCompatibleDC_(GetDC_(ImageID(NewImageID)))
If hdc
SetDIBits_(hdc, ImageID(NewImageID), 0, bmi2\bmiHeader\biHeight, Mem2, @bmi2, #DIB_RGB_COLORS) ; on envoie la liste dans l'image
DeleteDC_(hdc)
EndIf
FreeMemory(Mem2)
EndIf
FreeMemory(Mem)
EndIf
ProcedureReturn NewImageID
EndProcedure
;- ----------------------------------------
;- Test d'affichage d'image avec rotation
; On dessine une image
ImageNormale = CreateImage(#PB_Any, 80, 100, 32)
StartDrawing(ImageOutput(ImageNormale))
DrawingMode(#PB_2DDrawing_AlphaChannel)
Box(0, 0, 80, 100, $00000000)
DrawingMode(#PB_2DDrawing_Gradient | #PB_2DDrawing_AlphaBlend)
LinearGradient(0, 0, 80, 100)
GradientColor(0.0, $00000000)
GradientColor(1.0, $FF000000)
Box(0, 0, 80, 100)
DrawingMode(#PB_2DDrawing_AlphaBlend)
Box(5, 5, 35, 45, $B00000FF)
Box(40, 5, 35, 45, $FF00FF00)
Box(5, 50, 35, 45, $FFFF0000)
Box(40, 50, 35, 45, $80FFFFFF)
StopDrawing()
; Création de la fenêtre et de la GadgetList
If OpenWindow(0, 0, 0, 350, 400, "Effect - Rotation d'image", #PB_Window_SystemMenu | #PB_Window_ScreenCentered | #PB_Window_MinimizeGadget) = 0
End
EndIf
Angle.f = 30
Mode = 0
ImageRotation = RotateImageEx2(ImageID(ImageNormale), Angle, Mode)
TextGadget(#PB_Any, 10, 10, 100, 15, "Image normale")
ImageGadget(#PB_Any, 10, 25, 0, 0, ImageID(ImageNormale))
RotationTexte = TextGadget(#PB_Any, 10, 200, 100, 15, "Rotation de 30°")
Rotation = ImageGadget(#PB_Any, 10, 215, 0, 0, ImageID(ImageRotation))
RotationTemps = TextGadget(#PB_Any, 180, 270, 170, 15, "")
TextGadget(#PB_Any, 180, 200, 100, 15, "Mode :")
OptionGadget(0, 180, 215, 170, 15, "normal")
OptionGadget(1, 180, 230, 170, 15, "sans redimensionnement")
OptionGadget(2, 180, 245, 170, 15, "avec redimensionnement fixe")
SetGadgetState(0, 1)
AddWindowTimer(0, 1, 200)
Repeat
Event = WaitWindowEvent()
If Event = #PB_Event_Timer
If EventTimer() = 1
Angle + 1
If Angle = 360
Angle = 0
EndIf
Temps1 = ElapsedMilliseconds()
For n = 1 To 100
FreeImage(ImageRotation)
ImageRotation = RotateImageEx2(ImageID(ImageNormale), Angle, Mode)
Next
Temps2 = ElapsedMilliseconds()
SetGadgetState(Rotation, ImageID(ImageRotation))
SetGadgetText(RotationTexte, "Rotation de " + Str(Angle) + "°")
SetGadgetText(RotationTemps, StrF((Temps2 - Temps1) / 100, 2) + "ms")
EndIf
ElseIf Event = #PB_Event_Gadget
Select EventGadget()
Case 0
Mode = 0
Case 1
Mode = 1
Case 2
Mode = 2
EndSelect
EndIf
Until Event = #PB_Event_CloseWindow
End
Full librairie is here
http://www.lsi-dev.com/index.php?mod=do ... erid&id=40
Image symetry, rotation, and some effect about color
LSI
Re: Image Rotation routines for 24/32 bit with optional AA
Thanks luis, great code!
The only thing I dislike is the heavy line count. The code I'm using right now has about 100 lines and fits into one procedure.
But I think I have to accept this for AA, alpha support and non rectangle rotation.
The only thing I dislike is the heavy line count. The code I'm using right now has about 100 lines and fits into one procedure.
But I think I have to accept this for AA, alpha support and non rectangle rotation.

If any of you native English speakers have any suggestions for the above text, please let me know (via PM). Thanks!
Re: Image Rotation routines for 24/32 bit with optional AA
Well, if with "non rectangle rotation" you mean "free angle rotation" (I'm not sure) you can see there are a couple of routines included to do 90 degrees rotations and flipping/mirroring too. They are also obviously faster than the generic one. If you need only a subset of what this one does you can trim it down (that's the good thing of having the source !).c4s wrote:The code I'm using right now has about 100 lines and fits into one procedure.
But I think I have to accept this for AA, alpha support and non rectangle rotation.
Thanks for the thanks, they are always appreciated!
"Have you tried turning it off and on again ?"
A little PureBasic review
A little PureBasic review
Re: Image Rotation routines for 24/32 bit with optional AA
Sorry, I meant the rectangular rotation (90, 180, 270).luis wrote:Well, if with "non rectangle rotation" you mean "free angle rotation" (I'm not sure) you can see there are a couple of routines included to do 90 degrees rotations and flipping/mirroring too. They are also obviously faster than the generic one. If you need only a subset of what this one does you can trim it down (that's the good thing of having the source !).
Thanks for the thanks, they are always appreciated!
You are right. I can pick out the procedures I need so when I would remove the comments etc. the same line count will come up and it's then even cross-platform and supports alpha and retains the depth (in contrast to the code I used).
Now when I realized this your code is even better!
Maybe you should add a small note in the first post about having this only-rectangular-rotation-procedure thing?
If any of you native English speakers have any suggestions for the above text, please let me know (via PM). Thanks!
Re: Image Rotation routines for 24/32 bit with optional AA
After playing a bit with the code, taking out the things I need etc. I found out that I could need handling of images with lower depth like 16 bit.
Is it possible to just modifiy the CopyPixelXX(), ReadPixelXX(), WritePixelXX() procedures to support this or are there higher restrictions?
Is it possible to just modifiy the CopyPixelXX(), ReadPixelXX(), WritePixelXX() procedures to support this or are there higher restrictions?
If any of you native English speakers have any suggestions for the above text, please let me know (via PM). Thanks!
Re: Image Rotation routines for 24/32 bit with optional AA
It should work without modifications if I'm not mistaken... the real difference it's between 32 bit (rgb + alpha) and 24 bit (rgb without alpha).
The 24 bit routines should work for 16 bits also. I should try but I'm reasonably sure.
The 24 bit routines should work for 16 bits also. I should try but I'm reasonably sure.
"Have you tried turning it off and on again ?"
A little PureBasic review
A little PureBasic review
Re: Image Rotation routines for 24/32 bit with optional AA
Yes, you are right. Seems to work. But I forgot that PureBasic can't save in the "correct" bitrate, right?luis wrote:The 24 bit routines should work for 16 bits also. I should try but I'm reasonably sure.
Note, I just found a nasty memory leak or at least this behavior wasn't clear for me: The source image still exists after the modification!
To fix it I just added FreeImage(nSrcImage) after AllocateImageData(nSrcImage, @iBufferPitchSrc).
Anyway, thanks again for your great code and help.

If any of you native English speakers have any suggestions for the above text, please let me know (via PM). Thanks!
Re: Image Rotation routines for 24/32 bit with optional AA
Bitdepths for loading, saving and catchimage are not particulary clear, at least to me.c4s wrote: Yes, you are right. Seems to work. But I forgot that PureBasic can't save in the "correct" bitrate, right?
The best thing is to try and check the results I'm afraid.
See this bugreport for example:
http://www.purebasic.fr/english/viewtop ... 13#p303913
It's by design. You get a new image rotated, but the original is not deleted. You could have still some very good use for it for what I know.c4s wrote: Note, I just found a nasty memory leak or at least this behavior wasn't clear for me: The source image still exists after the modification!
That's why in the examples I wrote there is a FreeImage() for that. The intention was to make that clear, but maybe I should have wrote it explicitly. Well, I'm saying that here and now!
No problemc4s wrote: Anyway, thanks again for your great code and help.

"Have you tried turning it off and on again ?"
A little PureBasic review
A little PureBasic review
Re: Image Rotation routines for 24/32 bit with optional AA
Thank you very much. 

-
- Enthusiast
- Posts: 443
- Joined: Sun Apr 06, 2008 12:54 pm
- Location: Brisbane, Qld, Australia
- Contact:
Re: Image Rotation routines for 24/32 bit with optional AA
Many thanks, luis - just what I need.