Home

Info

Artikel

Produkte

Stickers

UserGroups

Events

Bücher


Suchen:



Addon
Jetzt bestellen!
> Kombiabo
> Jahres-CD 1999

Perl-Snapshot

Bilder-Trickser

von Michael Schilli


Das Modul Image::Magick konvertiert Bilder von einem Format ins andere, schneidet Teile aus, flickt Text hinein, montiert Einzelbilder zu kombinierten Darstellungen, erzeugt animierte GIFs und morpht sogar Übergänge. Alle Achtung!

ImageMagick dürfte Linux-Hardlinern wohlbekannt sein - diese Distribution stellt einige Utility-Programme zur Verfügung, die allerhand mit verschiedensten Graphikformaten anstellen. Ist die Perl-Schnittstelle Image::Magick von Kyle Shorter erst einmal installiert (siehe den lezten Abschnitt Installation), eröffnet sie den programmierten Zugriff und vereinfacht die Automatisierung von Bilderkonvertierungsaufgaben.

Konvertieren

Der Zugriff ist objektorientiert, ein neues Bild entsteht mit dem Konstruktor

$image = Image::Magick->new();

und mit Daten wird es mittels der Read-Methode gefüllt, die ein Bild von der Platte einliest:

$image->Read("test.gif") && die "Cannot read!";

Image::Magick folgt leider nicht der Perl-Konvention, im Erfolgsfall einen wahren und im Fehlerfall einen falschen Wert zurückzuliefern, sondern gibt bei auftretenden Fehlern einen Fehlerstring und, falls alles gutging, einen Leerstring zurueck - dann kommt der über eine and-Anweisung gekoppelte die-Befehl nicht zum Einsatz. Zurückgeschrieben wird auf die gleiche Weise:

$image->Write("test.jpg") && die "Cannot write!";

Weist der Name der Ausgabedatei eine andere Endung als das eingelesene Bild auf, konvertiert Image::Magick alles automatisch ins richtige Format, im vorliegenden Fall von GIF nach JPG. Weiter werden PNG, BMP, TIFF und viele andere Bildformate unterstützt. Ein Objekt vom Typ Image::Magick kann dabei nicht nur ein Bild aufnehmen, sondern eine ganze Reihe, jeder weitere Aufruf der Read-Methode hängt ein weiteres an. Listing 1 (tojpg.pl) zeigt eine Anwendung: Die foreach-Schleife liest alle Dateien, deren Namen über die Kommandozeile hereinkommen, der Reihe nach ein und hängt deren Inhalt immer wieder an das Objekt, das sich hinter $images verbirgt, an.

Über alle Bilder im Objekt kann man nun iterieren, indem man die Objektreferenz $images in ein Array konvertiert und so über die Elemente von @$images eiert. Diese sind wiederum Image::Magick-Objekte und verstehen daher neben den bereits besprochenen Methoden Read und Write auch Get (Attribute abfragen) und Set (Attribute setzen). Einige der wichtigsten Attribute lauten folgendermaßen:

base_columns   Breite des Original-Bildes
base_rows      Höhe des Original-Bildes
base_filename  Name der Eingabedatei
filesize       Größe der Eingabedatei in Bytes
total_colors   Anzahl der Farben
x-resolution   Auflösung in X-Richtung
y-resolution   Auflösung in Y-Richtung

tojpg.pl macht nun aus jedem hereinkommenden Dateinamen einen mit der Endung *.jpg, ruft die Write-Methode auf und konvertiert so alle angegebenen Dateien ins JPG-Format. Damit's spannend anzusehen ist, ermittelt es mittels des filesize-Attributs auch noch die ursprüngliche Dateigröße, und läßt anschließend den -s-Operator auf das frischgeschriebene File los, der anstandslos dessen Größe zurückliefert. Die commify-Funktion setzt Punkte in die zurückkommenden Zahlen, um sie übersichtlich in Dreiergruppen zu strukturieren. Ruft man also tojpg.pl mittels

tojpg.pl images/*.bmp

auf, lautet die Ausgabe etwa

images/lion.bmp->images/lion.jpg (717.606 -> 73.241 Bytes)
images/pieks.bmp->images/pieks.jpg (688.018 -> 53.743 Bytes)
images/schuh.bmp->images/schuh.jpg (708.302 -> 50.450 Bytes)

und für alle *.bmp-Dateien entstehen platzsparende JPEGs.

Listing 1: tojpg.pl

 1 #!/usr/bin/perl
 2 ##################################################
 3 # mschilli@perlmeister.com 1999
 4 # Dateien nach JPG konvertieren
 5 ##################################################
 6 use Image::Magick;
 7 
 8 $images = Image::Magick->new();
 9 
10 foreach $file (@ARGV) {
11     $images->Read(filename => $file) && 
12        die "Read failed";
13 }
14 
15 foreach $image (@$images) {
16 
17     $oldsize = $image->Get('filesize');
18 
19     ($newname = $image->Get('base_filename'))
20          =~ s/\.[^.]*$/.jpg/;
21 
22     $image->Write($newname) && die "Write failed";
23 
24     printf "%s->%s (%s -> %s Bytes)\n", 
25           $image->Get('base_filename'),
26           $newname,
27           commify($oldsize),
28           commify(-s $newname); 
29 }
30 
31 ##################################################
32 sub commify {    # Punkte in große Zahlen einfügen
33 ##################################################
34     my $number = shift;
35     while($number =~ s/(\d)(\d{3})\b/\1.\2/) { }
36     return $number;
37 }

Manipulieren

Von den Dutzenden von Methoden, die Image::Magick anbietet, um am Bildinhalt herumzuschustern, kann ich nur einen kleinen Teil besprechen: Crop zum Ausschneiden von Teilen, Scale zum Strecken und Stauchen, Frame zum Rahmenziehen und Annotate zum Hineinschreiben von Text. Für den Rest sei auf die ausführliche Dokumentation [2] verwiesen.

In Listing 2 (manip.pl) nimmt die Crop-Methode ein geometry-Attribut entgegegen, das wie in X-Windows üblich im Format WxH+X+Y aufgebaut ist. Crop ersetzt das ursprüngliche Bild durch den Ausschnitt. So schneidet es aus dem dritten Bild aus Abbildung 2 die abgebildete Tafel aus und streckt das Ergebnis anschließend mit der Scale-Methode von 100 auf 200 Pixels. Dies hat zur Folge, daß sich das Bild etwas verzerrt. Einen Rahmen zeichnet dann die Frame-Methode, und zwar mit einer Innenkante von 2 Pixels, einer Außenkante von 2 Pixels und einer oberen und unteren Rahmenbreite von 20 Pixels. Die Annotate-Methode schließlich schreibt den Text Woohoo! in Rot 55 Pixels vom linken und 30 Pixels vom oberen Rand entfernt ins Bild. Als Font wird Helvetica gewählt. Das Ergebnis, das die Write-Methode wegschreibt, zeigt Abbildung 1.


Abb. 1: Croppen, Ausziehen, Beschriften, Rahmen zeichnen

Listing 2: manip.pl

 1 #!/usr/bin/perl
 2 ##################################################
 3 # mschilli@perlmeister.com 1999
 4 # Ein Bild manipulieren
 5 ##################################################
 6 use Image::Magick;
 7 
 8 $image = Image::Magick->new;
 9 
10 $image->Read("lion.jpg") && 
11     die "Cannot read";
12 
13 $image->Crop(geom=>'155x300+110+100');
14 
15 $image->Scale(width => 200);
16 
17 $image->Frame(inner => 2, outer => 2, 
18               width => 20, height => 20);
19 
20 $image->Annotate(text => "Woohoo!", 
21                  geometry => "+55+30",
22                  pen => "red", font => 'helvetica',
23                  pointsize => 30);
24 
25 $image->Write("manip.gif") && 
26     die "Cannot write";

Montagen

Um Sammlungen von Bildern in Übersichtstafeln als kleine ``Thumbnails'' darzustellen, eignet sich die Montage-Methode. Listing 3 (montage.pl) zeigt, wie Montage alle im Objekt $images gespeicherten Bilder entsprechend den gesetzten Attributen zusammenfaßt und eine Referenz auf ein neues Objekt $montage zurückliefert. Das tile-Attribut gibt in der vorgestellten Form die Anzahl der Spalten an, in die Montage die Bildchen aufreiht, in der Form 3x4 ließe sich dazu auch noch die Anzahl der Zeilen begrenzen. Das auf True gesetzte Shadow-Attribut läßt rechts und unterhalb jedes Bildes einen kleinen Schatten erscheinen, der eine Tiefenwirkung vermittelt. Das label-Attribut schließlich gibt an, was als Beschriftung unter jeden Bild stehen wird, und neben normalem Text dürfen auch einige Makros stehen, hier die wichtigsten:

%b   Dateigröße
%f   Dateiname
%h   Höhe
%m   Typ (GIF, JPG)
%w   Breite


Abb.2: Montierte Bilder

Listing 3: montage.pl

 1 #!/usr/bin/perl
 2 ##################################################
 3 # mschilli@perlmeister.com 1999
 4 # Montage von Bildern
 5 ##################################################
 6 
 7 use Image::Magick;
 8 
 9 $images = Image::Magick->new();
10 
11 foreach $file (@ARGV) {
12     $images->Read($file) && die "Read failed";
13 }
14 
15 $montage = $images->Montage(label  => "%f", 
16                             shadow => "True",
17                             tile   => "2");
18 
19 $montage->Write("montage.gif") && 
20     die "Write failed";

Morphen

Und schließlich kann Image::Magick auch noch animierte GIFs schreiben - und die Animation sogar durch Morphen zwischen mehreren Bildern selbst erzeugen. Listing 4 (morph.pl) zeigt wie's geht. Für ein animiertes GIF, das langsam zwischen zwei Darstellungen wechselt und die Übergänge fließend herstellt, brauchen wir zwei statische GIFs, im Listing sind das book1.gif und book2.gif. Damit das animierte GIF, wenn es sich bis zum zweiten Bild durchgemorpht hat, nicht ruckartig zum ersten Bild zurückspringt, sondern auch ordentlich abmorpht (dieses Wort gefällt mir), speichert morph.pl die Dreierfolge book1.gif-book2.gif-book1.gif in $images ab und fordert die Morph-Methode auf, jeweils 10 Übergangsbilder (Frames-Attribut) zwischen den Eckpunkten zu erzeugen. Vor dem Schreiben des animierten GIFs mit der Write-Methode setzt morph.pl noch schnell die Attributwerte für delay und loop - die Anzahl von Hunderstelsekunden zwischen den einzelnen Frames und die Gesamtzahl der Schleifendurchläufe bis das animierte GIF stehenbleibt.


Abb. 3: Bildübergänge durch Morphen

Listing 4: morph.pl

 1 #!/usr/bin/perl
 2 
 3 use Image::Magick;
 4 
 5 $images = Image::Magick->new();
 6 
 7 foreach $file (qw(book1.gif book2.gif book1.gif)) {
 8     $images->Read(filename => $file) && die "Read failed";
 9 }
10 
11 $morph = $images->Morph(frames => 10);
12 
13 $morph->Set(delay => 20, loop => 10);
14 
15 $morph->Write("morph.gif") && 
16     die "Cannot write";

Installation

Ausgehend von einer Redhat-5.2-Installation, die bereits über die Bibliotheken libpng, libtiff, libjpeg und libz verfügt, fehlen noch drei Dinge (Fehlt mehr, hilft README.txt der ImageMagick-Distribution weiter. Die ImageMagick-Distribution, die in Version 4.1.8 vorliegt, holt man von der Original-Site [3] oder vom niederländischen Spiegel [4] als komprimierte Tar-Datei ImageMagick-4.1.8.tar.gz. Bevor's ans Auspacken geht, brauchen wir noch die Freetype-Bibliothek libttf, die unter [5] liegt. Weiter braucht's noch die BZLIB, die's unter [6] gibt. Sind alle drei Distributionen in einem Verzeichnis, kann die Installiererei losgehen (siehe Listing 5):

Listing 5: Installationsorgie

tar zxfv ImageMagick-4.1.8.tar.gz
cd ImageMagick-4.1.8
   
tar zxfv ../bzip2-0.9.0c.tar.gz
mv bzip2-0.9.0c bzlib
cd bzlib 
make
cd ..
    
tar zxfv ../freetype-1.2.tar.gz
mv freetype-1.2 ttf
cd ttf 
./configure
make
cd ..
    
./configure
make
make install

cd PerlMagick
make install
cd ..
    
cd ttf
make install
cd ..

Die Perl-Bibliothek PerlMagick liegt dem Ganzen als Version 1.60 schon bei und wird mit installiert. Falls übrigens die Environment-Variable LD_LIBRARY_PATH nicht den Pfad /usr/local/lib enthält, bitte nachziehen (oder den Pfad in /etc/ld.so.conf eintragen und als root /sbin/ldconfig aufrufen), sonst funktionieren die Binaries, die der ImageMagick-Distribution beiliegen (wie z.B. das handliche Programm convert) nicht. Sodann sollte ein einfaches

#!/usr/bin/perl -w

use Image::Magick;

funktionieren. Uff! Fröhliches Abmorphen und bis zum nächsten Mal - wenn es wieder heißt: News aus Perl-Land!

Infos

[1] PerlMagick-Dokumentation: http://www.wizards.dupont.com/cristy/www/perl.html
[2] ImageMagick User Guide: ftp://ftp.wizards.dupont.com/pub/ImageMagick/ImageMagick.pdf
[3] ImageMagick: ftp://ftp.wizards.dupont.com/pub/ImageMagick
[4] ImageMagick FTP-Mirror: ftp://ftp.oce.nl/pub/Internet/audio+video/ImageMagick
[5] Freetype-Bibliothek: ftp://ftp.freetype.org/pub/freetype/freetype-1.2.tar.gz
[6] BZLIB: http://www.muraroa.demon.co.uk/bzip2-0.9.0c.tar.gz

Der Autor

Michael Schilli arbeitet als Web-Engineer für AOL/Netscape in Mountain View, Kalifornien. Er ist Autor des 1998 bei Addison-Wesley erschienenen (und 1999 für den englischsprachigen Markt als "Perl Power" herausgekommenen) Buches "GoTo Perl 5" und unter michael@perlmeister.com oder http://perlmeister.com zu erreichen.

Copyright © 1999 Linux-Magazin Verlag