Besser als Pixmap.Paste

Übersicht BlitzMax, BlitzMax NG Codearchiv & Module

Neue Antwort erstellen

BlitzMoritz

Betreff: Besser als Pixmap.Paste

BeitragDi, Mai 06, 2008 21:54
Antworten mit Zitat
Benutzer-Profile anzeigen
Ich war mit der Methode Paste von TPixmap nicht zufrieden, und zwar vor allem deshalb, weil transparente Stellen der Quell-Pixmap ebenfalls transparente "Löcher" in die darunterliegende Ziel-Pixmap "gebrannt" haben, was wohl keiner will. Darum habe ich die Function PixmapPaste() gebastelt, die fast gar nicht langsamer ist als das "Original" und zwei Vorteile hat:
1.) Es besteht keine Absturzgefahr durch "Randprobleme": Pixmaps können auch über die Maße des Ziel-Pixmaps hinaus bzw. komplett "daneben" gepastet werden.
2.) Transparente Stellen der Quell-Pixmaps zerstören die darunterliegende Zielpixmap nicht: Alpha-Werte bzw. Farben werden gemischt.
Code: [AUSKLAPPEN]
Graphics 800,600,0
SetBlend ALPHABLEND
Local Ziel:TPixmap = LoadPixmap("GrossesBildmitTransparenz.png")
Local Quelle:TPixmap = LoadPixmap("KleinesBildmitTransparenz.png")
Local Ergebnis:TImage = LoadImage(Ziel)
Repeat
   Cls
   DrawText "Zufalls-PixmapPaste() durch Mausklick!", 10,10
   DrawImage Ergebnis, MouseX()-ImageWidth(Ergebnis)/2, MouseY()-ImageHeight(Ergebnis)/2
   Flip
   If MouseHit(1) Then
      Local x:Int = Rand(-PixmapWidth(Quelle), PixmapWidth(Ziel) + PixmapWidth(Quelle))
      Local y:Int = Rand(-PixmapHeight(Quelle), PixmapHeight(Ziel) + PixmapHeight(Quelle))
      PixmapPaste(Ziel,Quelle,x,y)
      'Ziel.Paste(Quelle,x,y)      '(zum Vergleich)
      Ergebnis = LoadImage(Ziel)
   End If
Until KeyDown(KEY_ESCAPE)
End
'########################################################
Function PixmapPaste(PMZ:TPixmap, PMQ:TPixmap, x:Int, y:Int)
'########################################################
   Local Breite_Z:Int = PixmapWidth(PMZ), Tiefe_Z:Int = PixmapHeight(PMZ)
   Local Breite_Q:Int = PixmapWidth(PMQ), Tiefe_Q:Int = PixmapHeight(PMQ)
   'Komplett daneben?:
   If x >= Breite_Z Or x+Breite_Q <= 0 Or y >= Tiefe_Z Or y+Tiefe_Q <= 0 Then Return
   'Alle Ränder abchecken:
   Local x_Start_Z:Int = Max(0,x),   x_Start_Q:Int = Max(0,-x)
   Local x_End_Q:Int = Breite_Q - 1
   If x + Breite_Q > Breite_Z Then x_End_Q = Breite_Z - x - 1
   Local y_Start_Z:Int = Max(0,y),   y_Start_Q:Int = Max(0,-y)
   Local y_End_Q:Int = Tiefe_Q - 1
   If y + Tiefe_Q > Tiefe_Z Then y_End_Q = Tiefe_Z - y - 1
   Local A_Q:Int, R_Q:Int, G_Q:Int, B_Q:Int, A_Z:Int, R_Z:Int, G_Z:Int, B_Z:Int
   Local ARGB_Q:Int, ARGB_Z:Int, xq:Int, yq:Int, xz:Int = x_Start_Z, yz:Int
   '----------------------------------------
   For xq = x_Start_Q To x_End_Q  'den nötigen Bereich durchlaufen
      yz = y_Start_z
      For yq = y_Start_Q To y_End_Q
         ARGB_Q = ReadPixel(PMQ, xq, yq) 'Farbe Quell-Pixmap
         A_Q = Byte((ARGB_Q & $FF000000) / $1000000)
         R_Q = Byte((ARGB_Q & $00FF0000) / $10000)
         G_Q = Byte((ARGB_Q & $0000FF00) / $100)
         B_Q = Byte(ARGB_Q & $000000FF)
         ARGB_Z = ReadPixel(PMZ, xz, yz) 'Farbe Ziel-Pixmap
         A_Z = Byte((ARGB_Z & $FF000000) / $1000000)
         R_Z = Byte((ARGB_Z & $00FF0000) / $10000)
         G_Z = Byte((ARGB_Z & $0000FF00) / $100)
         B_Z = Byte(ARGB_Z & $000000FF)
         '- - - - - - - - - - - - - - - - Mischen:
         A_Z = A_Q + (255-A_Q) * A_Z / 255
         R_Z = A_Q * R_Q / 255 + (255 - A_Q) * R_Z / 255
         G_Z = A_Q * G_Q / 255 + (255 - A_Q) * G_Z / 255
         B_Z = A_Q * B_Q / 255 + (255 - A_Q) * B_Z / 255
         ARGB_Z = A_Z*$1000000+R_Z*$10000+G_Z*$100+B_Z
         WritePixel(PMZ, xz, yz, ARGB_Z)
         '-------------------------------
         yz = yz + 1
      Next
      xz = xz + 1
   Next
'############################
End Function  '(PixmapPaste)
'############################


Edit:

Ich möchte obige Function ergänzen durch die folgende Function "ImagePaste()", deren Hauptmotivation es war, Bilder auch gedreht und transparent ineinander zu kleben. Wäre die Transparenz als weiterer Parameter ohne viel Aufwand auch in die PixmapPaste-Function einzubauen gewesen, so stieß ich bezüglich der Rotation an Grenzen: Es tauchten stets kleine Pixel-Schönheitsfehler auf, die mich an die alte RotateImage-Function von BlitzBasic2D erinnerte.
Darum wählte ich einen anderen, einfacheren Weg, und zwar über das Grabben. Die graphischen Ergebnisse waren nun aber perfekt. Und was die Geschwindigkeit angeht: Echtzeit-Realisierung ist eh für keine der beiden Funktionen ein Thema.
Noch einmal kurz zusammengefasst:

Vorteile:

1.) Images können gedreht gepastet werden (Voraussetzung: MidHandleImage(Quell-Image) )
2.) Images können transparent gepastet werden (Voraussetzung: SetBlend ALPHABLEND)
3.) Die Funktionalität ist von der Größe des Graphics-Fensters unabhängig! D.h. beliebig große Images können gepastet werden. (Ist das Fenster zu klein, wird in mehreren Teilen gegrabbt und die Teile mit obiger PixmapPaste-Function zusammengeklebt.)

Nachteile:

1.) Für das Grabben wird der BackBuffer zwischenzeitlich bemalt. Soll dies nicht sichtbar werden, muss er durch ein Cls o.a. erneut übermalt werden.
2.) Transparenz bzw. Alpha-Informationen des Zielbildes gehen durch das Grabben zumindest an den gepasteten Stellen verloren. Mit den letzten drei Parametern der Function kann daher optional die RGB-Farbe bestimmt werden, die dort anstelle der Transparenz erscheinen soll.

Code: [AUSKLAPPEN]
AppTitle = "ImagePaste-Demo: Zum Einkleben bitte linke Maustaste drücken!"
Graphics 800,600
SetBlend ALPHABLEND
Local Ziel:TImage = LoadImage("Ziel.png")
Local Quelle:TImage = LoadImage("Quelle.png")
MidHandleImage(Quelle)
Local Drehwinkel:Float = 30.0
Local Alpha:Float = 0.75
'------------------------------------------------------------------------------------
Repeat
   If MouseHit(1) Then
      Local PM:TPixmap = ImagePaste(Ziel, Quelle, MouseX(), MouseY(), Drehwinkel, Alpha)
      Ziel = LoadImage(PM)
   End If
   Cls
   SetColor 255,255,255
   SetRotation 0
   SetAlpha 1.0
   DrawImage Ziel,0, 0
   SetRotation Drehwinkel
   SetAlpha Alpha
   DrawImage Quelle, MouseX(), MouseY()
   Flip
Until KeyDown(KEY_ESCAPE)
'------------------------------------------------------------------------------------
'==========================================
Function ImagePaste:TPixmap(Ziel:TImage, Quelle:TImage, x:Int, y:Int, Drehung:Float, Alpha:Float, ClsRed:Int = 0, ClsGreen:Int = 0, ClsBlue:Int = 0)
'==========================================
   If Ziel = Null Then Return Null
   If Quelle = Null Then Return LockImage(Ziel)
   '-----------------------------------------------------------------------------
   Local Komposition:TPixmap = LockImage(Ziel)
   '-----------------------------------------------------------------------------
   Local Breite:Int = ImageWidth(Quelle) * Abs(Cos(Drehung)) + ImageHeight(Quelle) * Abs(Sin(Drehung))
   Local Tiefe:Int = ImageWidth(Quelle) * Abs(Sin(Drehung)) + ImageHeight(Quelle) * Abs(Cos(Drehung))
   Local Links:Int =  x - 0.5*Breite,   Oben:Int = y - 0.5*Tiefe
   '-----------------------------------------------------------------------------
   Local Schirmbreite:Int = GraphicsWidth(),   Schirmtiefe:Int = GraphicsHeight()
   '-----------------------------------------------------------------------------
   Local Horizontal_Wiederholung:Int = Breite / Schirmbreite
   Local Vertikal_Wiederholung:Int = Tiefe / Schirmtiefe
   Local Teil_Breite:Int = Breite / (Horizontal_Wiederholung+1)
   Local Teil_Tiefe:Int = Tiefe / (Vertikal_Wiederholung+1)
   '-----------------------------------------------------------------------------
   For Local i:Int = 0 To Horizontal_Wiederholung
      For Local j:Int = 0 To Vertikal_Wiederholung
         SetRotation 0
         SetAlpha 1.0
         SetColor ClsRed, ClsGreen, ClsBlue
         DrawRect 0, 0, Teil_Breite, Teil_Tiefe
         SetColor 255,255,255
         DrawImage Ziel, -Links-i*Teil_Breite, -Oben-j*Teil_Tiefe
         SetRotation Drehung
         SetAlpha Alpha
         DrawImage Quelle, -Links+x-i*Teil_Breite, -Oben+y-j*Teil_Tiefe         
         Local Teil_Pixmap:TPixmap = GrabPixmap(0, 0, Teil_Breite, Teil_Tiefe)
         PixmapPaste(Komposition, Teil_Pixmap, Links + i * Teil_Breite, Oben + j * Teil_Tiefe)
      Next
   Next
   UnlockImage Ziel
   SetRotation 0
   SetAlpha 1.0
   Return Komposition
'==========================================
End Function 'ImagePaste
'==========================================
'(PixmapPaste-Function nicht vergessen!)

Neue Antwort erstellen


Übersicht BlitzMax, BlitzMax NG Codearchiv & Module

Gehe zu:

Powered by phpBB © 2001 - 2006, phpBB Group