Forum Moderators: coopster

Message Too Old, No Replies

GD Library Resizing an Image Calculation

How do i resize the image and keep the con

         

scriptmasterdel

2:51 pm on Feb 24, 2007 (gmt 0)

10+ Year Member



Hello Webmaster World,

I have a function that creates a thumbnail representation of a real file, what I would like to do I be able to create a thumbnail with a canvas size of exactly 100 x 100 px and then be able the vertically and horizontally align the image in its container.

So far I have something like this:

// I create the image from a file
$img = Imagecreatefromjpeg($filename);

// Create the canvas
$img_n = imagecreatetruecolor($width, $height);

// Merge the file with the canvas
imagecopyresampled($img_n, $img, 0, 0, $xoffset, $yoffset, $width, $height, $org_width, $org_height);


So I guess my question is how can I get the image to reduce its size to fit in the containing image handle, vertically and horizontally? I altered the image canvas size and it appeared in the top left corner.

I hope this makes sense, I would really appreciate some help on this.

Thank you all for your time.

Del

jatar_k

3:11 pm on Feb 24, 2007 (gmt 0)

WebmasterWorld Administrator 10+ Year Member



well I was working an uploader recently and these are the parts that do size calc, it is a bit lazy but you get my drift

$imginfo = getimagesize($imgfiletmp);
$width = $imginfo[0];
$height = $imginfo[1];

then later

if ($width > $height) { 
$orient = 'wide';
$bigdim = $width;
} else {
$orient = 'tall';
$bigdim = $height;
}

then later

if ($bigdim > 600) { 
$longside = 600;
$shortside = 0;
if ($orient == 'wide'){
$shortside = round($longside/($width/$height));
$dest_x = $longside;
$dest_y = $shortside;
} else {
$shortside = round($longside/($height/$width));
$dest_x = $shortside;
$dest_y = $longside;
}

I am using 600 but you can swap that to whatever you want

and finally
$target_pic = imagecopyresized($target_id, $source_id, 0, 0, 0, 0, $dest_x, $dest_y, $width, $height);

the same rules would apply, obviously your last line would be different but the ratio stuff should be fine.

Birdman

4:54 pm on Feb 24, 2007 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Will all your originals be exactly square? If not, you may get distorded thumbs because X and Y will have different scale ratios.

This can be corrected by copying a square section of the original, rather than the whole image. I tested this and it works. If the pic is rectangle, it grabs the largest square portion from the center of the image.

<?php
$filename = 'image.jpg';
list($width, $height) = getimagesize($filename);

//now assign the coords to snip from the orig

if ($width > $height) {
$src_w = $src_h = $height;
$src_y = 0;
$src_x = round(($width - $height) / 2);
} else {
$src_w = $src_h = $width;
$src_x = 0;
$src_y = round(($height - $width) / 2);
}

//now create and resample

$dst_image = imagecreatetruecolor(100, 100);
$src_image = imagecreatefromjpeg($filename);

imagecopyresampled ( $dst_image, $src_image, 0, 0, $src_x, $src_y, 100, 100, $src_w, $src_h );

header('Content-type: image/jpeg');
imagejpeg($dst_image, null, 100);
?>

scriptmasterdel

5:25 pm on Feb 24, 2007 (gmt 0)

10+ Year Member



Thank you both for you input, it's very much appreciated.

I don't want the image to crop, i want it to fix in the containing image resource.

For example:

I have an image that's 400px / 200px and i want to fit this image into the 100px / 100px container, without cropping the image but by scaling the image.

So what i should be doing in reducing the size of the image in proportion using the larger image as the marker. Along with this i would like the image to be placed centre of the container no matter the width or height.

I don't want to crop the image, it's for a listing page, this is why i need it to be compact but viewable at the same time.

If i haven't made much more sense please let me know.

Thank you once again.

Del

Birdman

5:30 pm on Feb 24, 2007 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



That's fairly straightforward then:

<?php
$filename = 'image.jpg';
list($width, $height) = getimagesize($filename);

//now create and resample
$dst_image = imagecreatetruecolor(100, 100);
$src_image = imagecreatefromjpeg($filename);
imagecopyresampled ( $dst_image, $src_image, 0, 0, 0, 0, 100, 100, $width, $height );
header('Content-type: image/jpeg');
imagejpeg($dst_image, null, 100);
?>

scriptmasterdel

5:34 pm on Feb 24, 2007 (gmt 0)

10+ Year Member



Thank you Birdman,

But the problem is i do not want to compress the image, i merly want to scale the image, sorry i didn't say this sooner.

I want the imag to look exactly the same, just scaled down and so that it can fit in the 100px / 100px container.

Thank you again.

Del

scriptmasterdel

5:35 pm on Feb 24, 2007 (gmt 0)

10+ Year Member



By the way, just so you are aware it's not a problem if we have canvas colour either side.

Birdman

6:09 pm on Feb 24, 2007 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Ah, I get it now! This version does it and allows you to change background color:

<?php
$filename = $_SERVER['DOCUMENT_ROOT'] . '/presentations/images/816.jpg';
list($width, $height) = getimagesize($filename);

if ($width > $height) {
$dst_w = 100;
$dst_h = round((100 / $width) * $height);
$dst_x = 0;
$dst_y = round((100 - $dst_h) / 2);
} else {
$dst_w = round((100 / $height) * $width);
$dst_h = 100;
$dst_y = 0;
$dst_x = round((100 - $dst_w) / 2);
}

//now create and resample

$dst_image = imagecreatetruecolor(100, 100);
$background = imagecolorallocate($dst_image, 250, 250, 250);
imagefill($dst_image, 0, 0, $background);
$src_image = imagecreatefromjpeg($filename);

imagecopyresampled ( $dst_image, $src_image, $dst_x, $dst_y, 0, 0, $dst_w, $dst_h, $width, $height );

header('Content-type: image/jpeg');
imagejpeg($dst_image, null, 100);

?>

[edited by: Birdman at 6:10 pm (utc) on Feb. 24, 2007]

scriptmasterdel

7:56 pm on Feb 24, 2007 (gmt 0)

10+ Year Member



Thank you Birdman,

That is precicely what i was looking for.

I will naturally adapt this to my current code.

Thank you once again.

Del

jatar_k

8:59 pm on Feb 24, 2007 (gmt 0)

WebmasterWorld Administrator 10+ Year Member



Birdman, the image master ;)

nice

GD a la King

scriptmasterdel

1:55 pm on Feb 26, 2007 (gmt 0)

10+ Year Member



Once again, thanks for all the help.

I only managed to play with the code this morning and i am interested in finding out the following.

How could i make the image only resize if the new image size is smaller then the original and still keep the positioning centered verticaly and horizontally?

I assume this would be done by comparing the original height with the new height and then setting the positions but i didn't get very far.

Any help would be great.

Thank you

Del

Birdman

2:52 pm on Feb 26, 2007 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Once again, thanks for all the help.

My pleasure!

How could i make the image only resize if the new image size is smaller then the original and still keep the positioning centered verticaly and horizontally?

So you still want to create a new image and position it on a 100x100 canvas even if it is smaller than 100px? Also, are you actually serving these images on the fly or are you planning on saving them to files?

Birdman, the image master

Ha! NOT! I do have fun with GD though :)

scriptmasterdel

4:49 pm on Feb 26, 2007 (gmt 0)

10+ Year Member



I am getting the images to save on the server after gd has created the thumbnails.

I have some images that are like 65px / 50px and i don't want them to enlarge to 100px / 100px in the box so if they are not bigger then the specified height / width then i want them to stay at the original size.

I hope that makes sense.

Thanks again.

Del

jatar_k

5:00 pm on Feb 26, 2007 (gmt 0)

WebmasterWorld Administrator 10+ Year Member



make a preliminary test then that checks to see if one or both dimensions are greater than 100

scriptmasterdel

5:04 pm on Feb 26, 2007 (gmt 0)

10+ Year Member



Yes, but i would like the image to be output in the middle of the image, this is the part that i struggle at. If you could tell me how this is calculated then i will work it out, i am having problems understanding the concept of the position element when using the imagecopyresampled function. I took a look at php.net's documentation but i still struggled to understand how it works.

Thank you.

Birdman

5:07 pm on Feb 26, 2007 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



I would say wrap the resize code with anothe if/then:

<?php
$filename = $_SERVER['DOCUMENT_ROOT'] . '/presentations/images/816.jpg';
list($width, $height) = getimagesize($filename);
if ($width < 100 && $height < 100){
$dst_w = $width;
$dst_h = $height;
$dst_x = round((100 - $dst_w) / 2);
$dst_y = round((100 - $dst_h) / 2);
} else {
if ($width > $height) {
$dst_w = 100;
$dst_h = round((100 / $width) * $height);
$dst_x = 0;
$dst_y = round((100 - $dst_h) / 2);
} else {
$dst_w = round((100 / $height) * $width);
$dst_h = 100;
$dst_y = 0;
$dst_x = round((100 - $dst_w) / 2);
}
}
//now create and resample
$dst_image = imagecreatetruecolor(100, 100);
$background = imagecolorallocate($dst_image, 250, 250, 250);
imagefill($dst_image, 0, 0, $background);
$src_image = imagecreatefromjpeg($filename);
imagecopyresampled ( $dst_image, $src_image, $dst_x, $dst_y, 0, 0, $dst_w, $dst_h, $width, $height );
header('Content-type: image/jpeg');
imagejpeg($dst_image, null, 100);
?>

This one is not tested :)

Birdman

5:21 pm on Feb 26, 2007 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



I'll try to explain the calculation.

$dst_x is the x(from the left) position where you want your image to start on the 100x100 canvas.

$dst_y is the y(from the top) position where you want your image to start on the 100x100 canvas.

After you have determined the scaled dimensions or decided that the image doesn't need scaling, you calculate the x and y start points by subtracting the image size from the canvas size.

eg. your image is already smaller (60 x 40)
Get the difference of image and canvas for width and height
100-60 = 40 / 2 = 20
100-40 = 60 / 2 = 30

now you have your starting points for x(20 from left) and y(30 from top)

scriptmasterdel

8:42 pm on Feb 26, 2007 (gmt 0)

10+ Year Member



So we basically calculate the excess canvas each side then divide the size by two to calculate the axis starting point - brilliant.

That's exactly what i was looking for.

Thank you once again, the images i have resized look amazing and the functionality works a treat.

Once again, much appreciated.

Del

cmarshall

9:40 pm on Feb 26, 2007 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



I do this all the time.

After you resize to fit within a container, you subtract the short from the long, and divide by 2 to give the offset (already explained above, so this is redundant).

To wit:

$offset = intval ((100 - $short_len) / 2);

The resizing is merely keeping an aspect ratio (

$aspect = $x_size/$y_size
), and multiplying or dividing that by 100 to get the short side. If the aspect is greater than 1, then the image is wide, and the offset is on the Y-axis (from top), if less than 1, it is tall.

xMicrobex

8:01 am on May 14, 2008 (gmt 0)

10+ Year Member



This helped me solve my problem so thought I would post my expanded code.

This makes thumbnails 150 x 100. However it does a couple of extra tricks that I wanted.

If image is smaller than 150 x 100 it retains the size.

If image is almost square (say 600 x 590), the problem with the script and my not-square thumbs was that it made the height too big by keeping in it proportion. i.e. when width became 150, height was around 148.

I have added some code so that if the height is > 100 after resizing, then no matter what the width, it resizes using the height as the constraining factor.

There is some debug code that comes in handy for "those special moments"

Hope it helps someone.

if ($width > $height) {
if($width < 150){
$debug=1;
$thumb_w = $width;
$thumb_h = $height;
$dst_x = 0;
$dst_y = round(($dst_w - $dst_h) / 2);
}
else{
$debug=2;
$thumb_w = 150;
$thumb_h = round((150 / $width) * $height);
$dst_x = 0;
$dst_y = round((150 - $dst_h) / 2);
//if it is almost square we need to make width a bit smaller - treat it as if height is the bigger side
if($thumb_h> 100){
$debug=5;
$thumb_w = round((100 / $height) * $width);
$thumb_h = 100;
$dst_y = 0;
$dst_x = round((100 - $dst_w) / 2);
}
}
} else {
if($height < 100){
$debug=3;
$thumb_h = $height;
$thumb_w = width;
$dst_y = 0;
$dst_x = round(($dst_h - $dst_w) / 2);
}
else{
$debug=4;
$thumb_w = round((100 / $height) * $width);
$thumb_h = 100;
$dst_y = 0;
$dst_x = round((100 - $dst_w) / 2);
//if it is almost square we need to make width a bit smaller - treat it as if width is the bigger side
if($thumb_h> 100){
$debug=6;
$thumb_w = 150;
$thumb_h = round((150 / $width) * $height);
$dst_x = 0;
$dst_y = round((150 - $dst_h) / 2);
}
}
}
//echo " core.php line 163<br>d= " . $debug . " w = " . $thumb_w . " h = " . $thumb_h . " or = " . $width . " oh = " . $height; exit;

...sigh...sorry, I give up on making it look good

[edited by: xMicrobex at 8:03 am (utc) on May 14, 2008]