I make thumbnails using PHP and GD library but my code turn png transparency into a solid black color, Is there a solution to improve my code?
this is my php thumbnail maker code:
function cropImage($nw, $nh, $source, $stype, $dest) {
$size = getimagesize($source);
$w = $size[0];
$h = $size[1];
switch($stype) {
case 'gif':
$simg = imagecreatefromgif($source);
break;
case 'jpg':
$simg = imagecreatefromjpeg($source);
break;
case 'png':
$simg = imagecreatefrompng($source);
break;
}
$dimg = imagecreatetruecolor($nw, $nh);
$wm = $w/$nw;
$hm = $h/$nh;
$h_height = $nh/2;
$w_height = $nw/2;
if($w> $h) {
$adjusted_width = $w / $hm;
$half_width = $adjusted_width / 2;
$int_width = $half_width - $w_height;
imagecopyresampled($dimg,$simg,-$int_width,0,0,0,$adjusted_width,$nh,$w,$h);
} elseif(($w <$h) || ($w == $h)) {
$adjusted_height = $h / $wm;
$half_height = $adjusted_height / 2;
$int_height = $half_height - $h_height;
imagecopyresampled($dimg,$simg,0,-$int_height,0,0,$nw,$adjusted_height,$w,$h);
} else {
imagecopyresampled($dimg,$simg,0,0,0,0,$nw,$nh,$w,$h);
}
imagejpeg($dimg,$dest,100);
}
Thank you
After imagecreatetruecolor():
<?php
// ... Before imagecreatetruecolor()
$dimg = imagecreatetruecolor($width_new, $height_new); // png ?: gif
// start changes
switch ($stype) {
case 'gif':
case 'png':
// integer representation of the color black (rgb: 0,0,0)
$background = imagecolorallocate($dimg , 0, 0, 0);
// removing the black from the placeholder
imagecolortransparent($dimg, $background);
// turning off alpha blending (to ensure alpha channel information
// is preserved, rather than removed (blending with the rest of the
// image in the form of black))
imagealphablending($dimg, false);
// turning on alpha channel information saving (to ensure the full range
// of transparency is preserved)
imagesavealpha($dimg, true);
break;
default:
break;
}
// end changes
$wm = $w/$nw;
$hm = $h/$nh;
// ...
if the code of the correct answer don't work try this :
//After imagecreatetruecolor():
$white = imagecolorallocate($dimg, 255, 255, 255);
imagefill($dimg,0,0,$white);
The order of operations is important. for .gif images i found that i needed to copy resized image first, then assign the black background as transparent. for PNGs I found the code below resized images and kept the transparency backgrounds.
also, this code worked for me...
$resized_image = imagecreatetruecolor($target_width, $target_height);
switch ( $asset->a_mime_type )
{
case 'image/jpeg':
imagecopyresampled($resized_image, $source, 0, 0, 0, 0, $target_width, $target_height, $asset->a_image_width, $asset->a_image_height);
$r = imagejpeg($resized_image,$file_name);
break;
case 'image/png':
imagealphablending($resized_image, FALSE);
imagesavealpha($resized_image, TRUE);
imagecopyresampled($resized_image, $source, 0, 0, 0, 0, $target_width, $target_height, $asset->a_image_width, $asset->a_image_height);
$r = #imagepng($resized_image,$file_name);
break;
case 'image/gif':
imagecopyresampled($resized_image, $source, 0, 0, 0, 0, $target_width, $target_height, $asset->a_image_width, $asset->a_image_height);
$background = imagecolorallocate($resized_image, 0, 0, 0);
imagecolortransparent($resized_image, $background);
$r = #imagegif($resized_image,$file_name);
break;
}
Sometimes if the .jpg image got small errors inside (you cannot see that), all transparent pixels turn to black color.Try to use:
ini_set('gd.jpeg_ignore_warning', 1);
Just add this line :
imagesavealpha($image, true);
before
imagepng($image)
Here is my total test code. It works for me
$imageFileType = pathinfo($_FILES["image"]["name"], PATHINFO_EXTENSION);
$filename = 'test.' . $imageFileType;
move_uploaded_file($_FILES["image"]["tmp_name"], $filename);
$source_image = imagecreatefromjpeg($filename);
$source_imagex = imagesx($source_image);
$source_imagey = imagesy($source_image);
$dest_imagex = 400;
$dest_imagey = 600;
$dest_image = imagecreatetruecolor($dest_imagex, $dest_imagey);
imagecopyresampled($dest_image, $source_image, 0, 0, 0, 0, $dest_imagex, $dest_imagey, $source_imagex, $source_imagey);
imagesavealpha($dest_image, true);
$trans_colour = imagecolorallocatealpha($dest_image, 0, 0, 0, 127);
imagefill($dest_image, 0, 0, $trans_colour);
imagepng($dest_image,"test1.png",1);
change rgb to 255, it will give you transparent image, rather then black.
<?php
switch ($stype)
{
case "png":
// integer representation of the color black (rgb: 0,0,0)
$background = imagecolorallocate($simage, 255, 255, 255);
// removing the black from the placeholder
imagecolortransparent($simage, $background);
// turning off alpha blending (to ensure alpha channel information is preserved, rather than removed (blending with the rest of the image in the form of black))
imagealphablending($simage, false);
// turning on alpha channel information saving (to ensure the full range of transparency is preserved)
imagesavealpha($simage, true);
break;
case "gif":
// integer representation of the color black (rgb: 0,0,0)
$background = imagecolorallocate($simage, 255, 255, 255);
// removing the black from the placeholder
imagecolortransparent($simage, $background);
break;
}
?>
Some of the above made the black parts of the image turn white, while some didn't work at all. This, however, worked for me https://github.com/claviska/SimpleImage/issues/28
Related
First, I'm not master of PHP. I'm using a function for resize and crop images. It's working perfectly until I upload a transparent png. :)
It saves the png with black background. I found some answers on stackoverflow but I can't combine it with my codes.
Here is my function:
//resize and crop image
function resize_crop_image($max_width, $max_height, $source_file, $dst_dir, $quality = 90){
$imgsize = getimagesize($source_file);
$width = $imgsize[0];
$height = $imgsize[1];
$mime = $imgsize['mime'];
switch($mime){
case 'image/gif':
$image_create = "imagecreatefromgif";
$image = "imagegif";
$format = "gif";
break;
case 'image/png':
$image_create = "imagecreatefrompng";
$image = "imagepng";
$quality = 7;
$format = "png";
break;
case 'image/jpeg':
$image_create = "imagecreatefromjpeg";
$image = "imagejpeg";
$format = "jpg";
break;
default:
return false;
break;
}
$dst_img = imagecreatetruecolor($max_width, $max_height);
$src_img = $image_create($source_file);
$width_new = $height * $max_width / $max_height;
$height_new = $width * $max_height / $max_width;
//if the new width is greater than the actual width of the image, then the height is too large and the rest cut off, or vice versa
if($width_new > $width){
//cut point by height
$h_point = (($height - $height_new) / 2);
//copy image
imagecopyresampled($dst_img, $src_img, 0, 0, 0, $h_point, $max_width, $max_height, $width, $height_new);
}else{
//cut point by width
$w_point = (($width - $width_new) / 2);
imagecopyresampled($dst_img, $src_img, 0, 0, $w_point, 0, $max_width, $max_height, $width_new, $height);
}
// you can ignore these 4 lines. I'm using it for change the name.
$nameforimage = rand('11111111', '9999999999');
$nameforimage2 = rand('11111111', '9999999999');
$newname = $nameforimage."_".$nameforimage2;
$newdir = $dst_dir."".$newname.".".$format;
$image($dst_img, $newdir, $quality);
if($dst_img)imagedestroy($dst_img);
if($src_img)imagedestroy($src_img);
return $newname.".".$format;
}
EDIT:
Okay I've found a solution.
Just add these lines:
imagealphablending($dst_img, false);
imagesavealpha($dst_img, true);
$transparent = imagecolorallocatealpha($dst_img, 255, 255, 255, 127);
imagefilledrectangle($dst_img, 0, 0, $max_width, $max_height, $transparent);
After this line:
$dst_img = imagecreatetruecolor($max_width, $max_height);
You have to enable saving the alpha channel.
It can be done with imagesavealpha(), e.g.:
// As per the manual, alpha blending must be disabled
imagealphablending($dst_img, false);
imagesavealpha($dst_img, true);
I created a function that takes images, resizes them to fit at least one dimension perfectly onto a canvas and finally crops out excess image content.
Process:
Take a 640x400 image
Scale image fit into 450x450 canvas (image is now 450x281)
Crop out excess data if any
The problem I'm encountering currently involves images that are too small for the newly created thumbnail (such as the one provided in the example above). I expected the output to either have a white background(JPGs) or a transparent background(PNGs). However, despite my best efforts, this tends to be the resulting mess:
As can be observed, the image has a black background in place of a transparent/white background. I am completely stumped on how to correct this flaw.
A copy of my code:
function create_thumbnail($path, $saveto, $width, $height) {
ini_set('memory_limit', '128M'); //Unlocking more memory for download
$info = getimagesize($path);
$rate = $info[0]/$info[1];
// Determine image size/position
if ($info[0] < $width || $info[1] < $height) {
// Image is too small
if ($info[0] < $width && $info[1] < $height) {
// Both width and height too small
$nw = $info[0];
$nh = $info[1];
} else if ($info[0] < $width) {
// Width is too small
$nw = ($info[0]*$height)/$info[1];
$nh = $height;
} else if ($info[1] < $height) {
// Height is too small
$nw = $width;
$nh = ($info[1]*$width)/$info[0];
}
} else {
// Image fits
if (($width/$height) > $rate) {
$nw = $width;
$nh = $width/$rate;
} else {
$nw = $height*$rate;
$nh = $height;
}
}
$nw = round($nw);
$nh = round($nh);
$x_mid = round($nw/2);
$y_mid = round($nh/2);
switch($info[2]) {
case IMAGETYPE_PNG :
$src = imagecreatefrompng($path);
break;
case IMAGETYPE_JPEG :
$src = imagecreatefromjpeg($path);
break;
case IMAGETYPE_GIF :
$src = imagecreatefromgif($path);
break;
default :
return false;
}
// Create image
$proc = imagecreatetruecolor($nw, $nh);
$clr = imagecolorallocate($proc, 255, 255, 255);
imagefill($proc, 0, 0, $clr);
imagecopyresampled($proc, $src, 0, 0, 0, 0, $nw, $nh, $info[0], $info[1]);
$thmb = imagecreatetruecolor($width, $height);
$clr = imagecolorallocate($thmb, 255, 255, 255);
imagefill($thmb, 0, 0, $clr);
imagecopyresampled($thmb, $proc, 0, 0, ($x_mid-($width/2)), ($y_mid-($height/2)), $width, $height, $width, $height);
if ($info[2] == IMAGETYPE_PNG || $info[2] == IMAGETYPE_GIF) {
$trnprt_idx = imagecolortransparent($src);
if ($trnprt_idx >= 0) {
// Attempt to forcefully correct transparencies using original image's color index
$trnprt_clr = imagecolorsforindex($src, $trnprt_idx);
$trnprt_idx = imagecolorallocate($thmb, $trnprt_clr['red'], $trnprt_clr['green'], $trnprt_clr['blue']);
imagefill($thmb, 0, 0, $trnprt_idx);
imagecolortransparent($thmb, $trnprt_idx);
imagealphablending($thmb, false);
imagesavealpha($thmb, true);
} else if ($info[2] == IMAGETYPE_PNG) {
// Attempt to forcefully correct transparencies by shutting down blending
$clr = imagecolorallocatealpha($thmb, 0, 0, 0, 127);
imagefill($thmb, 0, 0, $clr);
imagealphablending($thmb, false);
imagesavealpha($thmb, true);
}
}
switch($info[2]) {
case IMAGETYPE_PNG :
imagepng($thmb, $saveto);
break;
case IMAGETYPE_JPEG :
imagejpeg($thmb, $saveto, 100);
break;
case IMAGETYPE_GIF :
imagegif($thmb, $saveto);
break;
default :
return false;
}
return true;
} //End of create_thumbnail()
I have attempted to correct the transparency/coloring (as visible in my code), but it only affects one side of the image. Everything I have tried has either resulting in one side having a transparent/white background or both sides being completely black.
After a long time spent playing around trying to figure out what exactly was going on and breaking, I have found the solution.
The problem is here:
$proc = imagecreatetruecolor($nw, $nh);
$clr = imagecolorallocate($proc, 255, 255, 255);
imagefill($proc, 0, 0, $clr);
imagecopyresampled($proc, $src, 0, 0, 0, 0, $nw, $nh, $info[0], $info[1]);
$thmb = imagecreatetruecolor($width, $height);
$clr = imagecolorallocate($thmb, 255, 255, 255);
imagefill($thmb, 0, 0, $clr);
imagecopyresampled($thmb, $proc, 0, 0, ($x_mid-($width/2)), ($y_mid-($height/2)), $width, $height, $width, $height);
The newly created image $proc was not transferring it's transparency over to $thmb when I was doing imagecopyresampled from one to the other. The solution I found was to either skip creating/using $thmb altogether, or to save $proc as a png/gif first, then use that saved image for imagecopyresample.
I am using PHP and GD to crop and output an image with the code below. it works fine but when i pass a transparent PNG into it i get a black background generated. How can i stop this?
//setup
switch ($source_type) {
case IMAGETYPE_JPEG: $source = imagecreatefromjpeg($img_path); break;
case IMAGETYPE_PNG: $source = imagecreatefrompng($img_path); break;
}
// setup cropped destination
$cropped = imagecreatetruecolor($cropped_width, $cropped_height);
// create cropped image
$x = (($source_width / 100) * IMAGE_X) - ($cropped_width / 2);
$y = (($source_height / 100) * IMAGE_Y) - ($cropped_height / 2);
imagecopy(
$cropped,
$source,
0, 0,
$x, $y,
$cropped_width, $cropped_height
);
// output inc header
header('Content-type: image/jpeg');
imagejpeg($cropped);
It should be something along the lines of:
switch ($source_type)
{
case IMAGETYPE_PNG:
$background = imagecolorallocate($source, 0, 0, 0);
// remove the black
imagecolortransparent($source, $background);
// turn off alpha blending
imagealphablending($source, false);
imagesavealpha($source, true);
break;
}
There is a similar question here
I am trying to allow the uploading of transparent profile pictures (PNGs and GIFs) on my site because it is sometimes quite annoying for the user to upload a transparent profile picture and the transparent areas become black. The problem is that the transparency is still being lost even after using the imagealpha*() functions.
I do realize that there are other questions about this, but the answers on them aren't working for me.
Here is my code:
// [...]
switch(strtolower($_FILES['picture']['type'])) {
case 'image/jpeg':
$image = imagecreatefromjpeg($_FILES['picture']['tmp_name']);
break;
case 'image/png':
$image = imagecreatefrompng($_FILES['picture']['tmp_name']);
break;
case 'image/gif':
$image = imagecreatefromgif($_FILES['picture']['tmp_name']);
break;
default:
msg('Sorry, but the type of file that you selected is not allowed. We only allow JPEG, PNG, and GIF.','error');
header("Location: /settings/profile");
exit;
}
// Target dimensions
$max_width = 143;
$max_height = 143;
// Get current dimensions
$old_width = imagesx($image);
$old_height = imagesy($image);
// Calculate the scaling we need to do to fit the image inside our frame
$scale = min($max_width/$old_width, $max_height/$old_height);
// Get the new dimensions
$new_width = ceil($scale*$old_width);
$new_height = ceil($scale*$old_height);
// Create new empty image
$new = imagecreatetruecolor($new_width, $new_height);
// Resize old image into new
imagecopyresampled($new, $image, 0, 0, 0, 0, $new_width, $new_height, $old_width, $old_height);
$file_name = 'avatar_'.randString(20).mt_rand(111,999).'.'.str_replace('image/','',$_FILES['picture']['type']);
switch(strtolower($_FILES['picture']['type'])) {
case 'image/jpeg':
$img = imagejpeg($new, 'user/uploads/'.$file_name, 95);
break;
case 'image/png':
imagealphablending($new, false);
imagesavealpha($new, true);
$img = imagepng($new, 'user/uploads/'.$file_name, 95);
break;
case 'image/gif':
imagealphablending($new, false);
imagesavealpha($new, true);
$img = imagegif($new, 'user/uploads/'.$file_name);
break;
}
imagedestroy($image);
imagedestroy($new);
if($img) {
$dbUpdate = mysql_query("UPDATE users SET user_pic = '$file_name' WHERE uid = $userid");
}
if($img && $dbUpdate) {
msg("Your profile picture has been changed successfully.","success");
header("Location: /settings/profile");
exit;
}
// [...]
I tried uploading this GIF just for testing:
But it lost its transparency after it was uploaded:
I am trying to keep the transparency information with it, but it doesn't seem to be working. Am I not doing something right?
Thanks in advance.
Create a transparent color and fill the $new image with that color before the copy. If you don't do that, the background color of the new image will default to black.
$new = imagecreatetruecolor($new_width, $new_height);
$transparent = imagecolorallocatealpha($new, 0, 0, 0, 127);
imagefill($new, 0, 0, $transparent);
imagealphablending($new, true);
You can also check this question
Current background is black. How to change the color to be white?
#assuming the mime type is correct
switch ($imgtype) {
case 'image/jpeg':
$source = imagecreatefromjpeg($source_image);
break;
case 'image/gif':
$source = imagecreatefromgif($source_image);
break;
case 'image/png':
$source = imagecreatefrompng($source_image);
break;
default:
die('Invalid image type.');
}
#Figure out the dimensions of the image and the dimensions of the desired thumbnail
$src_w = imagesx($source);
$src_h = imagesy($source);
#Do some math to figure out which way we'll need to crop the image
#to get it proportional to the new size, then crop or adjust as needed
$width = $info[0];
$height = $info[1];
$x_ratio = $tn_w / $src_w;
$y_ratio = $tn_h / $src_h;
if (($x_ratio * $height) < $tn_w) {
$new_h = ceil($x_ratio * $height);
$new_w = $tn_w;
} else {
$new_w = ceil($y_ratio * $width);
$new_h = $tn_h;
}
$x_mid = $new_w / 2;
$y_mid = $new_h / 2;
$newpic = imagecreatetruecolor(round($new_w), round($new_h));
imagecopyresampled($newpic, $source, 0, 0, 0, 0, $new_w, $new_h, $src_w, $src_h);
$final = imagecreatetruecolor($tn_w, $tn_h);
imagecopyresampled($final, $newpic, 0, 0, ($x_mid - ($tn_w / 2)), ($y_mid - ($tn_h / 2)), $tn_w, $tn_h, $tn_w, $tn_h);
#if we need to add a watermark
if ($wmsource) {
#find out what type of image the watermark is
$info = getimagesize($wmsource);
$imgtype = image_type_to_mime_type($info[2]);
#assuming the mime type is correct
switch ($imgtype) {
case 'image/jpeg':
$watermark = imagecreatefromjpeg($wmsource);
break;
case 'image/gif':
$watermark = imagecreatefromgif($wmsource);
break;
case 'image/png':
$watermark = imagecreatefrompng($wmsource);
break;
default:
die('Invalid watermark type.');
}
#if we're adding a watermark, figure out the size of the watermark
#and then place the watermark image on the bottom right of the image
$wm_w = imagesx($watermark);
$wm_h = imagesy($watermark);
imagecopy($final, $watermark, $tn_w - $wm_w, $tn_h - $wm_h, 0, 0, $tn_w, $tn_h);
}
if (imagejpeg($final, $destination, $quality)) {
return true;
}
return false;
}
Black & White
$final = imagecreatetruecolor($tn_w, $tn_h);
$backgroundColor = imagecolorallocate($final, 255, 255, 255);
imagefill($final, 0, 0, $backgroundColor);
//imagecopyresampled($final, $newpic, 0, 0, ($x_mid - ($tn_w / 2)), ($y_mid - ($tn_h / 2)), $tn_w, $tn_h, $tn_w, $tn_h);
imagecopy($final, $newpic, (($tn_w - $new_w)/ 2), (($tn_h - $new_h) / 2), 0, 0, $new_w, $new_h);
Here is your whole script (tested with portrait, landscape and square jpg):
<?php
function resize($source_image, $destination, $tn_w, $tn_h, $quality = 100, $wmsource = false)
{
$info = getimagesize($source_image);
$imgtype = image_type_to_mime_type($info[2]);
#assuming the mime type is correct
switch ($imgtype) {
case 'image/jpeg':
$source = imagecreatefromjpeg($source_image);
break;
case 'image/gif':
$source = imagecreatefromgif($source_image);
break;
case 'image/png':
$source = imagecreatefrompng($source_image);
break;
default:
die('Invalid image type.');
}
#Figure out the dimensions of the image and the dimensions of the desired thumbnail
$src_w = imagesx($source);
$src_h = imagesy($source);
#Do some math to figure out which way we'll need to crop the image
#to get it proportional to the new size, then crop or adjust as needed
$x_ratio = $tn_w / $src_w;
$y_ratio = $tn_h / $src_h;
if (($src_w <= $tn_w) && ($src_h <= $tn_h)) {
$new_w = $src_w;
$new_h = $src_h;
} elseif (($x_ratio * $src_h) < $tn_h) {
$new_h = ceil($x_ratio * $src_h);
$new_w = $tn_w;
} else {
$new_w = ceil($y_ratio * $src_w);
$new_h = $tn_h;
}
$newpic = imagecreatetruecolor(round($new_w), round($new_h));
imagecopyresampled($newpic, $source, 0, 0, 0, 0, $new_w, $new_h, $src_w, $src_h);
$final = imagecreatetruecolor($tn_w, $tn_h);
$backgroundColor = imagecolorallocate($final, 255, 255, 255);
imagefill($final, 0, 0, $backgroundColor);
//imagecopyresampled($final, $newpic, 0, 0, ($x_mid - ($tn_w / 2)), ($y_mid - ($tn_h / 2)), $tn_w, $tn_h, $tn_w, $tn_h);
imagecopy($final, $newpic, (($tn_w - $new_w)/ 2), (($tn_h - $new_h) / 2), 0, 0, $new_w, $new_h);
#if we need to add a watermark
if ($wmsource) {
#find out what type of image the watermark is
$info = getimagesize($wmsource);
$imgtype = image_type_to_mime_type($info[2]);
#assuming the mime type is correct
switch ($imgtype) {
case 'image/jpeg':
$watermark = imagecreatefromjpeg($wmsource);
break;
case 'image/gif':
$watermark = imagecreatefromgif($wmsource);
break;
case 'image/png':
$watermark = imagecreatefrompng($wmsource);
break;
default:
die('Invalid watermark type.');
}
#if we're adding a watermark, figure out the size of the watermark
#and then place the watermark image on the bottom right of the image
$wm_w = imagesx($watermark);
$wm_h = imagesy($watermark);
imagecopy($final, $watermark, $tn_w - $wm_w, $tn_h - $wm_h, 0, 0, $tn_w, $tn_h);
}
if (imagejpeg($final, $destination, $quality)) {
return true;
}
return false;
}
resize('teszt2.jpg', 'out.jpg', 100, 100);
?>
<img src="out.jpg">
This is working for me. Although it logically seems like it should fill the whole image with the $bgcolor, it only fills the parts that are "behind" the resampled image.
imagecopyresampled($resized_image, $original_image, $xoffset, $yoffset, 0, 0, $new_width, $new_height, $orig_width, $orig_height);
$bgcolor = imagecolorallocate($resized_image, $red, $green, $blue);
imagefill($resized_image, 0, 0, $bgcolor);