Aus Raspberry Pi Geek 04/2014

Grafikausgaben mit Python und Pygame (Seite 2)

Listing 2

 

# Datei simpleImage.py
import pygame
import sys
pygame.display.init()
imgSurf = pygame.image.load ( sys.argv [ 1 ] )
screen = pygame.display.set_mode ( imgSurf.get_size() )
screen.blit ( imgSurf, ( 0, 0 ) )
pygame.display.flip()
raw_input()
pygame.quit()

Zeile 8 erzeugt mittels set_mode ein Pygame-Fenster exakt in der Größe der Grafik aus der Datei, wozu imgSurf.get_size() deren Breite und Höhe ermittelt. Nun folgt eine der häufigsten Surface-Operationen: das Blitten von einer Surface auf eine andere. In Zeile 9 sehen Sie die typische Syntax, die blit auf der Ziel-Surface aufruft. Als erstes Argument folgt die Quell-Surface, gefolgt von den Zielkoordinaten. Optional könnte als drittes Argument ein rect folgen, das angibt, welchen Ausschnitt der Quell-Surface es zu kopieren gilt.

Bis hierhin erfolgen alle Operationen im Arbeitsspeicher. Zwar sorgt set_mode in Zeile 7 dafür, dass ein Fenster erscheint, doch das bleibt zunächst leer. Erst in Zeile 10 zeigt pygame.display.flip() das Bild dann an (Abbildung 1). Der Befehl raw_input() wartet darauf, dass der Benutzer per Tastendruck signalisiert, dass er das Bild wieder schließen will. Daraufhin beendet Zeile 13 dann Pygame.

Abbildung 1: Das Programm »simpleImage.py« erzeugt ein Fenster und zeigt darin »network.png« an.

Abbildung 1: Das Programm »simpleImage.py« erzeugt ein Fenster und zeigt darin »network.png« an.

Skripte direkt ausführen

Oft möchte man Skripte ausführen, ohne den Umweg über den expliziten Aufruf von python nehmen zu müssen. Um das zu erreichen, tragen Sie einfach den Pfad zum zugehörigen Interpreter in die erste Zeile des Skripts ein:

#! /usr/bin/python

Hierbei teilt das sogenannte Shebang (#!) der Shell mit, dass nun die Angabe des zu verwendenden Interpreters folgt. Falls Sie nicht wissen, wo auf dem Rechner Python liegt, stellen Sie das mit dem Befehl which python vorab auf der Kommandozeile fest.

Damit der Interpreter das Skript abarbeiten kann, müssen Sie es als ausführbare Datei kennzeichnen, indem Sie das entsprechende Bit der Dateieigenschaften setzen:

$ chmod a+x Skript.py

Schließlich erlaubt es diese Konstellation auch noch, auf die Dateinamenserweiterung .py zu verzichten, sodass Sie das Skript kurz und knapp mit seinem Namen aufrufen können.

Klasse zur Bildverwaltung

In Listing 3 finden Sie die Image-Management-Klasse imageHandler, die Pygame nutzt, um über Tastenkürzel das Laden und die Anzeige mehrerer Bilder zu ermöglichen. Einige Zeilen am Schluss des Listings enthalten Anwendungsbeispiele dazu. Die Klasse referenziert dabei über eine eindeutige ID die Bilder und zeichnet sie via render auf eine zur Verfügung gestellte Surface. Dabei kommen drei Funktionen zum Einsatz.

loadFromFile benötigt als Argument einen Dateinamen und optional eine ID. Bleibt die ID leer, belegt die Funktion Sie mit dem vollen Dateinamen inklusive Dateinamenserweiterung. Diese Methode kommt einmal beim Laden jedes Bilds zum Einsatz. loadFromSurface akzeptiert eine vorhandene Surface als erstes Argument, als zweites benötigt es die ID des zu ladenden Bilds.

Die Zeilen 10 und 13 verwenden die Funktion convert(). Sie passt die von pygame.image.load gelieferte Surface auf Pixelebene an das Ausgabefenster an. Ohne diesen Aufruf müsste die Anpassung während des Blittings erfolgen, was dieses deutlich verlangsamen würde. Bei der Anzeige einiger weniger Bilder spielt das zwar kaum eine Rolle, bei Bilderserien oder Animationen fällt der Unterschied aber ins Gewicht.

Die Hauptarbeit übernimmt die Methode render, der Sie als Argumente wenigstens eine Pygame-Surface und eine Bild-ID übergeben. Liefern Sie keine weiteren Parameter, gibt render das per id übergebene Bild mittig auf der Surface aus. Sie können über das Tupel position Koordinaten für die linke obere Ecke des Bilds vorgeben. Das ebenfalls optionale Argument clear akzeptiert als Wert False oder True – in letzterem Fall füllt es die Zeichenfläche vor Ausgabe der Grafik mit Schwarz. Über das Tupel size geben Sie bei Bedarf Breite und Höhe des Bilds an.

Listing 3

 

# Datei imageClass.py
import pygame
class imageHandler:
  def __init__ ( self ):
    self.pics = dict()
  def loadFromFile ( self, filename, id=None ):
    if id == None: id = filename
    self.pics [ id ] = pygame.image.load ( filename ).convert()
  def loadFromSurface ( self, surface, id ):
    self.pics [ id ] = surface.convert()
  def render ( self, surface, id, position = None, clear = False, size = None ):
    if clear == True:
      surface.fill ( ( 0, 0, 0 ) )
    if position == None:
      picX = int ( surface.get_width() / 2 - self.pics [ id ].get_width() / 2 )
      picY = int ( surface.get_height() / 2 - self.pics [ id ].get_height() / 2 )
    else:
      picX = position [ 0 ]
      picY = position [ 1 ]
    if size == None:
      surface.blit ( self.pics [ id ], ( picX, picY ) )
    else:
      surface.blit ( pygame.transform.smoothscale ( self.pics [ id ], size ), ( picX, picY ) )
pygame.display.init()
screen = pygame.display.set_mode ( ( 640, 480 ) )
handler = imageHandler()
handler.loadFromFile ( "images/network.png", "net" )
handler.loadFromFile ( "images/laptop.png", "laptop" )
handler.loadFromFile ( "images/presentation.png", "ppt" )
handler.render ( screen, "net", ( 0, 0 ), True, ( 100, 100 ) )
handler.render ( screen, "laptop", None, False )
handler.render ( screen, "ppt", ( 200, 200 ), None )
handler.loadFromSurface ( screen, "screenshot" )
pygame.display.flip()
raw_input()
pygame.quit()

Ab Zeile 31 von Listing 3 finden Sie einige Anwendungsbeispiele. Zunächst initialisiert das Skript das Display und erzeugt ein Ausgabefenster im Format 640 x 480 Pixel. Zeile 34 erzeugt eine Instanz der Klasse, es folgt je ein Aufruf von loadFromFile() für jedes Bild.

Ab Zeile 39 erfolgt der Abruf der Grafiken. Hier gibt das Skript die Bilder direkt auf die bereitgestellte Surface screen aus (Abbildung 2). Hier könnte man aber ebenso gut eine neue Surface erzeugen und die Bilder darauf rendern, etwa für eine Collage oder ein Bildraster.

Abbildung 2: Die Ausgabe des Beispielcodes von »imageClass.py« (Listing 3).

Abbildung 2: Die Ausgabe des Beispielcodes von »imageClass.py« (Listing 3).

Zeile 43 lässt die Flexibilität von Pygame erkennen: Da es sich bei screen um eine Surface handelt, lässt sich diese wiederum in die handler-Klasse einspeisen, um das gerenderte Ergebnis als neues Bild quasi in einem “Screenshot” zu konservieren.

Der Rest des Skripts liefert wieder die bereits von simpleImage.py (Listing 2) bereitgestellten Bedienfunktionen.

Zeichenmodul

Bis hierhin kamen bereits bestehende Bilder zum Einsatz, die wir von der Platte geladen haben. Jetzt nehmen wir das Zeichenmodul von Pygame näher unter die Lupe: Mit ihm erstellen Sie auf einfache Weise Linien und Formen.

Die dabei verwendeten Methoden benutzen durchgängig drei Argumente. In Surface übergeben Sie die zur Ausgabe bestimmte Surface, in color die gewünschte Zeichenfarbe. Beim dritten Argument, width, handelt es sich um die Linienbreite in Pixel. Geben Sie hier 0 an, erscheinen gefüllte Linien.

Die sechs Beispiele in Abbildung 3 bis Abbildung 8 zeigen den Code der wichtigsten Zeichenfunktionen und deren Ergebnisse, die wir jeweils mit pygame.image.save abgespeichert haben.

DIESEN ARTIKEL ALS PDF KAUFEN
EXPRESS-KAUF ALS PDFUmfang: HeftseitenPreis €0,99
(inkl. 19% MwSt.)
RASPBERRY PI GEEK KAUFEN
EINZELNE AUSGABE Print-Ausgaben Digitale Ausgaben
ABONNEMENTS Print-Abos Digitales Abo
TABLET & SMARTPHONE APPS Raspberry Pi Geek bei Google Play Readly Logo
Nach oben