Werbung einblenden Werbung ausblenden


Home / Tutorials / Perl Handbuch / Bildbearbeitung mit GD Modul


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

Was ist das GD Modul und welchen Nutzen hat es?

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.

Definition des Bildes und der Hintergrundfarbe / Methode rectangle
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.

Einen Text in ein Bild einfügen / Subroutine string

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.

Eine Linie / ein ausgefülltes Rechteck zeichnen

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;

Einen Kreis, einen Bogen oder ein Oval zeichnen

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);

Zentrum-X,
Zentrum-Y

Beschreibt den Mittelpunkt des Bogens. Zentrum-X ist der
Wert auf der X-Achse. Zentrum-Y ist der Wert auf der Y-Achse

Breite-X

Die Breite des Bogens auf der X-Achse

Breite-Y

Die Breite des Bogens auf der Y-Achse

Start-Bogen

Der Punkt, wo der Kreis starten soll. 0 ist 15 Minuten.

Grad-Bogen

Wieviel Grad der Bogen umspannen soll. Bei einem Kreis also 360

Farbe

die Farbe des Bogens


Eine gestrichelte Linie zeichnen

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.

Ein Polygon (Vieleck) zeichnen

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 einfügen

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;

Die Form einer Linie beeinflussen

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.

Die Farben von Linien 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.

Das Muster für die Umrisse definieren / wechseln

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;

Wie werden die Bilder auf der Festplatte gespeichert?

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.

einen Teil eines Bildes ausschneiden und in ein anderes Bild kopieren

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.

Einen Bildausschnitt, in ein anderes Bild kopieren und gleichzeitig verkleinern / vergrößern

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:

$bildle

Zeiger auf das Quellbild

1,1

linke, obere Ecke des Zielbildes

0,0

linke, obere Ecke des Quellbildes

20,24

Fläche auf die reduziert / vergrößert wird

155/179

Fläche, die ausgeschnitten wird


Die Breite und die Höhe eines Bildes bestimmen

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;

Ein PerlScript über den img tag auslösen

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.

vorhergehendes Kapitel