
Was ist das GD Modul
und welchen Nutzen hat es?
Definition des Bildes und der Hintergrundfarbe
Einen Text in ein Bild einfügen
Eine Linie / ein ausgefülltes Rechteck zeichnen
Einen Kreis, einen Bogen oder ein Oval zeichnen
Eine gestrichelte Linie zeichnen
Ein Polygon (Vieleck) zeichnen
Ein Hintergrundbild einfügen
Die Form einer Linie beeinflussen
Die Farben von Linien beeinflussen
Das Muster für die Umrisse definieren /
wechseln
Wie werden die Bilder auf der Festplatte gespeichert?
Einen Teil eines Bildes ausschneiden und in
ein anderes Bild kopieren
Einen Bildausschnitt, in ein anderes Bild kopieren
und gleichzeitig verkleinern / vergrößern
Die Breite und die Höhe eines Bildes bestimmen
Ein PerlScript über den img tag auslösen
Es sind zahlreiche Probleme denkbar, bei denen
es notwendig ist, Bilder zur Laufzeit des Programms zu manipulieren.
Man braucht dies z. B.:
-
zur Generation grafischer Seitenzähler
-
zur Darstellung von Daten als Balken, Torten
oder Liniendiagramm
-
zur Produktion von thumbnails aus Bildern
etc..
Dabei produziert dann Perl das Bild und schickt
es an ein Programm, welches in der Lage ist, diese Bilder
auch tatsächlich zu lesen. Das heißt, dass alle
hier vorgestellten Programme nur laufen, wenn sie im Browser
aufgerufen werden, da die Dos Box mit Bildern nichts anfangen
kann.
Es sei noch angemerkt, dass ältere Dokumentationen zum
GD Modul im Netz umherschwirren. Diese drucken Bilder noch
mit $objekt->gif. Diese Methode wird bedingt durch die Copyright
Probleme nicht mehr unterstützt. Drucken ist nur noch
im png oder jpeg Format möglich.
Das einfachste aller denkbaren Bilder wird von folgenden Skript
produziert:
use GD;
print "Content-type: image/png\n\n";
$bild = new GD::Image(100,100);
$blau = $bild->colorAllocate(0,0,255);
$rot = $bild->colorAllocate(255,0,0);
$bild->rectangle(20,20,80,80,$rot);
binmode STDOUT;
print $bild->png;

Zuerst muss allerdings das GD Modul geladen werden. Wie das
funktioniert siehe Arbeiten mit Modulen.
Wir erhalten jetzt ein blaues Bild mit einem rot umrandeten
Rechteck. Das Problem dabei ist nur, dass uns dies in 99 %
aller Fälle nichts nützt, da wir auf der selben
Seite auch noch Text haben wollen. Wenn wir nämlich vorgehen
wie im folgenden Beispie, funktioniert nichts mehr.
use GD;
print "Never change a running system";
$bild = new GD::Image(100,100);
$blau = $bild->colorAllocate(0,0,255);
$rot = $bild->colorAllocate(255,0,0);
$bild->rectangle(20,20,80,80,$rot);
binmode STDOUT;
print $bild->png;
Wir haben
es jetzt mit unterschiedlichen Datentypen zu tun, auf die
der Browser mit unterschiedlichen HTTP Headern vorbereitet
werden muss. (Beim Explorer kann man diesen weglassen. Er
erkennt selbst, was für ein Datentyp ankommt. Aber auch
der Explorer steigt aus, wenn Datentypen vermischt werden.)
Eine einfache Lösung für dieses Problem ist es,
das Perl Skript über den img tag aufzurufen.
<html><head><title>Mein
Picasso</title></head>
<body>
Never change a running system <br>
<img src=http://127.0.0.1/cgi-bin/testbild.pl>
</body></html>
Das funktioniert! Allerdings darf das Skript
testbild.pl dann wirklich nur noch ein Bild zurückgeben.
use GD;
$bild = new GD::Image(100,100);
$blau = $bild->colorAllocate(0,0,255);
$rot = $bild->colorAllocate(255,0,0);
$bild->rectangle(20,20,80,80,$rot);
binmode STDOUT;
print $bild->png;
Es ist deutlich
zu erkennen, dass dieses Modul ist objektorientiert programmiert
ist. Für Details siehe Referenzen
und Objektorientierte Programmierung.
Nachdem wir mit use GD das GD Modul eingebunden haben, bilden
wir eine Instanz der Klasse GD::Image. Diesem Objekt (also
der Instanz der Klasse GD::Image) ordnen wir dann zwei Farben
zu.
Der Subroutine collorAllocate werden drei Parameter übergeben,
nämlich der rot, grün und blau Wert einer Farbe.
Jede Farbe wird als eine Mischung aus diesen drei Grundfarben
definiert. Am einfachsten ist es, sich aus dem Internet ein
Tool zu holen, das die RGB Werte zu jeder Farbe ausgibt. Die
meisten Bildbearbeitungsprogramme machen das so (z.B. Photoimpact).
Es gibt solche Tools auch gratis im Internet.
Die erste Farbe, die zugewiesen wird, ist immer die Hintergrundfarbe
des Bildes. Die Werte für die anderen Farben werden in
einer Variablen abgespeichert und können dann zugewiesen
werden.
In unserem Beispiel wird dem Rechteck die Farbe rot zugewiesen.
Die Methode rectangle hat insgesamt fünf
Parameter. Die ersten zwei Parameter definieren die linke,
obere Ecke, die nächsten zwei die rechte, untere Ecke.
Der letzte Wert definiert die Farbe.
Meistens soll das Bild auch noch Text haben,
der in der Regel auch noch dynamisch produziert werden soll.
Wie Text in ein Bild einfügt wird, zeigt folgendes Skript:
use GD;
print "Content-type: image/png\n\n";
$bild = new GD::Image(110,110);
$blau = $bild->colorAllocate(0,0,255);
$rot = $bild->colorAllocate(255,0,0);
$gelb=$bild->colorAllocate(233,244,123);
$bild->rectangle(22,20,82,80,$rot);
$bild->string(gdLargeFont,2,5,"Andrés Ehmann",$gelb);
binmode STDOUT;
print $bild->png;

Der Subroutine string werden
vier Werte übergeben, wobei deren Bedeutung eigentlich
klar ist. Eine Feinsteuerung der Schrift ist nicht möglich,
man hat lediglich die Auswahl zwischen gdMediumBoldFont, gdTinyFont,
gdLargeFont und gdGiantFont.
Wie eine Linie gezeichnet wird, zeigt das folgende
Beispiel:
use GD;
print "Content-type: image/png\n\n";
$bild = new GD::Image(110,110);
$blau = $bild->colorAllocate(0,0,255);
$rot = $bild->colorAllocate(255,0,0);
$gelb=$bild->colorAllocate(233,244,123);
$gruen=$bild->colorAllocate(0,255,0);
$bild->rectangle(22,20,82,80,$rot);
$bild->string(gdLargeFont,2,5,"Andrés Ehmann",$gelb);
$bild->line(22,22,82,80,$gruen);
binmode STDOUT;
print $bild->png;

Das Rechteck kann auch in einer ausgefüllten
Form gezeichnet werden, das sieht dann so aus:
use GD;
print "Content-type: image/png\n\n";
$bild = new GD::Image(110,110);
$blau = $bild->colorAllocate(0,0,255);
$rot = $bild->colorAllocate(255,0,0);
$gelb=$bild->colorAllocate(233,244,123);
$gruen=$bild->colorAllocate(0,255,0);
$bild->filledRectangle(22,20,82,80,$rot);
$bild->string(gdLargeFont,2,5,"Andrés Ehmann",$gelb);
$bild->line(22,22,82,80,$gruen);
binmode STDOUT;
print $bild->png;

Soll ein Kreis, ein Oval oder ein Bogen entstehen,
dann sieht das so aus:
use GD;
print "Content-type: image/png\n\n";
$bild = new GD::Image(110,110);
$blau = $bild->colorAllocate(0,0,255);
$rot = $bild->colorAllocate(255,0,0);
$gelb=$bild->colorAllocate(233,244,123);
$gruen=$bild->colorAllocate(0,255,0);
$bild->filledRectangle(22,20,82,80,$rot);
$bild->arc(50,50,50,50,0,360,$gruen);
$bild->line(22,22,82,80,$gruen);
binmode STDOUT;
print $bild->png;
Entscheidend ist hier die Zeile: $bild->arc(50,50,50,50,0,360,$gruen);
Die Parameter bedeuten: $bild->arc(Zentrum-X,Zentrum-Y,Breite-X,Breite-Y,Start-Bogen,Grad-Bogen,Farbe);
| |
Beschreibt den Mittelpunkt des Bogens.
Zentrum-X ist der
Wert auf der X-Achse. Zentrum-Y ist der Wert auf der
Y-Achse |
| |
Die Breite des Bogens auf der X-Achse |
| |
Die Breite des Bogens auf der Y-Achse |
| |
Der Punkt, wo der Kreis starten soll.
0 ist 15 Minuten. |
| |
Wieviel Grad der Bogen umspannen soll.
Bei einem Kreis also 360 |
| |
|
Eine gestrichelte Linie lässt sich dann
so Zeichnen:
use GD;
print "Content-type: image/png\n\n";
$bild = new GD::Image(110,110);
$blau = $bild->colorAllocate(0,0,255);
$rot = $bild->colorAllocate(255,0,0);
$gelb=$bild->colorAllocate(233,244,123);
$gruen=$bild->colorAllocate(0,255,0);
$bild->filledRectangle(22,20,82,80,$rot);
$bild->arc(50,50,50,50,0,360,$gruen);
$bild->line(22,22,82,80,$gruen);
$bild->dashedLine(22,80,82,20,$blue);
binmode STDOUT;
print $bild->png;

Mit der Zeile: $bild->dashedLine(22,80,82,20,$blue); zeichnen
wir eine gestrichelte Linie.
Wie ein Polygon, ein Vieleck gezeichnet wird,
zeigt folgendes Skript.
use GD;
print "Content-type: image/png\n\n";
$bild = new GD::Image(110,110);
$blau = $bild->colorAllocate(0,0,255);
$rot = $bild->colorAllocate(255,0,0);
$blau = $bild->colorAllocate(0,0,255);
$vieleck = new GD::Polygon;
$vieleck ->addPt(90,5);
$vieleck ->addPt(80,99);
$vieleck->addPt(5,99);
$bild->polygon($vieleck,$rot);
binmode STDOUT;
print $bild->png;

Ein Vieleck ist ein Objekt und muss folglich
vorher definiert werden.
$vieleck = new GD::Polygon; mit $vieleck
->addPt(90,5); weist man diesem Objekt dann Punkte
zu.
Ruft man $bild->polygon($vieleck,$rot); auf,
werden diese Punkte miteinander verbunden. Es entsteht ein
Polygon. Wer will, kann dieses Polygon auch ausfüllen.
Das sieht dann so aus:
use GD;
print "Content-type: image/png\n\n";
$bild = new GD::Image(110,110);
$blau = $bild->colorAllocate(0,0,255);
$rot = $bild->colorAllocate(255,0,0);
$blau = $bild->colorAllocate(0,0,255);
$vieleck = new GD::Polygon;
$vieleck ->addPt(90,5);
$vieleck ->addPt(80,99);
$vieleck->addPt(5,99);
$bild->filledPolygon($vieleck,$rot);
binmode STDOUT;
print $bild->png;

Geändert wurde hier nur die Subroutine,
die das Polygon zusammenbaut. Aus polygon() wurde filledPolygon().
Soll zum Beispiel eine Graphik produzieren werden, die "die
Fieberkurve" der deutschen Wirtschaft anzeigt, so ist es ästhetisch
ansprechender, wenn ein Hintergrundbild vorhanden ist.
Ein Hintergrundbild kann mit folgendem Skript
eingefügt werden:
zeigt das nächste Beispiel: (Bilddownload wirtschaft.jpg)
use GD;
print "Content-type: image/png\n\n";
$bild = new GD::Image(300,220);
$rot = $bild->colorAllocate(255,0,0);
open (wirtschaft,"c:/test/wirtschaft.jpg") || die;
$bildle = newFromJpeg GD::Image(wirtschaft.jpg);
close(wirtschaft);
$bild->setTile($bildle);
$bild->filledRectangle(0,0,300,220,gdTiled);
binmode STDOUT;
print $bild->png;

Das Bild mit dem Namen wirtschaft.jpg kann man
hier downloaden.
Ein weiteres Bild, das wir mit gdtiled als Kachel einsetzen
wollen, muss vorher mit setTile dem Bild
zugewiesen werden. setTile wiederum arbeitet auch nicht direkt
mit dem Bild, sondern mit einem Zeiger auf das Bild. Diesen
Zeiger müssen wir mit newFromJpeg bzw. newFromPng bilden.(newFromGif
ist, wie bereits erwähnt, nicht mehr im Angebot).
Das Bild wird so oft in den definierten Rahmen eingebaut,
wie es reinpasst. Der Rahmen ist ein Rechteck mit 300 Pixel
Länge und 220 Pixel Höhe. In diesem Falle wird das
Bild nur einmal eingebaut.
Man beachte, dass der Bezugspunkt für den x und den y
Wert die linke, obere Ecke des Bildes ist.
Man kann das Bild auch in ein Polygon einbauen, das sieht
dann so aus:
use GD;
print "Content-type: image/png\n\n";
$bild = new GD::Image(300,220);
$rot = $bild->colorAllocate(255,0,0);
open (wirtschaft,"c:/test/wirtschaft.jpg") || die;
$bildle = newFromJpeg GD::Image(wirtschaft);
close(wirtschaft);
$bild->setTile($bildle);
$vieleck = new GD::Polygon;
$vieleck ->addPt(150,220);
$vieleck ->addPt(0,0);
$vieleck->addPt(300,0);
$bild->filledPolygon($vieleck,gdTiled);
binmode STDOUT;
print $bild->png;

Jetzt haben wir alle Bausteine zusammen, um
eine "Fieberkurve der Wirtschaft" auf einem Hintergrundbild
zu zeichnen.
Zuerst zeigen wir, wie es nicht geht. Nämlich so:
use GD;
print "Content-type: image/png\n\n";
$bild = new GD::Image(300,220);
$rot = $bild->colorAllocate(255,0,0);
$gelb=$bild->colorAllocate(233,244,123);
open (wirtschaft,"c:/test/wirtschaft.jpg") || die;
$bildle = newFromJpeg GD::Image(wirtschaft);
close(wirtschaft);
$bild->setTile($bildle);
$bild->filledRectangle(0,0,300,220,gdTiled);
$bild->string(gdLargeFont,60,180,"Auf und ab der Wirtschaft ",$gelb);
$bild->stringUp(gdLargeFont,25,160,"Bruttosozialprodukt",$gelb);
$bild->line(55,170,290,170,$gruen);
$bild->line(55,170,55,20,$gruen);
$vieleck = new GD::Polygon;
$vieleck ->addPt(55,170);
$vieleck ->addPt(105,120);
$vieleck->addPt(155,80);
$vieleck->addPt(205,130);
$vieleck->addPt(255,110);
$vieleck->addPt(299,50);
$bild->polygon($vieleck,$rot);
binmode STDOUT;
print $bild->png;

Das funktioniert nicht! Polygone sind immer
geschlossen, folglich wird das GD Modul automatisch das Polygon
schließen, und das ist ziemlich genau das, was wir nicht
wollen.
Wenn wir dies aus didaktischen Gründen machen wollen,
dann muss für jede Teilstrecke eine eigene Linie definiert
werden. In der Praxis würde das allerdings kein Mensch
machen, weil es zum Zeichnen komplexer Charts ein eigenes
Modell gibt, das diese Probleme löst, nämlich GD::Chart,
siehe Daten graphisch Aufbereiten: Störche,
Viagra, Geburtenrate.
Will man es dennoch "mit der Hand" machen, dann sieht das
so aus:
use GD;
print "Content-type: image/png\n\n";
$bild = new GD::Image(300,220);
$rot = $bild->colorAllocate(255,0,0);
$gelb=$bild->colorAllocate(233,244,123);
open (wirtschaft,"c:/test/wirtschaft.jpg") || die;
$bildle = newFromJpeg GD::Image(wirtschaft);
close(wirtschaft);
$bild->setTile($bildle);
$bild->filledRectangle(0,0,300,220,gdTiled);
$bild->string(gdLargeFont,60,180,"Auf und ab der Wirtschaft ",$gelb);
$bild->stringUp(gdLargeFont,25,160,"Bruttosozialprodukt",$gelb);
$bild->line(55,170,290,170,$gruen);
$bild->line(55,170,55,20,$gruen);
$bild->line(55,170,80,120,$gelb);
$bild->line(80,120,110,80,$gelb);
$bild->line(110,80,150,60,$gelb);
$bild->line(150,60,180,20,$gelb);
$bild->line(180,20,250,120,$gelb);
$bild->line(250,120,299,60,$gelb);
binmode STDOUT;
print $bild->png;

Bis jetzt haben wir noch keinen Einfluss auf
die Form der Linien genommen. Das hatte zur Konsequenz, dass
alle Umrisse und Linien ziemlich dünn waren.
Will man die Form einer Linie beeinflussen, so muss zuerst
ein Bild generiert werden. Dieses Bild kann man dann der Linie
zuweisen, so dass die Linie eine Aneinanderreihung dieses
Bildes wird. Über diesen Weg können alle Eigenschaften
der Linie festgelegt werden:
use GD;
print "Content-type: image/png\n\n";
$pinsel=new GD::Image(3,3);
$gruen=$pinsel->colorAllocate(0,255,0);
$pinsel->filledRectangle(0,0,2,2,$gruen);
$bild=new GD::Image(100,100);
$blau=$bild->colorAllocate(0,0,255);
$bild->setBrush($pinsel);
$bild->line(0,0,100,100,gdBrushed);
binmode STDOUT;
print $bild->png;

Hier werden zwei Bilder definiert. Das erste
ist die Pinselform, das zweite das eigentliche Bild. Mit setBrush setzen
wir die Pinselform für das eigentliche Bild. Wenn wir
dann ein Linie malen, können wir als Form der Linie das
erste Bild mit gdBrushed definieren.
Das funktioniert auch als Umriss für ein Rechteck, Polygon,
Kreis etc.:
use GD;
print "Content-type: image/png\n\n";
$pinsel=new GD::Image(3,3);
$gruen=$pinsel->colorAllocate(0,255,0);
$pinsel->filledRectangle(0,0,2,2,$gruen);
$bild=new GD::Image(100,100);
$blau=$bild->colorAllocate(0,0,255);
$bild->setBrush($pinsel);
$bild->rectangle(0,0,100,100,gdBrushed);
binmode STDOUT;
print $bild->png;
Soll z.B. ein Rechteck mit einem dickeren Umriss
entstehen, sieht das so aus:
use GD;
print "Content-type: image/png\n\n";
$pinsel=new GD::Image(3,3);
$gruen=$pinsel->colorAllocate(0,255,0);
$pinsel->filledRectangle(0,0,2,2,$gruen);
$bild=new GD::Image(100,100);
$blau=$bild->colorAllocate(0,0,255);
$bild->setBrush($pinsel);
$bild->rectangle(6,6,94,94,gdBrushed);
binmode STDOUT;
print $bild->png;

Ein Kreis sieht so aus:
use GD;
print "Content-type: image/png\n\n";
$pinsel=new GD::Image(3,3);
$gruen=$pinsel->colorAllocate(0,255,0);
$pinsel->filledRectangle(0,0,2,2,$gruen);
$bild=new GD::Image(100,100);
$blau=$bild->colorAllocate(0,0,255);
$bild->setBrush($pinsel);
$bild->arc(50,50,50,50,0,360,gdBrushed);
binmode STDOUT;
print $bild->png;

Will man den Bogen von 30 Minuten bis zur vollen
Stunde haben (der Startpunkt liegt bei 15 Minuten), dann sieht
das so aus:
use GD;
print "Content-type: image/png\n\n";
$pinsel=new GD::Image(3,3);
$gruen=$pinsel->colorAllocate(0,255,0);
$pinsel->filledRectangle(0,0,2,2,$gruen);
$bild=new GD::Image(100,100);
$blau=$bild->colorAllocate(0,0,255);
$bild->setBrush($pinsel);
$bild->arc(50,50,50,50,90,270,gdBrushed);
binmode STDOUT;
print $bild->png;
Das Aussehen der Linien kann noch genauer definiert
werden. Mit der Funktion dashedLine haben
wir ja nur eine gestrichelte Linie gezeichnet, konnten aber
die Farben dieser Linien nicht beeinflussen.
Will man die Farben beeinflussen will, dann
sieht das so aus:
use GD;
print "Content-type: image/png\n\n";
$bild=new GD::Image(100,100);
$rosa=$bild->colorAllocate(220,150,125);
$rot=$bild->colorAllocate(255,0,0);
$gruen=$bild->colorAllocate(0,255,0);
$schwarz=$bild->colorAllocate(0,0,0);
@linienfarben=( $rot,$rot,$rot, $rot,$rot,$rot, $rot,$rot,$rot,$gruen,$gruen,$gruen,$gruen,$gruen);
$bild->setStyle(@linienfarben);
$bild->rectangle(5,5,95,95,gdStyled);
binmode STDOUT;
print $bild->png;
Wir definieren einen Array mit Farbwerten. Hierbei
steht jedes Element des Arrays für ein Pixel der entsprechenden
Farbe.
Mit setStyle definieren wir
das Muster für die Umrisse, mit gdStyled rufen
wir das Muster ab.
Wer will, kann die Muster auch wechseln, das sieht dann so
aus:
use GD;
print "Content-type: image/png\n\n";
$bild=new GD::Image(100,100);
$weiss=$bild->colorAllocate(255,255,255);
$rot=$bild->colorAllocate(255,0,0);
$gruen=$bild->colorAllocate(0,255,0);
$schwarz=$bild->colorAllocate(0,0,0);
$gelb=$bild->colorAllocate(255,129,129);
$hellblau=$bild->colorAllocate(17,207,255);
@linienfarben1=( $rot,$rot,$rot, $rot,$rot,$rot, $rot,$rot,$rot,
$gruen,$gruen,$gruen,$gruen,$gruen);
$bild->setStyle(@linienfarben1);
$bild->rectangle(5,5,95,95,gdStyled);
@linienfarben2=( $gelb,$gelb,$gelb,$gelb,$gelb,$gelb,$gelb,$gelb,$gelb,$gelb,
$hellblau,$hellblau,$hellblau,$hellblau,$hellblau,$hellblau,$hellblau,$hellblau);
$bild->setStyle(@linienfarben2);
$bild->arc(50,50,50,50,0,360,gdStyled);
binmode STDOUT;
print $bild->png;

Bis jetzt wurden die Bilder immer in den Standard
Output geschossen. (im CGI Umfeld der Browser).
Die naheliegende Frage lautet, wie werden Bilder auf der Festplatte
gespeichert? So erstaunlich das klingen mag, aber hier gibt
es nichts besonderes zu berichten. Man druckt sie wie jede
x-beliebige Datei:
use GD;
print "Content-type: text/html\n\n";
$bild=new GD::Image(100,100);
$rosa=$bild->colorAllocate(220,150,125);
$rot=$bild->colorAllocate(255,0,0);
$gruen=$bild->colorAllocate(0,255,0);
$schwarz=$bild->colorAllocate(0,0,0);
@linienfarben=( $rot,$rot,$rot, $rot,$rot,$rot, $rot,$rot,$rot,
$gruen,$gruen,$gruen,$gruen,$gruen);
$bild->setStyle(@linienfarben);
$bild->rectangle(5,5,95,95,gdStyled);
$fertisch=$bild->png;
open(bildle,">c:/test/mein_bild.png");
binmode bildle;
print bildle $fertisch;
close(bildle);
print "Hurra, wir haben ein Bild gedruckt";
Ein
Bild wird also gedruckt wie jede x-beliebige Datei. Das Auffallende
dabei ist, dass das Drucken im binary Mode erfolgen muss,
da unter Windows der Ascii Mode Standard ist. Im binary mode
wird die Datei genauso abgespeichert, wie sie abgeschickt
wurde. Sie ist also bitgleich. Beim Ascii Mode startet das
Betriebsystem den Versuch, die Quelldatei so zu übersetzen,
dass die Zieldatei die gleiche Bedeutung hat wie die Quelldatei.
Das ist bei Textdateien sinnvoll, da verschiedene Betriebssysteme
Texte unterschiedlich abspeichern. Bei Bildern ist dies nicht
sinnvoll, da es hier nichts zu interpretieren gibt. Bei den
meisten Anwendungen, in denen ein Bild direkt aus einem HTML
Formular "upgeloaded" werden kann, siehe Bildupload
aus dem Browser, ist es günstig, von dem Bild erst
mal einen thumbnail zu produzieren. Darüber hinaus ist
es wünschenswert, aus einem Bild einen bestimmten Bereich
auszuschneiden und diesen ihn ein anderes Bild einzufügen.
Wie ein Teil eines Bildes ausgeschnitten und
in ein anderes Bild reinkopiert wird, zeigt das nächste
Beispiel: (Bilddownload kirsche.jpg)
use GD;
print "Content-type: text/html\n\n";
$bild=new GD::Image(100,100);
$rosa=$bild->colorAllocate(220,150,125);
$bildle = newFromJpeg GD::Image("c:/test/kirsche.jpg");
$bild->copy($bildle,0,0,60,60,100,30);
$bild->copy($bildle,0,50,60,60,100,30);
binmode STDOUT;
print $bild->png;
Entscheidend ist hier die Zeile: $bild->copy($bildle,0,0,60,60,100,30);.
Die Funktion copy hat sieben Parameter. Davon ist der erste
ein Zeiger auf das Quellbild, also das Bild, welches reinkopiert
werden soll. Die nächsten zwei Parameter (0,0) definieren
die Stelle im Zielbild, in die hineinkopiert wird. Die beiden
Werte sind hierbei der x und der y Wert der linken, oberen
Ecke des Zielbildes. Die nächsten zwei Parameter (60,60)
definieren den Bereich des Zielbildes, ab dem rauskopiert
werden soll. Die beiden Parameter (100,30) definieren den
Abschnitt, der rauskopiert werden soll. (In diesem Beispiel
soll also ab der rechten, oberen Ecke (60,60) 100 Pixel in
horizontaler und 30 Pixel in vertikaler Richtung ausgeschnitten
werden.) Zur Verdeutlichung kann das Procedere auch wiederholt
werden.
Im folgenden Beispiel wird ein Ausschnitt aus
dem Quellbild nicht einfach in das Zielbild eingefügt,
sondern es wird bei dieser Gelegenheit auch noch verkleinert.
(Produktion eines thumbnails)
use GD;
print "Content-type:image/jpeg\n\n";
$bild=new GD::Image(20,24);
$rosa=$bild->colorAllocate(220,150,125);
$bildle = newFromJpeg GD::Image("c:/test/kirsche.jpg");
$bild->copyResized($bildle,1,1,0,0,20,24,155,179);
binmode STDOUT;
print $bild->jpeg;
Das Skript
reduziert kirsche.jpg von 155/179 auf 20/24.
Die Funktion copyResize hat dabei folgende
Parameter:
|
|
|
|
|
linke, obere Ecke des Zielbildes
|
|
|
linke, obere Ecke des Quellbildes
|
|
|
Fläche auf die reduziert / vergrößert
wird |
|
|
Fläche, die ausgeschnitten wird
|
Ist die Fläche, in die projiziert wird,
kleiner als die ausgeschnittene Fläche, wird reduziert.
(Wenn die Proportionen nicht stimmen, wird gestaucht.) Ist
die Fläche, in die projiziert wird, größer,
wird vergrößert. (Wenn die Proportionen nicht stimmen,
wird auch hier gestaucht.) In der Praxis ist allerdings oft
nicht bekannt, wie groß das Originalbild ist. Das ist
aber die Bedingung, um das Bild ohne Stauchen zu verkleinern
oder zu vergrößern.
Die Breite und die Höhe eines Bildes lassen sich folgendermaßen
bestimmen:
use GD;
print "Content-type:text/html\n\n";
$bildle = newFromJpeg GD::Image("c:/test/kirsche.jpg");
($breite,$hoehe) = $bildle->getBounds();
print "Das Bild ist $breite breit und $hoehe hoch.";
Da die Größe des Bildes, das man
produzieren will, bekannt ist, kann man sich jetzt entweder
die Höhe oder die Breite des Bildes ausrechnen.
$Hoehe_Ziel= $Hoehe_Quelle / $Breite_Quelle * $Breite_Ziel;
Es folgt ein Skript, welches verkleinert ohne zu stauchen:
use GD;
print "Content-type:image/jpeg\n\n";
$bildle = newFromJpeg GD::Image("c:/test/kirsche.jpg");
($Breite_Quelle,$Hoehe_Quelle) = $bildle->getBounds();
$Hoehe_Ziel= $Hoehe_Quelle / $Breite_Quelle * 40;
$bild=new GD::Image(40,$Hoehe_Ziel);
$rosa=$bild->colorAllocate(220,150,125);
$bild->copyResized($bildle,1,1,0,0,40,$Hoehe_Ziel,$Breite_Quelle,$Hoehe_Quelle);
binmode STDOUT;
print $bild->jpeg;
Es folgt ein kleines PerlSkript das mit Hilfe
des GD-Modul einen grafischen Counter produziert. Dieses Script
muss in das cgi-bin Verzeichnis abgespeichert werden
#!usr/bin/perl
open(counti,"countiXX.txt");
$counti=<counti>;
close(counti);
$counti=$counti+1;
open(counti,">countiXX.txt");
print counti "$counti";
close(counti);
use GD;
print "Content-type: image/png\n\n";
$bild = new GD::Image(90,27);
$schwarz = $bild->colorAllocate(0,0,0);
$blau=$bild->colorAllocate(0,0,160);
$weiss=$bild->colorAllocate(255,255,255);
$bild->filledRectangle(3,2,87,23,$blau);
$bild->string(gdLargeFont,20,5,$counti,$weiss);
binmode STDOUT;
print $bild->png;
Jetzt brauchen wir nur noch den img tag der
uns den Counter anzeigt.

<img src="http://127.0.0.1/cgi-bin/counter.pl">
Geschafft, nach jedem neuen Aufruf der Seite
wird der Counter um eins nach oben gezählt.
|
 |