Bild drehen

Für allgemeine Fragen zur Programmierung mit PureBasic.
sobi
Beiträge: 170
Registriert: 05.02.2005 23:41
Wohnort: passau
Kontaktdaten:

Bild drehen

Beitrag von sobi »

Morgen Jungs und Mädels,

habe hier einen Code gefunden, der ein Bild dreht. Allerdings habe ich keinen Plan, wo ich den Code änderen muss, damit das bild nur um 45° gedreht wird und nicht um 270°.
In welcher Zeile muss ich den da Änderungen vornehmen?

Liebe Grüße,
Simon

Code: Alles auswählen

; German forum: http://robsite.de/php/pureboard/viewtopic.php?t=1596&highlight=
; Author: Andreas
; Date: 05. July 2003

#Window_0 = 0 
#Gadget_0 = 0 
#Gadget_1 = 1 

Procedure Rotate(Image$) 

Image1Dc = CreateCompatibleDC_(0) 
Image1 = LoadImage_(0,Image$,0,0,0,$2050) 
OldObject = SelectObject_(Image1DC,Image1) 
GetObject_(Image1,SizeOf(BITMAP),bmp.BITMAP) 

Image2Dc = CreateCompatibleDC_(0) 
Image2 = CreateCompatibleBitmap_(Image1DC,bmp\bmHeight,bmp\bmWidth) 
SelectObject_(Image2DC,Image2) 

ia = bmp\bmHeight 
While ia > 0 
  i = 0 
  While i < bmp\bmWidth 
    BitBlt_(Image2DC,bmp\bmHeight-ia,i,1,1,Image1DC,i,ia,#SRCCOPY) 
    i = i + 1 
  Wend 
  ia = ia - 1 
Wend 

CreateImage(2,bmp\bmHeight,bmp\bmWidth) 
Windc = StartDrawing(ImageOutput()) 
StretchBlt_(WinDC,0,0,bmp\bmHeight,bmp\bmWidth,Image2DC,0,0,bmp\bmHeight,bmp\bmWidth,#SRCCOPY) 
StopDrawing() 

ReleaseDC_(0,Image1DC) 
DeleteObject_(Image1) 
ReleaseDC_(0,Image2DC) 
DeleteObject_(Image2) 
EndProcedure 

Procedure Open_Window_0() 
  If OpenWindow(#Window_0, 381, 90, 313, 556,  #PB_Window_SystemMenu | #PB_Window_TitleBar , "New window ( 0 )") 
    If CreateGadgetList(WindowID()) 
      ImageGadget(#Gadget_0, 5, 5, 300, 200, UseImage(0)) 
      ImageGadget(#Gadget_1, 60, 245, 0, 0,0)      
    EndIf 
  EndIf 
EndProcedure 

font = LoadFont(0, "Arial", 40) 
CreateImage(0,300,200) 
StartDrawing(ImageOutput()) 
  DrawingFont(font) 
  Locate(100,100) 
  DrawText("AUTO") 
StopDrawing() 

Open_Window_0() 
SaveImage(0,"~~temp.bmp",#PB_ImagePlugin_BMP) 
rotate("~~temp.bmp") 
DeleteFile("~~temp.bmp") 
SetGadgetState(#Gadget_1,UseImage(2)) 


Repeat 
Until WaitWindowEvent()=#PB_Event_CloseWindow 

; ExecutableFormat=Windows
; FirstLine=1
; EnableX
Sorgen sind wie Blumen, wenn man sie nicht gießt, gehen sie ein.
Benutzeravatar
PureLust
Beiträge: 1145
Registriert: 21.07.2005 00:02
Computerausstattung: Hab aktuell im Grunde nur noch 'nen Lenovo Yoga 2 Pro im Einsatz.
Wohnort: am schönen Niederrhein

Beitrag von PureLust »

Moin sobi,

mit der vorliegenden Routine ist ein Drehen um 45° nicht ganz so einfach.


Du kannst zwar recht einfach durch ändern der Zeile 25 in:

Code: Alles auswählen

BitBlt_(Image2Dc,bmp\bmHeight-ia,i,1,1,Image1Dc,bmp\bmWidth-i,bmp\bmHeight-ia,#SRCCOPY) 
eine Drehung um 90° statt um 270° erreichen (oder auch 180°), aber einen anderen Drehwinkel als jeweils um 90° benötigt eine etwas andere Vorhegensweise.

Ich muss mich demnächst ebanfalls an soetwas dran setzen, wobei ich jedoch jeden Winkel realisieren muss (also nicht nur 45°).
Meine ersten Überlegungen in diese Richtung gingen dahin, dies per 'RotateSprite3D' zu realisieren.

Hoffe ich konnte helfen,
Gruß, PL.
[Dynamic-Dialogs] - komplexe dynamische GUIs einfach erstellen
[DeFlicker] - Fenster flimmerfrei resizen
[WinFX] - Window Effekte (inkl. 'durchklickbares' Window)
Benutzeravatar
MVXA
Beiträge: 3823
Registriert: 11.09.2004 00:45
Wohnort: Bremen, Deutschland
Kontaktdaten:

Beitrag von MVXA »

Vielleicht kann das hier weiter helfen:
http://forums.purebasic.com/german/view ... 4096#44096
kennt eventuel jemand ein gutes hausrezept gegen Schluckauf :roll:?
Ich werde schon seid 2 Stunden von diesem Fluch heim gesucht :evil:.
Eine PM reicht voll aus.
Bild
sobi
Beiträge: 170
Registriert: 05.02.2005 23:41
Wohnort: passau
Kontaktdaten:

Beitrag von sobi »

Hi PL,
PureLust hat geschrieben: Du kannst zwar recht einfach durch ändern der Zeile 25 in:

Code: Alles auswählen

BitBlt_(Image2Dc,bmp\bmHeight-ia,i,1,1,Image1Dc,bmp\bmWidth-i,bmp\bmHeight-ia,#SRCCOPY) 
eine Drehung um 90° statt um 270° erreichen (oder auch 180°), aber einen anderen Drehwinkel als jeweils um 90° benötigt eine etwas andere Vorhegensweise.
Hab das ausprobiert, leider ohne erfolg. Sorry, das ich nochmal nachfrage, aber was genau muss ich dieser Zeile ändern?

@MVXA
Hat sich dein Schluckauf gelegt?
Also ich hab mir den (die) Links angeschaut, aber mehr als Bahnhof habe ich da nicht verstanden! :?
Kannst du vielleicht (wenn ich ganz lieb "bitte bitte" sage,) den code, mit dem du deine zwei Probleme gelöst hast, nochmal posten?

Liebe Grüße,
Simon
Sorgen sind wie Blumen, wenn man sie nicht gießt, gehen sie ein.
Benutzeravatar
MVXA
Beiträge: 3823
Registriert: 11.09.2004 00:45
Wohnort: Bremen, Deutschland
Kontaktdaten:

Beitrag von MVXA »

http://purebasicforums.com/german/archi ... ht=gdiplus

Wenn du da das Archiv runter ladest sind da schon ein paar Beispiele
dabei, wenn ich mich richtig erinnern kann. Ich werde mal schauen
was sich machen lässt.
Bild
Benutzeravatar
PureLust
Beiträge: 1145
Registriert: 21.07.2005 00:02
Computerausstattung: Hab aktuell im Grunde nur noch 'nen Lenovo Yoga 2 Pro im Einsatz.
Wohnort: am schönen Niederrhein

Beitrag von PureLust »

@sobi, ...

sorry, war natürlich Zeile 24 (also die Zeile, in der bereits der BitBlt-Befehl steht).

Wenn Du den so änderst wie ich es beschrieben habe, so wird das Bild nicht mehr nach rechts, sondern nach links gedreht.

Die Rotationsroutine ist im Grunde ganz simpel:

- zuerst wird eine neue Bitmap erstellt, die in den Abmessungen der um 90° gedrehten Original-Bitmap entspricht (Zeile 17).
- Dann wird (sagen wir jetzt mal) ein Pixel oben links aus der Orig-Bitmap ausgelesen und oben rechts in die Ziel-Bitmap eingefügt (BitBlt-Befehl).
- Dann wird aus der Orig-Bitmap der Pixel ausgelesen, der genau rechts neben dem ersten Pixel ist und am rechten Rand unter den ersten Pixel in der Ziel-Bitmap eingesetzt (i=i+1).
- Somit wird also Pixel für Pixel immer eine waagerechte Zeile ausgelesen und in die Ziel-Bitmap als senkrechte Spalte eingefügt (While i < bmp\bmWidth).
- Das gleiche dann mit der 2ten, 3ten, 4ten Zeile usw. die dann von rechts gesehen zur 2ten, 3ten bzw. 4ten Spalte werden (ia Schleife)
- Somit wird Punkt für Punkt, Zeile für Zeile eine absolut verlustfreihe Drehung um 90° bewirkt.

Eine Drehung um einen anderen Winkel als 90 oder 270° würde eine komplett andere Vorgehensweise verlangen (180° wären noch auf ähnliche Weise möglich).

@MVXA:

Was macht Dein Schluckauf? ... geht's wieder?
Ich hatte leider kein Patentmittelchen parat ... sonst hättest Du 'ne PM von mir bekommen! ;)

Gruß, PL.
[Dynamic-Dialogs] - komplexe dynamische GUIs einfach erstellen
[DeFlicker] - Fenster flimmerfrei resizen
[WinFX] - Window Effekte (inkl. 'durchklickbares' Window)
sobi
Beiträge: 170
Registriert: 05.02.2005 23:41
Wohnort: passau
Kontaktdaten:

Beitrag von sobi »

super... vielen Dank. Jetzt habe ich das verstanden.

Dankeschön! :allright:
Sorgen sind wie Blumen, wenn man sie nicht gießt, gehen sie ein.
Benutzeravatar
PureLust
Beiträge: 1145
Registriert: 21.07.2005 00:02
Computerausstattung: Hab aktuell im Grunde nur noch 'nen Lenovo Yoga 2 Pro im Einsatz.
Wohnort: am schönen Niederrhein

Beitrag von PureLust »

Hi Zusammen, ...

anbei mal die bereits oben angesprochene Routine um ein Image in jedem Winkel drehen zu können.
Ich hab's allerdings doch nicht per RotateSprite3D, sondern komplett selber gelöst.
Auch hab ich noch einen Interpolations-Filter eingebaut um die Ausgabequalität zu verbessern.
Den Unterschied kann man sehr leicht sehen, wenn man den Filter per 'f' mal ein- bzw. ausschaltet.

Ich hoffe, die Kommentare helfen ein wenig dabei die Routine zu verstehen. ;)

Code: Alles auswählen

DefType.w OrigBreite,OrigHoehe,OrigXDrehpunkt,OrigYDrehpunkt,ZielBreite,ZielHoehe,Rand

; Standardvariablen definieren
#GFX_Mittelwertfilter = 1
OrigBreite=200
OrigHoehe=200
OrigXDrehpunkt=45
OrigYDrehpunkt=45
ZielBreite=OrigBreite
ZielHoehe=OrigHoehe
Rand=20
Filterung.b=#GFX_Mittelwertfilter
MaxFPS = 0
MinFPS = 999
Dim OrigPoint(OrigBreite+1,OrigHoehe+1)

If OpenWindow(0,10,10,OrigBreite*2+Rand*3,OrigHoehe+Rand*2,0," 2D Image-Rotation  <ESC>-Ende   <Space>-Pause   <F>-Filter")
   If CreateImage(1,OrigBreite,OrigHoehe)
      ; original Ausgangsbild erzeugen
      If StartDrawing(ImageOutput())
         Box(1,1,OrigBreite-2,OrigHoehe-2,RGB(255,255,255))
         Box(20,30,OrigBreite-40,30,RGB(20,200,200))
         Circle(OrigXDrehpunkt,OrigYDrehpunkt,4,RGB(0,0,255))
         Circle(OrigXDrehpunkt,OrigYDrehpunkt,2,RGB(255,255,255))
         Circle(40,OrigHoehe-41,30,RGB(200,33,33))
         ; Daten des Originalbildes in einem Array zwischenspeichern
         For x.w = 1 To OrigBreite
            For y.w = 1 To OrigHoehe
                OrigPoint(x,y)=Point(x-1,y-1)
            Next y
         Next x
         StopDrawing()
      EndIf
      If StartDrawing(WindowOutput())
         Hintergrundfarbe = Point(1,1)
         ; Im Bildpuffer einen Rahmen in Hintergrundfarbe um das Bild legen (für Filter)
         For x=0 To OrigBreite : OrigPoint(x,0)=Hintergrundfarbe : OrigPoint(x,OrigHoehe+1)=Hintergrundfarbe  : Next x
         For Y=0 To OrigHoehe  : OrigPoint(0,y)=Hintergrundfarbe : OrigPoint(OrigBreite+1,y)=Hintergrundfarbe : Next y         
         ; Originalbild auf Fenster ausgeben
         OrigImageID=UseImage(1)
         DrawImage(OrigImageID,Rand,Rand)
         StopDrawing()
      EndIf
      If CreateImage(2,ZielBreite,ZielHoehe)
         DisableDebugger ; Debugger ausschalten, falls nötig
         Repeat
            StartTimer = ElapsedMilliseconds()
            For w = 0 To 359
               Winkel.f = 3.141/180*w
               ; mehrfach benutzte Berechnungen puffern
               SinWinkel.f = Sin(Winkel)
               CosWinkel.f = Cos(Winkel)
               ZielImageID=UseImage(2)

               If StartDrawing(ImageOutput())
                  ; Zielimage löschen
                  Box(0,0,ZielBreite,ZielHoehe,Hintergrundfarbe)
                  For x.w = 1 To OrigBreite
                     ; mehrfach benutzte Berechnungen puffern
                     xSinWinkel.f = (x-OrigXDrehpunkt)*SinWinkel
                     xCosWinkel.f = (x-OrigXDrehpunkt)*CosWinkel
                     For y.w = 1 To OrigHoehe
                         zx.f=(xCosWinkel-(y-OrigYDrehpunkt)*SinWinkel)+OrigXDrehpunkt
                         zy.f=(xSinWinkel+(y-OrigYDrehpunkt)*CosWinkel)+OrigYDrehpunkt
                         Select Filterung 
                         Case #GFX_Mittelwertfilter
                            ; Berechnung mit Filter
                            zxi = Int(zx+0.5)
                            zyi = Int(zy+0.5)
                            If zx>0 And zx<ZielBreite+1 And zy>0 And zy<ZielHoehe+1
                               PixelFarbe1 = OrigPoint(zxi,zyi)
                               If zx<zxi
                                  PixelFarbe2 = OrigPoint(zxi-1,zyi)
                               Else
                                  PixelFarbe2 = OrigPoint(zxi+1,zyi)
                               EndIf
                               Gewichtung2.f=Abs(zx-zxi)
                               If zy>zyi
                                  PixelFarbe3 = OrigPoint(zxi,zyi+1)
                               Else
                                  PixelFarbe3 = OrigPoint(zxi,zyi-1)
                               EndIf
                               Gewichtung3.f=Abs(zy-zyi)
                               Gewichtung1.f=1-Gewichtung2-Gewichtung3
                               ; Pixelgewichtung berechnen
                               PixelRed=Red(PixelFarbe1)*Gewichtung1+Red(PixelFarbe2)*Gewichtung2+Red(PixelFarbe3)*Gewichtung3
                               PixelGreen=Green(PixelFarbe1)*Gewichtung1+Green(PixelFarbe2)*Gewichtung2+Green(PixelFarbe3)*Gewichtung3
                               PixelBlue=Blue(PixelFarbe1)*Gewichtung1+Blue(PixelFarbe2)*Gewichtung2+Blue(PixelFarbe3)*Gewichtung3
                               Plot(x-1,y-1,RGB(PixelRed,PixelGreen,PixelBlue))
                            EndIf
                         Default
                            ; Berechnung ohne Filter
                            If zx>=1 And zx<ZielBreite+1 And zy>=1 And zy<ZielHoehe+1 
                               Plot(x-1,y-1,OrigPoint(Int(zx),Int(zy)))
                            EndIf
                         EndSelect
                      Next y
                  Next x
                  StopDrawing()
               EndIf                 
               If StartDrawing(WindowOutput())
                  ; gedrehtes Image auf Fenster ausgeben
                  DrawImage(ZielImageID,rand*2+OrigBreite,Rand)
                  StopDrawing()
               EndIf
               Event=WindowEvent()                             
               If Event = #WM_KEYDOWN
                  ; Tastendrücke auswerten
                  If EventwParam() = #VK_SPACE
                     Repeat
                     Event=WaitWindowEvent()
                     Until Event = #WM_KEYDOWN
                  ElseIf EventwParam() = #VK_F
                     Filterung = #GFX_Mittelwertfilter-Filterung
                  ElseIf EventwParam() = #VK_ESCAPE
                     Break 2
                  EndIf
                  ResetFPS = 1
               EndIf
            If w%5=4
               ; Berechnung der FPS (Bilder pro Sekunde)
               If ResetFPS
                  MaxFPS = 0
                  MinFPS = 999
                  ResetFPS = 0
               Else
                  AktFPS = 5000/(ElapsedMilliseconds()-StartTimer+1)
                  If AktFPS < MinFPS : MinFPS = AktFPS : EndIf
                  If AktFPS > MaxFPS : MaxFPS = AktFPS : EndIf
                  SetWindowTitle(0," 2D Image-Rotation  <ESC>-Ende   <Space>-Pause   <F>-Filter    "+Str(MinFPS)+"-"+Str(MaxFPS)+" FPS")
               EndIf
               StartTimer = ElapsedMilliseconds()
            EndIf
            Next w
         ForEver
         EnableDebugger  ; Debugger wieder aktivieren
      EndIf
   EndIf
EndIf
End
Wer noch Fragen dazu hat ... einfach mal posten !!! ;)

Edit: Zum besseren Vergleich mit der schnelleren WinAPI-Routine (siehe weiter hinten in diesem Thread) habe ich in den Code noch nachträglich eine bessere FPS-Kalkulation eingebaut.
Zuletzt geändert von PureLust am 06.10.2005 22:31, insgesamt 1-mal geändert.
[Dynamic-Dialogs] - komplexe dynamische GUIs einfach erstellen
[DeFlicker] - Fenster flimmerfrei resizen
[WinFX] - Window Effekte (inkl. 'durchklickbares' Window)
Benutzeravatar
Ynnus
Beiträge: 855
Registriert: 29.08.2004 01:37
Kontaktdaten:

Beitrag von Ynnus »

Wow, ein cooles Skript! Sehr schön, und mit dem Filter zwar mit ca. 15 - 20 Frames nicht mehr sonderlich flott aber dafür hübsch anzusehen. Und wenn es nicht kontinuierlich sondern nur einmalig gedreht werden muss ist mit Filter ja durchaus möglich. Sieht jedenfalls gleich viel besser aus. :allright:
Könnte man direkt ins Code, Tipps und Tricks Forum aufnehmen (+ Code-Archiv wenn Andre das mal wieder aktualisiert).
Benutzeravatar
PureLust
Beiträge: 1145
Registriert: 21.07.2005 00:02
Computerausstattung: Hab aktuell im Grunde nur noch 'nen Lenovo Yoga 2 Pro im Einsatz.
Wohnort: am schönen Niederrhein

Beitrag von PureLust »

Hi Sunny,

Danke für die Lorbeeren. <)


Die Framerate macht mir auch etwas Sorgen, weshalb ich ja auch hier mal nach 'ner Alternative für den Plot-Befehl gefragt hatte.

Aber da Du Dich ja meines Wissens nach recht gut mit Pointern auskennst, hätte ich da mal 'ne Frage:

Wäre es irgendwie möglich über Pointer die Adresse der Image-Bitmap herauszufinden und dann direkt dort hinein zu schreiben (also Poken, statt Plotten)?
Hierzu würde ich natürlich auch noch irgendwo her weitere Infos über die Bitmap benötigen (Bit-tiefe, etc...).
[Dynamic-Dialogs] - komplexe dynamische GUIs einfach erstellen
[DeFlicker] - Fenster flimmerfrei resizen
[WinFX] - Window Effekte (inkl. 'durchklickbares' Window)
Antworten