Last update: 15.01.2011 | © 2024 Julian von Mendel | Datenschutz
Mit dieser Klasse kann man komfortabel Thumbnails erzeugen und allgemein mit den GD-Funktionen arbeiten. Sie ermittelt automatisch den Dateityp einer einzulesenden Datei, speichert automatisch mit den richtigen Funktionen, kann Bilder direkt an den Browser ausgeben und stellt ein vollständiges, objektorientiertes Interface für die GD-Funktionen von PHP dar, mit dem sich elegant Bilder bearbeiten lassen. Groß- und Kleinschreibung ist der Klasse egal, d. h. wer will kann jedes Substantiv groß schreiben und die Klasse per new Image einbinden.
Sie entwickelte sich ein wenig zum Testwerkzeug für Bildverarbeitungsalgorithmen weiter, die hier teils dokumentiert sind.
Um ein Bild aus einer Datei zu laden gibt's die Funktion createfromfile():
<?php
Es werden die Dateitypen
include("image.php");
$img = new image;
$img->createfromfile("fun/pinkyandbrain.jpg");
?>
automatisch erkannt, und zwar nicht anhand der Dateiendung, sondern am Inhalt. (Öfters mal lade ich Dateien, die mit .gif enden, aber eine .jpg-Datei sein sollen. Das stört die Klasse nicht.)
Alternativ kann man einen bereits erzeugten Image Identifier laden:
<?php
Um ein Bild komplett neu zu erzeugen kann man die createtruecolor-Funktion verwenden:
include("image.php");
$img = new image;
$img->sethandler($im);
?>
<?php
include("image.php");
$img = new image;
$img->createtruecolor(200, 150); // 200x150 Pixel großes, leeres Bild erzeugen
?>
Wenn man mit dem Bild nicht mehr arbeiten muss, ist es sinnvoll
<?php
aufzurufen, um Arbeitsspeicher freizugeben.
$img->close();
?>
Das Bild kann wahlweise in eine Datei gespeichert, als Image Identifier exportiert oder direkt zum Browser gesendet werden:
<?php
$img->save("neuedatei.png"); // Bild in eine Datei speichern, Dateityp wird anhand der Endung bestimmt
$img->save(); // Bild in die Datei speichern, die geöffnet wurde
$im = $img->handler(); // Image Identifier exportieren um diesen weiterzuverarbeiten
$img->output(); // Bild direkt zum Browser zu senden
?>
<?php
echo "Breite: ".$img->width()."px\n";
echo "Höhe: ".$img->height()."px\n";
echo "Dateityp: ".$img->filetype()."\n";
echo "Mimetype: ".$img->mimetype()."\n";
?>
Die Klasse fängt den Aufruf nicht-existenter Funktionen ab und versucht, diesen an die Standard-PHP-Funktionen weiterzuleiten. Somit kann man die Klasse als objektorientiertes Interface zu den GD-Funktionen von PHP verwenden:
<?php
$black = $img->colorallocate(0, 0, 0); // Schwarze Farbe
$img->colortransparent($black); // Farbe schwarz soll im Bild durchsichtig erscheinen
// $img nach $img2 kopieren und resizen (doppelte Breite...)
$img2 = new image;
$img2->createtruecolor($img->width()*2, $img->height());
$img2->copyresampled($img->handler(), 0, 0, 0, 0, $img->width()*2, $img->height(), $img->width(), $img->height());
$img2->interlace(); // Interlacing aktivieren
$img2->output();
$img2->close();
$img->close();
?>
Die rotate()-Methode ist langsam. Wer sie verbessern möchte, kann sie so anpassen, dass sie imagerotate() korrekt verwendet, über einen Patch würde ich mich freuen. Mein Interesse daran hält sich momentan in Grenzen.
<?php
$img->setchannel(image::black);
$img->filter();
?>
image::black konvertiert in Graustufen. image::red, image::green, image::blue filtern die anderen Farbkanäle heraus. Alternativ kann man setchannel() auch ein Array übergeben, das eine Farbe spezifiziert. array(0, 255, 0) wäre gleichbedeutend mit image::green; array(128, 255, 0) würde hingegen dazu führen, dass der Rot-Anteil des aktuellen Bildes die Helligkeit der per getpixel($x, $y, false) zurückgegebenen Pixel zu 33% aus macht, der Grün-Anteil hingegen 66%.
Original | Graustufen | |
---|---|---|
Roter Kanal | Grüner Kanal | Blauer Kanal |
<?php
image::thumbnail("nichtlustig.png", "lustig.gif", 500, 100, False);
?>
Fertig implementierte Algorithmen, die man in Kombination mit der Klasse laden und verwenden kann:
<?php
include("image.php");
include("image_invert.php");
$img = new image;
$img->createfromfile("bild.png");
$img->setchannel(Image::all)
->algorithm(new image_invert())
->save();
?>
<?php
include("image.php");
include("image_gauss.php");
$img = new image;
$img->createfromfile("bild.png");
$img->setchannel(Image::all)
->algorithm(new image_gauss())
->save();
?>
<?php
include("image.php");
include("image_laplace.php");
$img = new image;
$img->createfromfile("bild.png");
$img->setchannel(Image::green)
->algorithm(new laplace())
->save();
?>
<?php
include("image.php");
include("image_gauss.php");
include("image_sobel.php");
$img = new image;
$img->createfromfile("bild.png");
$algorithm = new image_sobel();
/*$algorithm->setthreshold(80);*/ /* filtert die dunkleren Kanten heraus */
/*$algorithm->setmaxbrightness(true); */ /* keine unterschiedlichen Kantenhelligkeiten, immer Maximum */
/*$algorithm->setcolors(false); */ /* deaktiviert farbige Markierungen der Kantenrichtungen */
$img->setchannel(array(90, 200, 10)) /* uebergebenes Array gibt fuer uns interessanteste Farbe an */
->algorithm(new image_gauss()) /* Unschaerfe! */
->algorithm($algorithm)
->save();
?>
Beachte: Hier wird auch ein Unschärfefilter angewendet, um das Rauschen zu verringern.
Damit die Kantendetektion Sinn gemacht hat, kann man dannach noch Formen in den Bildern suchen ;) Ein Beispiel dazu habe ich auch.
Wer einen Bildverarbeitungsalgorithmus implementieren möchte, muss häufig über jedes Pixel iterieren und benötigt zu den Pixeln Farbinformationen. Dann verändert man das Bild oder gibt eine Analyse aus. Farbinformationen zu jedem Pixel per $img->getpixel($x, $y) einzulesen ist vergleichsweise langsam, wer mehrmals auf ein Pixel zugreift sollte es deshalb in einer Variable zwischenspeichern. Wer zuviel Arbeitsspeicher hat und sich über Effektivität keine Gedanken macht kann alle Pixel in ein Array laden, das ist jedoch sehr langsam und braucht viel Arbeitsspeicher:
<?php
$img->setchannel(image::all);
$pixel = $img->pixel();
?>
Mit PHP jedes Pixel einzelnd einzulesen ist allgemein langsam und ineffizient. Sind die Pixelfarben einmal ausgelesen, geht alles schneller. Reicht der Arbeitsspeicher dafür nicht, was schon bei kleinen Bildern je nach festgelegter Grenze schnell passieren wird, geht gar nichts. Bildverarbeitungsalgorithmen in Kombination mit PHP sind nur zum Ausprobieren und Testen geeignet.
image::all legt hierbei fest, dass man an allen drei RGB-Werten interessiert ist. Das Array ist dreidimensional, auf erstem und zweitem Level stehen x- und y-Koordinaten, auf drittem die Farbwerte, Keys "red", "green" und "blue". Mit setchannel() kann man auch andere Farbkanäle festlegen, dann wird für "red", "green" und "blue" jeweils der gleiche Wert zurückgegeben.
$img->getpixel($x, $y, false) gibt die RGB-Werte einer Koordinate als Array zurück. Das false sagt, dass man den per setchannel() eingestellten Kanal wählt, ansonsten kann man auch einen anderen übergeben.
Die Klasse hat eine Funktion namens algorithm, der man eine Instanz einer eigenen Klasse übergeben kann, die das Interface imagealgorithm implementiert. Dieses sieht so aus:
<?php
interface imagealgorithm {
public function setoriginalimage(image $image);
public function option($get); /* return true or false */
public function algorithm($x, $y);
/* optional:
* public function setnewimage(image $image);
* public function return();
* possible options are:
* newimg (you want to replace the image by your own one but need
* the old one for information purposes)
* return (for own return value)
*/
}
?>
Die algorithm-Methode der image-Klasse wird über jedes Pixel im Bild iterieren und die algorithm-Methode der übergebenen Instanz aufrufen, mit momentaner x- und y-Koordinate als Parameter. Vorher übergibt sie per setoriginalimage() sich selbst und ein Array, in dem Farbinformationen zu allen Pixeln im Bild stehen an die andere Klasse, damit auf das ursprüngliche Bild zugegriffen werden kann. Die option-Methode verwendet die algorithm-Funktion der image-Klasse um zu bestimmen, wie sie mit der anderen Klasse interagieren soll. Gibt die andere Klasse bei option("newimg") true zurück, wird das eigene Bild am Ende mit einem von der fremden Klasse modifiziertem ersetzt. Diese muss dann eine setnewimage-Methode besitzen, der am Anfang eine neuerstellte image-Klasse übergeben wird. Die fremde Klasse kann dann die übergebene Klasse speichern, z. B. per createtruecolor sich ein neues Bild erzeugen und nach und nach in ihrer algorithm-Methode verändern.
Wer ausschließlich eine Maske auf jedes Pixel im Bild anwenden möchte kann das mit besonders wenig Programmcode tun, siehe Gauß-Beispiel.
Die Verwendung ist nicht so komplex wie wirr, Beispielklassen siehe oben, insbesondere das Beispiel zum Invertieren von Farben dürfte leicht verständlich sein.
Wer das alles viel zu umständlich findet oder sich nicht eindenken möchte kann natürlich auch die Klasse nur dazu verwenden, komfortabel auf die Bild-Informationen zugreifen zu können, und das Außenrum selbst implementieren. Bei den meisten Algorithmen sparrt man sich aber 10 bis 30 Zeilen, wenn man die algorithm()-Methode verwendet.
© 2009 Julian von Mendel (http://derjulian.net) | Datum: 05.11.2024