Programming & Webscripting FAQ: Image Manipulatie in PHP
Links
- http://nl2.php.net/manual/en/ref.image.php
Referentie naar alle GD-functies van PHP
- http://www.boutell.com/gd/
De officiële site van de GD-library
- http://www.imagemagick.org
Alternatief voor GD
FAQ
- Waarom kan ik geen GIF files (meer) maken?
- PHP zegt dat een GD-functie niet bestaat?
- WBMP? Waar staat dat voor?
- Waarom is mijn image corrupt?
- Waarom vermindert resizen van een image de kwaliteit?
- Ik wil tekst centreren op mijn plaatje. Hoe doe ik dat?
- Ik genereer plaatjes on the fly, en dit is erg langzaam. Wat nu?
- Waarom gaan JPEG files die geupload zijn met IE fout?
Onverwachte problemen bij het controleren op content-type
- Waarom zien mijn PNG's in IE anders uit dan in andere browsers?
Transparantie vs. Alpha Blending
- Ik vind GD te traag. Zijn er alternatieven?
Over ImageMagick
Waarom kan ik geen GIF files (meer) maken?
Zoals je onder andere op deze site kunt lezen, maakt het GIF-formaat gebruik van het LZW compressiealgoritme. Dit algoritme is echter gepatenteerd door Unisys, en zodra het GIF bestandsformaat een beetje populair begon te worden, is dit bedrijf geld in rekening gaan brengen voor licenties om dit algoritme te blijven gebruiken.
Om bovenstaande reden hebben veel makers van gratis tools, waaronder ook GD, besloten om GIF support uit hun tools te halen, totdat het LZW patent in juli 2004 verlopen was. Dit betekent dat de versies van GD die voor versie 1.6 uitgebracht zijn GIF support hadden, en ook alle versies vanaf versie 2.0.28. Heb je een versie die daar tussenin ligt, dan kun je helaas geen GIF images maken met GD.
PHP zegt dat een GD-functie niet bestaat?
Je leest dit waarschijnlijk omdat je een error zoals deze voor je neus hebt: Fatal error: Call to undefined function: imagecreatefromjpeg(). Deze foutmelding kan in principe door twee dingen veroorzaakt worden:
- Je hebt PHP niet ingesteld met GD-support.
- Je gebruikt een versie van PHP die deze functie niet ondersteunt.
Het eerste geval is te herkennen aan het feit dat er geen kopje "gd" te voorschijn komt als je je phpinfo bekijkt. Wanneer GD support gewoon werkt, zie je iets als dit verschijnen:
GD Support | enabled |
---|---|
GD Version | bundled (2.0.23 compatible) |
FreeType Support | enabled |
FreeType Linkage | with freetype |
FreeType Version | 2.1.5 |
GIF Read Support | enabled |
JPG Support | enabled |
PNG Support | enabled |
WBMP Support | enabled |
XBM Support | enabled |
Vanaf PHP 4.3.0 kun je deze informatie ook opvragen met de functie gd_info.
Krijg je bovenstaande info niet te zien, dan moet je afhankelijk van je OS wat handelingen verrichten. Windowsgebruikers zorgen dat er géén puntkomma staat voor de volgende regel van php.ini:
1
| extension=php_gd2.dll |
Linuxgebruikers moeten ervoor zorgen dat PHP gecompileerd is met --with-gd=/usr/local als schakeloptie.
Een andere reden waardoor de betreffende functie mogelijk niet werkt, kan zijn dat deze pas in een latere versie van PHP ondersteund wordt. Veel functies die gebruik maken van de GD-library zijn pas sinds PHP 4.3.0 of soms zelfs later ondersteunt, wat betekent dat je server redelijk up to date moet zijn om alle features te kunnen benutten. Controleer je PHP-versie met behulp van phpinfo of phpversion. Welke versie van PHP je nodig hebt voor de functie in kwestie kun je eenvoudigweg zien door de online manual open te slaan op de gebruikelijke manier: http://php.net/functienaam.
WBMP? Waar staat dat voor?
Zoals je in deze user note uit de documentatie van imagecreatefromwbmp kan lezen, staat WBMP niet voor Windows Bitmap, maar voor Wireless Bitmap. Dit betekent dus ook dat je niet de denkfout moet maken dat het content-type image/bmp moet zijn, maar juist image/vnd.wap.wbmp.
Waarom is mijn image corrupt?
Er zijn enkele redenen te bedenken waarom een image niet verschijnt, of een broken image is in je browser.
De meest voorkomende bug is nog dat je uitvoer voor de openingstag van PHP hebt staan, of achter de sluittag. Wanneer je een plaatje afdrukt, gebruik je sowieso een de functie header om het content-type in te stellen. Voor het versturen van headers mag er geen enkele uitvoer naar de browser verstuurd zijn. Bovendien levert het ook hoe dan ook een corrupte image op, aangezien deze uitvoer als onderdeel van het plaatje gezien zou worden. Let er op dat spaties en enters óók uitvoer zijn!
Fout:
1
2
3
4
5
6
7
8
9
| <!-- image creation script --> <?php header ( 'Content-type: image/jpeg' ); // foutmelding $image = imagecreatefromjpeg ( 'melp.jpg' ); imagejpeg ( $image ); ?> |
Goed:
1
2
3
4
5
6
7
| <?php header ( 'Content-type: image/jpeg' ); $image = imagecreatefromjpeg ( 'melp.jpg' ); imagejpeg( $image ); ?> |
Een andere reden voor broken images kan zijn dat je script een error afdrukt terwijl het met het plaatje aan het werken is. Als je de content-type header verstuurt, en je script laat daarna een error zien, dan wordt het plaatje corrupt. Laat de content-type header even weg, en kijk wat je script uitvoert zonder die header.
Waarom vermindert resizen van een image de kwaliteit?
Waarschijnlijk gebruik je nu de functie imagecopyresized. Deze functie resizet weliswaar je afbeelding, maar de snelheid die de functie met zich meebrengt pakt negatief uit voor de kwaliteit van de resulterende afbeelding. Wanneer kwaliteit belangrijk is, gebruik dan imagecopyresampled.
Ik wil tekst centreren op mijn plaatje. Hoe doe ik dat?
Er zijn helaas geen standaard functies om tekst te centreren op een afbeelding. Echter, met een vrij simpele toepassing van basisschoolwiskunde kom je er ook wel.
1
2
3
4
5
| function ImageStringCenter ( $im, $font, $width, $y, $text, $color ) { $x = ( $width - ( imagefontwidth ( $font ) * strlen ( $text ) ) ) / 2; imagestring ( $im, $font, $x, $y, $text, $color ); } |
Je trekt simpelweg de breedte van een letter maal het aantal letters af van de totale breedte van je afbeelding, en deelt daar de uitkomst van door 2. Op die manier kom je op een x-coördinaat uit die even ver van het midden af ligt als het einde van de string.
Denk er wel aan dat dit alleen goed werkt met fixed-width lettertypen. Je kan deze functie ook gebruiken met truetype fonts, maar hou er dan wel rekening mee dat de uitlijning niet perfect is.
Ik genereer plaatjes on the fly, en dit is erg langzaam. Wat nu?
Een van de grote nadelen van de GD-library is dat die vrij traag is. Een image van 1280x960 verkleinen naar 640x480 duurt op sommige systemen al gauw een seconde. Een image gallery maken waarin je thumbnails on the fly aanmaakt is dus geen goed idee.
Het beste wat je kan doen is zorgen dat de images eenmalig verkleind worden tot thumbnails, die je vervolgens gewoon opslaat op het filesystem. Dit komt de performance behoorlijk ten goede.
Waarom gaan JPEG files die geupload zijn met IE fout?
Als je in je uploadscript een beveiliging hebt ingebouwd die kijkt naar het content-type van een image, dan heb je waarschijnlijk iets in deze trant:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| $tmp = $_FILES['bestand']['tmp_name']; switch ( $contentType ) { case 'image/gif': $img = ImageCreateFromGIF ( $tmp ); break; case 'image/jpeg': $img = ImageCreateFromJPEG ( $tmp ); break; case 'image/png': $img = ImageCreateFromPNG ( $tmp ); break; } |
Je zult zien dat bovenstaande code fout uitpakt bij JPEG files die geupload zijn met Internet Explorer. Waarom? Nou, het blijkt dat Internet Explorer bij het uploaden van een JPEG file niet het image/jpeg content-type zet, maar image/pjpeg. Je zult je code dus iets moeten uitbreiden:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| $tmp = $_FILES['bestand']['tmp_name']; switch ( $contentType ) { case 'image/gif': $img = ImageCreateFromGIF ( $tmp ); break; case 'image/jpeg': case 'image/pjpeg': $img = ImageCreateFromJPEG ( $tmp ); break; case 'image/png': $img = ImageCreateFromPNG ( $tmp ); break; } |
Waarom zien mijn PNG's in IE anders uit dan in andere browsers?
Zoals je misschien wel weet heeft Internet Explorer in elk geval tot en met versie 6 problemen met het correct weergeven van PNG's die een alpha channel bevatten. Met het alpha channel kun je een extra waarde opnemen voor elke pixel die de transparantie van die pixel bepaalt.
Wanneer je echter een plaatje maakt met een alpha channel erin, en je probeert dat te bekijken in Internet Explorer, dan zul je waarschijnlijk een aantal grijze vlekken zien. Dit komt dus omdat Internet Explorer dat alpha channel niet correct kan lezen.
Als je het alpha channel nodig hebt, dan kun je beter proberen om een CSS hack te schrijven voor IE, of je kan proberen om met kleuren te spelen, waardoor je in het uiteindelijke plaatje dat je af gaat drukken geen alpha channel meer nodig hebt.
Als je überhaupt geen alpha channel nodig hebt, omdat je alleen maar één kleur volledig transparant wil maken, en verder niets, dan kun je de functie imagecolortransparent proberen te gebruiken. Vermijd in dat geval de functies waarin iets gedaan wordt met het alpha channel.
Overigens worden er ook regelmatig problemen geconstateerd met alpha blending en 24-bits PNG's. Zie ook deze note op php.net.
Ik vind GD te traag. Zijn er alternatieven?
Het meest gebruikte alternatief voor GD is ImageMagick. Dit is een commandline tool die oorspronkelijk voor Linux-varianten geschreven is, maar intussen ook is geport naar Windows. Het gebruik is vrij simpel:
1
| system( 'convert "' . $fromFile . '" "' . $toFile . '"', $retVal ); |
ImageMagick kan behalve met files ook met streams werken, en het ondersteunt talloze formaten; meer dan GD in elk geval.
Voor meer informatie over ImageMagick kun je terecht in de man pages die ervoor geschreven zijn.
[ Voor 101% gewijzigd door NMe op 20-07-2005 03:53 ]
'E's fighting in there!' he stuttered, grabbing the captain's arm.
'All by himself?' said the captain.
'No, with everyone!' shouted Nobby, hopping from one foot to the other.