Crop center square of image using imagecopyresampled - php

I am trying to create 2 cropped thumbnails (60x60 and 150x150) from a normal sized image. Everything works fine apart from the cropping, which does not work. That part is producing a thumbnail with a black line down the right side like this:
.............
. ...
. ...
. ...
.............
The resizing works fine, as the end thumbnails have the correct heights of 60 and 150 (working from a landscape image as the original) but they still come out landscape.
What I have:
list($thumb_width, $thumb_height) = getimagesize($thumb_target);
if ($thumb_width > $thumb_height) { // landscape
$thumb1_new_height = 60;
$thumb1_new_width = floor( $thumb_width * ( $thumb1_new_height / $thumb_height ));
$thumb1_crop_x = ceil(($thumb_width - $thumb_height) / 2);
$thumb1_crop_y = 0;
$thumb2_new_height = 150;
$thumb2_new_width = floor( $thumb_width * ( $thumb2_new_height / $thumb_height ));
$thumb2_crop_x = ceil(($thumb_width - $thumb_height) / 2);
$thumb2_crop_y = 0;
}
else if ($thumb_width < $thumb_height){ // portrait
$thumb1_new_width = 60;
$thumb1_new_height = floor( $thumb_height * ( $thumb1_new_width / $thumb_width ));
$thumb1_crop_x = 0;
$thumb1_crop_y = ceil(($thumb_height - $thumb_width) / 2);
$thumb2_new_width = 150;
$thumb2_new_height = floor( $thumb_height * ( $thumb2_new_width / $thumb_width ));
$thumb2_crop_x = 0;
$thumb2_crop_y = ceil(($thumb_height - $thumb_width) / 2);
} else { // square
$thumb1_new_width = 60;
$thumb1_new_height = 60;
$thumb1_crop_x = 0;
$thumb1_crop_y = 0;
$thumb2_new_width = 150;
$thumb2_new_height = 150;
$thumb2_crop_x = 0;
$thumb2_crop_y = 0;
}
$thumb1_tmp_img = imagecreatetruecolor($thumb1_new_width,$thumb1_new_height);
$thumb2_tmp_img = imagecreatetruecolor($thumb2_new_width,$thumb2_new_height);
imagecopyresampled($thumb1_tmp_img, $thumb_img, 0, 0, $thumb1_crop_x, $thumb1_crop_y, $thumb1_new_width, $thumb1_new_height, $thumb_width, $thumb_height);
imagecopyresampled($thumb2_tmp_img, $thumb_img, 0, 0, $thumb2_crop_x, $thumb2_crop_y, $thumb2_new_width, $thumb2_new_height, $thumb_width, $thumb_height);

I think you are going wrong in your thumb1_tmp_img near the end. I made this a class so I didn't have to duplicate so much like you have, but you can see the changes. See if this does it for you:
class ImageFactory
{
public function MakeThumb($thumb_target = '', $width = 60,$height = 60,$SetFileName = false, $quality = 80)
{
$thumb_img = imagecreatefromjpeg($thumb_target);
// size from
list($w, $h) = getimagesize($thumb_target);
if($w > $h) {
$new_height = $height;
$new_width = floor($w * ($new_height / $h));
$crop_x = ceil(($w - $h) / 2);
$crop_y = 0;
}
else {
$new_width = $width;
$new_height = floor( $h * ( $new_width / $w ));
$crop_x = 0;
$crop_y = ceil(($h - $w) / 2);
}
// I think this is where you are mainly going wrong
$tmp_img = imagecreatetruecolor($width,$height);
imagecopyresampled($tmp_img, $thumb_img, 0, 0, $crop_x, $crop_y, $new_width, $new_height, $w, $h);
if($SetFileName == false) {
header('Content-Type: image/jpeg');
imagejpeg($tmp_img);
}
else
imagejpeg($tmp_img,$SetFileName,$quality);
imagedestroy($tmp_img);
}
}
// Initiate class
$ImageMaker = new ImageFactory();
// Here is just a test landscape sized image
$thumb_target = 'http://media1.santabanta.com/full6/Outdoors/Landscapes/landscapes-246a.jpg';
// 60px x 60px
$ImageMaker->MakeThumb($thumb_target,60,60,'image60px.jpg');
// Here is a portrait for testing
$thumb_target = 'http://imgc.allpostersimages.com/images/P-488-488-90/55/5543/L6HLG00Z/posters/warning-you-are-entering-a-fart-zone.jpg';
// 150px x 150px
$ImageMaker->MakeThumb($thumb_target,150,150,'image150px.jpg');

Related

Cropping images in PHP leaves black space

This is likely a duplicate, but every solution I have looked at seems to not work for me, so not sure what I am doing differently.
I don't understand too much about image manipulation yet, but cropping images seems to add lots of black space around the right/bottom of the image when using imagecopyresampled to place it over another. They are all JPEGs.
This is my crop function:
function thumbImage($thumb_img,$img_size,$shape){
$width = 250;
$height = 250;
list($w, $h) = $img_size;
if($w > $h) {
$new_height = $height;
$new_width = floor($w * ($new_height / $h));
$crop_x = ceil(($w - $h) / 2);
$crop_y = 0;
} else {
$new_width = $width;
$new_height = floor( $h * ( $new_width / $w ));
$crop_x = 0;
$crop_y = ceil(($h - $w) / 2);
}
$tmp_img = imagecreatetruecolor($width,$height);
imagecopyresampled($tmp_img, $thumb_img, 0, 0, $crop_x, $crop_y, $new_width, $new_height, $w, $h);
return $tmp_img;
}
Any solutions with an explanation of how it works would be greatly appreciated.
Try this:
function thumbImage($source_img,$max_size){
list($w, $h) = getimagesize($source_img);
if($w>$h){
$width = ($max_size/$h)*$w;
$height = $max_size;
}else{
$width = $max_size;
$height = ($max_size/$w)*$h;
}
$x = ($max_size-$width)/2;
$y = ($max_size-$height)/2;
$thumb_img = imagecreatetruecolor($max_size,$max_size);
imagecopyresampled($thumb_img, $source_img, $x, $y, 0, 0, $width, $height, $w, $h);
return $thumb_img;
}

PHP Resize image and crop them to prevent stretching [duplicate]

I have a defined fixed width and height to resize an image. However, I have problem a with this, because the image can have any kind of size ratio (it can be vertical or the horizontal). In this case, fixed width and height cause a problem. I want to calculate width and height in a smarter way.
For example lets say I have defined width 1024px and height 768px. And I want to resize an image which is vertical (height 1100px and width 200px). So in my case it will resize to fixed size (1024x768), so the width will be increased from 100px to 768px, and it will be very ugly. Similarly if the image has height less than 768px, it will increase the height by force to 768px.
Therefore I would like to calculate the new image size based on the original image size ratio. Lets say if the above example image should be resized to maximum height of 768px, but then what about the width? it's already less than my "maximum width", which is 200px, so should the width remain unchanged? or should it be further decreased?
Similarly, if the image has the height 200px, and the width 1100px. So the width should be decreased to 1024px, but what about the height?
The third problem is that, let's suppose if both height and width are more than the maximum height and maximum width, let's say width: 1100px and height:4000px. Now since width and height both are more than the maximum width and maximum height but the image is vertical, it will make it horizontal. So how can I check if in this case if I should resize the image according to maximum height, or according to maximum width?
I appreciate any help with this.
Here's code from my personal grab bag of image resizing code. First, data you need:
list($originalWidth, $originalHeight) = getimagesize($imageFile);
$ratio = $originalWidth / $originalHeight;
Then, this algorithm fits the image into the target size as best it can, keeping the original aspect ratio, not stretching the image larger than the original:
$targetWidth = $targetHeight = min($size, max($originalWidth, $originalHeight));
if ($ratio < 1) {
$targetWidth = $targetHeight * $ratio;
} else {
$targetHeight = $targetWidth / $ratio;
}
$srcWidth = $originalWidth;
$srcHeight = $originalHeight;
$srcX = $srcY = 0;
This crops the image to fill the target size completely, not stretching it:
$targetWidth = $targetHeight = min($originalWidth, $originalHeight, $size);
if ($ratio < 1) {
$srcX = 0;
$srcY = ($originalHeight / 2) - ($originalWidth / 2);
$srcWidth = $srcHeight = $originalWidth;
} else {
$srcY = 0;
$srcX = ($originalWidth / 2) - ($originalHeight / 2);
$srcWidth = $srcHeight = $originalHeight;
}
And this does the actual resizing:
$targetImage = imagecreatetruecolor($targetWidth, $targetHeight);
imagecopyresampled($targetImage, $originalImage, 0, 0, $srcX, $srcY, $targetWidth, $targetHeight, $srcWidth, $srcHeight);
In this case the $size is just one number for both width and height (square target size). I'm sure you can modify it to use non-square targets. It should also give you an inspiration on what other resizing algorithms you can use.
$ratio = $originalWidth / $originalHeight
if you want to change the Height:
$targetWidth = $targetHeight * $ratio
if you want to change the Width:
$targetHeight = $targetWidth / $ratio
What you want is to maintain the aspect ratio of your original image. This is the ratio between the width and the height of the image. So you calculate the factor by which you have to resize the image in the vertical and horizontal direction and then you keep the higher of the two. In pseudocode:
target_height = 768
target_width = 1024
# v_fact and h_fact are the factor by which the original vertical / horizontal
# image sizes should be multiplied to get the image to your target size.
v_fact = target_height / im_height
h_fact = target_width / im_width
# you want to resize the image by the same factor in both vertical
# and horizontal direction, so you need to pick the correct factor from
# v_fact / h_fact so that the largest (relative to target) of the new height/width
# equals the target height/width and the smallest is lower than the target.
# this is the lowest of the two factors
im_fact = min(v_fact, h_fact)
new_height = im_height * im_fact
new_width = im_width * im_fact
image.resize(new_width, new_height)
this is working.
function calculateDimensions($width,$height,$maxwidth,$maxheight)
{
if($width != $height)
{
if($width > $height)
{
$t_width = $maxwidth;
$t_height = (($t_width * $height)/$width);
//fix height
if($t_height > $maxheight)
{
$t_height = $maxheight;
$t_width = (($width * $t_height)/$height);
}
}
else
{
$t_height = $maxheight;
$t_width = (($width * $t_height)/$height);
//fix width
if($t_width > $maxwidth)
{
$t_width = $maxwidth;
$t_height = (($t_width * $height)/$width);
}
}
}
else
$t_width = $t_height = min($maxheight,$maxwidth);
return array('height'=>(int)$t_height,'width'=>(int)$t_width);
}
How about this:
double ratio = imageWidth/imageHeight;
int newHeight = Math.min(displayHeight, displayWidth / ratio);
int newWidth = Math.min(displayWidth, displayHeight * ratio);
Check the php code below :
$new_width = 1024;
$new_height = 768;
$this_image = "images/my_image";
list($width, $height, $type, $attr) = getimagesize("$this_image");
if ($width > $height) {
$image_height = floor(($height/$width)*$new_width);
$image_width = $new_width;
} else {
$image_width = floor(($width/$height)*$new_height);
$image_height = $new_height;
}
echo "<img src='$this_image' height='$image_height' width='$image_width'>";
What you need is to 'maintain' the width/height ratio.
Originally you have an image of size (wxh) 500x1000, this width/height ratio is 0.5 . Assuming you are changing 1000 to 768 in height, your result width would be 0.5 * 768 = 384.
Another example, 1800 x 1200 and your new height is 200, then your new width is 300 because 300/200 is 1.5 and 1800/1200 is also 1.5.
Good luck.
You should resize it depending on what property is farer away from the maximum value. Then, calculate the ratio.
if(($w - $w_max) > ($h - $h_max)) {
$w_new = $w_max;
$h_new = (int) ($h * ($w_max / $w));
}
else {
$h_new = $h_max;
$w_new = (int) ($w * ($h_max / $h));
}
I reached this question and didn't find a suitable answer, so i set out on my own to answer the question.
i started with some basic logic, and after consulting a friend of mine who is a bit better at math, this is what we came up with.
function calculate_dimensions($width,$height,$max){
if($width != $height){
if($width > $height){
$t_height = $max;
$t_width = min(($width * $t_height)/$height);
}
if($height > $width){
$t_width = $max;
$t_height = min(($t_width * $height)/$width)
}
}else{
if($width > $max){
$t_width = $t_height = $max;
}
}
$res = ['height'=>$t_height,'width'=>$t_width]
return $res;
}
This snippet of code is reusable, so knock yourself out. just pass it the maximum smallest dimension allowed, and it will calculate the largest side's dimension, so you will get back a correctly scaled dimension, in which you can then center crop, resulting in a correctly shrinked and cropped image square image. this is useful for things like profile pictures and thumbnails.
credit to my friend, Justin Gillett for his brilliant suggestion of cross multiplication.
This example will shrink an image to fit a defined pixel perfect aspect ratio ( 16:9 ) creating an image no larger than a specified limit ( 1200 x 675 ).
Set your image ratio and any upper limit:
const RATIO_W = 16;
const RATIO_H = 9;
const RATIO_MULIPLIER_UPPER_LIMIT = 75;
Calculate the new image width and height
list($imageWidth, $imageHeight) = getimagesize($path_to_image);
if( ($imageWidth / $imageHeight) === (self::RATIO_W / self::RATIO_H) ){
return;
// Find closest ratio multiple to image size
if($imageWidth > $imageHeight){
// landscape
$ratioMultiple = round($imageHeight / self::RATIO_H, 0, PHP_ROUND_HALF_DOWN);
}else{
// portrait
$ratioMultiple = round($imageWidth / self::RATIO_W, 0, PHP_ROUND_HALF_DOWN);
}
$newWidth = $ratioMultiple * self::RATIO_W;
$newHeight = $ratioMultiple * self::RATIO_H;
if($newWidth > self::RATIO_W * self::RATIO_MULIPLIER_UPPER_LIMIT|| $newHeight > self::RATIO_H * self::RATIO_MULIPLIER_UPPER_LIMIT){
// File is larger than upper limit
$ratioMultiple = self::RATIO_MULIPLIER_UPPER_LIMIT;
}
$this->tweakMultiplier($ratioMultiple, $imageWidth, $imageHeight);
$newWidth = $ratioMultiple * self::RATIO_W;
$newHeight = $ratioMultiple * self::RATIO_H;
Resize image
$originalImage = imagecreatefromjpeg( $tempImagePath );
$newImage = imagecreatetruecolor($newWidth, $newHeight);
imagefilledrectangle($newImage, 0, 0, $newWidth, $newHeight, imagecolorallocate($newImage, 255, 255, 255));
imagecopyresampled($newImage, $originalImage, 0, 0, 0, 0, $newWidth, $newHeight, $imageWidth, $imageHeight);
imagejpeg($newImage, $tempImagePath, 100);
Loop through factors until both dimensions are less than the original image size
protected function tweakMultiplier( &$ratioMultiple, $fitInsideWidth, $fitInsideHeight ){
$newWidth = $ratioMultiple * self::RATIO_W;
$newHeight = $ratioMultiple * self::RATIO_H;
if($newWidth > $fitInsideWidth || $newHeight > $fitInsideHeight){
echo " Tweak ";
$ratioMultiple--;
$this->tweakMultiplier($ratioMultiple, $fitInsideWidth, $fitInsideHeight);
}else{
return;
}
}
If max height or width given or not, using #(jilles de wit) logic
considerations : these should already be defined!
$mh = given height limit; //optional
$mw = given width limit; //optional
$height = $nh =[your original height];
$width = $nw =[your original width];
The Code
if($mh || $mw){
if(is_numeric($mh)){$h_fact = $mh / $nh;}
if(is_numeric($mw)){$v_fact = $mw / $nw;}
if(is_numeric($v_fact) && is_numeric($h_fact) ){$im_fact = min($v_fact, $h_fact);}else{$im_fact=is_numeric($v_fact)?$v_fact:$h_fact;}
$nw = $nw * $im_fact;
$nh = $nh * $im_fact;
}
resampling
$dst_img = imagecreatetruecolor($nw,$nh);
imagecopyresampled ($dst_img, $image, 0, 0, 0, 0, $nw, $nh, $width , $height);
get the nearest Ratio
$r=getRatio(820,460);//41:23
$r=getRatio(160,40);//4:1
$r=getRatio(1743,367);//1743:367
function getRatio($num1, $num2){
if(abs($num1-$num2)<10 && $num1>100){
$num1=$num2;
}
for($i = $num2; $i > 1; $i--) {
if((($num1 % $i) == 0 && ($num2 % $i) == 0) ) {
$num1 = $num1 / $i;
$num2 = $num2 / $i;
}
}
return round($num1,1).':'.round($num2,1);
}
class Image_Aspect_Ratio_Resize {
var $image_to_resize;
var $new_width;
var $new_height;
var $ratio;
var $new_image_name;
var $save_folder;
function resize() {
if (!file_exists($this->image_to_resize)) {
exit("File " . $this->image_to_resize . " does not exist.");
}
$info = GetImageSize($this->image_to_resize);
if (empty($info)) {
exit("The file " . $this->image_to_resize . " doesn't seem to be an image.");
}
$width = $info[0];
$height = $info[1];
$mime = $info['mime'];
/* Keep Aspect Ratio? */
if ($this->ratio) {
$thumb = ($this->new_width < $width && $this->new_height < $height) ? true : false; // Thumbnail
$bigger_image = ($this->new_width > $width || $this->new_height > $height) ? true : false; // Bigger Image
if ($thumb) {
if ($this->new_width >= $this->new_height) {
$x = ($width / $this->new_width);
$this->new_height = ($height / $x);
} else if ($this->new_height >= $this->new_width) {
$x = ($height / $this->new_height);
$this->new_width = ($width / $x);
}
} else if ($bigger_image) {
if ($this->new_width >= $width) {
$x = ($this->new_width / $width);
$this->new_height = ($height * $x);
} else if ($this->new_height >= $height) {
$x = ($this->new_height / $height);
$this->new_width = ($width * $x);
}
}
}
$type = substr(strrchr($mime, '/'), 1);
switch ($type) {
case 'jpeg':
$image_create_func = 'ImageCreateFromJPEG';
$image_save_func = 'ImageJPEG';
$new_image_ext = 'jpg';
break;
case 'png':
$image_create_func = 'ImageCreateFromPNG';
$image_save_func = 'ImagePNG';
$new_image_ext = 'png';
break;
case 'bmp':
$image_create_func = 'ImageCreateFromBMP';
$image_save_func = 'ImageBMP';
$new_image_ext = 'bmp';
break;
case 'gif':
$image_create_func = 'ImageCreateFromGIF';
$image_save_func = 'ImageGIF';
$new_image_ext = 'gif';
break;
case 'vnd.wap.wbmp':
$image_create_func = 'ImageCreateFromWBMP';
$image_save_func = 'ImageWBMP';
$new_image_ext = 'bmp';
break;
case 'xbm':
$image_create_func = 'ImageCreateFromXBM';
$image_save_func = 'ImageXBM';
$new_image_ext = 'xbm';
break;
default:
$image_create_func = 'ImageCreateFromJPEG';
$image_save_func = 'ImageJPEG';
$new_image_ext = 'jpg';
}
// New Image
$image_c = ImageCreateTrueColor($this->new_width, $this->new_height);
$new_image = $image_create_func($this->image_to_resize);
ImageCopyResampled($image_c, $new_image, 0, 0, 0, 0, $this->new_width, $this->new_height, $width, $height);
if ($this->save_folder) {
if ($this->new_image_name) {
$new_name = $this->new_image_name . '.' . $new_image_ext;
} else {
$new_name = $this->new_thumb_name(basename($this->image_to_resize)) . '_resized.' . $new_image_ext;
}
$save_path = $this->save_folder . $new_name;
} else {
/* Show the image without saving it to a folder */
header("Content-Type: " . $mime);
$image_save_func($image_c);
$save_path = '';
}
$process = $image_save_func($image_c, $save_path);
return array('result' => $process, 'new_file_path' => $save_path);
}}
/* Function Call */
$resize_image = new Image_Aspect_Ratio_Resize;
$new_width = (int) $_POST['new_width'];
$new_height = (int) $_POST['new_height'];
$resize_image->new_width = $new_width;
$resize_image->new_height = $new_height;
$resize_image->image_to_resize = $image; // Full Path to the file
$resize_image->ratio = true; // Keep aspect ratio
// Name of the new image (optional) - If it's not set a new will be added automatically
$resize_image->new_image_name = 'water_lilies_thumbnail';
/* Path where the new image should be saved. If it's not set the script will output the image without saving it */
$resize_image->save_folder = 'thumbs/';
$process = $resize_image->resize(); // Output image

Alter my scale and crop class to work properly? [duplicate]

I have a defined fixed width and height to resize an image. However, I have problem a with this, because the image can have any kind of size ratio (it can be vertical or the horizontal). In this case, fixed width and height cause a problem. I want to calculate width and height in a smarter way.
For example lets say I have defined width 1024px and height 768px. And I want to resize an image which is vertical (height 1100px and width 200px). So in my case it will resize to fixed size (1024x768), so the width will be increased from 100px to 768px, and it will be very ugly. Similarly if the image has height less than 768px, it will increase the height by force to 768px.
Therefore I would like to calculate the new image size based on the original image size ratio. Lets say if the above example image should be resized to maximum height of 768px, but then what about the width? it's already less than my "maximum width", which is 200px, so should the width remain unchanged? or should it be further decreased?
Similarly, if the image has the height 200px, and the width 1100px. So the width should be decreased to 1024px, but what about the height?
The third problem is that, let's suppose if both height and width are more than the maximum height and maximum width, let's say width: 1100px and height:4000px. Now since width and height both are more than the maximum width and maximum height but the image is vertical, it will make it horizontal. So how can I check if in this case if I should resize the image according to maximum height, or according to maximum width?
I appreciate any help with this.
Here's code from my personal grab bag of image resizing code. First, data you need:
list($originalWidth, $originalHeight) = getimagesize($imageFile);
$ratio = $originalWidth / $originalHeight;
Then, this algorithm fits the image into the target size as best it can, keeping the original aspect ratio, not stretching the image larger than the original:
$targetWidth = $targetHeight = min($size, max($originalWidth, $originalHeight));
if ($ratio < 1) {
$targetWidth = $targetHeight * $ratio;
} else {
$targetHeight = $targetWidth / $ratio;
}
$srcWidth = $originalWidth;
$srcHeight = $originalHeight;
$srcX = $srcY = 0;
This crops the image to fill the target size completely, not stretching it:
$targetWidth = $targetHeight = min($originalWidth, $originalHeight, $size);
if ($ratio < 1) {
$srcX = 0;
$srcY = ($originalHeight / 2) - ($originalWidth / 2);
$srcWidth = $srcHeight = $originalWidth;
} else {
$srcY = 0;
$srcX = ($originalWidth / 2) - ($originalHeight / 2);
$srcWidth = $srcHeight = $originalHeight;
}
And this does the actual resizing:
$targetImage = imagecreatetruecolor($targetWidth, $targetHeight);
imagecopyresampled($targetImage, $originalImage, 0, 0, $srcX, $srcY, $targetWidth, $targetHeight, $srcWidth, $srcHeight);
In this case the $size is just one number for both width and height (square target size). I'm sure you can modify it to use non-square targets. It should also give you an inspiration on what other resizing algorithms you can use.
$ratio = $originalWidth / $originalHeight
if you want to change the Height:
$targetWidth = $targetHeight * $ratio
if you want to change the Width:
$targetHeight = $targetWidth / $ratio
What you want is to maintain the aspect ratio of your original image. This is the ratio between the width and the height of the image. So you calculate the factor by which you have to resize the image in the vertical and horizontal direction and then you keep the higher of the two. In pseudocode:
target_height = 768
target_width = 1024
# v_fact and h_fact are the factor by which the original vertical / horizontal
# image sizes should be multiplied to get the image to your target size.
v_fact = target_height / im_height
h_fact = target_width / im_width
# you want to resize the image by the same factor in both vertical
# and horizontal direction, so you need to pick the correct factor from
# v_fact / h_fact so that the largest (relative to target) of the new height/width
# equals the target height/width and the smallest is lower than the target.
# this is the lowest of the two factors
im_fact = min(v_fact, h_fact)
new_height = im_height * im_fact
new_width = im_width * im_fact
image.resize(new_width, new_height)
this is working.
function calculateDimensions($width,$height,$maxwidth,$maxheight)
{
if($width != $height)
{
if($width > $height)
{
$t_width = $maxwidth;
$t_height = (($t_width * $height)/$width);
//fix height
if($t_height > $maxheight)
{
$t_height = $maxheight;
$t_width = (($width * $t_height)/$height);
}
}
else
{
$t_height = $maxheight;
$t_width = (($width * $t_height)/$height);
//fix width
if($t_width > $maxwidth)
{
$t_width = $maxwidth;
$t_height = (($t_width * $height)/$width);
}
}
}
else
$t_width = $t_height = min($maxheight,$maxwidth);
return array('height'=>(int)$t_height,'width'=>(int)$t_width);
}
How about this:
double ratio = imageWidth/imageHeight;
int newHeight = Math.min(displayHeight, displayWidth / ratio);
int newWidth = Math.min(displayWidth, displayHeight * ratio);
Check the php code below :
$new_width = 1024;
$new_height = 768;
$this_image = "images/my_image";
list($width, $height, $type, $attr) = getimagesize("$this_image");
if ($width > $height) {
$image_height = floor(($height/$width)*$new_width);
$image_width = $new_width;
} else {
$image_width = floor(($width/$height)*$new_height);
$image_height = $new_height;
}
echo "<img src='$this_image' height='$image_height' width='$image_width'>";
What you need is to 'maintain' the width/height ratio.
Originally you have an image of size (wxh) 500x1000, this width/height ratio is 0.5 . Assuming you are changing 1000 to 768 in height, your result width would be 0.5 * 768 = 384.
Another example, 1800 x 1200 and your new height is 200, then your new width is 300 because 300/200 is 1.5 and 1800/1200 is also 1.5.
Good luck.
You should resize it depending on what property is farer away from the maximum value. Then, calculate the ratio.
if(($w - $w_max) > ($h - $h_max)) {
$w_new = $w_max;
$h_new = (int) ($h * ($w_max / $w));
}
else {
$h_new = $h_max;
$w_new = (int) ($w * ($h_max / $h));
}
I reached this question and didn't find a suitable answer, so i set out on my own to answer the question.
i started with some basic logic, and after consulting a friend of mine who is a bit better at math, this is what we came up with.
function calculate_dimensions($width,$height,$max){
if($width != $height){
if($width > $height){
$t_height = $max;
$t_width = min(($width * $t_height)/$height);
}
if($height > $width){
$t_width = $max;
$t_height = min(($t_width * $height)/$width)
}
}else{
if($width > $max){
$t_width = $t_height = $max;
}
}
$res = ['height'=>$t_height,'width'=>$t_width]
return $res;
}
This snippet of code is reusable, so knock yourself out. just pass it the maximum smallest dimension allowed, and it will calculate the largest side's dimension, so you will get back a correctly scaled dimension, in which you can then center crop, resulting in a correctly shrinked and cropped image square image. this is useful for things like profile pictures and thumbnails.
credit to my friend, Justin Gillett for his brilliant suggestion of cross multiplication.
This example will shrink an image to fit a defined pixel perfect aspect ratio ( 16:9 ) creating an image no larger than a specified limit ( 1200 x 675 ).
Set your image ratio and any upper limit:
const RATIO_W = 16;
const RATIO_H = 9;
const RATIO_MULIPLIER_UPPER_LIMIT = 75;
Calculate the new image width and height
list($imageWidth, $imageHeight) = getimagesize($path_to_image);
if( ($imageWidth / $imageHeight) === (self::RATIO_W / self::RATIO_H) ){
return;
// Find closest ratio multiple to image size
if($imageWidth > $imageHeight){
// landscape
$ratioMultiple = round($imageHeight / self::RATIO_H, 0, PHP_ROUND_HALF_DOWN);
}else{
// portrait
$ratioMultiple = round($imageWidth / self::RATIO_W, 0, PHP_ROUND_HALF_DOWN);
}
$newWidth = $ratioMultiple * self::RATIO_W;
$newHeight = $ratioMultiple * self::RATIO_H;
if($newWidth > self::RATIO_W * self::RATIO_MULIPLIER_UPPER_LIMIT|| $newHeight > self::RATIO_H * self::RATIO_MULIPLIER_UPPER_LIMIT){
// File is larger than upper limit
$ratioMultiple = self::RATIO_MULIPLIER_UPPER_LIMIT;
}
$this->tweakMultiplier($ratioMultiple, $imageWidth, $imageHeight);
$newWidth = $ratioMultiple * self::RATIO_W;
$newHeight = $ratioMultiple * self::RATIO_H;
Resize image
$originalImage = imagecreatefromjpeg( $tempImagePath );
$newImage = imagecreatetruecolor($newWidth, $newHeight);
imagefilledrectangle($newImage, 0, 0, $newWidth, $newHeight, imagecolorallocate($newImage, 255, 255, 255));
imagecopyresampled($newImage, $originalImage, 0, 0, 0, 0, $newWidth, $newHeight, $imageWidth, $imageHeight);
imagejpeg($newImage, $tempImagePath, 100);
Loop through factors until both dimensions are less than the original image size
protected function tweakMultiplier( &$ratioMultiple, $fitInsideWidth, $fitInsideHeight ){
$newWidth = $ratioMultiple * self::RATIO_W;
$newHeight = $ratioMultiple * self::RATIO_H;
if($newWidth > $fitInsideWidth || $newHeight > $fitInsideHeight){
echo " Tweak ";
$ratioMultiple--;
$this->tweakMultiplier($ratioMultiple, $fitInsideWidth, $fitInsideHeight);
}else{
return;
}
}
If max height or width given or not, using #(jilles de wit) logic
considerations : these should already be defined!
$mh = given height limit; //optional
$mw = given width limit; //optional
$height = $nh =[your original height];
$width = $nw =[your original width];
The Code
if($mh || $mw){
if(is_numeric($mh)){$h_fact = $mh / $nh;}
if(is_numeric($mw)){$v_fact = $mw / $nw;}
if(is_numeric($v_fact) && is_numeric($h_fact) ){$im_fact = min($v_fact, $h_fact);}else{$im_fact=is_numeric($v_fact)?$v_fact:$h_fact;}
$nw = $nw * $im_fact;
$nh = $nh * $im_fact;
}
resampling
$dst_img = imagecreatetruecolor($nw,$nh);
imagecopyresampled ($dst_img, $image, 0, 0, 0, 0, $nw, $nh, $width , $height);
get the nearest Ratio
$r=getRatio(820,460);//41:23
$r=getRatio(160,40);//4:1
$r=getRatio(1743,367);//1743:367
function getRatio($num1, $num2){
if(abs($num1-$num2)<10 && $num1>100){
$num1=$num2;
}
for($i = $num2; $i > 1; $i--) {
if((($num1 % $i) == 0 && ($num2 % $i) == 0) ) {
$num1 = $num1 / $i;
$num2 = $num2 / $i;
}
}
return round($num1,1).':'.round($num2,1);
}
class Image_Aspect_Ratio_Resize {
var $image_to_resize;
var $new_width;
var $new_height;
var $ratio;
var $new_image_name;
var $save_folder;
function resize() {
if (!file_exists($this->image_to_resize)) {
exit("File " . $this->image_to_resize . " does not exist.");
}
$info = GetImageSize($this->image_to_resize);
if (empty($info)) {
exit("The file " . $this->image_to_resize . " doesn't seem to be an image.");
}
$width = $info[0];
$height = $info[1];
$mime = $info['mime'];
/* Keep Aspect Ratio? */
if ($this->ratio) {
$thumb = ($this->new_width < $width && $this->new_height < $height) ? true : false; // Thumbnail
$bigger_image = ($this->new_width > $width || $this->new_height > $height) ? true : false; // Bigger Image
if ($thumb) {
if ($this->new_width >= $this->new_height) {
$x = ($width / $this->new_width);
$this->new_height = ($height / $x);
} else if ($this->new_height >= $this->new_width) {
$x = ($height / $this->new_height);
$this->new_width = ($width / $x);
}
} else if ($bigger_image) {
if ($this->new_width >= $width) {
$x = ($this->new_width / $width);
$this->new_height = ($height * $x);
} else if ($this->new_height >= $height) {
$x = ($this->new_height / $height);
$this->new_width = ($width * $x);
}
}
}
$type = substr(strrchr($mime, '/'), 1);
switch ($type) {
case 'jpeg':
$image_create_func = 'ImageCreateFromJPEG';
$image_save_func = 'ImageJPEG';
$new_image_ext = 'jpg';
break;
case 'png':
$image_create_func = 'ImageCreateFromPNG';
$image_save_func = 'ImagePNG';
$new_image_ext = 'png';
break;
case 'bmp':
$image_create_func = 'ImageCreateFromBMP';
$image_save_func = 'ImageBMP';
$new_image_ext = 'bmp';
break;
case 'gif':
$image_create_func = 'ImageCreateFromGIF';
$image_save_func = 'ImageGIF';
$new_image_ext = 'gif';
break;
case 'vnd.wap.wbmp':
$image_create_func = 'ImageCreateFromWBMP';
$image_save_func = 'ImageWBMP';
$new_image_ext = 'bmp';
break;
case 'xbm':
$image_create_func = 'ImageCreateFromXBM';
$image_save_func = 'ImageXBM';
$new_image_ext = 'xbm';
break;
default:
$image_create_func = 'ImageCreateFromJPEG';
$image_save_func = 'ImageJPEG';
$new_image_ext = 'jpg';
}
// New Image
$image_c = ImageCreateTrueColor($this->new_width, $this->new_height);
$new_image = $image_create_func($this->image_to_resize);
ImageCopyResampled($image_c, $new_image, 0, 0, 0, 0, $this->new_width, $this->new_height, $width, $height);
if ($this->save_folder) {
if ($this->new_image_name) {
$new_name = $this->new_image_name . '.' . $new_image_ext;
} else {
$new_name = $this->new_thumb_name(basename($this->image_to_resize)) . '_resized.' . $new_image_ext;
}
$save_path = $this->save_folder . $new_name;
} else {
/* Show the image without saving it to a folder */
header("Content-Type: " . $mime);
$image_save_func($image_c);
$save_path = '';
}
$process = $image_save_func($image_c, $save_path);
return array('result' => $process, 'new_file_path' => $save_path);
}}
/* Function Call */
$resize_image = new Image_Aspect_Ratio_Resize;
$new_width = (int) $_POST['new_width'];
$new_height = (int) $_POST['new_height'];
$resize_image->new_width = $new_width;
$resize_image->new_height = $new_height;
$resize_image->image_to_resize = $image; // Full Path to the file
$resize_image->ratio = true; // Keep aspect ratio
// Name of the new image (optional) - If it's not set a new will be added automatically
$resize_image->new_image_name = 'water_lilies_thumbnail';
/* Path where the new image should be saved. If it's not set the script will output the image without saving it */
$resize_image->save_folder = 'thumbs/';
$process = $resize_image->resize(); // Output image

Image resize with php [duplicate]

This question already has answers here:
Resize image in PHP
(13 answers)
Closed 6 years ago.
function resize($originalImage){
list($width, $height) = getimagesize($originalImage);
$newName=basename($originalImage);
$imageResized = imagecreatetruecolor(128, 128);
$imageTmp = imagecreatefromjpeg ($originalImage);
imagecopyresampled($imageResized, $imageTmp, 0, 0, 0, 0, 128, 128, $width, $height);
imagejpeg($imageResized, "resizedImg/$newName",100);
imageDestroy($imageResized);
}
The script returns the image with the correct name but it's just black? Any ideas?
If you have trouble with image resizing use this code for it. Do the modifications as you need it.
function resizeImage($file){
define ('MAX_WIDTH', 1500);//max image width
define ('MAX_HEIGHT', 1500);//max image height
define ('MAX_FILE_SIZE', 10485760);
//iamge save path
$path = 'storeResize/';
//size of the resize image
$new_width = 128;
$new_height = 128;
//name of the new image
$nameOfFile = 'resize_'.$new_width.'x'.$new_height.'_'.basename($file['name']);
$image_type = $file['type'];
$image_size = $file['size'];
$image_error = $file['error'];
$image_file = $file['tmp_name'];
$image_name = $file['name'];
$image_info = getimagesize($image_file);
//check image type
if ($image_info['mime'] == 'image/jpeg' or $image_info['mime'] == 'image/jpg'){
}
else if ($image_info['mime'] == 'image/png'){
}
else if ($image_info['mime'] == 'image/gif'){
}
else{
//set error invalid file type
}
if ($image_error){
//set error image upload error
}
if ( $image_size > MAX_FILE_SIZE ){
//set error image size invalid
}
switch ($image_info['mime']) {
case 'image/jpg': //This isn't a valid mime type so we should probably remove it
case 'image/jpeg':
$image = imagecreatefromjpeg ($image_file);
break;
case 'image/png':
$image = imagecreatefrompng ($image_file);
break;
case 'image/gif':
$image = imagecreatefromgif ($image_file);
break;
}
if ($new_width == 0 && $new_height == 0) {
$new_width = 100;
$new_height = 100;
}
// ensure size limits can not be abused
$new_width = min ($new_width, MAX_WIDTH);
$new_height = min ($new_height, MAX_HEIGHT);
//get original image h/w
$width = imagesx ($image);
$height = imagesy ($image);
//$align = 'b';
$zoom_crop = 1;
$origin_x = 0;
$origin_y = 0;
//TODO setting Memory
// generate new w/h if not provided
if ($new_width && !$new_height) {
$new_height = floor ($height * ($new_width / $width));
} else if ($new_height && !$new_width) {
$new_width = floor ($width * ($new_height / $height));
}
// scale down and add borders
if ($zoom_crop == 3) {
$final_height = $height * ($new_width / $width);
if ($final_height > $new_height) {
$new_width = $width * ($new_height / $height);
} else {
$new_height = $final_height;
}
}
// create a new true color image
$canvas = imagecreatetruecolor ($new_width, $new_height);
imagealphablending ($canvas, false);
if (strlen ($canvas_color) < 6) {
$canvas_color = 'ffffff';
}
$canvas_color_R = hexdec (substr ($canvas_color, 0, 2));
$canvas_color_G = hexdec (substr ($canvas_color, 2, 2));
$canvas_color_B = hexdec (substr ($canvas_color, 2, 2));
// Create a new transparent color for image
$color = imagecolorallocatealpha ($canvas, $canvas_color_R, $canvas_color_G, $canvas_color_B, 127);
// Completely fill the background of the new image with allocated color.
imagefill ($canvas, 0, 0, $color);
// scale down and add borders
if ($zoom_crop == 2) {
$final_height = $height * ($new_width / $width);
if ($final_height > $new_height) {
$origin_x = $new_width / 2;
$new_width = $width * ($new_height / $height);
$origin_x = round ($origin_x - ($new_width / 2));
} else {
$origin_y = $new_height / 2;
$new_height = $final_height;
$origin_y = round ($origin_y - ($new_height / 2));
}
}
// Restore transparency blending
imagesavealpha ($canvas, true);
if ($zoom_crop > 0) {
$src_x = $src_y = 0;
$src_w = $width;
$src_h = $height;
$cmp_x = $width / $new_width;
$cmp_y = $height / $new_height;
// calculate x or y coordinate and width or height of source
if ($cmp_x > $cmp_y) {
$src_w = round ($width / $cmp_x * $cmp_y);
$src_x = round (($width - ($width / $cmp_x * $cmp_y)) / 2);
} else if ($cmp_y > $cmp_x) {
$src_h = round ($height / $cmp_y * $cmp_x);
$src_y = round (($height - ($height / $cmp_y * $cmp_x)) / 2);
}
// positional cropping!
if ($align) {
if (strpos ($align, 't') !== false) {
$src_y = 0;
}
if (strpos ($align, 'b') !== false) {
$src_y = $height - $src_h;
}
if (strpos ($align, 'l') !== false) {
$src_x = 0;
}
if (strpos ($align, 'r') !== false) {
$src_x = $width - $src_w;
}
}
// positional cropping!
imagecopyresampled ($canvas, $image, $origin_x, $origin_y, $src_x, $src_y, $new_width, $new_height, $src_w, $src_h);
} else {
imagecopyresampled ($canvas, $image, 0, 0, 0, 0, $new_width, $new_height, $width, $height);
}
//Straight from Wordpress core code. Reduces filesize by up to 70% for PNG's
if ( (IMAGETYPE_PNG == $image_info[2] || IMAGETYPE_GIF == $image_info[2]) && function_exists('imageistruecolor') && !imageistruecolor( $image ) && imagecolortransparent( $image ) > 0 ){
imagetruecolortopalette( $canvas, false, imagecolorstotal( $image ) );
}
$quality = 100;
$nameOfFile = 'resize_'.$new_width.'x'.$new_height.'_'.basename($file['name']);
if (preg_match('/^image\/(?:jpg|jpeg)$/i', $image_info['mime'])){
imagejpeg($canvas, $path.$nameOfFile, $quality);
} else if (preg_match('/^image\/png$/i', $image_info['mime'])){
imagepng($canvas, $path.$nameOfFile, floor($quality * 0.09));
} else if (preg_match('/^image\/gif$/i', $image_info['mime'])){
imagegif($canvas, $path.$nameOfFile);
}
}

Having issues with GD thumbnail generator

I'm using PHP to generate thumbnails. The problem is that I have a set width and height the thumbnails need to be and often times the images are stretched.
What I'd like is the image to remain at the same proportions and just have black filler (or any color) either on the left & right for tall images or top & bottom for wide images.
Here is the code I'm currently using: (dumbed down a bit for readability)
$temp_image_file = imagecreatefromjpeg("http://www.example.com/image.jpg");
list($width,$height) = getimagesize("http://www.example.com/image.jpg");
$image_file = imagecreatetruecolor(166,103);
imagecopyresampled($image_file,$temp_image_file,0,0,0,0,166,103,$width,$height);
imagejpeg($image_file,"thumbnails/thumbnail.jpg",50);
imagedestroy($temp_image_file);
imagedestroy($image_file);
You'll need to calculate the new width & height to keep the image proportionat. Check out example 2 on this page:
http://us3.php.net/imagecopyresampled
Okay got it working, here's what I ended up doing:
$filename = "http://www.example.com/image.jpg";
list($width,$height) = getimagesize($filename);
$width_ratio = 166 / $width;
if ($height * $width_ratio <= 103)
{
$adjusted_width = 166;
$adjusted_height = $height * $width_ratio;
}
else
{
$height_ratio = 103 / $height;
$adjusted_width = $width * $height_ratio;
$adjusted_height = 103;
}
$image_p = imagecreatetruecolor(166,103);
$image = imagecreatefromjpeg($filename);
imagecopyresampled($image_p,$image,ceil((166 - $adjusted_width) / 2),ceil((103 - $adjusted_height) / 2),0,0,ceil($adjusted_width),ceil($adjusted_height),$width,$height);
imagejpeg($image_p,"thumbnails/thumbnail.jpg",50);
Here's a function I wrote that takes a GD image object, max width, max height, and rescales within those parameters:
function resized($im, $mx, $my) {
$x = $nx = imagesx($im);
$y = $ny = imagesy($im);
$ar = $x / $y;
while ($nx > $mx || $ny > $my) {
if ($nx > $mx) {
$nx = $mx;
$ny = $nx / $ar;
}
if ($ny > $my) {
$ny = $my;
$nx = $ny * $ar;
}
}
if ($nx != $x) {
$im2 = imagecreatetruecolor($nx, $ny);
imagecopyresampled($im2, $im, 0, 0, 0, 0, $nx, $ny, $x, $y);
return $im2;
} else {
return $im;
}
}
If the resulting image doesn't need rescaling then it just returns the original image.
Have a look at this upload class. It does what you want and a lot more besides.
This rescales the image to the larger size of the width and height and then crops it to the correct size.
// Crete an image forced to width and height
function createFixedImage($img, $id=0, $preFix=false, $mw='100', $mh='100', $quality=90){
// Fix path
$filename = '../'.$img;
// Check for file
if(file_exists($filename))
{
// Set a maximum height and width
$width = $mw;
$height = $mh;
// Get new dimensions
list($width_orig, $height_orig) = getimagesize($filename);
$ratio_orig = $width_orig/$height_orig;
if ($width/$height < $ratio_orig) {
$width = $height*$ratio_orig;
}else{
$height = $width/$ratio_orig;
}
// Resample
$image_p = imagecreatetruecolor($mw, $mh);
$image = imagecreatefromjpeg($filename);
imagecopyresampled($image_p, $image, 0, 0, 0, 0, $width, $height, $width_orig, $height_orig);
// Output
imagejpeg($image_p, "../images/stories/catalog/{$preFix}{$id}.jpg", $quality);
}
}

Categories