Crop and resize theory - php

I need some guidance on the theory behind cropping and resizing images around a focal point, with a bounding box.
In my situation, I have a variety of different image size requirements (100x100, 500x200, 1200x50 for example) at different definitions (1x, 2x, 3x etc.).
The definitions effectively turn 50x50 cropped image into a 100x100 cropped image, thus providing a 2x definition for higher screen definition devices.
I'm provided with a user's uploaded image with an x,y focal point, and a bounding box with two x,y coordinates (topLeft[x,y], bottomRight[x,y]).
What is the theory being turning my user provided image into a variety of images at different sizes and resolutions? Research has led me to find one or the other, but not all of my requirements together.
In my specific environment, I'm using PHP, Laravel and the image Intervention library, although this is somewhat irrelevant due to the nature of this question.

Here's an image class I wrote some while back which uses the GD lib.
https://github.com/delboy1978uk/image/blob/master/src/Image.php
I didn't write code for resizing and cropping based on a focal point, but I do have a resizeAndCrop() method that works on the premise that the focal point is in the centre:
public function resizeAndCrop($width,$height)
{
$target_ratio = $width / $height;
$actual_ratio = $this->getWidth() / $this->getHeight();
if($target_ratio == $actual_ratio){
// Scale to size
$this->resize($width,$height);
} elseif($target_ratio > $actual_ratio) {
// Resize to width, crop extra height
$this->resizeToWidth($width);
$this->crop($width,$height,true);
} else {
// Resize to height, crop additional width
$this->resizeToHeight($height);
$this->crop($width,$height,true);
}
}
here's the crop() method, which you can set a focal point to left, center or right:
/**
* #param $width
* #param $height
* #param string $trim
*/
public function crop($width,$height, $trim = 'center')
{
$offset_x = 0;
$offset_y = 0;
$current_width = $this->getWidth();
$current_height = $this->getHeight();
if($trim != 'left')
{
if($current_width > $width) {
$diff = $current_width - $width;
$offset_x = ($trim == 'center') ? $diff / 2 : $diff; //full diff for trim right
}
if($current_height > $height) {
$diff = $current_height - $height;
$offset_y = ($trim = 'center') ? $diff / 2 : $diff;
}
}
$new_image = imagecreatetruecolor($width,$height);
imagecopyresampled($new_image,$this->_image,0,0,$offset_x,$offset_y,$width,$height,$width,$height);
$this->_image = $new_image;
}
I won't bother explaining imagecopyresampled() since you were just looking for theory behind the cropping, but the docs are here http://php.net/manual/en/function.imagecopyresampled.php
Bear in mind, resizing images using PHP's GD library is memory intensive, depending on the size of the image. I like to use imagemagick, which PHP has a wrapper class called Imagick, worth looking at if you run into trouble.
I hope this helps you, good luck!

Related

How to restrict image width or height on upload

I would like manipulate/resize images in a similar way to Pinterest but I am not sure what is the best way to approach it. The goal is to allow a mix of both portrait and landscape images but put some restrictions on the maximum height and width.
The problem i can see is that if I resize to a width, a portrait image may become too thin, and the opposite it true for a landscape image.
Any ideas on how to achieve those sort of results with PHP?
You just need to understand which of the two edges of the image is longer, and compute the other dimension proportionally. If the maximum long-egde is 1024, then if one of the two edges is larger you will set that to 1024, and compute the other to fit the proportions. Then you will pass those two values to your image management functions.
Like here:
http://www.white-hat-web-design.co.uk/blog/resizing-images-with-php/
Or here:
http://www.9lessons.info/2009/03/upload-and-resize-image-with-php.html
try with this
$needheight = 1000;
$needwidth = 1000;
$arrtest = getimagesize($upload_image_physical_path);
$actualwidth = $arrtest[0];
$actualheight = $arrtest[1];
if($needwidth > $actualwidth || $needheight > $actualheight){
//uplaod code
}
cheers
Check for a max size and then resize based on a ratio. Here's a pseudo code example:
if($imageHeight > $maxHeight) {
$newHeight = $maxHeight;
$newWidth = $imageWidth * ($maxHeight / $imageHeight);
}
if($imageWidth > $maxWidth) {
$newWidth = $maxWidth;
$newHeight = $imageHeight * ($maxWidth / $imageWidth);
}
resize($image, $newWidth, $newHeight);
It first checks the height and if the height is greater, it scales it down. Then it checks the width. If the width is too big, it scales it down again. The end result, both height and width will be with in your bounds. It uses the ratio to do the scaling.
Note, this is pseudocodish. The actual resize function call will depend on your image manipulation library -- same goes for calls to obtain image size.

php: create custom-sized thumbnail

i'm familiar with resizing and cropping images under php using imagecopyresampled but now i'm having a special problem:
the task is cropping a large image from eg. 1600x1200 to 500x120, which means resizing down to 500px and crop its height that it'S 120px. is there some easy way or do i need to calculate the cropping values all on my own? thanks
There is PHP library that could help you out called PHPThumb. You can find here https://github.com/masterexploder/PHPThumb
They have an adaptive resize method that does what you're looking for. https://github.com/masterexploder/PHPThumb/wiki/Basic-Usage
You have to do it yourself.
I don't know if you want to crop or not, so here's how to calculate the values for both:
Scale image: resize to fit within new w x h keeping aspect ratio (so 1 side may be shorter than specified)
function calc_scale_dims($width_orig, $height_orig, $max_width, $max_height) {
$new_width=$width_orig;
$new_height=$height_orig;
$ratioh = $max_height/$new_height;
$ratiow = $max_width/$new_width;
$ratio = min($ratioh, $ratiow);
// New dimensions
$dims["w"] = intval($ratio*$new_width);
$dims["h"] = intval($ratio*$new_height);
return $dims;
}
Resize and Crop: Resizes image and crops it to fit into the specified w x h if new aspect ratio is different (e.g. if aspect ratios are different, image will be resized to match specified size on the short size and the longer size if cropped in the middle)
function calc_crop_resize_dims($width_orig, $height_orig, $new_width, $new_height) {
//Calculate scaling
$ratio_orig = $width_orig/$height_orig;
$ratio_new = $new_width/$new_height;
if ($ratio_new < $ratio_orig) {
$copy_width = $height_orig*$ratio_new;
$copy_height = $height_orig;
} else {
$copy_width = $width_orig;
$copy_height = $width_orig/$ratio_new;
}
//point to start copying from (to copy centre of image if we are cropping)
$dims["src_x"] = ($width_orig - $copy_width)/2;
$dims["src_y"] = ($height_orig - $copy_height)/2;
$dims["copy_width"] = $copy_width;
$dims["copy_height"] = $copy_height;
return $dims;
}

Resize image to fit perfectly a determined box

I want to do the following :
I need to resize images to fit and fill enterly 100x100 pixel box
not all image are perfect squares, and thats my problem for this task
I want to determine wich side (width or height) is the smallest.
Bring that Side to 100px while scaling down; Center back
Crop the overflow on both side
I've tried the width/height :100% technic but that doesnt give the result i want, (it is streched and ugly). Also i've seen some method but in C# ... I need in PHP.
I would appreciate any advice, directions, input, or ready script...
Thanks
using PHP 5.3.0
You must be able to calculate the aspect ratio by knowing the image dimensions beforehand. For more info, see getimagesize()
$width = 268;
$height = 300;
$MAX_SIZE = 100;
if($width > $MAX_SIZE || $height > $MAX_SIZE) {
$aspect = $width / $height;
if($width > $height) {
$width = $MAX_SIZE;
$height = intval($MAX_SIZE / $aspect);
} else {
$height = $MAX_SIZE;
$width = intval($MAX_SIZE * $aspect);
}
}
Afterwards, the scaled down height will be available in $height and the scaled down width will be available in $width.

PHP Thumbnail Image Resizing with proportions

As a brief run down, I am currently making a dating type site. Users can create accounts and upload profile pictures (up to 8). In order to display these in the browse area of the website, I am looking for a way in PHP (with third party processor/scripts) to resize all images uploaded to have thumbnails that adhere to certain dimensions.
As an example, I will want "profile" images (thumbnails) to be NO larger than 120*150px. The scripting needs to resize uploaded images (regardless of whether they are portrait or landscape, and regardless of proportions) to adhere to these dimensions without getting stretched.
The width (eg. 120pixels) should always remain the same, but the height (eg. 150px) can vary in order to keep the image in proportion. If it's a landscape photo, I'm assuming the script would need to take a chunk out of the middle of the image?
The reason that all images to be resized is so that when profiles are display in a grid that all thumbnails are roughly the same size.
Any input would be greatly appreciated.
$maxwidth = 120;
$maxheight = 150;
$img = imagecreatefromjpeg($jpgimage);
//or imagecreatefrompng,imagecreatefromgif,etc. depending on user's uploaded file extension
$width = imagesx($img); //get width and height of original image
$height = imagesy($img);
//determine which side is the longest to use in calculating length of the shorter side, since the longest will be the max size for whichever side is longest.
if ($height > $width)
{
$ratio = $maxheight / $height;
$newheight = $maxheight;
$newwidth = $width * $ratio;
}
else
{
$ratio = $maxwidth / $width;
$newwidth = $maxwidth;
$newheight = $height * $ratio;
}
//create new image resource to hold the resized image
$newimg = imagecreatetruecolor($newwidth,$newheight);
$palsize = ImageColorsTotal($img); //Get palette size for original image
for ($i = 0; $i < $palsize; $i++) //Assign color palette to new image
{
$colors = ImageColorsForIndex($img, $i);
ImageColorAllocate($newimg, $colors['red'], $colors['green'], $colors['blue']);
}
//copy original image into new image at new size.
imagecopyresized($newimg, $img, 0, 0, 0, 0, $newwidth, $newheight, $width, $height);
imagejpeg($newimg,$outputfile); //$output file is the path/filename where you wish to save the file.
//Have to figure that one out yourself using whatever rules you want. Can use imagegif() or imagepng() or whatever.
This will shrink any images down proportionally based on whichever side is longer (width or height), to the maximum size. It will also blow up any images smaller than max, which you can stop with a bit of checking on whether or not both width and height are less than their max. So, a 200x300 image will be shrunk to 100x150, and a 300x200 image will be shrunk to 120x80.
Hmm, you want the width to always be 120, so it would change a bit, and yeah, it would have to cut something out in the case of an image like 200x300, because that would shrink to 120x180 without any distortion, or it would have to shrink it farther and letterbox it, but that should get you started nicely.
Letterboxing this example would just involve figuring out what the proper x and y to start the drawing to the new image would be in the imagecopyresized() function. In the case of something like 100x150, the X would be 10, I think, so there would be 10px of blank space on each side for 120x150 in the end. Letterboxing 120x80 X would be 0 but Y would be 35, so there would be 35px of blank space above and below for 120x150.
You'd also want to make $newimg with $maxwidth,$maxheight rather than $newwidth,$newheight, but the imagecopyresized() would still use both $new values.
Since I'm bored and don't have anything else to do, these changes would do it:
if ($height > $width)
{
$ratio = $maxheight / $height;
$newheight = $maxheight;
$newwidth = $width * $ratio;
$writex = round(($maxwidth - $newwidth) / 2);
$writey = 0;
{
else
{
$ratio = $maxwidth / $width;
$newwidth = $maxwidth;
$newheight = $height * $ratio;
$writex = 0;
$writey = round(($maxheight - $newheight) / 2);
}
$newimg = imagecreatetruecolor($maxwidth,$maxheight);
//Since you probably will want to set a color for the letter box do this
//Assign a color for the letterbox to the new image,
//since this is the first call, for imagecolorallocate, it will set the background color
//in this case, black rgb(0,0,0)
imagecolorallocate($newimg,0,0,0);
//Loop Palette assignment stuff here
imagecopyresized($newimg, $img, $writex, $writey, 0, 0, $newwidth, $newheight, $width, $height);
That should work, haven't tried it yet.
GD or Imagick functions are what you need depending on your PHP configuration.
Sorry I'm a newbie I can't post both links in the same message :(
I have recently needed php resizing (thumbnail) solution and found Zebra_Image library, which is a lightweight image manipulation library written in PHP. The code is really clean and it's also easy to use. I highly recommend using this library. The example code is just enough to get you started.
Be make sure that you have enough memory limit set in php.ini file to manipulate images which have relatively big resolution (e.g 2560x1600). I had an error with big images and there was no error to print. I debugged the problem down to imagecreatefrom{gif,jpeg,png} calls in function _create_from_source in lines 1262, 1279, and 1288. The calls were silented with # so I couldn't have a change to get the error. I removed # lines and saw a PHP error that memory limit has been exceeded. The original memory limit was set to 32MB and I increased it to 64MB. Now I can manipulate 2560x1600 and I refuse to manipulate images which are bigger.
Below is the example code for controlling the image resolution.
$image_properties = getimagesize($UPLOADED_FILE_PATH);
$file_width = $image_properties[0];
$file_height = $image_properties[1];
if ($file_width > 2560 || $file_height > 1600) {
// handle your error whichever you like, I simply 'die' just to show
die('Cannot manipulate image bigger than 2560x1600');
}
(Note: I use Zebra Image version 2.2.2)
You can do this with ImageMagick:
convert susan.jpg -resize x200 susan_thumb.jpg
This runs with a shell command, so in PHP you'd use shell_exec() to run the above command. I don't think you need any PHP extensions.
A few flags can be found in the ImageMagick documentation to control the resizing operation. If I recall correctly, the x200 before the number means "scale with the same aspect ratio to 200px".
I wrote an install guide for ImageMagick (and ghostscript): How to install, test, convert, resize PDF using ImageMagick, Ghostscript, Windows Vista/7 x64 based on my bumbling around, maybe it can help you.
The other option is the GD library (detailed in dqhendricks answer). This is faster and apparently better documented, used for basic operations.
you don't need imagick. here is a link that will take you to a function that will resize any image using PHP GD to any arbitrary size. the function has options to use letterboxing or crop-to-fit methods to resize to the new aspect ratio. the function is also explained thoroughly. check it out.
http://www.spotlesswebdesign.com/blog.php?id=1
if this is what you are looking for, please select the check mark next to this answer. thanks!
Some says imagic faster, i use next
function resizeImageProportional($imagePath, $destinationPath, $width = false, $height = false, $filterType = \Imagick::FILTER_POINT, $blur = 1, $bestFit = false, $cropZoom = false)
{
if (!$width && !$height) {
trigger_error("WTF_IMAGE_RESIZE");
return false;
}
//The blur factor where > 1 is blurry, < 1 is sharp.
$imagick = new \Imagick(realpath($imagePath));
if (!$width || !$height) {
$orig_width = $imagick->getImageWidth();
$orig_height = $imagick->getImageHeight();
$proportion = $orig_height/$orig_width;
if (!$width) {
$width = $height*$proportion;
} elseif (!$height) {
$height = $width*$proportion;
}
}
if ($bestFit) {
$imagick->resizeImage($width, $height, $filterType, $blur, $bestFit);
} else {
$imagick->resizeImage($width, $height, $filterType, $blur);
}
if ($cropZoom) {
$cropWidth = $imagick->getImageWidth();
$cropHeight = $imagick->getImageHeight();
$newWidth = $cropWidth / 2;
$newHeight = $cropHeight / 2;
$imagick->cropimage(
$newWidth,
$newHeight,
($cropWidth - $newWidth) / 2,
($cropHeight - $newHeight) / 2
);
$imagick->scaleimage(
$imagick->getImageWidth() * 4,
$imagick->getImageHeight() * 4
);
}

Smart way of resizing images in PHP [closed]

As it currently stands, this question is not a good fit for our Q&A format. We expect answers to be supported by facts, references, or expertise, but this question will likely solicit debate, arguments, polling, or extended discussion. If you feel that this question can be improved and possibly reopened, visit the help center for guidance.
Closed 9 years ago.
I was wondering if someone can help me with an image resize function written in PHP but one wich has to resize an image, but in a manner like PHPThumb does. So, if I set the width and height of the new image, the function must fit the uploaded image (and mantain aspect ratio) in the new width and height.
Any help is appreciated.
Thank you.
I wrote this a couple years ago and it does exactly what you're looking for. Keep in mind this only calculates the width and height, you must call Imagick yourself to actually apply these calculations.
/**
* ImageIntelligentResize()
*
* #global Intelligently resizes images using a providid max width and height
* #param mixed $imagePath
* #param mixed $maxWidth
* #param mixed $maxHeight
* #param mixed $alwaysUpscale
* #return
*/
function ImageIntelligentResize( $imagePath, $maxWidth, $maxHeight, $alwaysUpscale )
{
// garbage in, garbage out
if ( IsNullOrEmpty($imagePath) || !is_file($imagePath) || IsNullOrEmpty($maxWidth) || IsNullOrEmpty($maxHeight) )
{
return array("width"=>"", "height"=>"");
}
// if our thumbnail size is too big, adjust it via HTML
$size = getimagesize($imagePath);
$origWidth = $size[0];
$origHeight = $size[1];
// Check if the image we're grabbing is larger than the max width or height or if we always want it resized
if ( $alwaysUpscale || $origWidth > $maxWidth || $origHeight > $maxHeight )
{
// it is so let's resize the image intelligently
// check if our image is landscape or portrait
if ( $origWidth > $origHeight )
{
// target image is landscape/wide (ex: 4x3)
$newWidth = $maxWidth;
$ratio = $maxWidth / $origWidth;
$newHeight = floor($origHeight * $ratio);
// make sure the image wasn't heigher than expected
if ($newHeight > $maxHeight)
{
// it is so limit by the height
$newHeight = $maxHeight;
$ratio = $maxHeight / $origHeight;
$newWidth = floor($origWidth * $ratio);
}
}
else
{
// target image is portrait/tall (ex: 3x4)
$newHeight = $maxHeight;
$ratio = $maxHeight / $origHeight;
$newWidth = floor($origWidth * $ratio);
// make sure the image wasn't wider than expected
if ($newWidth > $maxWidth)
{
// it is so limit by the width
$newWidth = $maxWidth;
$ratio = $maxWidth / $origWidth;
$newHeight = floor($origHeight * $ratio);
}
}
}
// it's not, so just use the current height and width
else
{
$newWidth = $origWidth;
$newHeight = $origHeight;
}
return array("width"=>$newWidth, "height"=>$newHeight);
}
When i started learning OOP, i wroted this image class to practice myself.
It uses GD, ans surely can be improved, hope it helps.
edit: after 2 downvotes for a issue where i dont have any control, i put the class on pastie.
The class
The Example
Remember, the class works fine, but it was a practice in order to learn basics OOP.
I hope this will be ok, you lazy users ;)
at Christmas we are all better people
the resize then crop approach: compute the aspect ratio of the source image and use it as a constraint to create an intermediate image which is going to be larger than the destination image (either in width or height) - finally crop the intermediate image to the destination dimensions.
use seam carving! also called "liquid rescale" in ImageMagick (see also there)
If you can rely on ImageMagick being installed on your server, it offers many more features than GD.
from my understanding, OP's question is more about calculating new dimensions, rather than resizing
#Psyche, this is actually a simple arithmetic issue. Suppose you have an 640x480 image and want to show it in a 200x200 "box".
$sw = 640; $sh = 480;
$dw = 200; $dh = 200;
find out the aspect ratio of the box, compare it with that of original and calculate either width of height for the new image
$sr = $sw / $sh;
$dr = $dw / $dh;
if($sr > $dr)
$dh = round($dw / $sr);
else
$dw = round($dh * $sr);
this gives you 200x150 and this is the size to which you need to scale the original image
I would use GD or ImageMagick. Both great libraries to do that and more.
at least this is small (and useful): http://www.white-hat-web-design.co.uk/articles/php-image-resizing.php

Categories