PHP: Image Resize and Crop to Portrait - php

I need to the re size and crop image to center. The end result image needs to be 250W x 330H.
I need to re size the image uploaded to 330 height but leave the correct ratio with the width. Then check to see if width is 250 or over, after the re size. If it is not, then I need to re size the image from the original to 250 width but leave the correct ratio with the height.
So if it did re size to 330 height and the width was 250 or over, then I need to crop the image to the center on width to 250. But if it re sized to 250 width, with height being 330 or over, then I need to crop image to the center on height to 330.
I was trying to create it myself but I'm so confused by the crop to center part.

With the use of Wideimage library (http://wideimage.sourceforge.net/):
$thumb = WideImage::load('uploaded_image.png')->resize(250, 330);
if ($thumb->getWidth() > 250 || $thumb->getHeight() > 330) {
$thumb = $thumb->crop('center', 'center', 250, 330);
}
$thumb->saveToFile('cropped_image.png');

I wrote a library to can do just that: Php Image Magician
<?php
require_once('../php_image_magician.php');
$magicianObj = new imageLib('racecar.jpg');
$magicianObj -> resizeImage(250, 330, 'crop');
$magicianObj -> saveImage('racecar_cropped.jpg', 100);
?>

here is a function ive just completed to force an exact pixel size - I cant guarantee it 100% but ive tested it with many options and got perfect results so far, it gives the closest result imo. First it resizes the SMALLEST difference between the source image and specified sizes by calculating ratios. Then trims off excess pixels. I have compensated for odd numbers, negative values, etc. I have had good results so far. Please let me know if ive missed something or if it breaks somehow:
PHP:
// set source/export paths and pixel sizes for final sizes
$src="path/to/source.jpg";
$exp="path/to/output.jpg";
$crop_w=300;
$crop_h=200;
$size = getimagesize("$src");
//check image sizes
if( ($size[0] < $crop_w) || ($size[1] < $crop_h) ){
echo 'Image not big enough to crop';
exit();
}
//get differential ratios of image vs crop sizes -
//smaller ratio must be resized
$ratio_w = $size[0]/$crop_w;
$ratio_h = $size[1]/$crop_h;
//square or landscape - shave sides
if($ratio_w >= $ratio_h){
//resize width / shave top&bottom
exec("convert $src -resize x".$crop_h." $exp ");
$size = getimagesize("$exp");
$diff=abs($crop_w-$size[1]);
//dividing 1 by 2 will leave a zero on round down - just force resize
if($diff < 2){
// skip shave - diff too small
exec('convert $exp -resize '.$crop_h.'X! $exp ');
}
else{
//divide difference by 2 for shave amount
$shave = round($diff/2,0,PHP_ROUND_HALF_DOWN); //halve & round difference down to avoid cropping smaller
exec('convert '.$exp.' -shave '.$shave.'x0 '.$exp.' '); //shave sides
//odd $diff leave a rounded down pixel - force height resize
if($diff%2 !==0){//if $diff was not divisible by two then 1 pixel is left from round down
exec('convert '.$exp.' -resize '.$crop_w.'x! '.$exp.' ');
}
}
}
//portrait - shave height
else{
//resize width / shave top&bottom
exec("convert $src -resize ".$crop_w."x $exp ");
$size = getimagesize("$exp");
$diff=abs($crop_h-$size[1]);
//dividing 1 by 2 will leave a zero on round down - just force resize
if($diff < 2){
exec('convert $exp -resize x'.$crop_h.'! $exp ');
}
else{
//divide difference by 2 for shave amount
$shave = round($diff/2,0,PHP_ROUND_HALF_DOWN); //halve & round difference down to avoid cropping smaller
exec('convert '.$exp.' -shave 0x'.$shave.' '.$exp.' '); //shave sides
//odd $diff leave a rounded down pixel - force height resize
if($diff%2 !==0){//if $diff was not divisible by two then 1 pixel is left from round down
exec('convert '.$exp.' -resize x'.$crop_h.'! '.$exp.' ');
}
}
}
Feel free to use / make comments. Php 5.4<, Imagemagick 6.8.8.1, Windows xampp.

Related

Automatically resize image on the shorter side regardless of orientation in imagemagick

Im struggling to resize an image regardless of orientation using imagemagick, is the program that terrible that a basic detection method is not even included? Do I have to now go and check the shortest side using getimagesize and comparing them or what?
-resize 125^
only works one way, the minute i flip the image 90 degrees the shorter side becomes smaller than 125.. ie its not resizing the shorter side on both orientations. Im trying to use less code if that makes a difference.
here is a function ive just completed to force an exact pixel size - I cant guarantee it 100% but ive tested it with many options and got perfect results so far, it gives the closest result imo. First it resizes the SMALLEST difference between the source image and specified sizes by calculating ratios. Then trims off excess pixels. I have compensated for odd numbers, negative values, etc. I have had good results so far. Please let me know if ive missed something or if it breaks somehow:
PHP:
// set source/export paths and pixel sizes for final sizes
$src="path/to/source.jpg";
$exp="path/to/output.jpg";
$crop_w=300;
$crop_h=200;
$size = getimagesize("$src");
//check image sizes
if( ($size[0] < $crop_w) || ($size[1] < $crop_h) ){
echo 'Image not big enough to crop';
exit();
}
//get differential ratios of image vs crop sizes -
//smaller ratio must be resized
$ratio_w = $size[0]/$crop_w;
$ratio_h = $size[1]/$crop_h;
//square or landscape - shave sides
if($ratio_w >= $ratio_h){
//resize width / shave top&bottom
exec("convert $src -resize x".$crop_h." $exp ");
$size = getimagesize("$exp");
$diff=abs($crop_w-$size[1]);
//dividing 1 by 2 will leave a zero on round down - just force resize
if($diff < 2){
// skip shave - diff too small
exec('convert $exp -resize '.$crop_w.'X! $exp ');
}
else{
//divide difference by 2 for shave amount
$shave = round($diff/2,0,PHP_ROUND_HALF_DOWN); //halve & round difference down to avoid cropping smaller
exec('convert '.$exp.' -shave '.$shave.'x0 '.$exp.' '); //shave sides
//odd $diff leave a rounded down pixel - force height resize
if($diff%2 !==0){//if $diff was not divisible by two then 1 pixel is left from round down
exec('convert '.$exp.' -resize '.$crop_w.'x! '.$exp.' ');
}
}
}
//portrait - shave height
else{
//resize width / shave top&bottom
exec("convert $src -resize ".$crop_w."x $exp ");
$size = getimagesize("$exp");
$diff=abs($crop_h-$size[1]);
//dividing 1 by 2 will leave a zero on round down - just force resize
if($diff < 2){
exec('convert $exp -resize x'.$crop_h.'! $exp ');
}
else{
//divide difference by 2 for shave amount
$shave = round($diff/2,0,PHP_ROUND_HALF_DOWN); //halve & round difference down to avoid cropping smaller
exec('convert '.$exp.' -shave 0x'.$shave.' '.$exp.' '); //shave sides
//odd $diff leave a rounded down pixel - force height resize
if($diff%2 !==0){//if $diff was not divisible by two then 1 pixel is left from round down
exec('convert '.$exp.' -resize x'.$crop_h.'! '.$exp.' ');
}
}
}
Feel free to use / make comments. Php 5.4<, Imagemagick 6.8.8.1, Windows xampp.

Create fixed thumbnail dimensions for images with different sizes

I just want to know if it is possible to get different images' sizes, and create fixed thumbnail dimension measurements for these pictures without losing their accurate aspect ratios.
So far, I have made these:
Resize different images
Maintain their aspect ratios
NOT supplying the same size (for example: 100px- height and 100px- width)
Here's the code that I am working with:
<?php
require("dbinfo.php");
$allPhotosQuery = mysql_query (" SELECT * FROM `placesImages` ");
while ($allPhotosArray = mysql_fetch_assoc ($allPhotosQuery))
{
$filename= $allPhotosArray['fileName'];
$placeId = $allPhotosArray['placeId'];
$imagePath = "placesImages/" . $placeId . "/" . $filename;
$imageSize = getimagesize($imagePath);
$imageWidth = $imageSize[0];
$imageHeight = $imageSize[1];
$newSize = ($imageWidth + $imageHeight)/($imageWidth*($imageHeight/45));
$newHeight = $imageHeight * $newSize;
$newWidth = $imageWidth * $newSize;
echo "<img src='".$imagePath."' width='".$newWidth."' height='".$newHeight."' />";
}
?>
Short of cropping, the simplest way to maintain aspect ratio while making a thumbnail is to do something similar to what you have, but set one fixed:
For example, if you want all your tumbs to be 100px wide:
$imageWidth = $imageSize[0];
$imageHeight = $imageSize[1];
$ratio=ImageWidth/$imageHeight;
$newHeight=(int)$ratio*100;
$newWidth=100;
The caveat with this is that you might end up with some funny sizes if the image has a funny ratio - as in it will happily go ahead and just do it. It might be a good idea to put some sort of check on the ratio in your code - if it it too low or too high, do something else, otherwise use this standard process.
feed this function your original image width and heights followed by the maximum constraints of your thumbnail limits and it will spit out an array with x/y of what you should set your thumbnail at to maintain aspect ratio. (anything smaller than the thumbnail will be enlarged)
function imageResizeDimensions($source_width,$source_height,$thumb_width,$thumb_height)
{
$source_ratio = $source_width / $source_height;
$thumb_ratio = $thumb_width / $thumb_height;
if($thumb_ratio > $source_ratio)
{
return array('x'=>$thumb_height * $source_ratio,'y'=>$thumb_height);
}
elseif($thumb_ratio < $source_ratio)
{
return array('x'=>$thumb_width,'y'=>$thumb_width/$source_ratio);
}
else
{
return array('x'=>$thumb_width,'y'=>$thumb_width);
}
}
Let’s begin with two constants, thumb_width and thumb_height, which are the desired width and height of your thumbnail images. They can be equal, but don’t have to be.
If you have an image that’s wider than it is tall (landscape) we can set the width to the desired width of the thumbnail, thumb_width, and adjust the height to maintain the aspect ratio.
new_width = thumb_width
new_height = thumb_height * old_height / old_width
See imagecreatetruecolor.
Then you can move the image to center it vertically within the limits of the thumbnail, producing a letterbox effect. See imagecopyresampled.
new_y = (thumb_height - new_height) / 2
For images that are taller than they are wide (portrait) the procedure is the same, but the math is a little different.
new_height = thumb_height
new_width = thumb_width * old_width / old_height
Then you can center it horizontally within the limits of the thumbnail.
new_x = (thumb_width - new_width) / 2
For more information on the basics of creating thumbnail images see Resizing images in PHP with GD and Imagick

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.

Quickly get brightness / luminosity of images

I'm working in php, and going through each image pixel-by-pixel to get an average brightness for each image is going to be way to cpu intensive...
I've looked through both GD and imagemagick docs, but haven't found a way to return the average brightness of an image... Can this be done quickly either in these libraries, or in another package easily accessible by php?
Here is an interesting post using ImageMagick for computing the average graylevel of an image. This post also discusses Mark Ransom's technique of size reduction to 1x1 using ImageMagick.
In Imagemagick command line, you can convert to HSI or LAB and get the brightness (Intensity or Luminosity) from the average of the I or L channel. Any of these methods should work. Note that -scale 1x1 does a simple average of the whole image/channel and saves that value in 1 pixel result. -scale is very fast. It is not like -resize, which uses a specific filter function. Alternately, you can just compute the mean of the image without writing to 1 pixel.
convert image -colorspace HSI -channel b -separate +channel -scale 1x1 -format "%[fx:100*u]\n" info:
convert image -colorspace LAB -channel r -separate +channel -scale 1x1 -format "%[fx:100*u]\n" info:
convert image -colorspace HSI -channel b -separate +channel -format "%[fx:100*u.mean]\n" info:
convert image -colorspace LAB -channel r -separate +channel -format "%[fx:100*u.mean]\n" info:
convert image -colorspace HSI -channel b -separate +channel -format "%[mean]\n" info:
convert image -colorspace LAB -channel r -separate +channel -format "%[mean]\n" info:
The result will be between 0 and 100% with 0 being black and 100 white for all but the last two, where fx range is between 0 and 1. Thus the 100 factor to get percent. For the last two commands, the values will be between 0-255 for Q8 install and 0-65535 for Q16 install.
Note that channels are labeled in order as if they were r,g,b. But for modern versions of Imagemagick, you can use 0,1,2.
Alternately, you can get the pixel color for the channel which will be some gray value:
convert image -colorspace HSI -channel b -separate +channel -scale 1x1 -format "%[pixel:u.p{0,0}]\n" info:
convert image -colorspace LAB -channel r -separate +channel -scale 1x1 -format "%[pixel:u.p{0,0}]\n" info:
Sorry I do not know Imagick, but see
http://us3.php.net/manual/en/imagick.scaleimage.php
http://us3.php.net/manual/en/imagick.getimagepixelcolor.php
http://us3.php.net/manual/en/imagick.transformimagecolorspace.php
http://us3.php.net/manual/en/imagick.getimagechannelstatistics.php
or possibly
http://us3.php.net/manual/en/imagick.getimageproperty.php
Perhaps an Imagick expert would be kind enough to convert one of these commands from command line to Imagick code.
Sample? Just pick 10% of random pixels instead of 100%... Error rate will rise obviously but 10% of the pixels seems fine to me, in most cases it should yield great results!
Cache the values if using them more then once, because this is not a fast solution. I tried first to resize the image to 1x1 pixel with imagick, but the results were not good. Best results I got without imagick resize, but its very slow with big images. The example resizes to 1000x1000 pixels. Keep in mind this example does not cover images with alpha channel.
function getImageBrightness( $path )
{
$width = 1000;
$height = 1000;
try
{
$imagick = new imagick( $path );
$imagick->resizeImage( $width, $height );
$_brightness = 0;
for( $i=0; $i < $width; $i++ )
for( $j=0; $j < $height; $j++ )
if( $pixel = $imagick->getImagePixelColor($i, $j) )
if( $colors = $pixel->getColor() AND isset($colors['r']) )
{
$brightness = ($colors['r'] + $colors['g'] + $colors['b']) / (3* 255);
$_brightness = $brightness + $_brightness;
}
$_brightness = $_brightness / ( $height * $width );
return $_brightness; // from 0 (black) to 1 (white)
} catch( ImagickException $e )
{}
return 0.5; // default
}
Imagick has a histogram feature to return colors by count. You can more quickly average the same information without processing pixel-by-pixel.
Performance will be dependent on the number of colors in the image/histogram (e.g. a single color image will be extremely fast).
<?php
$image = new Imagick('image.jpg');
$pixels = $image->getImageHistogram(); // Generate histogram of colors
$sumbright = 0; // sum of brightness values
$cntbright = 0; // count of pixels
foreach($pixels as $p){
$color = $p->getColor(); // Get rbg pixel color
$cnt = $p->getColorCount(); // Get number of pixels with above color
$sumbright += (($color['r'] + $color['g'] + $color['b']) / (3*255)) * $cnt; // Calculate 0.0 - 1.0 value of brightness (0=rgb[0] 1=rgb[255])
$cntbright += $cnt;
}
$avgbright = $sumbright / $cntbright; // Average 0-1 brightness of all pixels in the histogram
?>

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;
}

Categories