Hier könnt Ihr gute, von Euch geschriebene Codes posten. Sie müssen auf jeden Fall funktionieren und sollten möglichst effizient, elegant und beispielhaft oder einfach nur cool sein.
ich habe für ein kleines Programm die schnelle Spiegelung von Images benötigt und wollte Euch meine "geistigen Ergüsse" nicht vorenthalten.
Wichtig dabei: ich arbeite immer mit 32 Bit Farbtiefe. Nur dann funktioniert das vertikale Spiegeln. Es gibt durchaus Images mit weniger Farbtiefe... diese müsste man dann ggf. konvertieren oder die Routine etwas umbauen, was sie aber wieder langsamer machen würde...
EnableExplicit
Structure einzeln ; Zugriff auf die einzenen Farbkanäle
pix_r.a
pix_g.a
pix_b.a
pix_a.a
EndStructure
Structure pixel ; Zugriff auf komplettes Pixel oder Farbkanäle
StructureUnion
pix_l.l
pix.einzeln
EndStructureUnion
EndStructure
Procedure hspiegeln(image)
Protected zeilenlaenge ; Länge (in Byte) einer Zeile im Image
Protected hoehe ; Image-Höhe
Protected tiefe ; Farbtiefe des Images in Byte (echte Tiefe im Speicher)
Protected *obere.pixel ; Adresse der oberen Zeile im Speicher
Protected *untere.pixel ; Adresse der unteren Zeile im Speicher
Protected i ; Laufvariable
Protected halbe_hoehe ; Image-Höhe / 2 für optimierten Durchlauf
Protected *zeilenpuffer ; Zwischenspeicher für 1 Zeile
; Daten über das Image holen
StartDrawing(ImageOutput(image))
*obere.pixel = DrawingBuffer()
zeilenlaenge = DrawingBufferPitch()
StopDrawing()
*zeilenpuffer = AllocateMemory(zeilenlaenge)
hoehe = ImageHeight(image)
tiefe = ImageDepth(image) / 8 ; Bytes pro Pixel
halbe_hoehe = hoehe / 2 ; in eine Durchlauf linkes und rechtes Pixel tauschen, daher muss nur die halbe Länge durchlaufen werden
*untere = *obere + (zeilenlaenge * (hoehe-1)) ; Adresse der unteren Zeile ermitteln
For i = 1 To halbe_hoehe
CopyMemory(*obere, *zeilenpuffer, zeilenlaenge) ; obere Zeile merken
CopyMemory(*untere, *obere, zeilenlaenge) ; untere Zeile in obere Zeile
CopyMemory(*zeilenpuffer, *untere, zeilenlaenge) ; obere Zeile in untere zeile
*obere + zeilenlaenge
*untere - zeilenlaenge
Next i
FreeMemory(*zeilenpuffer)
EndProcedure
Procedure vspiegeln(image)
Protected zeilenlaenge ; Länge (in Byte) einer Zeile im Image
Protected hoehe ; Image-Höhe
Protected breite ; Image-Breite
Protected tiefe ; Farbtiefe des Images in Byte (echte Tiefe im Speicher)
Protected *linkes.pixel ; Adresse des linken Pixels im Speicher
Protected *rechtes.pixel ; Adresse des rechten Pixels im Speicher
Protected i, j, k ; Laufvariablen
Protected halbe_breite ; Image-Breite / 2 für optimierten Durchlauf
Protected farbpuffer ; Zwischenspeicher für 1 Pixel
; Daten über das Image holen
StartDrawing(ImageOutput(image))
*linkes.pixel = DrawingBuffer()
zeilenlaenge = DrawingBufferPitch()
StopDrawing()
hoehe = ImageHeight(image)
breite = ImageWidth(image)
tiefe = ImageDepth(image) / 8 ; Bytes pro Pixel
halbe_breite = breite / 2 ; in eine Durchlauf linkes und rechtes Pixel tauschen, daher muss nur die halbe Länge durchlaufen werden
If tiefe = 4
For i = 1 To hoehe
k = zeilenlaenge
*rechtes = *linkes + (tiefe * (breite-1)) ; Adresse des letzten Pixels in der Zeile
For j = 1 To halbe_breite
farbpuffer = *linkes\pix_l ; Farbe des linken Pixels merken
*linkes\pix_l = *rechtes\pix_l ; Farbe des rechten Pixels in linkes Pixel
*rechtes\pix_l = farbpuffer ; Farbe des linken Pixels in rechtes Pixel
*linkes + tiefe ; nächstes Pixel links
*rechtes - tiefe ; nächstes Pixel rechts
k - tiefe
Next
*linkes + k ; Start der nächsten Zeile
Next
Else
Debug "VSpiegeln(): Image-Tiefe ist nicht 32Bit!"
EndIf
EndProcedure
; --- Beispiel
UseJPEGImageDecoder()
UsePNGImageDecoder()
UseTIFFImageDecoder()
Global dateiname.s
Global bild
Global t
dateiname = OpenFileRequester("Image auswählen...", "", "Image|*.bmp;*.jpg;*.png;*.tif", 0)
If dateiname <> ""
bild = LoadImage(#PB_Any, dateiname)
If bild
t = ElapsedMilliseconds()
hspiegeln(bild)
t = ElapsedMilliseconds() - t
MessageRequester("Info", "Horizontales spiegeln: " + Str(t) + "ms")
SaveImage(bild, GetPathPart(dateiname) + "horizontal.bmp")
hspiegeln(bild)
t = ElapsedMilliseconds()
vspiegeln(bild)
t = ElapsedMilliseconds() - t
MessageRequester("Info", "Vertikales spiegeln: " + Str(t) + "ms")
SaveImage(bild, GetPathPart(dateiname) + "vertikal.bmp")
EndIf
EndIf
End
Eine Kleinigkeit: kann es sein, dass Du die Spiegelachsen vertauscht hast (Horizontal = 1 / Vertikal = 0)?
Ich habe mein vertikales Spiegeln unter dem Geschwindigkeitsaspekt noch mal bearbeitet. Die Funktion arbeitet jetzt in Abhängigkeit von der Farbtiefe nach der alten (schnellen) Methode bei 32 Bit oder mit CopyMemory() bei 24 Bit.
Da PB intern nur mit 24 oder 32 Bit Farbtiefe arbeitet, kann es nur 3 oder 4 Bytes pro Pixel geben. Bei 3 Bytes sind 2 x Poke() (einmal 2 Bytes + einmal 1 Byte) schneller als CopyMemory() für 3 Bytes. Ist nur ein marginaler Unterschied der selbst bei größeren Bildern nur einige Millisekunden ausmacht, aber immerhin.
Procedure vspiegeln(image)
Protected zeilenlaenge ; Länge (in Byte) einer Zeile im Image
Protected hoehe ; Image-Höhe
Protected breite ; Image-Breite
Protected tiefe ; Farbtiefe des Images in Byte (echte Tiefe im Speicher)
Protected *linkes.pixel ; Adresse des linken Pixels im Speicher
Protected *rechtes.pixel ; Adresse des rechten Pixels im Speicher
Protected i, j, k, l ; Laufvariablen
Protected halbe_breite ; Image-Breite / 2 für optimierten Durchlauf
Protected farbpuffer ; Zwischenspeicher für 1 Pixel bei 32Bit Farbtiefe
Protected *pixelpuffer ; Zwischenspeicher ganzes Image bei 24Bit Farbtiefe
; Daten über das Image holen
StartDrawing(ImageOutput(image))
*linkes.pixel = DrawingBuffer()
zeilenlaenge = DrawingBufferPitch()
StopDrawing()
hoehe = ImageHeight(image)
breite = ImageWidth(image)
tiefe = ImageDepth(image) / 8 ; Bytes pro Pixel
halbe_breite = breite / 2 ; in eine Durchlauf linkes und rechtes Pixel tauschen, daher muss nur die halbe Länge durchlaufen werden
l = ((breite - 1) * tiefe) ; Zeilenlänge in Pixel * Farbtiefe
If tiefe = 4 ; "Paranoia-Abfrage" - Image sollte immer eine Tiefe von 32Bit haben!
For i = 1 To hoehe
k = zeilenlaenge
*rechtes = *linkes + (tiefe * (breite-1)) ; Adresse des letzten Pixels in der Zeile
For j = 1 To halbe_breite
farbpuffer = *linkes\pix_l ; Farbe des linken Pixels merken
*linkes\pix_l = *rechtes\pix_l ; Farbe des rechten Pixels in linkes Pixel
*rechtes\pix_l = farbpuffer ; Farbe des linken Pixels in rechtes Pixel
*linkes + tiefe ; nächstes Pixel links
*rechtes - tiefe ; nächstes Pixel rechts
k - tiefe
Next
*linkes + k ; Start der nächsten Zeile
Next
ProcedureReturn -1
ElseIf tiefe = 3
*pixelpuffer = AllocateMemory(zeilenlaenge * hoehe)
For i = 0 To hoehe-1
k = i * zeilenlaenge
For j = 0 To breite-1
; CopyMemory(*linkes + k + (j * tiefe), *pixelpuffer + k + (l - j * tiefe), tiefe)
PokeU(*pixelpuffer + k + (l - j * tiefe), PeekU(*linkes + k + (j * tiefe)))
PokeA(*pixelpuffer + k + (l - j * tiefe) + 2, PeekA(*linkes + k + (j * tiefe) + 2))
Next
Next
CopyMemory(*pixelpuffer, *linkes, hoehe * zeilenlaenge)
FreeMemory(*pixelpuffer)
Else
Debug "VSpiegeln(): Farb-Tiefe muss 24 oder 32 Bit sein!"
EndIf
EndProcedure
Hier nochmal mein Code den ich vorübergehend wieder entfernt hatte da mir noch en Bug aufgefallen war.
Unterstützt alle PB (internen) Image - Formate.
Das Bild kann in alle Richtungen gespiegelt werden.