How do I resize pngs with transparency in PHP? - php

I'm attempting to resize pngs with transparent backgrounds in PHP and the code samples I've found online don't work for me. Here's the code I'm using, advice will be much appreciated!
$this->image = imagecreatefrompng($filename);
imagesavealpha($this->image, true);
$newImage = imagecreatetruecolor($width, $height);
// Make a new transparent image and turn off alpha blending to keep the alpha channel
$background = imagecolorallocatealpha($newImage, 255, 255, 255, 127);
imagecolortransparent($newImage, $background);
imagealphablending($newImage, false);
imagesavealpha($newImage, true);
imagecopyresampled($newImage, $this->image, 0, 0, 0, 0, $width, $height, $this->getWidth(), $this->getHeight());
$this->image = $newImage;
imagepng($this->image,$filename);
Update
By 'not working' I meant to say the background color changes to black when I resize pngs.

From what I can tell, you need to set the blending mode to false, and the save alpha channel flag to true before you do the imagecolorallocatealpha()
<?php
/**
* https://stackoverflow.com/a/279310/470749
*
* #param resource $image
* #param int $newWidth
* #param int $newHeight
* #return resource
*/
public function getImageResized($image, int $newWidth, int $newHeight) {
$newImg = imagecreatetruecolor($newWidth, $newHeight);
imagealphablending($newImg, false);
imagesavealpha($newImg, true);
$transparent = imagecolorallocatealpha($newImg, 255, 255, 255, 127);
imagefilledrectangle($newImg, 0, 0, $newWidth, $newHeight, $transparent);
$src_w = imagesx($image);
$src_h = imagesy($image);
imagecopyresampled($newImg, $image, 0, 0, 0, 0, $newWidth, $newHeight, $src_w, $src_h);
return $newImg;
}
?>
UPDATE : This code is working only on background transparent with opacity = 0. If your image have 0 < opacity < 100 it'll be black background.

Here is a final solution that is working fine for me.
function resizePng($im, $dst_width, $dst_height) {
$width = imagesx($im);
$height = imagesy($im);
$newImg = imagecreatetruecolor($dst_width, $dst_height);
imagealphablending($newImg, false);
imagesavealpha($newImg, true);
$transparent = imagecolorallocatealpha($newImg, 255, 255, 255, 127);
imagefilledrectangle($newImg, 0, 0, $width, $height, $transparent);
imagecopyresampled($newImg, $im, 0, 0, 0, 0, $dst_width, $dst_height, $width, $height);
return $newImg;
}

using imagescale is better compared to imagecopyresampled. No empty image resource required for the resized image, requires only two arguments compared to the ten required by imagecopyresampled. Also produces better quality with smaller sizes. If using PHP 5.5.18 or earlier, or PHP 5.6.2 or earlier, you should provide the height which is the 3rd argument as the aspect ratio calculation was incorrect.
$this->image = imagecreatefrompng($filename);
$scaled = imagescale($this->image, $width);
imagealphablending($scaled, false);
imagesavealpha($scaled, true);
imagepng($scaled, $filename);

The filling of the new image with a transparent colour is also required (as Dycey coded but I'm guessing forgot to mention :)), not just the 'strategic' saving by itself.
IIRC, you also need to be sure PNGs are 24bit, ie truecolor, and not 8bit to avoid buggy behaviour.

old thread, but just in case - Dycey's example should work, if you name things correctly. Here is a modified version used in my image resizing class. Notice the check to make sure imagecolorallocatealpha() is defined, which it won't be if you are using GD <2.0.8
/**
* usually when people use PNGs, it's because they need alpha channel
* support (that means transparency kids). So here we jump through some
* hoops to create a big transparent rectangle which the resampled image
* will be copied on top of. This will prevent GD from using its default
* background, which is black, and almost never correct. Why GD doesn't do
* this automatically, is a good question.
*
* #param $w int width of target image
* #param $h int height of target image
* #return void
* #private
*/
function _preallocate_transparency($w, $h) {
if (!empty($this->filetype) && !empty($this->new_img) && $this->filetype == 'image/png')) {
if (function_exists('imagecolorallocatealpha')) {
imagealphablending($this->new_img, false);
imagesavealpha($this->new_img, true);
$transparent = imagecolorallocatealpha($this->new_img, 255, 255, 255, 127);
imagefilledrectangle($this->new_img, 0, 0, $tw, $th, $transparent);
}
}
}

It's probably related to the newer versions of PHP (I tested with PHP 5.6) but this now works without the need to fill the image with a transparent background:
$image_p = imagecreatetruecolor(480, 270);
imageAlphaBlending($image_p, false);
imageSaveAlpha($image_p, true);
$image = imagecreatefrompng('image_with_some_transaprency.png');
imagecopyresampled($image_p, $image, 0, 0, 0, 0, 480, 270, 1920, 1080);
imagepng($image_p, 'resized.png', 0);

this is also not working for me :(
thisis my solution.. but i also get a black background and the image is not transparent
<?php
$img_id = 153;
$source = "images/".$img_id.".png";
$source = imagecreatefrompng($source);
$o_w = imagesx($source);
$o_h = imagesy($source);
$w = 200;
$h = 200;
$newImg = imagecreatetruecolor($w, $h);
imagealphablending($newImg, false);
imagesavealpha($newImg,true);
$transparent = imagecolorallocatealpha($newImg, 255, 255, 255, 127);
imagefilledrectangle($newImg, 0, 0, $w, $h, $transparent);
imagecopyresampled($newImg, $source, 0, 0, 0, 0, $w, $h, $o_w, $o_h);
imagepng($newImg, $img_id.".png");
?>
<img src="<?php echo $img_id.".png" ?>" />

Here is full code working for png files with preserving their images transparency..
list($width, $height) = getimagesize($filepath);
$new_width = "300";
$new_height = "100";
if($width>$new_width && $height>$new_height)
{
$image_p = imagecreatetruecolor($new_width, $new_height);
imagealphablending($image_p, false);
imagesavealpha($image_p, true);
$image = imagecreatefrompng($filepath);
imagecopyresampled($image_p, $image, 0, 0, 0, 0, $new_width, $new_height, $width, $height);
imagepng($image_p,$filepath,5);
}

Full example. Notice that for some png images found on internet it works incorrect, but for my own created with photoshop it works fine.
header('Content-Type: image/png');
$filename = "url to some image";
$newWidth = 300;
$newHeight = 300;
$imageInfo = getimagesize($filename);
$image = imagecreatefrompng($filename); //create source image resource
imagesavealpha($image, true); //saving transparency
$newImg = imagecreatetruecolor($newWidth, $newHeight); //creating conteiner for new image
imagealphablending($newImg, false);
imagesavealpha($newImg,true);
$transparent = imagecolorallocatealpha($newImg, 255, 255, 255, 127); //seting transparent background
imagefilledrectangle($newImg, 0, 0, $newWidth, $newHeight, $transparent);
imagecopyresampled($newImg, $image, 0, 0, 0, 0, $newWidth, $newHeight, $imageInfo[0], $imageInfo[1]);
imagepng($newImg); //printout image string

You can simply resize the image with imagescale()
This code works fine for me:
$image = imagescale($image, 720, -1, IMG_BICUBIC);
imagepng($image);

Nor the above solution worked for me. This is the way what i found out to solve the issue.
// upload directory
$upload_dir = "../uploads/";
// valid image formats
$valid_formats = array("jpg", "jpeg", "png");
// maximum image size 1 mb
$max_size = 1048576;
// crop image width, height
$nw = $nh = 800;
$nw1 = $nh1 = 400;
$nw3 = $nh3 = 200;
$nw2 = $nh2 = 100;
// checks that if upload_dir a directory/not
if (is_dir($upload_dir) && is_writeable($upload_dir)) {
// not empty file
if (!empty($_FILES['image'])) {
// assign file name
$name = $_FILES['image']['name'];
// $_FILES to execute all files within a loop
if ($_FILES['image']['error'] == 4) {
$message = "Empty FIle";
}
if ($_FILES['image']['error'] == 0) {
if ($_FILES['image']['size'] > $max_size) {
echo "E-Image is too large!<br>";
$_SESSION['alert'] = "Image is too large!!";
} else if (!in_array(pathinfo($name, PATHINFO_EXTENSION), $valid_formats)) {
$_SESSION['alert'] = "This image is not a valid image format!!";
echo "E-This image is not a valid image format<br>";
} else if (file_exists($upload_dir . $name)) {
$_SESSION['alert'] = "Image already exists!!";
echo "E-Image already exists<br>";
} else { // No error found! Move uploaded files
$size = getimagesize($_FILES['image']['tmp_name']);
$x = (int) $_POST['x'];
$y = (int) $_POST['y'];
$w = (int) $_POST['w'] ? $_POST['w'] : $size[0];
$h = (int) $_POST['h'] ? $_POST['h'] : $size[1];
// path for big image
$big_image_path = $upload_dir . "big/" . $name;
// medium image path
$medium_image_path = $upload_dir . "medium/" . $name;
// small image path
$small_image_path = $upload_dir . "small/" . $name;
// check permission
if (!is_dir($upload_dir . "big/") && !is_writeable($upload_dir . "big/")) {
mkdir($upload_dir . "big/", 0777, false);
}
if (!is_dir($upload_dir . "medium/") && !is_writeable($upload_dir . "medium/")) {
mkdir($upload_dir . "medium/", 0777, false);
}
if (!is_dir($upload_dir . "small/") && !is_writeable($upload_dir . "small/")) {
mkdir($upload_dir . "small/", 0777, false);
}
// image raw data from form
$data = file_get_contents($_FILES["image"]["tmp_name"]);
// create image
$vImg = imagecreatefromstring($data);
//create big image
$dstImg = imagecreatetruecolor($nw, $nh);
imagealphablending($dstImg, false);
$trans_colour = imagecolorallocatealpha($dstImg, 0, 0, 0, 127);
imagefilledrectangle($dstImg, 0, 0, $w, $h, $trans_colour);
imagesavealpha($dstImg, true);
imagecopyresampled($dstImg, $vImg, 0, 0, $x, $y, $nw, $nh, $w, $h);
imagepng($dstImg, $big_image_path);
//create medium thumb
$dstImg1 = imagecreatetruecolor($nw1, $nh1);
imagealphablending($dstImg1, false);
$trans_colour1 = imagecolorallocatealpha($dstImg1, 0, 0, 0, 127);
imagefilledrectangle($dstImg1, 0, 0, $w, $h, $trans_colour1);
imagesavealpha($dstImg1, true);
imagecopyresampled($dstImg1, $vImg, 0, 0, $x, $y, $nw1, $nh1, $w, $h);
imagepng($dstImg1, $medium_image_path);
// create smallest thumb
$dstImg2 = imagecreatetruecolor($nw2, $nh2);
imagealphablending($dstImg2, false);
$trans_colour2 = imagecolorallocatealpha($dstImg2, 0, 0, 0, 127);
imagefilledrectangle($dstImg2, 0, 0, $w, $h, $trans_colour2);
imagesavealpha($dstImg2, true);
imagecopyresampled($dstImg2, $vImg, 0, 0, $x, $y, $nw2, $nh2, $w, $h);
imagepng($dstImg2, $small_image_path);
/*
* Database insertion
*/
$sql = "INSERT INTO tbl_inksand_product_gallery ("
. "Product_Id,Gallery_Image_Big,Gallery_Image_Medium,Gallery_Image_Thumb,"
. "Gallery_Status,Created_By,Created_Datetime"
. ") VALUES ("
. "'{$Product_Id}','{$big_image_path}','{$medium_image_path}','{$small_image_path}',"
. "'A','$Created_By','{$time}'"
. ")";
db_query($sql);
if (db_affected_rows() == 1) {
if (imagedestroy($dstImg)) {
$_SESSION['success'] = "Image uploaded successfully.";
echo "S-Image uploaded successfully<br>";
} else {
$_SESSION['alert'] = "Image not uploaded!!";
echo "S-Image not uploaded";
}
} else {
$_SESSION['alert'] = "Error in uploading image!!";
echo "E-Error in uploading image!!";
}
}
}
}
} else {
mkdir($upload_dir, 0777);
}

Related

PHP - Resizing and saving PNG images. Some are all black

I'm resizing and saving PNGs with PHP. The first example doesn't work, the PNG ends up being completely black, but the second example works. The first example doesn't have a transparent background but the second one does. Why doesn't the first example work? Is it a problem with the URL?
<?php
$id = "example";
//$originalFile = "https://th.bing.com/th/id/OIP.v_YT6iKMW6sOOVdCxVYQkwHaE8?pid=ImgDet&rs=1.png"; // Doesn't work
$originalFile = "https://cdn.globalxetfs.com/content/files/210618-China_Materials_02.png"; // Works
list($originalWidth, $originalHeight) = getimagesize($originalFile);
$originalImage = #imagecreatefrompng($originalFile);
$newHeight = 255;
$newWidth = 255;
// Create empty canvas
$resizedImage = "";
$resizedImage = imagecreatetruecolor($newWidth, $newHeight); // width, height
// Preserve transparency
imagesavealpha($resizedImage, true);
$color = imagecolorallocatealpha($resizedImage, 0, 0, 0, 127);
imagefill($resizedImage, 0, 0, $color);
// Resize image
imagecopyresampled(
$resizedImage, $originalImage, 0, 0, 0, 0,
$newWidth, $newHeight, $originalWidth, $originalHeight
);
header('Content-type: image/png');
$imageName = $id;
$imageName = $imageName . ".png";
if(imagepng($resizedImage, "images/" . $imageName)){
echo "Image uploaded";
}
?>
The "first example" actually is a JPG file (after the server image rendering) , so you need to use
#imagecreatefromjpeg instead of #imagecreatefrompng
So the codes (working) should be:
<?php
$id = "example";
$originalFile = "https://th.bing.com/th/id/OIP.v_YT6iKMW6sOOVdCxVYQkwHaE8?pid=ImgDet&rs=1.png";
//$originalFile = "https://cdn.globalxetfs.com/content/files/210618-China_Materials_02.png";
list($originalWidth, $originalHeight) = getimagesize($originalFile);
$originalImage = #imagecreatefromjpeg($originalFile);
$newHeight = 255;
$newWidth = 255;
// Create empty canvas
$resizedImage = "";
$resizedImage = imagecreatetruecolor($newWidth, $newHeight); // width, height
// Preserve transparency
imagesavealpha($resizedImage, true);
$color = imagecolorallocatealpha($resizedImage, 0, 0, 0, 127);
imagefill($resizedImage, 0, 0, $color);
// Resize image
imagecopyresampled(
$resizedImage, $originalImage, 0, 0, 0, 0,
$newWidth, $newHeight, $originalWidth, $originalHeight
);
header('Content-type: image/png');
//$imageName = $id;
//$imageName = $imageName . ".png";
//if(imagepng($resizedImage, "images/" . $imageName)){
// echo "Image uploaded";
//}
imagepng($resizedImage);
?>

PHP GD Lib PNG-24 to PNG-8 conversion: The bigger the resulting image the less colors remain

The following code works with intial 8bit-png's but when i use a 24 bit alpha transp png, it seems to work worse when the resulting image gets bigger. The bigger the resulting image the less colors remain. Both pictures where exported from PS via Web-Export.
How can I solve the problem? Is something wrong with the code or may it be a bug? (I am on Windows 10, PHP 5.6.6)
$imgPath = 'image-24bit-alpha-transp-from-ps-960x533.png';
$imgDirname = pathinfo($imgPath, PATHINFO_DIRNAME);
$imgFilename = pathinfo($imgPath, PATHINFO_FILENAME);
$imgExtension = pathinfo($imgPath, PATHINFO_EXTENSI
ON);
$newWidths = [80, 160, 320, 640, 960];
$img = imagecreatefrompng($imgPath);
list($width, $height) = getimagesize($imgPath);
if($width * $height > PHP_INT_MAX)
throw new Exception('The picture exceeds the maximum number of pixels ('.INT_MAX.').');
$ratio = $height / $width;
$alphaTransparency = imagecolortransparent($img) >=0 || (ord(file_get_contents($imgPath, false, null, 25, 1)) & 4);
$numberOfColors = imagecolorstotal($img);
$trueColorImage = $numberOfColors === 0;
foreach($newWidths as $newWidth)
{
$newImgPath = $imgDirname.DIRECTORY_SEPARATOR.$imgFilename.'_w'.$newWidth.'.'.$imgExtension;
$newHeight = ceil($newWidth * $ratio);
$newImg = $trueColorImage ? imagecreatetruecolor($newWidth, $newHeight) : imagecreate($newWidth, $newHeight);
imagealphablending($newImg, false);
imagesavealpha($newImg,true);
$color = imagecolorallocatealpha($newImg, 255, 255, 255, 127);
imagefill($newImg, 0, 0, $color);
imagetruecolortopalette($newImg, false, $trueColorImage ? 255 : $numberOfColors);
imagecopyresampled($newImg, $img, 0, 0, 0, 0, $newWidth, $newHeight, $width, $height);
imagepng($newImg, $newImgPath, 6);
imagedestroy($newImg);
}
imagedestroy($img);

black background is coming for transparent images while creating image in php [duplicate]

This question already has an answer here:
PHP & GD - transparent background being filled with nearby color
(1 answer)
Closed 8 years ago.
I am writing the code for watermark in php using below code but for transaparent images, black background is coming:
$font_path = $_SERVER['DOCUMENT_ROOT'] . "/fonts/arial.ttf"; // Font file
$water_mark_text_2 = "IndustrialStores.com"; // Watermark Text
list($owidth,$oheight) = getimagesize($oldimage_name);
$width = $owidth;
$height = $oheight;
$image = imagecreatetruecolor($width, $height);
$extension = pathinfo($oldimage_name, PATHINFO_EXTENSION);
$extension = strtolower($extension);
if($extension=="jpg" || $extension=="jpeg" ){
$image_src = imagecreatefromjpeg($oldimage_name);
}
else if($extension=="png"){
$image_src = imagecreatefrompng($oldimage_name);
}
else if($extension=="gif"){
$image_src = imagecreatefromgif($oldimage_name);
}
else if($extension=="bmp"){
$image_src = imagecreatefrombmp($oldimage_name);
}
else{
copy($oldimage_name, $new_image_name);
unlink($oldimage_name);
return true;
}
imagecopyresampled($image, $image_src, 0, 0, 0, 0, $width, $height, $owidth, $oheight);
$blue = imagecolorallocate ($image, 179, 179, 179);
$bbox = imageftbbox($width/15, 0, $font_path, 'IndustrialStores.com');
$x = $bbox[0] + (imagesx($image) / 2) - ($bbox[4] / 2);
$y = $bbox[1] + (imagesy($image) / 2) - ($bbox[5] / 2) - 5;
imagettftext($image, $width/15, 0, $x, $y, $blue, $font_path, $water_mark_text_2);
imagejpeg($image, $new_image_name, 100);
imagedestroy($image);
unlink($oldimage_name);
I already tried so many other answers fro stackoverflow like using :
$im = imagecreatetruecolor(55, 30);
$red = imagecolorallocate($im, 255, 0, 0);
$black = imagecolorallocate($im, 0, 0, 0);
// Make the background transparent
imagecolortransparent($im, $black);
but there is no use of all this
Would adding these lines help?
else{
copy($oldimage_name, $new_image_name);
unlink($oldimage_name);
return true;
}
// add these lines here!
imagealphablending($image, false);
imagesavealpha($image, true);
imagecopyresampled($image, $image_src, 0, 0, 0, 0, $width, $height, $owidth, $oheight);
$blue = imagecolorallocate ($image, 179, 179, 179);

Adding Watermark to Ajax Crop

Im using Ajax Crop from enter link description here and I'd like to add a watermark to the script. The following is my script.
WATERMARK
$image_path = "watermark.png";
function watermark_image($oldimage_name, $new_image_name){
global $image_path;
list($owidth,$oheight) = getimagesize($oldimage_name);
$width = 500; $height = 100;
$im = imagecreatetruecolor($width, $height);
$img_src = imagecreatefromjpeg($oldimage_name);
imagecopyresampled($im, $img_src, 0, 0, 0, 0, $width, $height, $owidth, $oheight);
$watermark = imagecreatefrompng($image_path);
list($w_width, $w_height) = getimagesize($image_path);
$pos_x = $width - $w_width;
$pos_y = $height - $w_height;
imagecopy($im, $watermark, $pos_x, $pos_y, 0, 0, $w_width, $w_height);
imagejpeg($im, $new_image_name, 100);
imagedestroy($im);
unlink($oldimage_name);
return true;
}
UPLOAD AND RESIZE PART
function resizeThumb($arr){
$date = md5(time());
$arr['temp_uploadfile'] = $arr['img_src'];
$arr['new_uploadfile'] = $arr['uploaddir'].strtolower($date).'.jpg';
asidoImg($arr);
exit;
}
I tried adding
$arr = watermark_image($arr['temp_uploadfile'],
$arr['uploaddir'].strtolower($date).'.jpg');
in place of
$arr['new_uploadfile'] = $arr['uploaddir'].strtolower($date).'.jpg';
but this didnt work.
Could someone help me?
Download the files and test
It turns out the script uses ASIDO and it has a built in WATERMARK TOOL.
In func.php I done the following.
function asidoImg2($arr){
include('asido/class.asido.php');
asido::driver('gd');
$height = $arr['height'];
$width = $arr['width'];
$x = $arr['x'];
$y = $arr['y'];
// process
$i1 = asido::image($arr['temp_uploadfile'], $arr['new_uploadfile']);
// fit and add white frame
if($arr['thumb'] === true){
Asido::Crop($i1, $x, $y, $width, $height);
asido::watermark($i1, 'watermark.png', ASIDO_WATERMARK_MIDDLE_LEFT, ASIDO_WATERMARK_SCALABLE_ENABLED, 1);
}
else{
Asido::Frame($i1, $width, $height, Asido::Color(255, 255, 255));
asido::watermark($i1, 'watermark.png', ASIDO_WATERMARK_MIDDLE_LEFT, ASIDO_WATERMARK_SCALABLE_ENABLED, 1);
}
// always convert to jpg
Asido::convert($i1, 'image/jpg');
$i1->Save(ASIDO_OVERWRITE_ENABLED);
$data = array(
'photo'=> $arr['new_uploadfile']
);
// echo $user_id;
// delete old file
echo $data['photo'];
}

How to preserve transparency in PHP GD on a PNG

I am using this code:
<?php
list($width, $height, $type, $attr) = getimagesize("terrain.png");
$canvas = imagecreatetruecolor($width, $height);
$src = imagecreatefrompng("terrain.png");
if($_GET['glass'] == 1){
$src2 = imagecreatefrompng("rock.png");
}
imagecopymerge($canvas, $src, 0, 0, 0, 0, $width, $height, 100);
if($_GET['glass'] == 1){
imagecopy($canvas, $src2, 0, 0, 0, 0, 16, 16);
}
imagealphablending($canvas, true);
imagesavealpha($canvas, true);
header("Content-type: image/png");
imagepng($canvas);
imagedestroy($dest);
imagedestroy($src);
?>
Terrain.png is at http://hogofwar.co.uk/experiment/mc/terrain.png (which is transparent)
How do I preserve the transparency when using GD?
You can try
Parameters:
$new_image = image resource identifier such as returned by imagecreatetruecolor(). must be passed by reference
$image_source = image resource identifier returned by imagecreatefromjpeg, imagecreatefromgif and imagecreatefrompng. must be passed by reference
<?php
function setTransparency($new_image,$image_source)
{
$transparencyIndex = imagecolortransparent($image_source);
$transparencyColor = array('red' => 255, 'green' => 255, 'blue' => 255);
if ($transparencyIndex >= 0) {
$transparencyColor = imagecolorsforindex($image_source, $transparencyIndex);
}
$transparencyIndex = imagecolorallocate($new_image, $transparencyColor['red'], $transparencyColor['green'], $transparencyColor['blue']);
imagefill($new_image, 0, 0, $transparencyIndex);
imagecolortransparent($new_image, $transparencyIndex);
}
?>
You can check for more details,
http://www.php.net/manual/en/function.imagecolortransparent.php
Try this:
$img = imagecreatefrompng("yourimage.png");
$width = imagesx($img);
$height = imagesy($img);
$new_width=500;//this is the new width of the output image
$newheight=($height/$width)*$new_width;
$target=imagecreatetruecolor($new_width,$newheight);
$transparent=imagecolorallocatealpha($target,0,0,0,127);
imagefill($target,0,0,$transparent);
imagecopyresampled($target,$img,0,0,0,0,$new_width,$newheight,$width,$height);
imagealphablending($target,false);
imagesavealpa($target,true);
imagepng($target,"your_target_filename.png");
Done...

Categories