I want to add watermark on image when i upload in CakePHP. I found many components on Google but I don't know how to use them like ImageTool, Qimage etc. I don't know what value should pass to component function to add watermark. Could anybody help me.
Here is the ImageToolComponent::watermark() function:-
public static function watermark($options = array()) {
$options = array_merge(array(
'afterCallbacks' => null,
'scale' => false,
'strech' => false,
'repeat' => false,
'watermark' => null,
'output' => null,
'input' => null,
'position' => 'center',
'compression' => 9,
'quality' => 100,
'chmod' => null,
'opacity' => 100
), $options);
// if output path (directories) doesn’t exist, try to make whole path
if (!self::createPath($options['output'])) {
return false;
}
$img = self::openImage($options['input']);
unset($options['input']);
if (empty($img)) {
return false;
}
$src_wm = self::openImage($options['watermark']);
unset($options['watermark']);
if (empty($src_wm)) {
return false;
}
// image size
$img_im_w = imagesx($img);
$img_im_h = imagesy($img);
// watermark size
$img_wm_w = imagesx($src_wm);
$img_wm_h = imagesy($src_wm);
if ($options['scale']) {
if ($options['strech']) {
$r = imagecopyresampled($img, $src_wm, 0, 0, 0, 0, $img_im_w, $img_im_h, $img_wm_w, $img_wm_h);
} else {
$x = 0;
$y = 0;
$w = $img_im_w;
$h = $img_im_h;
if (($img_im_w / $img_im_h) > ($img_wm_w / $img_wm_h)) {
$ratio = $img_im_h / $img_wm_h;
$w = $ratio * $img_wm_w;
$x = round(($img_im_w - $w) / 2);
} else {
$ratio = $img_im_w / $img_wm_w;
$h = $ratio * $img_wm_h;
$y = round(($img_im_h - $h) / 2);
}
$r = imagecopyresampled($img, $src_wm, $x, $y, 0, 0, $w, $h, $img_wm_w, $img_wm_h);
}
} else if ($options['repeat']) {
if (is_array($options['position'])) {
$options['position'] = 5;
}
switch ($options['position']) {
case 'top-left':
for ($y = 0; $y < $img_im_h; $y+=$img_wm_h) {
for ($x = 0; $x < $img_im_w; $x+=$img_wm_w) {
$r = self::imagecopymerge_alpha($img, $src_wm, $x, $y, 0, 0, $img_wm_w, $img_wm_h, $options['opacity']);
}
}
break;
case 'top-right':
for ($y = 0; $y < $img_im_h; $y+=$img_wm_h) {
for ($x = $img_im_w; $x > -$img_wm_w; $x-=$img_wm_w) {
$r = self::imagecopymerge_alpha($img, $src_wm, $x, $y, 0, 0, $img_wm_w, $img_wm_h, $options['opacity']);
}
}
break;
case 'bottom-right':
for ($y = $img_im_h; $y > -$img_wm_h; $y-=$img_wm_h) {
for ($x = $img_im_w; $x > -$img_wm_w; $x-=$img_wm_w) {
$r = self::imagecopymerge_alpha($img, $src_wm, $x, $y, 0, 0, $img_wm_w, $img_wm_h, $options['opacity']);
}
}
break;
case 'bottom-left':
for ($y = $img_im_h; $y > -$img_wm_h; $y-=$img_wm_h) {
for ($x = 0; $x < $img_im_w; $x+=$img_wm_w) {
$r = self::imagecopymerge_alpha($img, $src_wm, $x, $y, 0, 0, $img_wm_w, $img_wm_h, $options['opacity']);
}
}
break;
case 'center':
default:
$pos_x = -(($img_im_w % $img_wm_w) / 2);
$pos_y = -(($img_im_h % $img_wm_h) / 2);
for ($y = $pos_y; $y < $img_im_h; $y+=$img_wm_h) {
for ($x = $pos_x; $x < $img_im_w; $x+=$img_wm_w) {
$r = self::imagecopymerge_alpha($img, $src_wm, $x, $y, 0, 0, $img_wm_w, $img_wm_h, $options['opacity']);
}
}
break;
}
} else {
// custom location
if (is_array($options['position'])) {
list($pos_x, $pos_y) = $options['position'];
} else {
// predefined location
switch ($options['position']) {
case 'top-left':
$pos_x = 0;
$pos_y = 0;
break;
case 'top-right':
$pos_x = $img_im_w - $img_wm_w;
$pos_y = 0;
break;
case 'bottom-right':
$pos_x = $img_im_w - $img_wm_w;
$pos_y = $img_im_h - $img_wm_h;
break;
case 'bottom-left':
$pos_x = 0;
$pos_y = $img_im_h - $img_wm_h;
break;
case 'center':
default:
$pos_x = round(($img_im_w - $img_wm_w) / 2);
$pos_y = round(($img_im_h - $img_wm_h) / 2);
break;
}
}
$r = self::imagecopymerge_alpha($img, $src_wm, $pos_x, $pos_y, 0, 0, $img_wm_w, $img_wm_h, $options['opacity']);
}
if (!$r) {
return false;
}
if (!self::afterCallbacks($img, $options['afterCallbacks'])) {
return false;
}
return self::saveImage($img, $options);
}
I don't know what parameter should i pass to watermark function.`
Related
i'm trying to work a little bit with images and php. Please have a look at the following script.
<?php
//testcall prepare.php?img=https://images-eu.ssl-images-amazon.com/images/I/515SENGgRnL.jpg&h=200&n=test.png
$file=$_GET["img"];
$height=$_GET["h"];
$name=$_GET["n"];
function transparent($picture)
{
$img_w = imagesx($picture);
$img_h = imagesy($picture);
$newPicture = imagecreatetruecolor( $img_w, $img_h );
imagesavealpha( $newPicture, true );
$rgb = imagecolorallocatealpha( $newPicture, 0, 0, 0, 127 );
imagefill( $newPicture, 0, 0, $rgb );
$color = imagecolorat( $picture, $img_w-1, 1);
for( $x = 0; $x < $img_w; $x++ ) {
for( $y = 0; $y < $img_h; $y++ ) {
$c = imagecolorat( $picture, $x, $y );
if($color!=$c){
imagesetpixel( $newPicture, $x, $y, $c);
}
}
}
echo "habs transparent gemacht! <br> ";
return $newPicture;
}
function resize($img,$w,$name){
$ratio = imagesx($img)/imagesy($img);
if( $ratio > 1) {
$width = $w;
$height = $w/$ratio;
}
else {
$width = $w*$ratio;
$height = $w;
}
$dst = imagecreatetruecolor($width,$height);
imagesavealpha($dst, true);
$color = imagecolorallocatealpha($dst, 0, 0, 0, 127);
imagefill($dst, 0, 0, $color);
imagecopyresampled($dst,$img,0,0,0,0,$width,$height,imagesx($img),imagesy($img));
imagepng($dst, "test.png");
};
function crop($img){
$img = imagecreatefromjpeg($img);
$b_top = 0;
$b_btm = 0;
$b_lft = 0;
$b_rt = 0;
for(; $b_top < imagesy($img); ++$b_top) {
for($x = 0; $x < imagesx($img); ++$x) {
if(imagecolorat($img, $x, $b_top) != 0xFFFFFF) {
break 2;
}
}
}
for(; $b_btm < imagesy($img); ++$b_btm) {
for($x = 0; $x < imagesx($img); ++$x) {
if(imagecolorat($img, $x, imagesy($img) - $b_btm-1) != 0xFFFFFF) {
break 2;
}
}
}
for(; $b_lft < imagesx($img); ++$b_lft) {
for($y = 0; $y < imagesy($img); ++$y) {
if(imagecolorat($img, $b_lft, $y) != 0xFFFFFF) {
break 2;
}
}
}
for(; $b_rt < imagesx($img); ++$b_rt) {
for($y = 0; $y < imagesy($img); ++$y) {
if(imagecolorat($img, imagesx($img) - $b_rt-1, $y) != 0xFFFFFF) {
break 2;
}
}
}
$newimg = imagecreatetruecolor(imagesx($img)-($b_lft+$b_rt), imagesy($img)-($b_top+$b_btm));
imagecopy($newimg, $img, 0, 0, $b_lft, $b_top, imagesx($newimg), imagesy($newimg));
return $newimg;
};
$pic_cropped=crop($file);
$pic_transparent=transparent($pic_cropped);
$pic_resized=resize($pic_transparent,$height,$name);
?>
Input is a jpg, height and output name. First function crop crops the white space on all sides. Then set the white background color to transparent and the resize the whole pic to the height. So far the script is running fine on my Mac with MAMP. I tried to run on raspberry pi and on Ubuntu Linux in hosted area. The out on my mac is perfect: https://ibb.co/fNeFzk
Output on Raspberry and hosted Linux is bad: https://ibb.co/kdbCek
Hope you can see the difference. Same PHP Version, Same Apache Version. Any Ideas how to solve that?
I am trying to built an option unto my site where users can upload a profile picture, so far so good, but the data is saved again and again in my database(table) when I refresh the page
++ the image doesn't show, it just shows a black square.
Thanks for any help, as you can see, I'm still an absolute beginner learning eagerly and ferociously
$images = (isset ($_FILES['images']['name']));
$paths= [];
if ($images)
{
$saveto = "uploads/$user.jpg";
move_uploaded_file($_FILES['images']['tmp_name'], $saveto);
$typeok = TRUE;
$paths[] = $saveto;
$date1=date("Y-m-d h:m:s");
$link=mysqli_connect("localhost","root","","vlindr");
mysqli_select_db($link,"imageupload"); //database connectivity
mysqli_query($link,"insert into images
(images_id, images_path, submission_date)
VALUES (NULL,'$user','$date1')")
or die(mysqli_error($link));
switch($_FILES['images']['type'])
{
case "image/gif": $src = imagecreatefromgif($saveto); break;
case "image/jpeg": // Both regular and progressive jpegs
case "image/pjpeg": $src = imagecreatefromjpeg($saveto); break;
case "image/png": $src = imagecreatefrompng($saveto); break;
default: $typeok = FALSE; break;
}
if ($typeok)
{
list($w, $h) = getimagesize($saveto);
$max = 150;
$tw = $w;
$th = $h;
if ($w > $h && $max < $w) {
$th = $max ;
$tw = $max;
}
elseif ($h > $w && $max < $h) {
$tw = $max / $h * $w;
$th = $max;
}
elseif ($max < $w) {
$tw = $th = $max;
}
$tmp = imagecreatetruecolor($tw, $th);
imagecopyresampled($tmp, $src, 0, 0, 0, 0, $tw, $th, $w, $h);
imageconvolution($tmp, array(array(-1, -1, -1),
array(-1, 16, -1),
array(-1, -1, -1)),
8, 0);
imagejpeg($tmp, $saveto);
imagedestroy($tmp);
imagedestroy($src);
}
}
Please let me know if the code below works.
I also recommend prepared statements, although the code below is not the neatest it will get the job done!
$images = (isset ($_FILES['images']['name']));
$paths= [];
if ($images)
{
$saveto = "uploads/$user.jpg";
move_uploaded_file($_FILES['images']['tmp_name'], $saveto);
$typeok = TRUE;
$paths[] = $saveto;
$date1=date("Y-m-d h:m:s");
$link=mysqli_connect("localhost","root","","vlindr");
mysqli_select_db($link,"imageupload"); //database connectivity
//Checks if Image already exists in database
$stmt = $link->prepare("SELECT * FROM images WHERE images_path=(?)");
$stmt->bind_param("s",$saveto);
$stmt->execute();
$stmt->store_result();
//If the amount of rows returned is zero, the script will insert the image into the database
if($stmt->num_rows === 0) {
//Inserts the image into the database
$stmt2 = $link->prepare("INSERT INTO images (images_id,images_path,submission_date) VALUES (NULL,?,?)");
$stmt2->bind_param("ss",$saveto,$date1);
if($stmt2->execute()) {
echo "Image is unique and uploaded to database";
}
switch($_FILES['images']['type'])
{
case "image/gif": $src = imagecreatefromgif($saveto); break;
case "image/jpeg": // Both regular and progressive jpegs
case "image/pjpeg": $src = imagecreatefromjpeg($saveto); break;
case "image/png": $src = imagecreatefrompng($saveto); break;
default: $typeok = FALSE; break;
}
if ($typeok)
{
list($w, $h) = getimagesize($saveto);
$max = 150;
$tw = $w;
$th = $h;
if ($w > $h && $max < $w)
{
$th = $max ;
$tw = $max;
}
elseif ($h > $w && $max < $h)
{
$tw = $max / $h * $w;
$th = $max;
}
elseif ($max < $w)
{
$tw = $th = $max;
}
$tmp = imagecreatetruecolor($tw, $th);
imagecopyresampled($tmp, $src, 0, 0, 0, 0, $tw, $th, $w, $h);
imageconvolution($tmp, array(array(-1, -1, -1),
array(-1, 16, -1), array(-1, -1, -1)), 8, 0);
imagejpeg($tmp, $saveto);
imagedestroy($tmp);
imagedestroy($src);
}
}//end if
else {
echo "Image Already Exists";
}//end else
Trying to add a transparent PNG watermark to jpg images get's me different results either if i'm on localhost or production server.
Here's the results...
On my localhost (PHP Version 5.6.24)
On production server (PHP Version 5.5.9-1ubuntu4.21)
I don't even know what to call this problem of the blue color turning pink and the logo doesn't get correctly rendered...
The code is this:
function getBrightness($gdHandle) {
$width = imagesx($gdHandle);
$height = imagesy($gdHandle);
$totalBrightness = 0;
for ($x = 0; $x < $width; $x++) {
for ($y = 0; $y < $height; $y++) {
$rgb = imagecolorat($gdHandle, $x, $y);
$red = ($rgb >> 16) & 0xFF;
$green = ($rgb >> 8) & 0xFF;
$blue = $rgb & 0xFF;
$totalBrightness += (max($red, $green, $blue) + min($red, $green, $blue)) / 2;
}
}
// imagedestroy($gdHandle);
return ($totalBrightness / ($width * $height)) / 2.55;
}
function render_text_on_gd_image(&$source_gd_image, $text, $font, $size, $color, $opacity, $rotation, $bpx, $bpy, $wnewx) {
$source_width = imagesx($source_gd_image);
$source_height = imagesy($source_gd_image);
$bb = imagettfbbox($size, $rotation, $font, $text);
$x0 = min($bb[0], $bb[2], $bb[4], $bb[6]);
$x1 = max($bb[0], $bb[2], $bb[4], $bb[6]);
$y0 = min($bb[1], $bb[3], $bb[5], $bb[7]);
$y1 = max($bb[1], $bb[3], $bb[5], $bb[7]);
$bb_width = abs($x1 - $x0);
$bb_height = abs($y1 - $y0);
$alpha_color = imagecolorallocatealpha(
$source_gd_image,
hexdec(substr($color, 0, 2)),
hexdec(substr($color, 2, 2)),
hexdec(substr($color, 4, 2)),
127 * (100 - $opacity) / 100
);
return imagettftext($source_gd_image, $size, $rotation, $bpx + $wnewx/2 - $bb_width/2 , $bpy, $alpha_color, $font, $text);
}
$val = array();
//$val["displayName"] = "Administrador";
$val["displayName"] = "Afonso Ferreira Gomes";
$val["relFile"] = "imagem.jpg";
list($val["width_original"], $val["height_original"]) = getimagesize($val["relFile"]);
if ($val["width_original"] > $val["height_original"] && $val["width_original"] >= 1200) {
$val["height_resized"] = $val["height_original"] * (1200/$val["width_original"]);
$val["width_resized"] = 1200;
} elseif ($val["height_original"] > $val["width_original"] && $val["height_original"] >= 1200) {
$val["height_resized"] = 1200;
$val["width_resized"] = (1200/$val["height_original"]) * $val["width_original"];
} else {
$val["height_resized"] = $val["height_original"];
$val["width_resized"] = $val["width_original"];
}
$i = imagecreatefromjpeg($val["relFile"]);
$i = imagescale($i, $val["width_resized"], $val["height_resized"]);
$val["width_new"] = imagesx($i);
$val["height_new"] = imagesy($i);
if ($val["width_new"] < $val["height_new"]) {
$val["portait"] = true;
$val["smallest"] = $val["width_new"];
} else {
$val["portait"] = false;
$val["smallest"] = $val["height_new"];
}
/* GERAR WATERMARK LOGOTIPO */
$val["racio"] = 0.20;
$val["marLeft"] = 40;
$val["marBottom"] = 40;
$val["bright"] = getBrightness($i);
if ($val["bright"] < 30) {
$val["opacidade"] = 20;
} else {
$val["opacidade"] = 40;
}
$w = imagecreatefrompng("jbw_260_40.png");
if ($val["portait"]) {
$val["water_width"] = $val["width_new"] * $val["racio"];
$val["water_height"] = $val["width_new"] * $val["racio"];
} else {
$val["water_width"] = $val["height_new"] * $val["racio"];
$val["water_height"] = $val["height_new"] * $val["racio"];
}
$wnew = imagescale($w, $val["water_width"], $val["water_height"]);
$val["water_width"] = imagesx($wnew);
$val["water_height"] = imagesy($wnew);
/* GERAR WATERMARK TEXTO AUTOR */
if ($val["displayName"] == "Administrador") {
$val["autor"] = "";
$val["marBottom"] = 20;
$val["marLeft"] = 20;
} else {
$val["autor"] = $val["displayName"];
}
// PRIMEIRO E ULTIMO NOME SÓ!!
$autorNomes = explode(" ", $val["autor"]);
if (count($autorNomes) >= 2) {
$val["autor"] = $autorNomes[0] . " " . $autorNomes[count($autorNomes) - 1];
} else {
$val["autor"] = $autorNomes[0];
}
$font = "../font/Montserrat.ttf";
$color = "FFFFFF";
$flagSize = false;
$val["fontSize"] = 12;
for ($size = 7; $size <= 50; $size += 0.5) {
$bb = imagettfbbox($size, 0, $font, $val["autor"]);
$x0 = min($bb[0], $bb[2], $bb[4], $bb[6]);
$x1 = max($bb[0], $bb[2], $bb[4], $bb[6]);
$y0 = min($bb[1], $bb[3], $bb[5], $bb[7]);
$y1 = max($bb[1], $bb[3], $bb[5], $bb[7]);
$val["bbox_width"] = abs($x1 - $x0);
$val["bbox_height"] = abs($y1 - $y0);
if (($val["bbox_width"] >= $val["water_width"] && !$flagSize) || $size == 50) {
$val["fontSize"] = $size;
$flagSize = true;
break;
}
}
$val["posY_water"] = $val["height_new"] - $val["water_height"] - $val["marBottom"];
$val["posY_text"] = $val["height_new"] - $val["marBottom"] + $val["bbox_height"] - 5;
imagecopy($i, $wnew, $val["marLeft"], $val["posY_water"] , 0, 0, $val["water_width"], $val["water_height"]);
render_text_on_gd_image($i, $val["autor"], $font, $val["fontSize"], $color, $val["opacidade"] ,0 , $val["marLeft"] , $val["posY_text"], $val["water_width"]);
// echo "<pre>"; print_r($val); echo "</pre>"; die;
/* OUTPUT IMAGEM E LIMPA BUFFER */
header('Content-type: image/png');
imagepng($i);
imagedestroy($i);
imagedestroy($w);
And this are the gd section of phpinfo for localhost and production server
What am I missing? this is driving me insane!
Those issues almost always object to the alpha channel of either the source or destination not beeing preserved or the output not really beeing true color.
Try using the imagesavealpha() function and search for "alpha" in the comments of the PHP documentation because there are many people having solutions to similiar issues.
This comment might be helpful and is kinda what Esko said:
http://php.net/manual/en/function.imagecreatefrompng.php#90364
Basically it copies an image to a buffer using imagecreatetruecolor().
I'm having the same issue. The imageScale function in Ubuntu seems to turn greens and blues to pink. Solution could be to use imagecopyresampled and imagecreatetruecolor. However this solution is way slower.
I have a function that, given an image with a transparent background and an unknown object in it, finds the top, left, right and bottom boundaries of the object. The purpose is so that I can simply draw a box around the boundaries of the object. I'm not trying to detect the actual edges of the object - just the top most, bottom most, etc.
My function works well, but is slow because it scans every single pixel in the image.
My question is: Is there a faster, more efficient way to detected the upper-most, left-most, right-most, and bottom-most non-transparent pixel in an image, using stock PHP/GD functionality?
There's a catch that affects the options: the object in the image may have transparent parts. For example, if it's an image of a non-filled shape.
public static function getObjectBoundaries($image)
{
// this code looks for the first non white/transparent pixel
// from the top, left, right and bottom
$imageInfo = array();
$imageInfo['width'] = imagesx($image);
$imageInfo['height'] = imagesy($image);
$imageInfo['topBoundary'] = $imageInfo['height'];
$imageInfo['bottomBoundary'] = 0;
$imageInfo['leftBoundary'] = $imageInfo['width'];
$imageInfo['rightBoundary'] = 0;
for ($x = 0; $x <= $imageInfo['width'] - 1; $x++) {
for ($y = 0; $y <= $imageInfo['height'] - 1; $y++) {
$pixelColor = imagecolorat($image, $x, $y);
if ($pixelColor != 2130706432) { // if not white/transparent
$imageInfo['topBoundary'] = min($y, $imageInfo['topBoundary']);
$imageInfo['bottomBoundary'] = max($y, $imageInfo['bottomBoundary']);
$imageInfo['leftBoundary'] = min($x, $imageInfo['leftBoundary']);
$imageInfo['rightBoundary'] = max($x, $imageInfo['rightBoundary']);
}
}
}
return $imageInfo;
}
Function calls in PHP are expensive. Calling imagecolorat() per pixel will absolutely ruin performance. Efficient coding in PHP means finding a built-in function that can somehow do the job. The following code makes use of the palette GD functions. At a glance it might not be intuitive but the logic is actually pretty simple: the code keeps copying the image a line of pixels at a time until it notices that it requires more than one colors to represent them.
function getObjectBoundaries2($image) {
$width = imagesx($image);
$height = imagesy($image);
// create a one-pixel high image that uses a PALETTE
$line = imagecreate($width, 1);
for($y = 0; $y < $height; $y++) {
// copy a row of pixels into $line
imagecopy($line, $image, 0, 0, 0, $y, $width, 1);
// count the number of colors in $line
// if it's one, then assume it's the transparent color
$count = imagecolorstotal($line);
if($count > 1) {
// okay, $line has employed more than one color so something's there
// look at the first color in the palette to ensure that our initial
// assumption was correct
$firstColor = imagecolorsforindex($line, 0);
if($firstColor['alpha'] == 127) {
$top = $y;
} else {
// it was not--the first color encountered was opaque
$top = 0;
}
break;
}
}
if(!isset($top)) {
// image is completely empty
return array('width' => $width, 'height' => $height);
}
// do the same thing from the bottom
$line = imagecreate($width, 1);
for($y = $height - 1; $y > $top; $y--) {
imagecopy($line, $image, 0, 0, 0, $y, $width, 1);
$count = imagecolorstotal($line);
if($count > 1) {
$firstColor = imagecolorsforindex($line, 0);
if($firstColor['alpha'] == 127) {
$bottom = $y;
} else {
$bottom = $height - 1;
}
break;
}
}
$nonTransparentHeight = $bottom - $top + 1;
// scan from the left, ignoring top and bottom parts known to be transparent
$line = imagecreate(1, $nonTransparentHeight);
for($x = 0; $x < $width; $x++) {
imagecopy($line, $image, 0, 0, $x, $top, 1, $nonTransparentHeight);
$count = imagecolorstotal($line);
if($count > 1) {
$firstColor = imagecolorsforindex($line, 0);
if($firstColor['alpha'] == 127) {
$left = $x;
} else {
$left = 0;
}
break;
}
}
// scan from the right
$line = imagecreate(1, $nonTransparentHeight);
for($x = $width - 1; $x > $left; $x--) {
imagecopy($line, $image, 0, 0, $x, $top, 1, $nonTransparentHeight);
$count = imagecolorstotal($line);
if($count > 1) {
$firstColor = imagecolorsforindex($line, 0);
if($firstColor['alpha'] == 127) {
$right = $x;
} else {
$right = $width - 1;
}
break;
}
}
return array('width' => $width, 'height' => $height, 'topBoundary' => $top, 'bottomBoundary' => $bottom, 'leftBoundary' => $left, 'rightBoundary' => $right);
}
I think you could test the 4 sides one after an other, stopping as soon as a pixel is found.
For the top boundary (untested code) :
// false so we can test it's value
$bound_top = false;
// The 2 loops have 2 end conditions, if end of row/line, or pixel found
// Loop from top to bottom
for ($y = 0; $y < $img_height && $bound_top === false; $y++) {
// Loop from left to right (right to left would work to)
for ($x = 0; $x < $img_width && $bound_top === false; $x++) {
if (imageColorAt($img, $x, $y) != 2130706432) {
$bound_top = $y;
}
}
}
After the loops, if $bound_top is still false, don't bother checking the other sides, you checked all pixels, the image is empty. If not, just do the same for the other sides.
Not every pixel needs to be examined. The following code checks columns from left to right to get leftBoundary, right to left to get rightBoundary, rows from top to bottom (while excluding pixels we've already checked) to get topBoundary, and similarly for bottomBoundary.
function get_boundary($image)
{
$imageInfo = array();
$imageInfo['width'] = imagesx($image);
$imageInfo['height'] = imagesy($image);
for ($x = 0; $x < $imageInfo['width']; $x++) {
if (!is_box_empty($image, $x, 0, 1, $imageInfo['height'])) {
$imageInfo['leftBoundary'] = $x;
break;
}
}
for ($x = $imageInfo['width']-1; $x >= 0; $x--) {
if (!is_box_empty($image, $x, 0, 1, $imageInfo['height'])) {
$imageInfo['rightBoundary'] = $x;
break;
}
}
for ($y = 0; $y < $imageInfo['height']; $y++) {
if (!is_box_empty($image, $imageInfo['leftBoundary'], $y, $imageInfo['rightBoundary']-$imageInfo['leftBoundary']+1, 1)) {
$imageInfo['topBoundary'] = $y;
break;
}
}
for ($y = $imageInfo['height']-1; $y >= 0; $y--) {
if (!is_box_empty($image, $imageInfo['leftBoundary'], $y, $imageInfo['rightBoundary']-$imageInfo['leftBoundary']+1, 1)) {
$imageInfo['bottomBoundary'] = $y;
break;
}
}
return $imageInfo;
}
function is_box_empty($image, $x, $y, $w, $h)
{
for ($i = $x; $i < $x+$w; $i++) {
for ($j = $y; $j < $y+$h; $j++) {
$pixelColor = imagecolorat($image, $i, $j);
if ($pixelColor != 2130706432) { // if not white/transparent
return false;
}
}
}
return true;
}
On upload of images, the code creates several different thumbnails. In some cases, the thumbnail may be larger than the original image, in which case a padding is applied. In the case of JPEGs, the padding is white, and all is well. In the case of GIFs and PNGs, the padding should be transparent. And it is. Or not. Which is weird.
If I was getting an entirely black or transparent padding, I'd have some idea where the problem is, but I'm getting paddings which are transparent in places and black in others, which makes no sense.
Sample PNG and GIF images at http://filedump.xn--es-zka.info/broken_thumbs/ (on a shocking pink background colour so you can see the difference between white and transparent).
Any bright ideas?
class Image {
public static function exec($path) {
// This function receives the path to an image.
// Logic here skipped: For each thumbnail, check whether Crop is set. If it is, call self::crop(). Otherwise, call self::resize().
return true;
}
public static function resize($file, $class, $width='-', $height='-', $fit=0) {
$a = getimagesize($file);
switch ($a[2]) {
case 1:
$tag = 'gif';
break;
case 2:
$tag = 'jpeg';
break;
case 3:
$tag = 'png';
break;
default:
return;
}
$w = $a[0];
$h = $a[1];
if ($width == 0) {
$fw = 0;
$fh = $h / $height;
} elseif ($height == 0) {
$fw = $w / $width;
$fh = 0;
} else {
$fw = $w / $width;
$fh = $h / $height;
}
if (($fw == 1) and ($fh == 1)) {
$file2 = dirname($file) . '/' . $class . basename($file);
copy($file, $file2);
return true;
} elseif (($fw >= 1) and ($fh >= 1)) {
if ($fw > $fh) {
$w = $width;
$h = floor($h / $fw);
} else {
$h = $height;
$w = floor($w / $fh);
}
} elseif ($fh == 0) {
if ($fw > 1) {
$fit = 0;
$w = $width;
$h = floor($h / $fw);
} else {
if ($fit) {
$height = $h;
}
}
} elseif ($fw == 0) {
if ($fh > 1) {
$fit = 0;
$w = floor($w / $fh);
$h = $height;
} else {
if ($fit) {
$width = $w;
}
}
} elseif (($fw < 1) and ($fh < 1)) {
//
} elseif ($fw > $fh) {
if ($fw >= 1) {
$w = $width;
$h = floor($h / $fw);
}
} elseif ($fh > $fw) {
if ($fh >= 1) {
$w = floor($w / $fh);
$h = $height;
}
}
if ($fit) {
$x = ($width - $w) / 2;
$y = ($height - $h) / 2;
$cw = $width;
$ch = $height;
} else {
$x = 0;
$y = 0;
$cw = $w;
$ch = $h;
}
$file2 = dirname($file) . '/' . $class . basename($file);
$f1 = 'imagecreatefrom' . $tag;
$src = $f1($file);
$new = imagecreatetruecolor($cw, $ch);
return self::create($new, $src, $file2, $x, $y, $w, $h, $a);
}
public static function crop($file, $class, $width='-', $height='-', $fit=0) {
if (!$class) return trigger_error('ExecImage: Original image can not be overwritten.');
$small = 0;
$a = getimagesize($file);
switch ($a[2]) {
case 1:
$tag = 'gif';
break;
case 2:
$tag = 'jpeg';
break;
case 3:
$tag = 'png';
break;
default:
return;
}
$w = $a[0];
$h = $a[1];
if ($height == 0) {
//resize by width -- height will follow
$fh = 0;
$fw = $w / $width;
} elseif ($width == 0) {
//resize by height -- width will follow
$fw = 0;
$fh = $h / $height;
} else {
$fw = $w / $width;
$fh = $h / $height;
}
if (($fw <= 1) and ($fh <= 1)) {
$small = 1;
//don't resize
} else {
$fit = 1;
//chop by the smallest
if ($fh < $fw) {
//Crop By Height
$h = $height;
$w = floor($w / $fh);
//$w = $width;
//$h = floor($h /$fw);
//$w = $width;
} else {
//Crop By Width
$w = $width;
$h = floor($h /$fw);
//$h = $height;
//$w = floor($w / $fh);
}
}
$file2 = dirname($file) . '/' . $class . basename($file);
$f1 = 'imagecreatefrom' . $tag;
$src = $f1($file);
if ($small) {
if ($fit) {
//image must be padded
$x = ($width - $w) / 2;
$y = ($height - $h) / 2;
} else {
//image goes as is -- shrinked
$x = 0;
$y = 0;
}
} else {
//image must be centered -- this should be a square from js
$x = ($width - $w) / 2;
$y = ($height - $h) / 2;
}
if ($small) {
if ($fit) {
//create with the full size
$new = imagecreatetruecolor($width, $height);
} else {
//nah, just with the original size
$new = imagecreatetruecolor($w, $h);
}
} else {
if ($fit) {
$new = imagecreatetruecolor($width, $height);
} else {
$new = imagecreatetruecolor($w, $h);
}
}
return self::create($new, $src, $file2, $x, $y, $w, $h, $a);
}
private static function create($new, $src, $file2, $x, $y, $w, $h, $a) {
switch ($a[2]) {
case 1: // GIF
case 3: // PNG
// http://www.akemapa.com/2008/07/10/php-gd-resize-transparent-image-png-gif/
// http://www.mummey.org/2008/11/transparent-gifs-with-php-and-gd/
imagealphablending($new, false);
imagesavealpha($new, true);
$back = imagecolorallocatealpha($new, 255, 255, 255, 127);
imagefilledrectangle($new, 0, 0, $w, $h, $back);
imagecolortransparent($new, $back);
break;
case 2: // JPEG
$back = imagecolorallocate($new, 255, 255, 255);
break;
}
imagefill($new, 0, 0, $back);
imagecopyresampled($new, $src, $x, $y, 0, 0, $w, $h, $a[0], $a[1]);
if (file_exists($file2)) unlink($file2);
switch ($a[2]) {
case 1:
imagegif($new, $file2);
break;
case 2:
imagejpeg($new, $file2, 100);
break;
case 3:
imagepng($new, $file2, 0);
break;
}
imagedestroy($src);
imagedestroy($new);
return true;
}
}
Revision/Edit to add:
Well, I've solved the main problem: padding added to PNG or GIF images is now transparent, instead of black. The smaller problem, that GIF transparency becomes black, is still with us, but I don't use GIF transparency much.
<?php
class Image {
public static function exec($path) {
$file = Nearest::file('.config.php', dirname($path) . '/', BD . '/images/');
if (!file_exists($file)) exit('The ".config.php" file doesnt exist');
require $file;
foreach ($config['operations'] as $k => $v) {
if (!isset($v['class'])) $v['class'] = '.' . $k . '.';
if (Core::val($v, 'crop')) {
self::crop($path, $v['class'], Core::val($v, 'width', '-'), Core::val($v, 'height', '-'), Core::val($v, 'fit', 0));
} else {
self::resize($path, $v['class'], Core::val($v, 'width', '-'), Core::val($v, 'height', '-'), Core::val($v, 'fit', 0));
}
}
return true;
}
public static function delete($path) {
$a = glob(dirname($path) . '/.*.' . basename($path));
foreach ($a as $v) unlink($v);
unlink($path);
}
public static function resize($file, $class, $width='-', $height='-', $fit=0) {
$a = getimagesize($file);
switch ($a[2]) {
case 1:
$tag = 'gif';
break;
case 2:
$tag = 'jpeg';
break;
case 3:
$tag = 'png';
break;
default:
return;
}
$w = $a[0];
$h = $a[1];
if ($width == 0) {
$fw = 0;
$fh = $h / $height;
} elseif ($height == 0) {
$fw = $w / $width;
$fh = 0;
} else {
$fw = $w / $width;
$fh = $h / $height;
}
if (($fw == 1) and ($fh == 1)) {
$file2 = dirname($file) . '/' . $class . basename($file);
copy($file, $file2);
return true;
} elseif (($fw >= 1) and ($fh >= 1)) {
if ($fw > $fh) {
$w = $width;
$h = floor($h / $fw);
} else {
$h = $height;
$w = floor($w / $fh);
}
} elseif ($fh == 0) {
if ($fw > 1) {
$fit = 0;
$w = $width;
$h = floor($h / $fw);
} else {
if ($fit) {
$height = $h;
}
}
} elseif ($fw == 0) {
if ($fh > 1) {
$fit = 0;
$w = floor($w / $fh);
$h = $height;
} else {
if ($fit) {
$width = $w;
}
}
} elseif (($fw < 1) and ($fh < 1)) {
//
} elseif ($fw > $fh) {
if ($fw >= 1) {
$w = $width;
$h = floor($h / $fw);
}
} elseif ($fh > $fw) {
if ($fh >= 1) {
$w = floor($w / $fh);
$h = $height;
}
}
if ($fit) {
$x = ($width - $w) / 2;
$y = ($height - $h) / 2;
$cw = $width;
$ch = $height;
} else {
$x = 0;
$y = 0;
$cw = $w;
$ch = $h;
}
$file2 = dirname($file) . '/' . $class . basename($file);
$f1 = 'imagecreatefrom' . $tag;
$src = $f1($file);
$new = imagecreatetruecolor($cw, $ch);
return self::create($new, $src, $file2, $x, $y, $w, $h, $cw, $ch, $a);
}
public static function crop($file, $class, $width='-', $height='-', $fit=0) {
if (!$class) exit('ExecImage: Original image can not be overwrite.');
$small = 0;
$a = getimagesize($file);
switch ($a[2]) {
case 1:
$tag = 'Gif';
break;
case 2:
$tag = 'Jpeg';
break;
case 3:
$tag = 'Png';
break;
default:
return;
}
$w = $a[0];
$h = $a[1];
if ($height == 0) {
//resize by width -- height will follow
$fh = 0;
$fw = $w / $width;
} elseif ($width == 0) {
//resize by height -- width will follow
$fw = 0;
$fh = $h / $height;
} else {
$fw = $w / $width;
$fh = $h / $height;
}
if (($fw <= 1) and ($fh <= 1)) {
$small = 1;
//dont resize
} else {
$fit = 1;
//chop by the smallest
if ($fh < $fw) {
//Crop By Height
$h = $height;
$w = floor($w / $fh);
//$w = $width;
//$h = floor($h /$fw);
//$w = $width;
} else {
//Crop By Width
$w = $width;
$h = floor($h /$fw);
//$h = $height;
//$w = floor($w / $fh);
}
}
$file2 = dirname($file) . '/' . $class . basename($file);
$f1 = 'ImageCreateFrom' . $tag;
$src = $f1($file);
if ($small) {
if ($fit) {
//image must be padded
$x = ($width - $w) / 2;
$y = ($height - $h) / 2;
} else {
//image goes as is -- shrinked
$x = 0;
$y = 0;
}
} else {
//image must be centered -- this should be a square from js
$x = ($width - $w) / 2;
$y = ($height - $h) / 2;
}
if ($small) {
if ($fit) {
//create with the full size
$new = imagecreatetruecolor($width, $height);
return self::create($new, $src, $file2, $x, $y, $w, $h, $width, $height, $a);
} else {
//nah, just with the original size
$new = imagecreatetruecolor($w, $h);
return self::create($new, $src, $file2, $x, $y, $w, $h, $w, $h, $a);
}
} else {
if ($fit) {
//create with the full size
$new = imagecreatetruecolor($width, $height);
return self::create($new, $src, $file2, $x, $y, $w, $h, $width, $height, $a);
} else {
//nah, just with the original size
$new = imagecreatetruecolor($w, $h);
return self::create($new, $src, $file2, $x, $y, $w, $h, $w, $h, $a);
}
}
}
private static function create($new, $src, $file2, $x, $y, $w, $h, $cw, $ch, $a) {
switch ($a[2]) {
case 1: // GIF
case 3: // PNG
// http://www.akemapa.com/2008/07/10/php-gd-resize-transparent-image-png-gif/
// http://www.mummey.org/2008/11/transparent-gifs-with-php-and-gd/
imagealphablending($new, false);
imagesavealpha($new, true);
$back = imagecolorallocatealpha($new, 255, 255, 255, 127);
imagefilledrectangle($new, 0, 0, $cw, $ch, $back);
imagecolortransparent($new, $back);
break;
case 2: // JPEG
$back = imagecolorallocate($new, 255, 255, 255);
break;
}
imagefill($new, 0, 0, $back);
imagecopyresampled($new, $src, $x, $y, 0, 0, $w, $h, $a[0], $a[1]);
if (file_exists($file2)) unlink($file2);
switch ($a[2]) {
case 1:
imagegif($new, $file2);
break;
case 2:
imagejpeg($new, $file2, 100);
break;
case 3:
imagepng($new, $file2, 0);
break;
}
imagedestroy($src);
imagedestroy($new);
return true;
}
}
So, any hints on how to preserve GIF transparency?
You put a link with your answer ;)
You're using imageCopyResampled which acts weird with alpha. Use imageCopyResized instead.
http://www.mummey.org/2008/11/transparent-gifs-with-php-and-gd/comment-page-1/#comment-94