Scale Image Using PHP and Maintaining Aspect Ratio

Scale Image Using PHP and Maintaining Aspect Ratio

I had written a peice of code like this for another project I've done. I've copied it below, might need a bit of tinkering! (It does required the GD library)

These are the parameters it needs:

$image_name - Name of the image which is uploaded
$new_width - Width of the resized photo (maximum)
$new_height - Height of the resized photo (maximum)
$uploadDir - Directory of the original image
$moveToDir - Directory to save the resized image

It will scale down or up an image to the maximum width or height

function createThumbnail($image_name,$new_width,$new_height,$uploadDir,$moveToDir)
{
$path = $uploadDir . '/' . $image_name;

$mime = getimagesize($path);

if($mime['mime']=='image/png') {
$src_img = imagecreatefrompng($path);
}
if($mime['mime']=='image/jpg' || $mime['mime']=='image/jpeg' || $mime['mime']=='image/pjpeg') {
$src_img = imagecreatefromjpeg($path);
}

$old_x = imageSX($src_img);
$old_y = imageSY($src_img);

if($old_x > $old_y)
{
$thumb_w = $new_width;
$thumb_h = $old_y*($new_height/$old_x);
}

if($old_x < $old_y)
{
$thumb_w = $old_x*($new_width/$old_y);
$thumb_h = $new_height;
}

if($old_x == $old_y)
{
$thumb_w = $new_width;
$thumb_h = $new_height;
}

$dst_img = ImageCreateTrueColor($thumb_w,$thumb_h);

imagecopyresampled($dst_img,$src_img,0,0,0,0,$thumb_w,$thumb_h,$old_x,$old_y);

// New save location
$new_thumb_loc = $moveToDir . $image_name;

if($mime['mime']=='image/png') {
$result = imagepng($dst_img,$new_thumb_loc,8);
}
if($mime['mime']=='image/jpg' || $mime['mime']=='image/jpeg' || $mime['mime']=='image/pjpeg') {
$result = imagejpeg($dst_img,$new_thumb_loc,80);
}

imagedestroy($dst_img);
imagedestroy($src_img);

return $result;
}

PHP Image resizing with aspect ratio

"Keep aspect ratio" means that the following equation must hold:

$new_height / $new_width == $height / $width

Thus, the equation for calculating the new height is:

$new_height = ceil($height * ($new_width/$width));

Note that ceil ensures that the new height is an integer value and at least 1 (given that new width and old width+height are all positive).

resize image by height and keeping width by original aspect ratio

You could use $rat * 540 to keep the same ratio, instead of 'auto':

$newimg = imagescale($newimg, $rat * 540, 540, IMG_BICUBIC);

So, if ratio is 4/3 by example, the width will be: 540*4/3 = 720.
If the ratio is 16/9, 540*16/19 = 960.

Resize image and crop to new aspect ratio

After a lot of fiddling, this works.

It resizes and crops, so images becomes either 4:3 or 3:4, depending on dominant initial width/height.

When using very small images, there should also be some checking and/or bypassing, so they don't get upscaled etc.

$max_width = 800;
$max_height = 800;

$image_size_info = getimagesize($image_temp);
$image_width = $image_size_info[0];
$image_height = $image_size_info[1];

$image_res = imagecreatefromjpeg($image_temp);

if ($image_height < $image_width) {

$cropfactor = $image_height / $image_width;
$cropfactor = ($cropfactor > 0.75) ? $cropfactor : 0.75;
$max_height = ceil($max_height * $cropfactor);

} elseif ($image_width < $image_height) {

$cropfactor = $image_width / $image_height;
$cropfactor = ($cropfactor > 0.75) ? $cropfactor : 0.75;
$max_width = ceil($max_width * $cropfactor);

}

$new_width = $image_height * $max_width / $max_height;
$new_height = $image_width * $max_height / $max_width;

$canvas = imagecreatetruecolor($max_width, $max_height);

if ($new_width > $image_width) {

$cut_x = 0;
$cut_y = (($image_height - $new_height) / 2);
$new_width_canvas = $image_width;
$new_height_canvas = $new_height;

} else {

$cut_x = (($image_width - $new_width) / 2);
$cut_y = 0;
$new_width_canvas = $new_width;
$new_height_canvas = $image_height;

}

imagecopyresampled($canvas, $image_res, 0, 0, $cut_x, $cut_y, $max_width, $max_height, $new_width_canvas, $new_height_canvas);

imagejpeg($canvas, 'images/image.jpg', 85);

imagedestroy($image_res);

How to maintain aspect ratio while resizing the uploaded image

It is quite complicated to both resize and crop multiple images, but here's a solution that might work for you:

 if($_SERVER["REQUEST_METHOD"] == "POST"){
$image =$_FILES["file"]["name"];
$uploadedfile = $_FILES['file']['tmp_name'];

if($image){
$filename = stripslashes($_FILES['file']['name']);
$extension = getExtension($filename);
$extension = strtolower($extension);

if(($extension != "jpg") && ($extension != "jpeg") && ($extension != "png") && ($extension != "gif")) {
$change='<div class="msgdiv">Unknown Image extension </div> ';
$errors=1;
} else {
$size=filesize($_FILES['file']['tmp_name']);

if($size > MAX_SIZE*1024){
$change='<div class="msgdiv">You have exceeded the size limit!</div> ';
$errors=1;
}

if($extension=="jpg" || $extension=="jpeg" ) {
$uploadedfile = $_FILES['file']['tmp_name'];
$src = imagecreatefromjpeg($uploadedfile);
} else if($extension=="png"){
$uploadedfile = $_FILES['file']['tmp_name'];
$src = imagecreatefrompng($uploadedfile);
} else {
$src = imagecreatefromgif($uploadedfile);
}

list($width,$height)=getimagesize($uploadedfile);

/* ORIGINAL ASPECT RATIO */
$original_aspect_ratio = $width / $height;

/* RESIZE AND CROP THUMBNAIL (MEDIUM SIZE) */
$new_width = 960; // SET DESIRED WIDTH
$new_height = 400; // SET DESIRED HEIGHT
$new_aspect_ratio = $new_width / $new_height;

if ($original_aspect_ratio > $new_aspect_ratio) {
/* source image is wider */
$temp_height = $new_height;
$temp_width = (int) ($new_height * $original_aspect_ratio);
} else {
/* source image is similar or taller */
$temp_width = $new_width;
$temp_height = (int) ($new_width / $original_aspect_ratio);
}

/* Resize to a temporary GD image */
$temp = imagecreatetruecolor($temp_width, $temp_height);
imagecopyresampled($temp,$src,0,0,0,0,$temp_width,$temp_height,$width,$height);

/* Copy cropped region from temporary image into the desired GD image */
$x0 = ($temp_width - $new_width) / 2;
$y0 = ($temp_height - $new_height) / 2;
$medium = imagecreatetruecolor($new_width, $new_height);
imagecopy($medium,$temp,0,0,$x0,$y0,$new_width,$new_height);

/* SAVE TO FILE AND CLEAN UP */
imagedestroy($temp);// CLEANUP TEMP IMAGE
$medium_filename = "images/medium/". $_FILES['file']['name'];
imagejpeg($medium,$medium_filename,100);
imagedestroy($medium);

/* RESIZE AND CROP SMALL IMAGES, SAME PROCEDURE AS ABOVE */
$new_width = 310; // SET DESIRED WIDTH
$new_height = 230; // SET DESIRED HEIGHT
$new_aspect_ratio = $new_width / $new_height;

if ($original_aspect_ratio > $new_aspect_ratio) {
$temp_height = $new_height;
$temp_width = (int) ($new_height * $original_aspect_ratio);
} else {
$temp_width = $new_width;
$temp_height = (int) ($new_width / $original_aspect_ratio);
}

$temp = imagecreatetruecolor($temp_width, $temp_height);
imagecopyresampled($temp,$src,0,0,0,0,$temp_width,$temp_height,$width,$height);

$x0 = ($temp_width - $new_width) / 2;
$y0 = ($temp_height - $new_height) / 2;
$small = imagecreatetruecolor($new_width, $new_height);
imagecopy($small,$temp,0,0,$x0,$y0,$new_width,$new_height);

/* SAVE TO FILE AND CLEAN UP */
imagedestroy($temp);// CLEANUP TEMP IMAGE
$small_filename = "images/thumbnail/small". $_FILES['file']['name'];
imagejpeg($small,$small_filename,100);
imagedestroy($small);

/* ORIGINAL SIZE. NO RESIZING OR CROPPING... NOT NEEDED? YOU DECIDE... */
$full=imagecreatetruecolor($width,$height);
imagecopyresampled($full,$src,0,0,0,0,$width,$height,$width,$height);

/* SAVE TO FILE AND CLEAN UP */
$full_filename = "images/full/". $_FILES['file']['name']; // ORIGINAL
imagejpeg($full,$full_filename,100);
imagedestroy($full);

imagedestroy($src); // CLEAN UP ORIGINAL SOURCE FILE

}
}
}

The code is not tested and mainly inspired from this blog post: http://salman-w.blogspot.se/2009/04/crop-to-fit-image-using-aspphp.html

It is a lot of repeating code in my suggested solution since you have multiple images. You could consider to chunk some of the repeated code into smaller reusable functions, for instance the calculation of aspect ratio for the different images.

Resize image without distortion keeping aspect ratio then crop excess using WideImage

You might try:

$img->resize(200, 150, 'outside')->crop('center', 'middle', 200, 150);

Some users post their versions of calculations... Here's also my version:

$sourceWidth = 1000;
$sourceHeight = 250;

$targetWidth = 200;
$targetHeight = 150;

$sourceRatio = $sourceWidth / $sourceHeight;
$targetRatio = $targetWidth / $targetHeight;

if ( $sourceRatio < $targetRatio ) {
$scale = $sourceWidth / $targetWidth;
} else {
$scale = $sourceHeight / $targetHeight;
}

$resizeWidth = (int)($sourceWidth / $scale);
$resizeHeight = (int)($sourceHeight / $scale);

$cropLeft = (int)(($resizeWidth - $targetWidth) / 2);
$cropTop = (int)(($resizeHeight - $targetHeight) / 2);

var_dump($resizeWidth, $resizeHeight, $cropLeft, $cropTop);

Resize images and fit each image into the square mantaining aspect ratio (backend)

You can try this approach (tested). It will fit your images into an 800x800 square canvas while maintaining the aspect ratio of your images.

resize_image(): This function will maintain the aspect ratio of your image.

function resize_image($img,$maxwidth,$maxheight) {
//This function will return the specified dimension(width,height)
//dimension[0] - width
//dimension[1] - height

$dimension = array();
$imginfo = getimagesize($img);
$imgwidth = $imginfo[0];
$imgheight = $imginfo[1];
if($imgwidth > $maxwidth){
$ratio = $maxwidth/$imgwidth;
$newwidth = round($imgwidth*$ratio);
$newheight = round($imgheight*$ratio);
if($newheight > $maxheight){
$ratio = $maxheight/$newheight;
$dimension[] = round($newwidth*$ratio);
$dimension[] = round($newheight*$ratio);
return $dimension;
}else{
$dimension[] = $newwidth;
$dimension[] = $newheight;
return $dimension;
}
}elseif($imgheight > $maxheight){
$ratio = $maxheight/$imgheight;
$newwidth = round($imgwidth*$ratio);
$newheight = round($imgheight*$ratio);
if($newwidth > $maxwidth){
$ratio = $maxwidth/$newwidth;
$dimension[] = round($newwidth*$ratio);
$dimension[] = round($newheight*$ratio);
return $dimension;
}else{
$dimension[] = $newwidth;
$dimension[] = $newheight;
return $dimension;
}
}else{
$dimension[] = $imgwidth;
$dimension[] = $imgheight;
return $dimension;
}
}

And now comes your code,

$product = getProductById($productid);

$filesArray = array();

if (isset($_GET['files']) && $productid > 0) {
$error = false;
$files = array();
$fileName = '';

$uploaddir = "../images/products/";
foreach ($_FILES as $file) {
$ext = pathinfo($file['name'], PATHINFO_EXTENSION);
$random_name = $widgets->randomFileName();
$randomFullFileName = $productid .'_'. $random_name . '.' . $ext;

//copy to location
//----------------
//HERE I NEED TO CREATE A 800x800px SQUARE and fit the image into it

// Create image from file
$image = null;
switch(strtolower($file['type']))
{
case 'image/jpeg':
$image = imagecreatefromjpeg($file['tmp_name']);
break;
case 'image/png':
$image = imagecreatefrompng($file['tmp_name']);
break;
case 'image/gif':
$image = imagecreatefromgif($file['tmp_name']);
break;
default:
exit('Unsupported type: '.$file['type']);
}

// Get current dimensions
$old_width = imagesx($image);
$old_height = imagesy($image);

// Get the new dimensions
$dimension = resize_image($file, 800, 800);
$new_width = $dimension[0];
$new_height = $dimension[1];

// Create new empty image
$new = imagecreatetruecolor($new_width, $new_height);

// Resize old image into new
imagecopyresampled($new, $image, 0, 0, 0, 0, $new_width, $new_height, $old_width, $old_height);

// Catch and save the image
$status = false;
switch(strtolower($file['type']))
{
case 'image/jpeg':
$status = imagejpeg($new, $uploaddir . $randomFullFileName, 90);
break;
case 'image/png':
$status = imagepng($new, $uploaddir . $randomFullFileName, 0);
break;
case 'image/gif':
$status = imagegif($new, $uploaddir . $randomFullFileName);
break;
}

// Destroy resources
imagedestroy($image);
imagedestroy($new);

//save to database
if($status){
$image_id = updateProduct('default_image', 'images/products/'.$randomFullFileName, $productid);

if ($image_id > 0) {
echo 'Added new image';
} else {
echo 'Error, unable to add. <br> Please try again.';
}
}else{
echo 'Error, unable to add. <br> Please try again.';
}

//----------------
//if (move_uploaded_file($file['tmp_name'], $uploaddir . $randomFullFileName)) {
// //save to database
// $image_id = updateProduct('default_image', 'images/products/'.$randomFullFileName, $productid);

// if ($image_id > 0) {
// echo 'Added new image';
// } else {
// echo 'Error, unable to add. <br> Please try again.';
// }
//} else {
// echo 'Error, unable to add. <br> Please try again.';
//}

}
}

scale an image proportionally without knowing both dimensions

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.



Related Topics



Leave a reply



Submit