j'ai également corrigé un petit problème sur le dimensionnement de l'image après rotation.
Code : Tout sélectionner
ProcedureDLL.l RotateImageEx3(ImageID, Angle.f, CouleurFond.l, 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 = RGB(Blue(CouleurFond), Green(CouleurFond), Red(CouleurFond))
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
bmi\bmiHeader\biCompression = #BI_RGB
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
bmi2\bmiHeader\biCompression = #BI_RGB
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
ReleaseDC_(0, hdc)
EndIf
CX1 = bm\bmWidth - 1
CY1 = bm\bmHeight - 1
CX2 = bmi2\bmiHeader\biWidth - 1
CY2 = bmi2\bmiHeader\biHeight - 1
CX1b = CX1 * 0.5
CY1b = CY1 * 0.5
CX2b = CX2 * 0.5
CY2b = CY2 * 0.5
Mem01 = Mem + bm\bmWidth * 4
Mem10 = Mem + 4
Mem11 = Mem01 + 4
Mem2Temp = Mem2
For nn = 0 To CY2
y1b.f = nn - CY2b
Temp1.f = CX1b - y1b * Sin
Temp2.f = CY1b + y1b * Cos
For n = 0 To CX2
x1b.f = n - CX2b
x1.f = Temp1 + x1b * Cos
y1.f = Temp2 + x1b * Sin
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
f10.f = 1 - fy
f01.f = f00 * fy
f00 * f10
f10 * fx
f11.f = fx * fy
MemTemp = (x2 + y2 * bm\bmWidth) * 4
DefType.l c00, c01, c11, c10
If x2 >= 0 And x2 <= CX1
If y2 >= 0 And y2 <= CY1
MOV eax, Mem
ADD eax, MemTemp
MOV eax, [eax]
MOV c00, eax
; c00 = PeekL(Mem + MemTemp)
Else
c00 = CouleurFond
EndIf
If y2b >= 0 And y2b <= CY1
MOV eax, Mem01
ADD eax, MemTemp
MOV eax, [eax]
MOV c01, eax
; c01 = PeekL(Mem01 + MemTemp)
Else
c01 = CouleurFond
EndIf
Else
c00 = CouleurFond
c01 = CouleurFond
EndIf
If x2b >= 0 And x2b <= CX1
If y2 >= 0 And y2 <= CY1
MOV eax, Mem10
ADD eax, MemTemp
MOV eax, [eax]
MOV c10, eax
; c10 = PeekL(Mem10 + MemTemp)
Else
c10 = CouleurFond
EndIf
If y2b >= 0 And y2b <= CY1
MOV eax, Mem11
ADD eax, MemTemp
MOV eax, [eax]
MOV c11, eax
; c11 = PeekL(Mem11 + MemTemp)
Else
c11 = CouleurFond
EndIf
Else
c10 = CouleurFond
c11 = CouleurFond
EndIf
DefType.l r1, r2, r3, r4, g1, g2, g3, g4, b1, b2, b3, b4
MOV eax, c00
MOV ebx, eax
MOV ecx, eax
And eax, $FF
MOV r1, eax
And ebx, $FF00
MOV g1, ebx
And ecx, $FF0000
MOV b1, ecx
MOV eax, c10
MOV ebx, eax
MOV ecx, eax
And eax, $FF
MOV r2, eax
And ebx, $FF00
MOV g2, ebx
And ecx, $FF0000
MOV b2, ecx
MOV eax, c01
MOV ebx, eax
MOV ecx, eax
And eax, $FF
MOV r3, eax
And ebx, $FF00
MOV g3, ebx
And ecx, $FF0000
MOV b3, ecx
MOV eax, c11
MOV ebx, eax
MOV ecx, eax
And eax, $FF
MOV r4, eax
And ebx, $FF00
MOV g4, ebx
And ecx, $FF0000
MOV b4, ecx
r = r1 * f00 + r2 * f10 + r3 * f01 + r4 * f11 ; pure fait très bien tout ça
g = g1 * f00 + g2 * f10 + g3 * f01 + g4 * f11
b = b1 * f00 + b2 * f10 + b3 * f01 + b4 * f11
MOV eax, r
MOV ebx, g
MOV ecx, b
And eax, $FF ; toute l'astuce consiste à laisser les triplets à leur place et à les multiplier là. On évite ainsi les décalages
And ebx, $FF00
And ecx, $FF0000
Or eax, ebx
Or eax, ecx
MOV ebx, Mem2Temp
MOV [ebx], eax
Else
MOV ebx, Mem2Temp
MOV eax, CouleurFond
MOV [ebx], eax
EndIf
Mem2Temp + 4
Next
Next
; On crée la nouvelle image
NewImageID = CreateImage(#PB_Any, bmi2\bmiHeader\biWidth, bmi2\bmiHeader\biHeight)
hdc = CreateCompatibleDC_(GetDC_(ImageID()))
If hdc
SetDIBits_(hdc, ImageID(), 0, bmi2\bmiHeader\biHeight, Mem2, @bmi2, #DIB_RGB_COLORS) ; on envoie la liste dans l'image
ReleaseDC_(0, 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)
StartDrawing(ImageOutput())
Box(0, 0, 80, 100, $6F6F6F)
Box(5, 5, 35, 45, $FF)
Box(40, 5, 35, 45, $FF00)
Box(5, 50, 35, 45, $FF0000)
Box(40, 50, 35, 45, $FFFFFF)
StopDrawing()
; Création de la fenêtre et de la GadgetList
If OpenWindow(0, 0, 0, 350, 400, #PB_Window_SystemMenu | #PB_Window_ScreenCentered | #PB_Window_MinimizeGadget, "Effect - Rotation d'image") = 0 Or CreateGadgetList(WindowID()) = 0
End
EndIf
Angle.f = 30
Mode = 0
CouleurFondFenetre = GetSysColor_(#COLOR_3DFACE) - $101010 ; Couleur de fond des fenêtres de Windows mais légèrement foncé (le - $101010)
ImageRotation = RotateImageEx3(UseImage(ImageNormale), Angle, CouleurFondFenetre, Mode)
TextGadget(#PB_Any, 10, 10, 100, 15, "Image normale")
ImageGadget(#PB_Any, 10, 25, 0, 0, UseImage(ImageNormale))
RotationTexte = TextGadget(#PB_Any, 10, 200, 100, 15, "Rotation de 30°")
Rotation = ImageGadget(#PB_Any, 10, 215, 0, 0, UseImage(ImageRotation))
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)
SetTimer_(WindowID(), 0, 25, 0)
Repeat
Event = WaitWindowEvent()
If Event = #WM_TIMER
Angle + 1
If Angle = 360
Angle = 0
EndIf
FreeImage(ImageRotation)
ImageRotation = RotateImageEx3(UseImage(ImageNormale), Angle, CouleurFondFenetre, Mode)
SetGadgetState(Rotation, UseImage(ImageRotation))
SetGadgetText(RotationTexte, "Rotation de " + StrF(Angle, 1) + "°")
ElseIf Event = #PB_EventGadget
Select EventGadgetID()
Case 0
Mode = 0
Case 1
Mode = 1
Case 2
Mode = 2
EndSelect
EndIf
Until Event = #PB_EventCloseWindow
KillTimer_(WindowID(), 0)
End