Seite 1 von 3

Bild drehen

Verfasst: 24.08.2005 03:17
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

Verfasst: 24.08.2005 04:07
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.

Verfasst: 24.08.2005 04:13
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.

Verfasst: 24.08.2005 10:59
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

Verfasst: 24.08.2005 14:26
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.

Verfasst: 24.08.2005 17:29
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.

Verfasst: 24.08.2005 18:00
von sobi
super... vielen Dank. Jetzt habe ich das verstanden.

Dankeschön! :allright:

Verfasst: 03.10.2005 00:07
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.

Verfasst: 03.10.2005 01:04
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).

Verfasst: 03.10.2005 11:03
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...).