PHP-GD: Resize Transparent Image PNG & GIF
| Posted in Programming | Posted on 10-07-2008
48
By default, you will get black background if you resize a transparent image. To fix it, you need set alpha channel imagecolorallocatealpha to 127.
With imagecolorallocatealpha, it will allocate a color for an image.
Usage:
int imagecolorallocatealpha ( resource image, int red, int green, int blue, int alpha)
From PHP manual:
imagecolorallocatealpha() behaves identically to imagecolorallocate() with the addition of the transparency parameter alpha which may have a value between 0 and 127. 0 indicates completely opaque while 127 indicates completely transparent.
Returns FALSE if the allocation failed.
Before using it, you must set to false the blending mode for an image and set true the flag to save full alpha channel information.
Example:
-
<?
-
$newImg = imagecreatetruecolor($nWidth, $nHeight);
-
imagealphablending($newImg, false);
-
imagesavealpha($newImg,true);
-
$transparent = imagecolorallocatealpha($newImg, 255, 255, 255, 127);
-
imagefilledrectangle($newImg, 0, 0, $nWidth, $nHeight, $transparent);
-
imagecopyresampled($newImg, $im, 0, 0, 0, 0, $nWidth, $nHeight, $imgInfo[0], $imgInfo[1]);
-
?>
Full source code for resizing image:
-
<?
-
function resize($img, $w, $h, $newfilename) {
-
-
//Check if GD extension is loaded
-
if (!extension_loaded('gd') && !extension_loaded('gd2')) {
-
trigger_error("GD is not loaded", E_USER_WARNING);
-
return false;
-
}
-
-
//Get Image size info
-
$imgInfo = getimagesize($img);
-
switch ($imgInfo[2]) {
-
case 1: $im = imagecreatefromgif($img); break;
-
case 2: $im = imagecreatefromjpeg($img); break;
-
case 3: $im = imagecreatefrompng($img); break;
-
default: trigger_error('Unsupported filetype!', E_USER_WARNING); break;
-
}
-
-
//If image dimension is smaller, do not resize
-
if ($imgInfo[0] <= $w && $imgInfo[1] <= $h) {
-
$nHeight = $imgInfo[1];
-
$nWidth = $imgInfo[0];
-
}else{
-
//yeah, resize it, but keep it proportional
-
if ($w/$imgInfo[0] > $h/$imgInfo[1]) {
-
$nWidth = $w;
-
$nHeight = $imgInfo[1]*($w/$imgInfo[0]);
-
}else{
-
$nWidth = $imgInfo[0]*($h/$imgInfo[1]);
-
$nHeight = $h;
-
}
-
}
-
$nWidth = round($nWidth);
-
$nHeight = round($nHeight);
-
-
$newImg = imagecreatetruecolor($nWidth, $nHeight);
-
-
/* Check if this image is PNG or GIF, then set if Transparent*/
-
if(($imgInfo[2] == 1) OR ($imgInfo[2]==3)){
-
imagealphablending($newImg, false);
-
imagesavealpha($newImg,true);
-
$transparent = imagecolorallocatealpha($newImg, 255, 255, 255, 127);
-
imagefilledrectangle($newImg, 0, 0, $nWidth, $nHeight, $transparent);
-
}
-
imagecopyresampled($newImg, $im, 0, 0, 0, 0, $nWidth, $nHeight, $imgInfo[0], $imgInfo[1]);
-
-
//Generate the file, and rename it to $newfilename
-
switch ($imgInfo[2]) {
-
case 1: imagegif($newImg,$newfilename); break;
-
case 2: imagejpeg($newImg,$newfilename); break;
-
case 3: imagepng($newImg,$newfilename); break;
-
default: trigger_error('Failed resize image!', E_USER_WARNING); break;
-
}
-
-
return $newfilename;
-
}
-
?>
Script usage:
-
<?
-
include_once("resizeimage.php");
-
$image = "some/dir/image.png"; // File image location
-
$newfilename = "thumb_image.png"; // New file name for thumb
-
$w = 100;
-
$h = 100;
-
-
$thumbnail = resize($img, $w, $h, $newfilename);
-
-
echo "<img src='".$thumbnail."'>";
-
?>
No, i’m not provide any downloadable source-code.
Just copy-paste this code, and use it well.
–



wow just simple, it’s work !!! thanks
wow nice!!!
Fantastic job!
First, my english is a little…
I have a problem. Im trying to open a png file with a transparent object inside (not all, just the border). Then i write some text and save the file as another .png file.
The problem is that de quality of the object border is too bad (¿pixeled?). How can i fix that?
have u tried this code?
i have the same problem with you before.
the image quality is sooo bad.
but this code has fix it.
Many thanks! Just the help I needed.
The script gets hinkey if you have a file that is smaller in height than the minimum, but longer in width… you end up resizing huge in width to get the right height.
It needs to resize down by which ever length is too long, or both if they are both too long.
I HAVE AN IMPROVEMENT THAT FIXES THIS:
//If image dimension is smaller, do not resize
if ($imgInfo[0] <= $w && $imgInfo[1] = $w && $imgInfo[1] <= $h) {
$nWidth = $w;
$nHeight = $imgInfo[1]*($w/$imgInfo[0]);
}else{
//if h larger but not w, resize it, but keep it proportional
if ($imgInfo[0] = $h) {
$nWidth = $imgInfo[0]*($h/$imgInfo[1]);
$nHeight = $h;
}else{
//if both w and h are larger, resize it, but keep it proportional
if ($w/$imgInfo[0] > $h/$imgInfo[1]) {
$nWidth = $w;
$nHeight = $imgInfo[1]*($w/$imgInfo[0]);
}else{
$nWidth = $imgInfo[0]*($h/$imgInfo[1]);
$nHeight = $h;
}
}
}
}
$nWidth = round($nWidth);
$nHeight = round($nHeight);
this is one i’m looking for
Thnx for this great code!
Ahhh… just realised through lotsa testing that the line:
if ($w/$imgInfo[0] > $h/$imgInfo[1]) {
Should be
if ($w/$imgInfo[0] < $h/$imgInfo[1]) {
Gif -> Png transparent conversion failed.
From gif files it is not working.. It is making a gif file, even if I selected PNG. And it is not transparent.
Sorry, just had to removed the switches and directly let it to open as gif and save as png. It worked really fine. Just removed some if-s.
thats for sure, bro
thats it, man
Is anyone having a problem with transparent gifs background coming through black?
Specifically, this:
http://upload.wikimedia.org/wikipedia/commons/8/8d/Klocka_transparent.GIF
@oliver:
i’m having that problem too before.
but after using this code, the problem has gone.
try using this code without any modifying first.
Good Day,
I tried copying the code, without any changes, and uploading it, but it’s still black in the background. Can you try locally with that image:
http://upload.wikimedia.org/wikipedia/commons/8/8d/Klocka_transparent.GIF
Hi Oliver,
I have the same problem as you. I copied the code, didn’t make changes and it’s still black in the background. No idea what to do. Does anyone have an idea?
Stefan
I had the same issue, so (since I really don’t need it to be transparent) I forced it not to be transparent and just preserve whatever color the trasparent area was started as. Like transparent green shows green without transparency.
I believe the acctual issue is the fact that the transparent color is mandatorily white in this code, and none of my gifs ever end up with pure white as the transparent color after I optimize them. (Just my guess on the reason though.)
It has to do with the imagecreatetruecolor call. This call does not work with gifs, as a gif only has 256 colors. I tried to convert the gif to png, then resize it, and then re-convert back to gif, but that didn’t work. Anyone have any thoughts?
Hmmm, can you go into more detail though? My prob is I have a cms where users are uploading pics. Most of the time they’re non-transparent jpegs, gifs, or pngs, in which case it’s fine (even though the resizing/resampling of gifs loses alot of the quality).
If you use imagecreate instead of imagecreatetruecolor, you’ll get the transparent background, but like I said, the quality is awful.
If you’ve got image magick installed, you can use this:
$image = new Imagick($source);
$image->resizeImage($nWidth,$nHeight,imagick::FILTER_LANCZOS,1);
$image->writeImage($destination);
It makes it so the quality is slightly better, and still transparent. Only run that code if it’s a gif though; the qaulity goes down if it’s a png or jpeg.
I’m still looking for a specific function which will improve gif quality when it gets resized. I believe the route I need to go is to convert it to a png, resize, resample, get rid of opacity for the images, and the resave as gif.
Thoughts?
Here is the code section that doesn’t do transparent on the gif… it splits the IF PNG and the IF GIF into two sections:
/* Check if this image is PNG , then set if Transparent*/
if($imgInfo[2] == 3){
imagealphablending($newImg, false);
imagesavealpha($newImg,true);
$transparent = imagecolorallocatealpha($newImg, 255, 255, 255, 127);
imagefilledrectangle($newImg, 0, 0, $nWidth, $nHeight, $transparent);
}
/* Check if this image is GIF , then DONT transparent */
if($imgInfo[2] == 1){
imagealphablending($newImg, true);
imagesavealpha($newImg,false);
$transparent = imagecolorallocatealpha($newImg, 255, 255, 255, 127);
imagefilledrectangle($newImg, 0, 0, $nWidth, $nHeight, $transparent);
}
imagecopyresampled($newImg, $im, 0, 0, 0, 0, $nWidth, $nHeight, $imgInfo[0], $imgInfo[1]);
Oh! You probably will need this alteration too:
//Get Image size info
$imgInfo = getimagesize($img);
switch ($imgInfo[2]) {
case 1: $im = imagecreatefromgif($img); break;
case 2: $im = imagecreatefromjpeg($img); break;
case 3: $im = imagecreatefrompng($img); break;
default: $im = imagecreatefrombmp($img); break; // If it doesn’t fit a previous type, try it as a BMP
}
The BMP section is some custom function as below:
<? // Accept BMP FILES
function ConvertBMP2GD($src, $dest = false) {
if(!($src_f = fopen($src, “rb”))) {
trigger_error(“Can’t open $src”, E_WARNING);
return false;
}
if(!($dest_f = fopen($dest, “wb”))) {
trigger_error(“Can’t open $dest”, E_WARNING);
return false;
}
$header = unpack(“vtype/Vsize/v2reserved/Voffset”, fread($src_f, 14));
$info =
unpack(“Vsize/Vwidth/Vheight/vplanes/vbits/Vcompression/Vimagesize/Vxres/Vyr
es/Vncolor/Vimportant”, fread($src_f, 40));
extract($info);
extract($header);
if($type != 0x4D42) { // signature “BM”
return false;
}
$palette_size = $offset – 54;
$ncolor = $palette_size / 4;
$gd_header = “”;
// true-color vs. palette
$gd_header .= ($palette_size == 0) ? “\xFF\xFE” : “\xFF\xFF”;
$gd_header .= pack(“n2″, $width, $height);
$gd_header .= ($palette_size == 0) ? “\x01″ : “\x00″;
if($palette_size) {
$gd_header .= pack(“n”, $ncolor);
}
// no transparency
$gd_header .= “\xFF\xFF\xFF\xFF”;
fwrite($dest_f, $gd_header);
if($palette_size) {
$palette = fread($src_f, $palette_size);
$gd_palette = “”;
$j = 0;
while($j > 3;
$scan_line_align = ($scan_line_size & 0×03) ? 4 – ($scan_line_size & 0×03)
: 0;
if($bits == 24) {
{
$j = 0;
$k = 1;
$m = 2;
$function = ‘return “‘;
while($j < $scan_line_size) {
$function .= “\\{\$s\{$m}}\{\$s\{$k}}\{\$s\{$j}}”;
$j += 3;
$k += 3;
$m += 3;
}
$function .= ‘”;’;
}
else if($bits == 32) {
$function = ‘return “‘;
$j = 0;
$k = 1;
$m = 2;
$n = 3;
while($j < $scan_line_size) {
$function .= “\\{\$s\{$m}}\{\$s\{$k}}\{\$s\{$j}}”;
$j += 4;
$k += 4;
$m += 4;
$n += 4;
}
$function .= ‘”;’;
}
else if($bits ==
$function = ‘return $s;’;
}
else if($bits == 4) {
$j = 0;
$function = ”;
while($j >4);”;
$function .= “\$a[]=chr(\$b&0x0F);”;
$j++;
}
$function .= “return substr(implode(\$a), 0, \$width);”;
}
else if($bits == 1) {
$j = 0;
$function = ”;
while($j < $scan_line_size) {
$function .= “\$b=ord(\$s\{$j});”;
$function .= “\$a[]=chr((int)((\$b&0×80)!=0));”;
$function .= “\$a[]=chr((int)((\$b&0×40)!=0));”;
$function .= “\$a[]=chr((int)((\$b&0×20)!=0));”;
$function .= “\$a[]=chr((int)((\$b&0×10)!=0));”;
$function .= “\$a[]=chr((int)((\$b&0×08)!=0));”;
$function .= “\$a[]=chr((int)((\$b&0×04)!=0));”;
$function .= “\$a[]=chr((int)((\$b&0×02)!=0));”;
$function .= “\$a[]=chr((int)((\$b&0×01)!=0));\n”;
$j++;
}
$function .= “return substr(implode(\$a), 0, \$width);”;
}
$f = create_function(‘$s, $width’, $function);
for($i = 0, $l = $height – 1; $i varname = $url["host"];
$this->position = 0;
$this->buffer = @$GLOBALS[$this->varname];
return true;
}
function stream_close()
{
$GLOBALS[$this->varname] = $this->buffer;
}
function stream_read($count)
{
$ret = substr($this->buffer, $this->position, $count);
$this->position += strlen($ret);
return $ret;
}
function stream_write($data)
{
$this->buffer .= $data;
$this->position += strlen($data);
return strlen($data);
}
function stream_tell()
{
return $this->position;
}
function stream_eof()
{
return $this->position >= strlen($this->buffer);
}
function stream_stat() {
return array( ‘size’ => strlen($this->buffer) );
}
}
function imagecreatefrombmp($filename) {
// use a memory stream instead of a temp file
// where possible
if(function_exists(‘stream_wrapper_register’)
&& stream_wrapper_register(“mem”, “MemoryStream”)) {
$tmp_name = “mem://GD_TMP_FILE”;
$del_tmp = false;
}
else {
$tmp_name = tempnam(“/tmp”, “GD”);
$del_tmp = true;
}
if(ConvertBMP2GD($filename, $tmp_name)) {
$img = imagecreatefromgd($tmp_name);
if($del_tmp) {
unlink($tmp_name);
}
return $img;
} return false;
}
?>
and the Save section to handle the BMP looks like this:
$temp_array1 = explode(“.”, $img);
if (($temp_array1[1] != “bmp”)&&($temp_array1[1] != “BMP”)){
//Generate the file, and rename it to $newfilename
switch ($imgInfo[2]) {
case 1: imagegif($newImg,$newfilename); break;
case 2: imagejpeg($newImg,$newfilename); break;
case 3: imagepng($newImg,$newfilename); break;
default: trigger_error(‘Failed resize image!’, E_USER_WARNING); break;
}
}else{
imagepng($newImg,$newfilename); // Force it to save as a png type if it was a bmp but leave the .bmp extention
}
Err… it stuck in a smile where it is supposed to be ’8 )’
Here also is a sweet function that may be of use:
<? // Rotate
function rotateit($img, $angle) {
//Set the new file name the same as the old file name
$newfilename = $img;
//Get Image size info
$imgInfo = getimagesize($img);
switch ($imgInfo[2]) {
case 1: $im = imagecreatefromgif($img); break;
case 2: $im = imagecreatefromjpeg($img); break;
case 3: $im = imagecreatefrompng($img); break;
default: trigger_error(‘Unsupported filetype!’, E_USER_WARNING); break;
}
// .. what colour will the uncovered bits be?
$bgColour = 0xFFFFFF; // red
// rotate the image by $angle degrees
$newImg = imagerotate($im, $angle, $bgColour);
//Generate the file, and rename it to $newfilename
switch ($imgInfo[2]) {
case 1: imagegif($newImg,$newfilename); break;
case 2: imagejpeg($newImg,$newfilename); break;
case 3: imagepng($newImg,$newfilename); break; // This will rotate any that are BMP but are loaded up into PNG Type
default: trigger_error(‘Failed to rotate image!’, E_USER_WARNING); break;
}
echo “Image Rotated: ” . $newfilename . ” “;
return $newfilename;
}
?>
So you’re not using the transparent gif?
So for example, if someone uploaded this file, what would your code do?
http://upload.wikimedia.org/wikipedia/commons/8/8d/Klocka_transparent.GIF
the transparent part would be gray like it looks if you open it in an editor program.
See the slight gray in the resize here:
http://cecolts.com/ofiles/Klocka_transparent_S.gif
hmmmm
there’s no way around that i guess eh?
Not that I see unless you use the orrigional code and make sure all your transparent areas are pure white.
That sucks.
What I don’t get, is I can accomplish the task in photoshop. I take the 300×300 gif, turn it into a png, resize it to 72×72, then turn it back to a gif, and save it.
Transparency is preserved, resize quality is perfect. There must be a way somehow in php. I’ve been looking around with image magick, but can’t seem to find it (nor is this documented anywhere online, oddly enough; gif resizing is, but not the kind of quality maintenance you get from photoshop)
I’m still stuck on trying to get gifs to resize perfectly. Thats wsweet about the bmp’s though. I’ll test that out and see how they resize
Finally, someone who has got this right. This code can resize a png with aphablending properly. I’ve been looking for this for so long, and have tried around 6 examples. Well done and thank you!
The only thing I would like is to be able to select a max width (trying to add this myself). If you select 120,120 in the function you get an image which might be 120×147 for example, too big for my purposes.
As Posted Above (with later correction), reposted for Dan.
This section does what you need.
//If image dimension is smaller, do not resize
if ($imgInfo[0] <= $w && $imgInfo[1] = $w && $imgInfo[1] <= $h) {
$nWidth = $w;
$nHeight = $imgInfo[1]*($w/$imgInfo[0]);
}else{
//if h larger but not w, resize it, but keep it proportional
if ($imgInfo[0] = $h) {
$nWidth = $imgInfo[0]*($h/$imgInfo[1]);
$nHeight = $h;
}else{
//if both w and h are larger, resize it, but keep it proportional
if ($w/$imgInfo[0] < $h/$imgInfo[1]) {
$nWidth = $w;
$nHeight = $imgInfo[1]*($w/$imgInfo[0]);
}else{
$nWidth = $imgInfo[0]*($h/$imgInfo[1]);
$nHeight = $h;
}
}
}
}
$nWidth = round($nWidth);
$nHeight = round($nHeight);
Hi,
Many thanks for the function … I’ll be using it later in ePinoyBiz.com/directory …
Finally i found it….tahnk mate
thanks for your tutorial
yes! just what i was looking for. many thanks.
Man you rock!!!! Thank you very very much for your script!!!
One thing about the transparent gifs, I am pretty sure you cannot preserve transparency AND use imagecopyresampled. I am having the same problem with black background, however changing imagecopyresampled to imagecopyresized fixes transparency, but gives a crappy resize. Am investigating this further to see if there is a good solution.
I currently have all my functions setup to resize whatever size I need – jpg mime type is cool – but I get jagged edges – this is wher IM HOPING this nifty lil script can save my ass – but for the life of me I can’t seem to figure how to implemant it – I copied and pasted and got tons of warnings.
[php]
Warning: Unsupported filetype! in C:\wamp\www\cool\functions\fns_photo.php on line 228
Warning: imagecreatetruecolor() [function.imagecreatetruecolor]: Invalid image dimensions in C:\wamp\www\cool\functions\fns_photo.php on line 268
Warning: imagecopyresampled(): supplied argument is not a valid Image resource in C:\wamp\www\cool\functions\fns_photo.php on line 286
Warning: Failed resize image! in C:\wamp\www\cool\functions\fns_photo.php on line 300
[/php]
it seems It;s not getting the image I need to set – but how do I do that…
Greatly appreciated if anyone can help
thanks
sorry jagged edges with png and gif
The best information i have found exactly here. Keep going Thank you
Well done! Thanks a lot!
Thank you so much
Большое пасибо!
[...] LinkedIn [...]
just want to say a great script, i ever found thanks dude
I was looking for this problem and this helped me. thank you