Basically I want to upload an image (which i\'ve sorted) and scale it down to certain constraints such as max width and height but maintain the aspect ratio of the original
I was thinking about how to achieve this and i came with a pretty nice solution that works in any case... Lets say you want to resize heavy images that users upload to your site but you need it to maintain the ratio. So i came up with this :
<?php
// File
$filename = 'test.jpg';
// Get sizes
list($width, $height) = getimagesize($filename);
//obtain ratio
$imageratio = $width/$height;
if($imageratio >= 1){
$newwidth = 600;
$newheight = 600 / $imageratio;
}
else{
$newidth = 400;
$newheight = 400 / $imageratio;
};
// Load
$thumb = imagecreatetruecolor($newwidth, $newheight);
$source = imagecreatefromjpeg($filename);
// Resize
imagecopyresized($thumb, $source, 0, 0, 0, 0, $newwidth, $newheight, $width,
$height);
// Output
imagejpeg($thumb, "img/test.jpg");
imagedestroy();
?>
In this case if width is bigger than height, i wanted the width to be 600px and if the height was bigger than the width, i wanted the width to be 400px
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
Class ResizedImage
{
public $imgfile;
public $string = '';
public $new_width = 0;
public $new_height = 0;
public $angle = 0;
public $max_font_size = 1000;
public $cropped = false;//whether crop the original image if h or w > new h or w
public $font = 'fonts/arialbd.ttf';
private $img;
private $trans_colour;
private $orange;
private $white;
private $whitetr;
private $blacktr;
public function PrintAsBase64()
{
$this->SetImage();
ob_start();
imagepng($this->img);
$b64img = ob_get_contents();
ob_clean();
imagedestroy($this->img);
$b64img = base64_encode($b64img);
echo($b64img);
}
public function PrintAsImage()
{
$this->SetImage();
header('Content-type: image/png');
imagepng($this->img);
imagedestroy($this->img);
}
private function SetImage()
{
if ($this->imgfile == '') {$this->imgfile='NoImageAvailable.jpg';}
$this->img = imagecreatefromstring(file_get_contents($this->imgfile));
$this->trans_colour = imagecolorallocatealpha($this->img, 0, 0, 0, 127);
$this->orange = imagecolorallocate($this->img, 220, 210, 60);
$this->white = imagecolorallocate($this->img, 255,255, 255);
$this->whitetr = imagecolorallocatealpha($this->img, 255,255, 255, 95);
$this->blacktr = imagecolorallocatealpha($this->img, 0, 0, 0, 95);
if ((!$this->cropped) && ($this->string !=''))
{$this->watermarkimage();}
if (($this->new_height > 0) && ($this->new_width > 0)) {$this->ResizeImage();};
if (($this->cropped) && ($this->string !=''))
{$this->watermarkimage();}
imageAlphaBlending($this->img, true);
imageSaveAlpha($this->img, true);
}
////
private function ResizeImage()
{
# 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 = $this->new_height / imagesy($this->img);//target_height / im_height;
$h_fact = $this->new_width / imagesx($this->img);//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
if($this->cropped)
{ $im_fact = max($v_fact, $h_fact); }
else
{ $im_fact = min($v_fact, $h_fact); }
$new_height = round(imagesy($this->img) * $im_fact);
$new_width = round(imagesx($this->img) * $im_fact);
$img2 = $this->img;
$this->img = imagecreatetruecolor($new_width, $new_height);
imagecopyresampled($this->img, $img2, 0, 0, 0, 0, $new_width, $new_height, imagesx($img2), imagesy($img2));
$img2 = $this->img;
$this->img = imagecreatetruecolor($this->new_width, $this->new_height);
imagefill($this->img, 0, 0, $this->trans_colour);
$dstx = 0;
$dsty = 0;
if ($this->cropped)
{
if (imagesx($this->img) < imagesx($img2))
{ $dstx = round((imagesx($this->img)-imagesx($img2))/2); }
if (imagesy($this->img) < imagesy($img2))
{ $dsty = round((imagesy($this->img)-imagesy($img2))/2); }
}
else
{
if (imagesx($this->img) > imagesx($img2))
{ $dstx = round((imagesx($this->img)-imagesx($img2))/2); }
if (imagesy($this->img) > imagesy($img2))
{ $dsty = round((imagesy($this->img)-imagesy($img2))/2); }
}
imagecopy ( $this->img, $img2, $dstx, $dsty, 0, 0, imagesx($img2) , imagesy($img2));
imagedestroy($img2);
}
////
private function calculateTextBox($text,$fontFile,$fontSize,$fontAngle)
{
/************
simple function that calculates the *exact* bounding box (single pixel precision).
The function returns an associative array with these keys:
left, top: coordinates you will pass to imagettftext
width, height: dimension of the image you have to create
*************/
$rect = imagettfbbox($fontSize,$fontAngle,$fontFile,$text);
$minX = min(array($rect[0],$rect[2],$rect[4],$rect[6]));
$maxX = max(array($rect[0],$rect[2],$rect[4],$rect[6]));
$minY = min(array($rect[1],$rect[3],$rect[5],$rect[7]));
$maxY = max(array($rect[1],$rect[3],$rect[5],$rect[7]));
return array(
"left" => abs($minX) - 1,
"top" => abs($minY) - 1,
"width" => $maxX - $minX,
"height" => $maxY - $minY,
"box" => $rect );
}
private function watermarkimage($font_size=0)
{
if ($this->string == '')
{die('Watermark function call width empty string!');}
$box = $this->calculateTextBox($this->string, $this->font, $font_size, $this->angle);
while ( ($box['width'] < imagesx($this->img)) && ($box['height'] < imagesy($this->img)) && ($font_size <= $this->max_font_size) )
{
$font_size++;
$box = $this->calculateTextBox($this->string, $this->font, $font_size, $this->angle);
}
$font_size--;
$box = $this->calculateTextBox($this->string, $this->font, $font_size, $this->angle);
$vcenter = round((imagesy($this->img) / 2) + ($box['height'] / 2));
$hcenter = round((imagesx($this->img) - $box['width']) / 2 );
imagettftext($this->img, $font_size, $this->angle, $hcenter, $vcenter, $this->blacktr, $this->font, $this->string);
imagettftext($this->img, $font_size, $this->angle, $hcenter+1, $vcenter-2, $this->whitetr, $this->font, $this->string);
}
}
?>
Also I have been using the accepted answer but it does not keep the ratio in some cases. I have found some good answers on the forum and have put them in together and finally created a Class which resizes an image. As extra function u can put a watermark text.
u can see what happens when choose to crop or not, if not a transparent area will be added to the new resized image.
This example is more than asked, but I think it is a good example.
works perfecly for me
static function getThumpnail($file){
$THUMBNAIL_IMAGE_MAX_WIDTH = 150; # exmpl.
$THUMBNAIL_IMAGE_MAX_HEIGHT = 150;
$src_size = filesize($file);
$filename = basename($file);
list($src_width, $src_height, $src_type) = getimagesize($file);
$src_im = false;
switch ($src_type) {
case IMAGETYPE_GIF : $src_im = imageCreateFromGif($file); break;
case IMAGETYPE_JPEG : $src_im = imageCreateFromJpeg($file); break;
case IMAGETYPE_PNG : $src_im = imageCreateFromPng($file); break;
case IMAGETYPE_WBMP : $src_im = imagecreatefromwbmp($file); break;
}
if ($src_im === false) { return false; }
$src_aspect_ratio = $src_width / $src_height;
$thu_aspect_ratio = $THUMBNAIL_IMAGE_MAX_WIDTH / $THUMBNAIL_IMAGE_MAX_HEIGHT;
if ($src_width <= $THUMBNAIL_IMAGE_MAX_WIDTH && $src_height <= $THUMBNAIL_IMAGE_MAX_HEIGHT) {
$thu_width = $src_width;
$thu_height = $src_height;
} elseif ($thu_aspect_ratio > $src_aspect_ratio) {
$thu_width = (int) ($THUMBNAIL_IMAGE_MAX_HEIGHT * $src_aspect_ratio);
$thu_height = $THUMBNAIL_IMAGE_MAX_HEIGHT;
} else {
$thu_width = $THUMBNAIL_IMAGE_MAX_WIDTH;
$thu_height = (int) ($THUMBNAIL_IMAGE_MAX_WIDTH / $src_aspect_ratio);
}
$thu_im = imagecreatetruecolor($thu_width, $thu_height);
imagecopyresampled($thu_im, $src_im, 0, 0, 0, 0, $thu_width, $thu_height, $src_width, $src_height);
$dst_im = imagecreatetruecolor($THUMBNAIL_IMAGE_MAX_WIDTH,$THUMBNAIL_IMAGE_MAX_WIDTH);
$backcolor = imagecolorallocate($dst_im,192,192,192);
imagefill($dst_im,0,0,$backcolor);
imagecopy($dst_im, $thu_im, (imagesx($dst_im)/2)-(imagesx($thu_im)/2), (imagesy($dst_im)/2)-(imagesy($thu_im)/2), 0, 0, imagesx($thu_im), imagesy($thu_im));
imagedestroy($src_im);
imagedestroy($thu_im);
}