I wanted to create a php script to resize and/or create pictures thumbnail. I searched and I found a script which I modified a little and it works perfect.
The problem is that it creates picture thumbnails resizing and cropping the picture. I want to be able to resize a picture without cropping, only resize and keep proportions. I added a variable $crop and when that variable is 1 I want the picture to be resized and cropped and when it's 0 to be only resized without cropping and proportions to be the same.
Here it's the function
function resize_image($tmp_image, $type, $name, $width, $height, $crop, $upload_folder){
/* Get original image size */
list($tmp_width, $tmp_height) = getimagesize($tmp_image);
if($crop == 1)
{
/* Calculate new image size with ratio */
$ratio = max($width/$tmp_width, $height/$tmp_height);
$tmp_height = ceil($height / $ratio);
$x = ($tmp_width - $width / $ratio) / 2;
$tmp_width = ceil($width / $ratio);
/* New file name */
$path = $upload_folder.$name;
/* Read binary data from image file */
$img_string = file_get_contents($tmp_image);
/* Create image from string */
$image = imagecreatefromstring($img_string);
$tmp = imagecreatetruecolor($width, $height);
/* Keep transparency */
imagealphablending($tmp, false);
imagesavealpha($tmp, true);
imagecopyresampled($tmp, $image,
0, 0,
$x, 0,
$width, $height,
$tmp_width, $tmp_height);
/* Save image */
if($type == 'image/jpeg')
{
imagejpeg($tmp, $path, 100);
}
elseif($type == 'image/png')
{
imagepng($tmp, $path, 9);
}
}
else
{
// no crop, resize but keep proportions
}
/* cleanup memory */
imagedestroy($image);
imagedestroy($tmp);
}
Quite simple. If the height is greater than the width, get the ratio by dividing the new height with the old one and finally multiply the width with the ratio to get the new width, if the width is greater than the height you do the opposite, like in the example code below:
That's it, it's a very simply algorithm.
if ($height > $width)
{
$ratio = $maxheight / $height;
$newheight = $maxheight;
$newwidth = $width * $ratio;
}
else
{
$ratio = $maxwidth / $width;
$newwidth = $maxwidth;
$newheight = $height * $ratio;
}
Related
I am trying to batch resize images to the size of 250 x 250 in PHP
All source images are way bigger than 250 x 250 so that is helpful.
I want to maintain aspect ratio but make them all 250 x 250. I know that a portion of the image will be cropped off to do this. That is not an issue for me
The problem is that my current script only works on width and makes height according to aspect but sometimes, the image will now end up being let's say, 250 x 166. I can't use that.
In that cause It would need to be resized in the opposite manner (height to width)
How would the script have to look to always make the final image 250 x 250 without stretching. Again, I don't care if there is cropping. I assume there is going to be an else in the somewhere but this is way over my head now. I am more of a front end guy.
Any help would be great.
Below is just the relevant portion of my full script:
$width = 250;
$height = true;
// download and create gd image
$image = ImageCreateFromString(file_get_contents($url));
// calculate resized ratio
// Note: if $height is set to TRUE then we automatically calculate the height based on the ratio
$height = $height === true ? (ImageSY($image) * $width / ImageSX($image)) : $height;
// create image
$output = ImageCreateTrueColor($width, $height);
ImageCopyResampled($output, $image, 0, 0, 0, 0, $width, $height, ImageSX($image), ImageSY($image));
// save image
ImageJPEG($output, $destdir, 100);
$newWidth = 250;
$newHeight = 250;
// download and create gd image
$image = ImageCreateFromString(file_get_contents($url));
$width = ImageSX($image);
$height = ImageSY($image);
$coefficient = $newHeight / $height;
if ($newHeight / $width > $coefficient) {
$coefficient = $newHeight / $width;
}
// create image
$output = ImageCreateTrueColor($newWidth, $newHeight);
ImageCopyResampled($output, $image, 0, 0, 0, 0, $width * $coefficient, $height * $coefficient, $width, $height);
// save image
ImageJPEG($output, $destdir, 100);
$newimg = imagecreatefromjpeg($tempname);
Now I need to scale this image proportionally but don't know both dimensions in advance.
$newimg = imagescale($newimg, 160, auto, IMG_BICUBIC); //doesn't work
or
$newimg = imagescale($newimg, auto, 160, IMG_BICUBIC); // doesn't work
Is there a way to say auto or something to calculate width or height automatically.
If no, how can I calculate this?
The accepted solution here doesn't work. I doesn't keep aspect ratio.
I made a function that will do what you need. I have tested this function with scaling down images and it works as intended.
This function will size an image preserving the aspect ratio to completely fit inside the dimensions that you specify. The image will also be centered.
The function also has the ability to crop. If you use the crop parameter, it will oversize the image to make sure the smallest side of the image fills the desired dimensions. It will then crop the image to fit inside the dimensions, thus completely filling the given dimensions. The image will be centered.
Here is the function:
function scaleMyImage($filePath, $newPath, $newSize, $crop = NULL){
$img = imagecreatefromstring(file_get_contents($filePath));
$dst_x = 0;
$dst_y = 0;
$width = imagesx($img);
$height = imagesy($img);
$newWidth = $newSize;
$newHeight = $newSize;
if($width < $height){ //Portrait.
if($crop){
$newWidth = floor($width * ($newSize / $width));
$newHeight = floor($height * ($newSize / $width));
$dst_y = (floor(($newHeight - $newSize)/2)) * -1;
}else{
$newWidth = floor($width * ($newSize / $height));
$newHeight = $newSize;
$dst_x = floor(($newSize - $newWidth)/2);
}
} elseif($width > $height) { //Landscape
if($crop){
$newWidth = floor($width * ($newSize / $height));
$newHeight = floor($height * ($newSize / $height));
$dst_x = (floor(($newWidth - $newSize)/2)) * -1;
}else{
$newWidth = $newSize;
$newHeight = floor($height * ($newSize / $width));
$dst_y = floor(($newSize - $newHeight)/2);
}
}
$finalImage = imagecreatetruecolor($newSize, $newSize);
imagecopyresampled($finalImage, $img, $dst_x, $dst_y, 0, 0, $newWidth, $newHeight, $width, $height);
imagejpeg($finalImage, $newPath, 60); //Set your compression.
imagedestroy($img);
imagedestroy($finalImage);
}
How to use:
$newSize = 160;
$filePath = 'path/myImg.jpg';
$newPath = 'path/newImg.jpg';
$crop = 1; //Set to NULL if you don't want to crop.
scaleMyImage($filePath, $newPath, $newSize, 1);
This should do exactly what you want with the crop parameter set to 1.
First of all you will have to mention al-least one dimension (either height or width) then using aspect ration of original image you can identify another. Here is a sample code which i used in my case:
$width = 160; // User-defined
$height = ''; // User-defined
$path = $uploadDir . '/' . $tempname;
$mime = getimagesize($path);
// Load original image
if($mime['mime']=='image/png') {
$orig_img = imagecreatefrompng($path);
}
if($mime['mime']=='image/jpg' || $mime['mime']=='image/jpeg' || $mime['mime']=='image/pjpeg') {
$orig_img = imagecreatefromjpeg($path);
}
// Get original image height and width
$width_orig = imagesx($orig_img);
$height_orig = imagesy($orig_img);
// Aspect ratio of original image
$aspectRatio = $width_orig / $height_orig;
// If any one dimension available then calculate other with the help of aspect-ratio of original image
if ($width == '' && $height != '') {
$newheight = $height;
$newwidth = round($height * $aspectRatio);
}
if ($width != '' && $height == '') {
$newheight = round($width / $aspectRatio);
$newwidth = $width;
}
$newimg = imagescale($orig_img, $newwidth, $newheight, IMG_BICUBIC);
Following PHP function works great for jpg files. However it creates pixelated and too cropped png files.
How do I have to alter the function to create better quality png files?
/**
* Resize image (while keeping aspect ratio and cropping it off sexy)
*
*
* #param string $source_image The location to the original raw image.
* #param string $destination The location to save the new image.
* #param int $final_width The desired width of the new image
* #param int $final_height The desired height of the new image.
* #param int $quality The quality of the JPG to produce 1 - 100
*
*
* #return bool success state
*/
public static function resizeImage($source_image, $file_ext, $destination, $final_width = 470, $final_height = 470, $quality = 85)
{
$image = imagecreatefromstring(file_get_contents($source_image));
$width = imagesx($image);
$height = imagesy($image);
if (!$width || !$height) {
return false;
}
$original_aspect = $width / $height;
$final_aspect = $final_width / $final_height;
if ($original_aspect >= $final_aspect) {
// horizontal image
$new_height = $final_height;
$new_width = $width / ($height / $final_height);
} else {
// vertical image
$new_width = $final_width;
$new_height = $height / ($width / $final_width);
}
$thumb = imagecreatetruecolor($final_width, $final_height);
// Resize and crop
imagecopyresampled($thumb,
$image,
0 - ($new_width - $final_width) / 2, // Center the image horizontally
0 - ($new_height - $final_height) / 2, // Center the image vertically
0, 0,
$new_width, $new_height,
$width, $height);
// if the file is a jpg file
if ($file_ext == 'jpg') {
// add '.jpg' to file path, save it as a .jpg file with our $destination_filename parameter
$destination .= '.jpg';
imagejpeg($thumb, $destination, $quality);
// if the file is a png file
} elseif ($file_ext == 'png') {
// add '.png' to file path, save it as a .jpg file with our $destination_filename parameter
$destination .= '.png';
imagepng($thumb, $destination);
}
if (file_exists($destination)) {
return true;
}
// default return
return false;
}
I have very limited knowledge about image files and therefore I do not understand why this function works fine for jpg- and not for png-files.
I would be very thankful for any kind of help!
I use imagick for thumbnail crop, but sometimes cropped thumbnails are missing top part of the images (hair, eyes).
I was thinking to resize the image then crop it. Also, I need to keep the image size ratio.
Below is the php script I use for crop:
$im = new imagick( "img/20130815233205-8.jpg" );
$im->cropThumbnailImage( 80, 80 );
$im->writeImage( "thumb/th_80x80_test.jpg" );
echo '<img src="thumb/th_80x80_test.jpg">';
Thanks..
This task is not easy as the "important" part may not always be at the same place. Still, using something like this
$im = new imagick("c:\\temp\\523764_169105429888246_1540489537_n.jpg");
$imageprops = $im->getImageGeometry();
$width = $imageprops['width'];
$height = $imageprops['height'];
if($width > $height){
$newHeight = 80;
$newWidth = (80 / $height) * $width;
}else{
$newWidth = 80;
$newHeight = (80 / $width) * $height;
}
$im->resizeImage($newWidth,$newHeight, imagick::FILTER_LANCZOS, 0.9, true);
$im->cropImage (80,80,0,0);
$im->writeImage( "D:\\xampp\\htdocs\\th_80x80_test.jpg" );
echo '<img src="th_80x80_test.jpg">';
(tested)
should work. The cropImage parameters (0 and 0) determine the upper left corner of the cropping area. So playing with these gives you differnt results of what stays in the image.
Based on Martin's answer I made a more general function that resizes and crops Imagick image to fit given width and height (i.e. behaves exactly as CSS background-size: cover declaration):
/**
* Resizes and crops $image to fit provided $width and $height.
*
* #param \Imagick $image
* Image to change.
* #param int $width
* New desired width.
* #param int $height
* New desired height.
*/
function image_cover(Imagick $image, $width, $height) {
$ratio = $width / $height;
// Original image dimensions.
$old_width = $image->getImageWidth();
$old_height = $image->getImageHeight();
$old_ratio = $old_width / $old_height;
// Determine new image dimensions to scale to.
// Also determine cropping coordinates.
if ($ratio > $old_ratio) {
$new_width = $width;
$new_height = $width / $old_width * $old_height;
$crop_x = 0;
$crop_y = intval(($new_height - $height) / 2);
}
else {
$new_width = $height / $old_height * $old_width;
$new_height = $height;
$crop_x = intval(($new_width - $width) / 2);
$crop_y = 0;
}
// Scale image to fit minimal of provided dimensions.
$image->resizeImage($new_width, $new_height, imagick::FILTER_LANCZOS, 0.9, true);
// Now crop image to exactly fit provided dimensions.
$image->cropImage($new_width, $new_height, $crop_x, $crop_y);
}
Hope this may help somebody.
My code. Please vote
// Imagick
$image = new Imagick($img);
// method 1 - resize to max width
if($type==1){
$image->resizeImage($newWidth,0,Imagick::FILTER_LANCZOS,1);
// method 2 - resize to max height
}else if($type==2){
$image->resizeImage(0,$newHeight,Imagick::FILTER_LANCZOS,1);
// method 1 - resize to max width or height
}else if($type==3){
if($image->getImageHeight() <= $image->getImageWidth()){
$image->resizeImage($newWidth,0,Imagick::FILTER_LANCZOS,1);
}else{
$image->resizeImage(0,$newHeight,Imagick::FILTER_LANCZOS,1);
}
// method 4 - resize and crop to center
}else if($type==4){
if($image->getImageHeight() <= $image->getImageWidth()){
$image->resizeImage(0,$newheight,Imagick::FILTER_LANCZOS,1);
}else{
$image->resizeImage($newwidth,0,Imagick::FILTER_LANCZOS,1);
}
$cropWidth = $image->getImageWidth();
$cropHeight = $image->getImageHeight();
$image->cropimage(
$newwidth,
$newheight,
($cropWidth - $newwidth) / 2,
($cropHeight - $newheight) / 2
);
}
$image->setImageFormat("jpeg");
$image->setImageCompression(Imagick::COMPRESSION_JPEG);
$image->writeImages($newImg, true);
$image->clear();
$image->destroy();
I'd like crop an image in PHP and save the file. I know your supposed to use the GD library but i'm not sure how. Any ideas?
Thanks
You could use imagecopy to crop a required part of an image. The command goes like this:
imagecopy (
resource $dst_im - the image object ,
resource $src_im - destination image ,
int $dst_x - x coordinate in the destination image (use 0) ,
int $dst_y - y coordinate in the destination image (use 0) ,
int $src_x - x coordinate in the source image you want to crop ,
int $src_y - y coordinate in the source image you want to crop ,
int $src_w - crop width ,
int $src_h - crop height
)
Code from PHP.net - a 80x40 px image is cropped from a source image
<?php
// Create image instances
$src = imagecreatefromgif('php.gif');
$dest = imagecreatetruecolor(80, 40);
// Copy
imagecopy($dest, $src, 0, 0, 20, 13, 80, 40);
// Output and free from memory
header('Content-Type: image/gif');
imagegif($dest);
imagedestroy($dest);
imagedestroy($src);
?>
This function will crop image maintaining image aspect ratio :)
function resize_image_crop($image, $width, $height)
{
$w = #imagesx($image); //current width
$h = #imagesy($image); //current height
if ((!$w) || (!$h)) { $GLOBALS['errors'][] = 'Image couldn\'t be resized because it wasn\'t a valid image.'; return false; }
if (($w == $width) && ($h == $height)) { return $image; } //no resizing needed
$ratio = $width / $w; //try max width first...
$new_w = $width;
$new_h = $h * $ratio;
if ($new_h < $height) { //if that created an image smaller than what we wanted, try the other way
$ratio = $height / $h;
$new_h = $height;
$new_w = $w * $ratio;
}
$image2 = imagecreatetruecolor ($new_w, $new_h);
imagecopyresampled($image2,$image, 0, 0, 0, 0, $new_w, $new_h, $w, $h);
if (($new_h != $height) || ($new_w != $width)) { //check to see if cropping needs to happen
$image3 = imagecreatetruecolor ($width, $height);
if ($new_h > $height) { //crop vertically
$extra = $new_h - $height;
$x = 0; //source x
$y = round($extra / 2); //source y
imagecopyresampled($image3,$image2, 0, 0, $x, $y, $width, $height, $width, $height);
} else {
$extra = $new_w - $width;
$x = round($extra / 2); //source x
$y = 0; //source y
imagecopyresampled($image3,$image2, 0, 0, $x, $y, $width, $height, $width, $height);
}
imagedestroy($image2);
return $image3;
} else {
return $image2;
}
}
To crop an image using GD you need to use a combination of GD methods, and if you look at "Example #1" on PHP's documentation of the imagecopyresampled method, it shows you how to crop and output an image, you would just need to add some code to that to capture and write the output to a file...
http://us2.php.net/manual/en/function.imagecopyresampled.php
There are also other options, including Image Magick which, if installed on your server, can be accessed directly using PHP's exec method (or similar) or you can install the PHP Imagick extension, which yields higher quality images and, in my opinion, is a little more intuitive and flexible to work with.
Finally, I've used the open source PHPThumb class library, which has a pretty simple interface and can work with multiple options depending on what's on your server, including ImageMagick and GD.
I use this script in some projects and it's pretty easy to use:
http://shiftingpixel.com/2008/03/03/smart-image-resizer/
The script requires PHP 5.1.0 (which is out since 2005-11-24 - time to upgrade if not yet at this version) and GD (which is rarely missing from good Web hosts).
Here is an example of it's use in your HTML:
<img src="/image.php/coffee-bean.jpg?width=200&height=200&image=/wp-content/uploads/2008/03/coffee-bean.jpg" alt="Coffee Bean" />
I just created this function and it works for my needs, creating a centered and cropped thumbnail image. It is streamlined and doesn't require multiple imagecopy calls like shown in webGautam's answer.
Provide the image path, the final width and height, and optionally the quality of the image. I made this for creating thumbnails, so all images are saved as JPGs, you can edit it to accommodate other image types if you require them. The main point here is the math and method of using imagecopyresampled to produce a thumbnail. Images are saved using the same name, plus the image size.
function resize_crop_image($image_path, $end_width, $end_height, $quality = '') {
if ($end_width < 1) $end_width = 100;
if ($end_height < 1) $end_height = 100;
if ($quality < 1 || $quality > 100) $quality = 60;
$image = false;
$dot = strrpos($image_path,'.');
$file = substr($image_path,0,$dot).'-'.$end_width.'x'.$end_height.'.jpg';
$ext = substr($image_path,$dot+1);
if ($ext == 'jpg' || $ext == 'jpeg') $image = #imagecreatefromjpeg($image_path);
elseif($ext == 'gif') $image = #imagecreatefromgif($image_path);
elseif($ext == 'png') $image = #imagecreatefrompng($image_path);
if ($image) {
$width = imagesx($image);
$height = imagesy($image);
$scale = max($end_width/$width, $end_height/$height);
$new_width = floor($scale*$width);
$new_height = floor($scale*$height);
$x = ($new_width != $end_width ? ($width - $end_width) / 2 : 0);
$y = ($new_height != $end_height ? ($height - $end_height) / 2 : 0);
$new_image = #imagecreatetruecolor($new_width, $new_height);
imagecopyresampled($new_image,$image,0,0,$x,$y,$new_width,$new_height,$width - $x,$height - $y);
imagedestroy($image);
imagejpeg($new_image,$file,$quality);
imagedestroy($new_image);
return $file;
}
return false;
}
You can use below method to crop image,
/*parameters are
$image =source image name
$width = target width
$height = height of image
$scale = scale of image*/
function resizeImage($image,$width,$height,$scale) {
//generate new image height and width of source image
$newImageWidth = ceil($width * $scale);
$newImageHeight = ceil($height * $scale);
//Create a new true color image
$newImage = imagecreatetruecolor($newImageWidth,$newImageHeight);
//Create a new image from file
$source = imagecreatefromjpeg($image);
//Copy and resize part of an image with resampling
imagecopyresampled($newImage,$source,0,0,0,0,$newImageWidth,$newImageHeight,$width,$height);
//Output image to file
imagejpeg($newImage,$image,90);
//set rights on image file
chmod($image, 0777);
//return crop image
return $image;
}