How to crop image using GD image functions - php

everything in my code is working great for creating a thumbnail image of an uploaded picture.
now all i need to do is crop the $thumb from the center of the image into a square shape (50x50)
heres my function so far
$ext = end(explode('.', $_FILES['profile_photo']['name']));
if ($ext == 'jpg' || $ext == 'jpeg' || $ext == 'png' || $ext == 'gif')
{
$tmp = $_FILES['profile_photo']['tmp_name'];
if ($ext=='jpg' || $ext=='jpeg')
$src = imagecreatefromjpeg($tmp);
else if ($ext=='png')
$src = imagecreatefrompng($tmp);
else
$src = imagecreatefromgif($tmp);
list($width,$height) = getimagesize($tmp);
$thumb_width = 50;
$thumb_height = ($height/$width) * $thumb_width;
$thumb_tmp = imagecreatetruecolor($thumb_width, $thumb_height);
$full_width = 200;
$full_height = ($height/$width) * $full_width;
$full_tmp = imagecreatetruecolor($full_width, $full_height);
imagecopyresampled($thumb_tmp, $src, 0, 0, 0, 0, $thumb_width, $thumb_height, $width, $height);
imagecopyresampled($full_tmp, $src, 0, 0, 0, 0, $full_width, $full_height, $width, $height);
imagejpeg($thumb_tmp, 'images/profile/'.$user['id'].'_'.time().'_thumb.'.$ext, 100);
imagejpeg($full_tmp, 'images/profile/'.$user['id'].'_'.time().'_full.'.$ext, 100);
imagedestroy($src);
imagedestroy($thumb_tmp);
imagedestroy($full_tmp);
// delete old image from server if it is not none.png
}
any help would be greatly appreciated! i know that it has something to do with imagecopyresampled but i can't figure out the math for the cropping from the center of the image. i want this to be my own function so please dont recommend me using other peoples classes.

Right after $full_tmp = imagecreatetruecolor($full_width, $full_height);, add...
if ($thumb_width > $thumb_height) {
$thumb_offset = array('x' => ($thumb_width/2 - 25), 'y' => 0);
} else {
$thumb_offset = array('x' => 0, 'y' => ($thumb_height/2 - 25));
}
$square_tmp = imagecreatetruecolor($thumb_width, $thumb_height);
imagecopyresampled($square_tmp, $src, 0, 0, $thumb_offset['x'], $thumb_offset['y'], 50, 50, $width, $height);
Then save and destroy the temp like the other two images.

Take a look at the parameters that should be passed to imagecopyresampled, as per the PHP manual:
imagecopyresampled ( resource $dst_image , resource $src_image , int $dst_x , int $dst_y , int $src_x , int $src_y , int $dst_w , int $dst_h , int $src_w , int $src_h )
From the third parameter on, you basically define how a rectangle on the source image maps to a rectangle on the destination image.
So the first thing you have to do is calculate the rectanle (x, y, width and height) which defines the visible area of your original image. These will be the 5th, 6th, 9th and 10th parameters to the function, respectively.
For the destination rectangle, use 0,0 for x,y, and $thumb_width,$thumb_height for w,h, just as you are currently doing.

Related

Cropping images with Php

I'm using Jquery plugin ImgAreaSelect with PHP 5.3.9 with GD 2.0.34.
Following some examples from the plugin, I added a form that gives X and Y values from where I start selecting the image till the end of the selection.
This is going OK, because I recieve the values correctly, but I cannot crop the image. Followed some examples/tutorials but always failed.
Here is my PHP code:
$x1 = $_POST['x1']; //this one gives me the point where start to crop
$x2 = $_POST['x2']; //the end of X axis
$y1 = $_POST['y1']; //same for Y1 and Y2
$y2 = $_POST['y2'];
$w = $x2 - $x1; //getting the width for the new image
$h = $y2 - $y1; //getting the height for the new image
$src_img = "path/image";
$format = end(explode(".", $src_img)); //taking the image format (jpg, png, gif)
$size = getimagesize($src_img);
switch($format) {
case "jpg":
$copy = imagecreatefromjpeg($src_img);
$new = ImageCreateTrueColor($w, $h);
imagecopyresampled($new, $copy, 0, 0, $x1, $y1, $w, $h, $size[0], $size[1]);
header('Content-type: image/jpeg');
imagejpeg($new);
break;
}
I would like to know if there's something wrong (most probably).
Thanks for all and taking your time to help.
imagecopyresampled($new, $copy, $x1, $y1, 0, 0, $w, $h, $size[0], $size[1]);
http://php.net/manual/en/function.imagecopyresampled.php
In other words, imagecopyresampled() will take a rectangular area from src_image of width src_w and height src_h at position (src_x,src_y) and place it in a rectangular area of dst_image of width dst_w and height dst_h at position (dst_x,dst_y).
in other words, you need to change it to:
imagecopyresampled($new, $copy,0 ,0 ,$x1, $y1, $w, $h, $w, $h);
Anyway you can try this code also
<?php
$x1 = $_POST['x1']; //this one gives me the point where start to crop
$x2 = $_POST['x2']; //the end of X axis
$y1 = $_POST['y1']; //same for Y1 and Y2
$y2 = $_POST['y2'];
$w = ( $x2 - $x1 ); //getting the width for the new image
$h = ( $y2 - $y1 ); //getting the height for the new image
$src = "path_to_file";
$info = getimagesize( $src );
switch( $info[2] ) {
case IMAGETYPE_JPEG:
$copy = imagecreatefromjpeg( $src );
$new = imagecreatetruecolor( $w, $h );
imagecopyresampled( $new, $copy, 0, 0, $x1, $y1, $info[0], $info[1], $w, $h );
header( 'Content-type: image/jpeg' );
imagejpeg( $new );
break;
default:
break;
}
?>
//resize and crop image by center
function resize_crop_image($max_width, $max_height, $source_file, $dst_dir, $quality = 80){
$imgsize = getimagesize($source_file);
$width = $imgsize[0];
$height = $imgsize[1];
$mime = $imgsize['mime'];
switch($mime){
case 'image/gif':
$image_create = "imagecreatefromgif";
$image = "imagegif";
break;
case 'image/png':
$image_create = "imagecreatefrompng";
$image = "imagepng";
$quality = 7;
break;
case 'image/jpeg':
$image_create = "imagecreatefromjpeg";
$image = "imagejpeg";
$quality = 80;
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,
Resize and crop image from center with PHP
$max_height, $width_new, $height);
}
$image($dst_img, $dst_dir, $quality);
if($dst_img)imagedestroy($dst_img);
if($src_img)imagedestroy($src_img);
}
//usage example
resize_crop_image(100, 100, "test.jpg", "test.jpg");
thanks to all, #Deepanshu gave me a link wich I saw a piece of code, but somehow strange:
bool imagecopyresampled ( resource $dst_image , resource $src_image , int $dst_x , int $dst_y , int $src_x , int $src_y , int $dst_w , int $dst_h , int $src_w , int $src_h )
the last $src_w and $src_h I had to put the new width and the new height, instead the width and height of the original image.
so, the final code working properly is:
imagecopyresampled($new, $copy, 0, 0, $x1, $y1, $w, $h, $w, $h);

Crop distorting / scaling image

I have the follow PHP code:
$w = 300; // Width of new image
$h = 300; // Height of new image
$oh = 540; // Original file height
$ow = 720; // Original file width
$x = 196;
$y = 50;
$image = imagecreatefromjpeg('fileToCrop.jpg');
$cropped_image = imagecreatetruecolor($w, $h);
imagecopyresampled($cropped_image, $image, 0, 0, $x, $y, $ow, $oh, $w, $h);
imagejpeg($cropped_image, 'fileToCrop.jpg', 100);
And want to crop the image, but my images are distorting / higher than original, eg:
Original:
Cropped ("N" for "Not" are showing):
I can't see what is wrong with my code, and what are happening to images goes bigger..
You inverted the last 4 parameters of imagecopyresampled
bool imagecopyresampled ( resource $dst_image , resource $src_image , int $dst_x , int $dst_y , int $src_x , int $src_y , int $dst_w , int $dst_h , int $src_w , int $src_h )
Change it for
imagecopyresampled($cropped_image, $image, 0, 0, $x, $y, $w, $h, $ow, $oh);
But in fact, are you sure you're not looking for a straight copy of the cropped region?
imagecopy($cropped_image, $image, 0, 0, $x, $y, $ow, $oh);
because you omitted the quality on imagejpeg() it defaults to 75%
http://php.net/manual/en/function.imagejpeg.php
can you try adding 95 on 3rd parameter?
imagejpeg($cropped_image, 'fileToCrop.jpg', 95);
P.S.
If you can use a 3rdparty php script I'll suggest you just use timthumb
http://www.binarymoon.co.uk/projects/timthumb/
if you need a change of cropping location,
http://www.binarymoon.co.uk/2010/08/timthumb-part-4-moving-crop-location/

PHP custom postcard

i am creating a new feature on my site that allow people to send postcard to friends. in this section they can choose the image they want to send (they already uplaoded the image to their profile -> my pictures section)
i am using the php function to create the text that goes on the right but how can i add another image to this image with the text?
i use imagettftext to create the text, imagecreatefromjpeg to open the main image (see below) and imagedestroy when im done
thanks
i am using this postcard:
First you will have to crop the image to fit in your postcard.
Based on your image here's what you have to do:
<?php
$sourceImage = './postcard-template.jpg';
$uploadedImage = '/path/to/image/hong-kong2.jpg'; // let's get hong kong as example
$mime = '';
$font = '/path/to/font/arial.ttf';
function CroppedThumbnail($source, $width, $height, &$mime) {
$data = getimagesize($source);
$sourceWidth = $data[0];
$sourceHeight = $data[1];
$mime = $data['mime'];
$image = imagecreatefromjpeg($source);
$sourceRatio = $sourceWidth/$sourceHeight;
if (($width/$height) > $sourceRatio) {
$newHeight = $width/$sourceRatio;
$newWidth = $width;
}
else {
$newWidth = $height*$sourceRatio;
$newHeight = $height;
}
$croppedImage = imagecreatetruecolor(round($newWidth), round($newHeight));
imagecopyresampled($croppedImage, $image, 0, 0, 0, 0, $newWidth, $newHeight, $sourceWidth, $sourceHeight);
$thumb = imagecreatetruecolor($width, $height);
imagecopyresampled($thumb, $croppedImage, 0, 0, (($newWidth/2)-($width/2)), (($newHeight/2)-($height/2)), $width, $height, $width, $height);
imagedestroy($croppedImage);
imagedestroy($image);
return $thumb;
}
// Create the cropped image first
$newThumb = CroppedThumbnail($uploadedImage,240,315, $mime);
switch($mime) {
case 'image/gif':
$image = imagecreatefromgif($sourceImage);
break;
case 'image/jpeg':
$image = imagecreatefromjpeg($sourceImage);
break;
case 'image/png':
$image = imagecreatefrompng($sourceImage);
break;
default:
// error or stop script
break;
}
$message = "this is some text\nsome other text\ntext text";
imagettftext($image, 21, 0, 320, 255, imagecolorallocate($image, 0, 0, 0), $font, $message);
imagecopy($image, $newThumb, 40, 40, 0, 0, 240, 315);
header('Content-Type: image/jpeg');
imagejpeg($image);
imagedestroy($image);
For example I use this image ( needs to be cropped ) :
then it will output:
Use imagecopymerge to copy the photo onto the post card
bool imagecopymerge ( resource $dst_im , resource $src_im , int $dst_x , int $dst_y , int $src_x , int $src_y , int $src_w , int $src_h , int $pct )

PHP GD crop & scale image

I'm using jQuery's imgAreaSelect plugin in order to crop an image and save the thumbnail to use in cases where, for example, the ratio changes. Unfortunelly the results are far from what I would expect, and I can't get it right. The image gets resized as a whole instead of being cropped.
Here's the test example :
<?php
/***
*
* $_GET returned values
*
* x1 = 0
* x2 = 400
* y1 = 66
* y2 = 258
* w = 400
* h = 192
* folder = widethumb
* filename = IMG_4591.jpg
* scale = 48
*
* Original image properties
*
* width = 600px
* height = 900px
*
***/
define('DOCROOT', realpath(dirname(__FILE__)).DIRECTORY_SEPARATOR);
extract($_GET);
$fn = $filename;
$filename = DOCROOT.$filename;
list($width, $height) = getimagesize($filename);
$src = imagecreatefromjpeg($filename);
$dst = imagecreatetruecolor($w, $h);
imagecopyresampled($dst, $src, 0, 0, (int) $x1, (int) $y1, (int) $w, (int) $h, $width, $height);
header('Content-Type: image/jpeg');
imagejpeg($dst);
What am I mising here?
Cheers!
From PHP Documentation:
bool imagecopyresampled ( resource $dst_image , resource $src_image , int $dst_x , int $dst_y , int $src_x , int $src_y , int $dst_w , int $dst_h , int $src_w , int $src_h )
imagecopyresampled() copies a rectangular portion of one image to another image, smoothly interpolating pixel values so that, in particular, reducing the size of an image still retains a great deal of clarity.
In other words, imagecopyresampled() will take an rectangular area from src_image of width src_w and height src_h at position (src_x,src_y) and place it in a rectangular area of dst_image of width dst_w and height dst_h at position (dst_x,dst_y).
So to get the result you are looking for, you need to avoid scaling. for that use:
imagecopy($dst, $src, 0, 0, $x1, $y1, $w, $h);
// this can also be done but is less efficient (over 10 times slower)
imagecopyresampled($dst, $src, 0, 0, (int) $x1, (int) $y1, $w, $h, $w, $h);
Here we are are taking the same sized rectangle from source as we are putting it into destination image.
I have just tested it and it works just fine.
Update:
I have just tried again on my test server and it is working fine. I'm using following code:
$filename = "test.jpg";
extract($_GET);
$src = imagecreatefromjpeg($filename);
$dst = imagecreatetruecolor($w, $h);
imagecopy($dst, $src, 0, 0, $x1, $y1, $w, $h);
// this is over 10 times slower, as we are only cropping we should use imagecopy
//imagecopyresampled($dst, $src, 0, 0, $x1, $y1, $w, $h, $w, $h);
header('Content-Type: image/jpeg');
imagejpeg($dst);
And I'm calling it like this:
http://localserver/test/gd_crop.php?x1=906&y1=267&w=501&h=355
Performance Update
As we are not resizing we can simply use imagecopy. Performance of 3 functions as i have measured is given below.
imagecopyresampled 69ms
imagecopyresized 5.5ms
imagecopy 4.5ms
So there is an order of 10 speed difference between resampled and the two other functions.
I have finally come up with following line in place of imagecopyresampled function, try it, I have also updated the above code listing:
imagecopy($dst, $src, 0, 0, $x1, $y1, $w, $h);
Use the WideImage library instead.
This is my own cropping function:
function createThumbnail($file, $cropX, $cropY, $cropWidth, $cropHeight, $desiredWidth, $desiredHeight, $shrink = false)
{
if(file_exists(MPS_ROOT_PATH . "$file") && $cropWidth && $cropHeight)
{
$source_path = MPS_ROOT_PATH . $file;
list( $source_width, $source_height, $source_type ) = getimagesize( $source_path );
switch ( $source_type )
{
case IMAGETYPE_GIF:
$source_gdim = imagecreatefromgif( $source_path );
break;
case IMAGETYPE_JPEG:
$source_gdim = imagecreatefromjpeg( $source_path );
break;
case IMAGETYPE_PNG:
$source_gdim = imagecreatefrompng( $source_path );
break;
default:
return false;
}
if(!$desiredWidth)
{
// Desired width not set, computing new width based on original
// image's aspect ratio...
$desiredWidth = $cropWidth * ($desiredHeight / $cropHeight);
}
if(!$desiredHeight)
{
// Desired height not set, computing new height based on original
// image's aspect ratio
$desiredHeight = $cropHeight * ($desiredWidth / $cropWidth);
}
if(!$desiredWidth || !$desiredHeight)
{
// Desired height or width not set.
// Halting image processing and returning file
return $file;
}
$source_aspect_ratio = $cropWidth / $cropHeight;
$desired_aspect_ratio = $desiredWidth / $desiredHeight;
if($shrink)
{
// Shrink to fit flag set. Inverting computations to make image fit
// within the desired dimensions...
if($source_aspect_ratio > $desired_aspect_ratio)
{
// Source image is wider than desired aspect ratio,
// setting thumbnail width to the desired width and the height
// will be computed based on the original image's aspect ratio
$temp_width = $desiredWidth;
$temp_height = (int) ($desiredWidth / $source_aspect_ratio);
}
else
{
// Source image is taller than desired aspect ratio,
// setting thumbnail height to the desired height and the width
// will be computed based on the original image's aspect ratio
$temp_height = $desiredHeight;
$temp_width = (int) ($desiredHeight * $source_aspect_ratio);
}
}
// shrink to fit not set
else
{
if($source_aspect_ratio > $desired_aspect_ratio)
{
// Source image is wider than desired aspect ratio,
// setting thumbnail height to the desired height to fill the
// desired aspect ratio and the width will be computed based on
// the original image's aspect ratio
$temp_height = $desiredHeight;
$temp_width = (int) ($desiredHeight * $source_aspect_ratio);
}
else
{
// Source image is taller than desired aspect ratio,
// setting thumbnail width to the desired width to fill the
// desired aspect ratio and the width will be computed based on
// the original image's aspect ratio");
$temp_width = $desiredWidth;
$temp_height = (int) ($desiredWidth / $source_aspect_ratio);
}
}
$temp_gdim = imagecreatetruecolor($temp_width, $temp_height);
// Copying a $cropWidth x $cropHeight image from the source
// file at ($cropX, $cropY) and resampling it to fit the temporary
// $temp_width x $temp_height thumbnail at (0, 0)
imagecopyresampled(
$temp_gdim,
$source_gdim,
0, 0,
$cropX, $cropY,
$temp_width, $temp_height,
$cropWidth, $cropHeight
);
$x0 = ($desiredWidth - $temp_width) / 2;
$y0 = ($desiredHeight - $temp_height) / 2;
// Positioning the temporary $temp_width x $temp_height thumbnail in
// the center of the final $desiredWidth x $desiredHeight thumbnail...
// Creating final thumbnail canvas at $desiredWidth x $desiredHeight
$desired_gdim = imagecreatetruecolor($desiredWidth, $desiredHeight);
$white = imagecolorallocate($desired_gdim, 255, 255, 255);
imagefill($desired_gdim, 0, 0, $white);
// Filling final thumbnail canvas with white
// Copying a $temp_width x $temp_height image from the temporary
// thumbnail at (0, 0) and placing it in the final
// thumbnail at ($x0, $y0)
imagecopy(
$desired_gdim,
$temp_gdim,
$x0, $y0,
0, 0,
$temp_width, $temp_height
);
$pathInfo = pathinfo($file);
$thumbFile = "images/thumbs/thumb_" . basename($pathInfo["filename"]) . ".jpg";
if(imagejpeg($desired_gdim, MPS_ROOT_PATH . $thumbFile, 80))
{
return $thumbFile;
}
else
{
return 1;
}
}
else
{
echo "Image File Does not exist or Invalid crop parameters!";
return false;
}
}
Why don't you look into using imagemagik; it's great for image manipulation and cropping is just a simple case of using cropImage($width, $height, $x, $y);
Here's a function that you can pass the destination dimension to and will scale and crop from the center, maintain aspect ratio, and will scale up. This is easy to implement with the picture element for responsive design. If you change your destination dimensions, just delete the outputted files and this will recreate the images in their absence.
<?php
function scaleCrop($src, $dest, $destW, $destH, $anchor){
if(!file_exists($dest) && is_file($src) && is_readable($src)){
$srcSize = getimagesize($src);
$srcW = $srcSize[0];
$srcH = $srcSize[1];
$srcRatio = $srcW / $srcH;
$destRatio = $destW / $destH;
$img = (imagecreatefromjpeg($src));
$imgNew = imagecreatetruecolor($destW, $destH);
if ($srcRatio < $destRatio){
$scale = $srcW / $destW;
}
elseif($srcRatio >= $destRatio){
$scale = $srcH / $destH;
}
$srcX = ($srcW - ($destW * $scale)) / 2;
if($anchor = 'middle'){
$srcY = ($srcH - ($destH * $scale)) / 2;
}
elseif($anchor = 'top'){
$srcY = 0;
}
elseif($anchor = 'bottom'){
$srcY = $srcH - ($destH * $scale);
}
if($srcX < 0){$srcX = 0;};
if($srcY < 0){$srcY = 0;};
imagecopyresampled($imgNew, $img, 0, 0, $srcX, $srcY, $destW, $destH, $destW * $scale, $destH * $scale);
imagejpeg($imgNew, $dest, 70);
imagedestroy($img);
imagedestroy($imgNew);
}
return $dest;
}
?>
<img src="<?php echo scaleCrop('srcfolder/srcfile.jpg', 'destfolder/destfile.jpg', 320, 240, 'top'); ?>">

JPEG Images Turn all black when converting from a PNG with PHP

The problem: When converting any PNG image into a JPEG, the image turns all black.
To start off, I've searched the internet and stackoverflow to find out how to do this. I've tried every method I could find in the PHP Manual and on Stack Overflow. The problem still exists. I'm using GD (don't have ImageMagick installed).
My code is below. This is the call to the function:
$tempImage = $dirPath.$filename.$tempMini.".jpg";
createTempImage($sourcefile, $tempImage, $tempMini_width, $tempMini_height, 100);
I've commented out the different methods that I've tried.
function createTempImage($sourcefile, $setNewName, $maxwidth, $maxheight, $quality){
$fileInfoArray = getimagesize($sourcefile);
$imagetype = $fileInfoArray['mime'];
if($imagetype == 'image/jpeg'){
$img = imagecreatefromjpeg($sourcefile);
}elseif($imagetype == 'image/gif'){
$img = imagecreatefromgif($sourcefile);
}elseif(($imagetype == 'image/png')||($imagetype == 'image/x-png')){
$img = imagecreatefrompng($sourcefile);
}
$width = imagesx( $img );
$height = imagesy( $img );
if ($width > $maxwidth || $height > $maxheight){
$factor = min(($maxwidth/$width),($maxheight/$height));
$newwidth = round($width*$factor);
$newheight = round($height*$factor);
} else {
$newwidth = $width;
$newheight = $height;
}
$tmpimg = imagecreatetruecolor( $newwidth, $newheight );
imagecopyresampled($tmpimg, $img, 0, 0, 0, 0, $newwidth, $newheight, $width, $height );
imagejpeg($tmpimg, $setNewName, 100);
imagedestroy($tmpimg);
imagedestroy($img);
}
The following have also been attempted:
$white = imagecolorallocate($tmpimg, 255, 255, 255);
ImageFill($tmpimg, 0, 0, $white);
ImageSaveAlpha($tmpimg, false);
ImageAlphaBlending($tmpimg, false);
$white = imagecolorallocate($tmpimg, 255, 255, 255);
imagefilledrectangle($tmpimg, 0, 0, $newwidth, $newheight, $white);
Update: The top black box is the image result: http://twitpic.com/30ywf5
Just a couple of ideas:
$newHeight = $maxheight; seems to be a typo, "newheight" is spelled without the capital "H" throughout the code.
The code to determine the new size can be shortened sigificantly:
if ($width > $maxwidth || $height > $maxheight){
$factor = min(($maxwidth/$width),($maxheight/$height));
$newwidth = round($width*$factor);
$newheight = round($height*$factor);
}
You use imagecopyresampled to create the new image - this only works in specific GD-versions ("version 2"), try to use imagecopyresized otherwise.
I seemed to have fixed the problem by recreating the whole function from scratch. Thank you guys for your input.
The problem was that PNG's weren't being uploaded. When executing the script with already uploaded URLs, it worked fine.
Thanks again.

Categories