PHP GD Move Picture Up 1 Px - php

I need to take an image and move it upwards 1 px in certain situations for my code, but with what GD function would I use to do that? I couldn't find another question that asked this, so I asked it. But the middle of the picture is a number and the background is transparent, and the height and width is almost always different

Here's an example. The key part is imagecopymerge() function. play with it's 0,0,1,0 values.
<?php
$src = imagecreatefromgif($img);
list($w,$h) = getimagesize($img);
$sprite = imagecreatetruecolor($w,$h);
$trans = imagecolortransparent($sprite);
imagealphablending($sprite, false);
imagesavealpha($sprite, true);
imagepalettecopy($sprite,$src);
imagefill($sprite,0,0,imagecolortransparent($src));
imagecolortransparent($sprite,imagecolortransparent($src));
imagecopy($sprite,$src,0,0,1,0,$w,$h);
imagegif($sprite,$img);
imagedestroy($sprite);
imagedestroy($src);
?>

Related

Calculate nearest possible dimension value PHP (keeping ratio)

I am trying to implement API for image resizing. It is created not exactly for image processing, this is only one part/feature of API.
What I want to implement.
I have url for retrieving image from server it looks like
mywebpage.com/api/product/42/image
This url will return URL to full image of product with id 42.
Everything is ok.
We can specify desired size with GET parameters like this
mywebpage.com/api/product/42/image?width=200&height=300
It also looks fine
But my question if following.
As we can have different images on server with different dimension and aspect ratio, I need to keep this ratio while resizing.
For example I need image to fit 200x300 container but I have 1024x576 (16:9) image on the server. I need to resize this image but keep initial aspect ratio(16:9) but to fit desired container.
How can I efficiently calculate new image size to return depending on incoming desired dimension and current image aspect ratio.
I want to thank everyone in advance for any help or advises.
Here is a script I used to make similar thing. Quite old , so may be not up to date.
<?php
if( isset($_GET["width"]) && is_numeric($_GET["width"]))
$target_width = intval($_GET["width"]);
else
$target_width= 200;//default value
if( isset($_GET["height"]) && is_numeric($_GET["height"]))
$target_height = intval($_GET["width"]);
else
$target_height= 300;//default value
if( isset($_GET["id"]) && is_numeric($_GET["id"]))//prevent any unwanted filesystem access
$original_image_path = "img/products/$id.jpg";
else
$original_image_path = "placeholder.png"
//http://php.net/manual/fr/function.getimagesize.php
$image_size = getimagesize($original_image_path);
//get the ratio of the original image
$image_ratio= $image_size[1]/ $image_size[0];
$original_image = imagecreatefromjpeg($original_image_path);
$new_image = imagecreatetruecolor($target_width, $image_ratio * $target_width);
//paints the image in white
//http://php.net/manual/en/function.imagefill.php
//http://php.net/manual/en/function.imagecolorallocatealpha.php
imagefill( $new_image, 0, 0, imagecolorallocatealpha($new_image, 255,255,255,127) );
imagesavealpha($new_image, TRUE);
/*
Copies the original to the new, preserving the ratio.
The original image fills all the width of the new,
and is placed on the top of the new.
http://php.net/manual/en/function.imagecopyresized.php
*/
imagecopyresized(
$new_image,$original_image,
0,0,
0,0,
$target_width,$image_ratio * $target_width,
$image_size[0],$image_size[1]
);
//image is returned in response to the request
header ("Content-type: image/png");
imagepng( $new_image );
?>
Well if you need to always fit a container of 200x300 (or what ever is passed through the URL), you may not because able to simply resize it because as you are aware it will affect the images aspect ratio.
If this is the case what you can do is resize the image to the closest size then crop the remainder of the image.
I assume you will be using imagemagick for this. Have you checked out the documentation? The cropThumbnailImage method does what I just explained.
Example usage:
/* Read the image */
$im = new imagick( "test.png" );
/* create the thumbnail */
$im->cropThumbnailImage( 80, 80 );
/* Write to a file */
$im->writeImage( "th_80x80_test.png" );
http://php.net/manual/en/imagick.cropthumbnailimage.php

PHP GD Image Library change image color - gif works but jpegs wont

Thanks for taking the time to read my problem:
I'm using the following code to get an image and then change the color 201,2,255 (r,g,b) - which is a shade of purple then output the image.
$imgname = "input.gif";
$im = imagecreatefromgif ($imgname);
$index = imagecolorclosest ( $im, 201,2,255 ); // get White COlor
imagecolorset($im,$index,60,140,48); // SET NEW COLOR
$imgname = "output.gif";
imagegif($im, $imgname ); // save image as gif
imagedestroy($im);
This works perfectly which can be seen here : http://www.office-desks.co.uk/cache_images/test.php (top 2 images)
The problem is when I try todo exactly the same but using a jpeg instead it doesn't work.. (bottom 2 images)
$imgname = "input.jpg";
$im = imagecreatefromjpeg ($imgname);
$index = imagecolorclosest ( $im, 201,2,255 ); // get pink/purple COlor
imagecolorset($im,$index,60,140,48); // SET NEW DECENT COLOR
$imgname = "output.jpg";
imagejpeg($im, $imgname ); // save image as gif
imagedestroy($im);
If anyone could help me shed some light on the problem, would be much appreciated. Thanks in advance all.
A bit late, but I think that has to do with the 'artifacts' (compression errors) generated by JPG. Zoom in on a JPG and you see 'grains' of pixels that won't match the neighbors. This means big planes of a single color will become many colors and not 1 single value.
Stick with lossless image formats like gif or png.

circularize an image with imagick

Trying to take a rectangular photo, crop it into a square region, and then mask it into a circular with a transparent background.
//$dims is an array with the width, height, x, y of the region in the rectangular image (whose path on disk is $tempfile)
$circle = new \Imagick();
$circle->newImage($dims['w'], $dims['h'], 'none');
$circle->setimageformat('png');
$circle->setimagematte(true);
$draw = new \ImagickDraw();
$draw->setfillcolor('#ffffff');
$draw->circle($dims['w']/2, $dims['h']/2, $dims['w']/2, $dims['w']);
$circle->drawimage($draw);
$imagick = new \Imagick();
$imagick->readImage($tempfile);
$imagick->setImageFormat( "png" );
$imagick->setimagematte(true);
$imagick->cropimage($dims['w'], $dims['h'], $dims['x'], $dims['y']);
$imagick->compositeimage($circle, \Imagick::COMPOSITE_DSTIN, 0, 0);
$imagick->writeImage($tempfile);
$imagick->destroy();
The result is the rectangular image, uncropped and without being circularized. What am I doing wrong?
Example image:
Example input for $dims = {"x":253,"y":0,"x2":438.5,"y2":185.5,"w":185.5,"h":185.5}
Rough expected output:
Image i'm getting looks roughly like the input image.
For those with an older version of Imagick (setimagematte does not exist in version lower than 6.2.9), I came up with an easy solution. The thing here is to copy opacity from the mask to the original image.
Original Image:
Mask:
Result:
The code:
$base = new Imagick('original.jpg');
$mask = new Imagick('mask.png');
$base->compositeImage($mask, Imagick::COMPOSITE_COPYOPACITY, 0, 0);
$base->writeImage('result.png');
You could use an Imagick black circle as mask but I though it wasn't perfect so I used my own.
Of course you will certainly have to resize / crop your images but that's another story.
Hope this helps.
J.
This works for me:
<?php
//$dims is an array with the width, height, x, y of the region in the rectangular image (whose path on disk is $tempfile)
$tempfile = 'VDSlU.jpg';
$outfile = 'blah.png';
$circle = new Imagick();
$circle->newImage(185.5, 185.5, 'none');
$circle->setimageformat('png');
$circle->setimagematte(true);
$draw = new ImagickDraw();
$draw->setfillcolor('#ffffff');
$draw->circle(185.5/2, 185.5/2, 185.5/2, 185.5);
$circle->drawimage($draw);
$imagick = new Imagick();
$imagick->readImage($tempfile);
$imagick->setImageFormat( "png" );
$imagick->setimagematte(true);
$imagick->cropimage(185.5, 185.5, 253, 0);
$imagick->compositeimage($circle, Imagick::COMPOSITE_DSTIN, 0, 0);
$imagick->writeImage($outfile);
$imagick->destroy();
?>
<img src="blah.png">
I always try to keep the code simple until I get it working and then add all the variables etc. That could be the problem or there could be a problem with your version of Imagick.
It's namespaced
Still do not know what it means! - I am getting a bit behind with php as I do not use it very much these days.
There's also another workaround that I suggest here :
// create an imagick object of your image
$image = new \Imagick('/absolute/path/to/your/image');
// crop square your image from its center (100px witdh/height in my example)
$image->cropThumbnailImage(100, 100);
// then round the corners (0.5x the width and height)
$image->roundCorners(50, 50);
// force the png format for transparency
$image->setImageFormat("png");
// write the new image
$image->writeImage('/absolute/path/to/your/new/image');
// done!
Many thanks to all previous answers and contributors that lead me to this code!
Feel free to test/comment my solution!
I stumbled upon this as I was searching for a similar solution for Ruby on Rails, notice that this Stackoverflow question uses vignette instead which seems to be a much simpler way to solve the problem.
I used vignette to solve my problem with rounded images in Ruby on Rails using Dragonfly.

Imagick Resize, Center, and Sparse Fill problems

My end goal here is to resize the input image to 100px width, 125px height. Some of the input images are a different Aspect Ratio, so I wish for them to be in a 100x125 container with the background sparse filled from their edge color.
Ok, so this works for the basic resize:
$image = new Imagick($imgFile);
$image->resizeImage(100,0, Imagick::FILTER_LANCZOS, 1, false);
$image->writeImage("$Dir/$game.png");
header("Content-type: ".$image->getImageFormat());
echo $image;
$image->clear();
$image->destroy();
However I've been searching for hours, and I cannot find a simple "This is how you center an image in a canvas" bit for PHP's Imagick library. Everything is for the actual ImageMagick convert application, which is not really what I'm after. I've tried compositing the resized image into an empty newImage with the set width and height, but it just seems to overwrite the dimensions regardless of the composite type, setting the Gravity to center and then the extent to 100x125 has no effect ( It always sits at 0,0, and trying to set the y offset to ((125-imageheight)/2) resulted in an offset that was way more than it should have been )
Edit:
$imageOutput = new Imagick();
$image = new Imagick($imgFile);
$image->resizeImage(100,0, Imagick::FILTER_LANCZOS, 1, false);
$imageOutput->newImage(100, 125, new ImagickPixel('black'));
$imageOutput->compositeImage($image, Imagick::COMPOSITE_ADD, 0, ((125 - $image->getImageHeight()))/2 );
$imageOutput->setImageFormat('png');
$imageOutput->writeImage("$Dir/$game.png");
header("Content-type: ".$imageOutput->getImageFormat());
echo $imageOutput;
$image->clear();
$image->destroy();
So I got my centering working, gravity apparently has no effect on actual images.
I have absolutely no idea where I would even begin to try and recreate a command line edge-in sparse fill in PHP with the library.
I ended up using a combination of Imagick and shell calls to convert itself, I'll eventually rewrite it to use entirely shell calls. I also changed my dimensions, here's the code:
$imageOutput = new Imagick(); // This will hold the resized image
$image = new Imagick($imgFile); // Open image file
$image->resizeImage(120,0, Imagick::FILTER_LANCZOS, 1, false); // Resize it width-wise
$imageOutput->newImage(120, 150, "none"); // Make the container with transparency
$imageOutput->compositeImage($image, Imagick::COMPOSITE_ADD, 0, ((150 - $image->getImageHeight())/2) ); // Center the resized image inside of the container
$imageOutput->setImageFormat('png'); // Set the format to maintain transparency
$imageOutput->writeImage("$Dir/$game.temp.png"); // Write it to disk
$image->clear(); //cleanup -v
$image->destroy();
$imageOutput->clear();
$imageOutput->destroy();
//Now the real fun
$edge = shell_exec("convert $Dir/$game.temp.png -channel A -morphology EdgeIn Diamond $Dir/$game.temp.edge.png"); // Get the edges of the box, create an image from just that
$shepards = shell_exec("convert $Dir/$game.temp.edge.png txt:- | sed '1d; / 0) /d; s/:.* /,/;'"); // get the pixel coordinates
$final = shell_exec("convert $Dir/$game.temp.edge.png -alpha off -sparse-color shepards '$shepards' png:- | convert png:- $Dir/$game.temp.png -quality 90 -composite $Dir/$game.jpg"); // Sparse fill the entire container using the edge of the other image as shepards , then composite that on top of this new image
unlink("$Dir/$game.temp.png"); // cleanup temp files
unlink("$Dir/$game.temp.edge.png");
set_header_and_serve("$Dir/$game.jpg"); // serve the newly created file

Detect main colors in an image with PHP

I am trying to replicate the functionality that Dribbble.com does with detecting the predominant colors in an Image. In the image below you can see a screenshot from Dribbble.com that shows the 8 predominant colors in the image to the left. Here is the actual page in the image http://dribbble.com/shots/528033-Fresh-Easy?list=following
I need to be able to do this in PHP, once I get the colors I need I will save them to a database so the processing does not need to be run on every page load.
After some research on how to get these colors out of an Image, some people said you simply examine an image pixel by pixel and then save the colors that occur the most. Other say there is more to it and that getting the colors that exist the most frequent won't give the desired affect. They say you need to Quantize the image/colors (I am lost at this point).
In the image below the Dribble shot below is a Javascript library that does the same thing, that page can be viewed here http://lokeshdhakar.com/projects/color-thief/
Viewing the source of that page I can see there is a Javascript file named quantize.js and the results are really good. So I am hoping to be able to do what that Javascript library does but with PHP and GD/ImageMagick
I had found this function that will return the colors and count in an Image with PHP but the results are different from the Javascript version above and the Dribble results
/**
* Returns the colors of the image in an array, ordered in descending order, where the keys are the colors, and the values are the count of the color.
*
* #return array
*/
function Get_Color()
{
if (isset($this->image))
{
$PREVIEW_WIDTH = 150; //WE HAVE TO RESIZE THE IMAGE, BECAUSE WE ONLY NEED THE MOST SIGNIFICANT COLORS.
$PREVIEW_HEIGHT = 150;
$size = GetImageSize($this->image);
$scale=1;
if ($size[0]>0)
$scale = min($PREVIEW_WIDTH/$size[0], $PREVIEW_HEIGHT/$size[1]);
if ($scale < 1)
{
$width = floor($scale*$size[0]);
$height = floor($scale*$size[1]);
}
else
{
$width = $size[0];
$height = $size[1];
}
$image_resized = imagecreatetruecolor($width, $height);
if ($size[2]==1)
$image_orig=imagecreatefromgif($this->image);
if ($size[2]==2)
$image_orig=imagecreatefromjpeg($this->image);
if ($size[2]==3)
$image_orig=imagecreatefrompng($this->image);
imagecopyresampled($image_resized, $image_orig, 0, 0, 0, 0, $width, $height, $size[0], $size[1]); //WE NEED NEAREST NEIGHBOR RESIZING, BECAUSE IT DOESN'T ALTER THE COLORS
$im = $image_resized;
$imgWidth = imagesx($im);
$imgHeight = imagesy($im);
for ($y=0; $y < $imgHeight; $y++)
{
for ($x=0; $x < $imgWidth; $x++)
{
$index = imagecolorat($im,$x,$y);
$Colors = imagecolorsforindex($im,$index);
$Colors['red']=intval((($Colors['red'])+15)/32)*32; //ROUND THE COLORS, TO REDUCE THE NUMBER OF COLORS, SO THE WON'T BE ANY NEARLY DUPLICATE COLORS!
$Colors['green']=intval((($Colors['green'])+15)/32)*32;
$Colors['blue']=intval((($Colors['blue'])+15)/32)*32;
if ($Colors['red']>=256)
$Colors['red']=240;
if ($Colors['green']>=256)
$Colors['green']=240;
if ($Colors['blue']>=256)
$Colors['blue']=240;
$hexarray[]=substr("0".dechex($Colors['red']),-2).substr("0".dechex($Colors['green']),-2).substr("0".dechex($Colors['blue']),-2);
}
}
$hexarray=array_count_values($hexarray);
natsort($hexarray);
$hexarray=array_reverse($hexarray,true);
return $hexarray;
}
else die("You must enter a filename! (\$image parameter)");
}
So I am asking if anyone knows how I can do such a task with PHP? Possibly something exist already that you know of or any tips to put me a step closer to doing this would be appreciated
Here's exactly what you're looking for in PHP: https://github.com/thephpleague/color-extractor
Example :
use League\ColorExtractor\Palette;
$palette = Palette::fromFilename('some/image.png');
$topEightColors = $palette->getMostUsedColors(8);
This is my simple method to get the main color of an image
$image=imagecreatefromjpeg('image.jpg');
$thumb=imagecreatetruecolor(1,1);
imagecopyresampled($thumb,$image,0,0,0,0,1,1,imagesx($image),imagesy($image));
$mainColor=strtoupper(dechex(imagecolorat($thumb,0,0)));
echo $mainColor;
You need to scale down the picture and you will get the main colors of the picture. If you need 4 colors in the pallet, scale it down to about 8x8, 6 colors to about 12x8 and so on...
imagecopyresized for scaled down image then check every pixels and store them in array imagecolorat($image,px,py)
Try this out
<?php
// EXAMPLE PICTURE
$url='https://www.nordoff-robbins.org.uk/sites/default/files/google.jpg';
//var_dump(getColorPallet($url));
echoColors(getColorPallet($url));
function echoColors($pallet){ // OUTPUT COLORSBAR
foreach ($pallet as $key=>$val)
echo '<div style="display:inline-block;width:50px;height:20px;background:#'.$val.'"> </div>';
}
function getColorPallet($imageURL, $palletSize=[16,8]){ // GET PALLET FROM IMAGE PLAY WITH INPUT PALLET SIZE
// SIMPLE CHECK INPUT VALUES
if(!$imageURL) return false;
// IN THIS EXEMPLE WE CREATE PALLET FROM JPG IMAGE
$img = imagecreatefromjpeg($imageURL);
// SCALE DOWN IMAGE
$imgSizes=getimagesize($imageURL);
$resizedImg=imagecreatetruecolor($palletSize[0],$palletSize[1]);
imagecopyresized($resizedImg, $img , 0, 0 , 0, 0, $palletSize[0], $palletSize[1], $imgSizes[0], $imgSizes[1]);
imagedestroy($img);
//CHECK IMAGE
/*header("Content-type: image/png");
imagepng($resizedImg);
die();*/
//GET COLORS IN ARRAY
$colors=[];
for($i=0;$i<$palletSize[1];$i++)
for($j=0;$j<$palletSize[0];$j++)
$colors[]=dechex(imagecolorat($resizedImg,$j,$i));
imagedestroy($resizedImg);
//REMOVE DUPLICATES
$colors= array_unique($colors);
return $colors;
}
?>
Works perfect for me.
The page you linked to has a link to the source code on GitHub so if you want to know exactly how they are doing you could replicate their source in PHP.
The big difference between how they are doing it and how you are doing it, is that they are using clustering to find the color. Instead of rounding the color when they store it, they are storing all of the raw colors in an array. Then they loop through this array until they find a cluster that has the highest ratio of points in the cluster to number of colors in the cluster. The center point of this is the most common color. The palette is then defined by the next highest sets of clusters, with some logic to prevent near complete overlap of the clusters.
Try this: http://www.coolphptools.com/color_extract
Works with JPEG and PNG.
And best!: no hustle with composer, just require_once
require_once 'colorextract/colors.inc.php';
$ex=new GetMostCommonColors();
$num_results=20;
$reduce_brightness=1;
$reduce_gradients=1;
$delta=24;
$colors=$ex->Get_Color( 'image.png', $num_results, $reduce_brightness, $reduce_gradients, $delta);
print_r($colors);
give you something like this:
Array (
[3060a8] => 0.55827380952381
[f0a848] => 0.19791666666667
[000000] => 0.069642857142857
[483018] => 0.02047619047619
[786018] => 0.01827380952381
[183060] => 0.01797619047619
[4878a8] => 0.016011904761905
[181800] => 0.015119047619048
[a87830] => 0.014345238095238
[a8c0d8] => 0.011904761904762
[6090c0] => 0.01172619047619
[d89030] => 0.011011904761905
[90a8d8] => 0.0071428571428571
[ffffff] => 0.0070238095238095
[604830] => 0.006547619047619
[f0f0f0] => 0.0063095238095238
[d8d8f0] => 0.005297619047619
[c0d8d8] => 0.0044047619047619
[f0f0ff] => 0.00041666666666667
[181830] => 0.00011904761904762 )
I tried it with different images and it seems reliable.
The idea of getting the predominant colors of the image is a bit tricky, because for example the most frequent pixel color could be so widely scattered in the image that it is not perceived as a predominant color at all.
I think an algorithm like Color coherence vector will be good enough to overcome this issue, because it clusters the colors into coherent and incoherent (which is quite intuitive), and then you can use them to discard those false positive predominant colors.
I see it is an easy algorithm to implement, this tutorial Image Retrieval: Color Coherence Vector describes describes its steps with examples of how it works and there is even a matlab implementation mentioned at the end of it.
I have a Unix bash shell script with ImageMagick called dominantcolor that may do what you want. See my scripts web site at http://www.fmwconcepts.com/imagemagick/index.php. You an run it from PHP exec(). See my pointers for use on my home page.
Input:
dominantcolor -n 6 -p all -s save plate.png
count,hexcolor
586,#5ECADC
520,#AFA85D
469,#3C3126
462,#B9C8BB
258,#488A70
205,#B06928
The -n 6 is the desired number of colors in the color quantization. The -p all means print all counts and colors for the resulting 6 colors. The -s save indictates to save a swatch image.
Colors below are shown with the dominant color on the left and decreasing count colors towards the right according to the list above.

Categories