Getting the uncompressed image size - php

I have a small PHP script which converts image files to thumbnails. The uploader I have has a 100MB max, which I'd like to keep.
The problem is, when opening the file, GD decompresses it, causing it to be huge and make PHP run out of memory (Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 64000 bytes)). I don't want to increase my memory any further than this allowed size.
I don't care about the image, I can just make it show a default thumbnail, that's fine. But I do need a way to catch the error imagecreatefromstring(file_get_contents($file)) spawns when the image is too big.
Since the error spawned is fatal, it cannot be try-catched, and since it loads it in one command, I can't keep looking after it to make sure it's not approaching the limit. I need a way to calculate how big the image will be before trying to process it.
Is there a way to do this? filesize wouldn't work as it gives me the compressed size...
My code is as follows:
$image = imagecreatefromstring(file_get_contents($newfilename));
$ifilename = 'f/' . $string . '/thumbnail/thumbnail.jpg';
$thumb_width = 200;
$thumb_height = 200;
$width = imagesx($image);
$height = imagesy($image);
$original_aspect = $width / $height;
$thumb_aspect = $thumb_width / $thumb_height;
if ( $original_aspect >= $thumb_aspect )
{
// Image is wider than thumbnail.
$new_height = $thumb_height;
$new_width = $width / ($height / $thumb_height);
}
else
{
// Image is taller than thumbnail.
$new_width = $thumb_width;
$new_height = $height / ($width / $thumb_width);
}
$thumb = imagecreatetruecolor( $thumb_width, $thumb_height );
// Resize and crop
imagecopyresampled($thumb,
$image,
0 - ($new_width - $thumb_width) / 2, // Center the image horizontally
0 - ($new_height - $thumb_height) / 2, // Center the image vertically
0, 0,
$new_width, $new_height,
$width, $height);
imagejpeg($thumb, $ifilename, 80);

Tried looking at the original image size before re-sizing? Maybe multiplying it by a set % based of average format compression?
$averageJPGFileRatio = 0.55;
$orgFileSize = filesize ($newfilename) * 0.55;
and looking at that before doing any work?
Secondary idea
Calculate it like this: width * height * 3 = filesize
The 3 is for the red, green, and blue values if you're working with images with an alpha channel use 4 instead of 3. This should give you a VERY close estimation of the bitmap size. Does not take into account header info, but that should be negligible at a few bytes.

Related

How do I Resize images to fixed width & height while maintaing aspect ratio in PHP?

I am trying to batch resize images to the size of 250 x 250 in PHP
All source images are way bigger than 250 x 250 so that is helpful.
I want to maintain aspect ratio but make them all 250 x 250. I know that a portion of the image will be cropped off to do this. That is not an issue for me
The problem is that my current script only works on width and makes height according to aspect but sometimes, the image will now end up being let's say, 250 x 166. I can't use that.
In that cause It would need to be resized in the opposite manner (height to width)
How would the script have to look to always make the final image 250 x 250 without stretching. Again, I don't care if there is cropping. I assume there is going to be an else in the somewhere but this is way over my head now. I am more of a front end guy.
Any help would be great.
Below is just the relevant portion of my full script:
$width = 250;
$height = true;
// download and create gd image
$image = ImageCreateFromString(file_get_contents($url));
// calculate resized ratio
// Note: if $height is set to TRUE then we automatically calculate the height based on the ratio
$height = $height === true ? (ImageSY($image) * $width / ImageSX($image)) : $height;
// create image
$output = ImageCreateTrueColor($width, $height);
ImageCopyResampled($output, $image, 0, 0, 0, 0, $width, $height, ImageSX($image), ImageSY($image));
// save image
ImageJPEG($output, $destdir, 100);
$newWidth = 250;
$newHeight = 250;
// download and create gd image
$image = ImageCreateFromString(file_get_contents($url));
$width = ImageSX($image);
$height = ImageSY($image);
$coefficient = $newHeight / $height;
if ($newHeight / $width > $coefficient) {
$coefficient = $newHeight / $width;
}
// create image
$output = ImageCreateTrueColor($newWidth, $newHeight);
ImageCopyResampled($output, $image, 0, 0, 0, 0, $width * $coefficient, $height * $coefficient, $width, $height);
// save image
ImageJPEG($output, $destdir, 100);

Resize image and place in center of canvas

I'm trying to do the following in iMagick and I can't get it to work:
Check if image is over 390 pixels high, if it is then resize it to 390 pixels high, if it isn't keep the dimensions.
Add a white canvas, 300px wide by 400px high and then place the image into the center of that.
My Code is:
$im = new Imagick("test.jpg");
$imageprops = $im->getImageGeometry();
$width = $imageprops['width'];
$height = $imageprops['height'];
if($height > '390'){
$newHeight = 390;
$newWidth = (390 / $height) * $width;
}else{
$newWidth = $imageprops['width'];
$newHeight = $imageprops['height'];
}
$im->resizeImage($newWidth,$newHeight, Imagick::FILTER_LANCZOS, 0.9, true);
$canvas = new Imagick();
$canvas->newImage(300, 400, 'white', 'jpg');
$canvas->compositeImage($im, Imagick::COMPOSITE_OVER, 100, 50);
$canvas->writeImage( "test-1.jpg" );
When the images are produced the large ones are scaled to 388 pixels high for some reason and the small ones are left to their original dimensions.
The placing on the canvas is always incorrect although does work on the large images with 100,50 added to the composite image.
Most of the images are tall and thin however there are a few that are wider than they are tall.
Any ideas where I am going wrong ?
Thanks,
Rick
Mark's comments may be the better option. Extent respects the gravity, and ensures that the finial image will always be 300x400. For placing the image in the center using Imagick::compositeImage, you'll need to calculate the offset -- which is easy as you already have the width/height of the subject & canvas images.
$canvas = new Imagick();
$finalWidth = 300;
$finalHeight = 400;
$canvas->newImage($finalWidth, $finalHeight, 'white', 'jpg' );
$offsetX = (int)($finalWidth / 2) - (int)($newWidth / 2);
$offsetY = (int)($finalHeight / 2) - (int)($newHeight / 2);
$canvas->compositeImage( $im, imagick::COMPOSITE_OVER, $offsetX, $offsetY );

Resizing image with exact width and height in php

I am sure this topic has been discussed number of times and I have started doing this from yesterday evening but till now no complete satisfaction.I am using the following code and it gives me a resized image but the scaling is not correct.The height and width is not in it's correct proportion.
I couldn't find any good fiddle like jsfiddle where you can see the output so pasting my code here.
You can see the original image url here also I have attached a resized image.
http://distilleryimage4.s3.amazonaws.com/b1da08e4484511e38e4d0a7011810191_7.jpg
$filename = 'http://distilleryimage4.s3.amazonaws.com/b1da08e4484511e38e4d0a7011810191_7.jpg';
//the resize will be a percent of the original size
$percent = 0.589;
$percent_height = 0.294;
// Content type
header('Content-Type: image/jpeg');
// Get new sizes
list($width, $height) = getimagesize($filename);
$newwidth = $width * $percent;
$newheight = $height * $percent_height;
// Load
$thumb = imagecreatetruecolor($newwidth, $newheight);
$source = imagecreatefromjpeg($filename);
// Resize
imagecopyresized($thumb, $source, 0, 0, 0, 0, $newwidth, $newheight, $width, $height);
imagejpeg($thumb);
imagedestroy($thumb);
This is basically a Math problem:
You are scaling width and height to both different proportions ($percent and $percent_height). You should scale both of them (width and height) by the same percent, to get an image resized to the same ratio. Maybe I didn't understand your question but I think you should change this line:
$newheight = $height * $percent_height;
to
$newheight = $height * $percent;
(and remove $percent_height = 0.294; if we are not gonna use it here)
I would use Imagick. I was doing resizing with imagecreatetruecolor, but it takes a lot of time (0,5 seconds) to resize 1920*1080 image to 150*120.
If you still want to use imagecreatetruecolor: to get the correct scalling use this code.

PHP crop tall images

This is my code, but I dont know why but when I upload a vertical image it is resized and I get two black stripes on the sides. With wide images it works well most of the time but with some images I get black stripes as well. How can I fix it?
My purpose is to crop every image, horizontal just a hint to fit my box, and vertical I want to crop so the width is the same and they are cut no top and bottom.
$thumb_height = 200;
$thumb_width = 300;
$thumb = imagecreatetruecolor($thumb_width, $thumb_height);
if($width >= $height) {
// If image is wider than thumbnail (in aspect ratio sense)
$new_height = $thumb_height;
$new_width = $width / ($height / $thumb_height);
} else {
// If the thumbnail is wider than the image
$new_width = $thumb_width;
$new_height = $height / ($width / $thumb_width);
}
$output_filename_mid = 'uploads/'.IMG_L.$fileName;
imagecopyresampled($thumb,
$image,
0 - ($new_width - $thumb_width) / 2, // Center the image horizontally
0 - ($new_height - $thumb_height) / 2, // Center the image vertically
0, 0,
$new_width, $new_height,
$width, $height);
imagejpeg($thumb, $output_filename_mid, 85);
You're almost there. You've figured out that you need to determine the ratio between the old height and the destination height to resize the side that'll be cropped. However, you need to determine this in relation to the destination ratio.
if(($width / $height) > ($thumb_width / $thumb_height)) {
// If image is wider than thumbnail (in aspect ratio sense)
$new_height = $thumb_height;
$new_width = $width / ($height / $thumb_height);
} else {
// If the thumbnail is wider than the image
$new_width = $thumb_width;
$new_height = $height / ($width / $thumb_width);
}
I'm actually working with this a lot. Here is my code which is VERY similar to yours. Can you find the difference/problem yourself?
My code works 100% and does exactly what you need and ONLY that. Feel free to use it!
Variables explained: $imagewidth and $imageheight are naturally the original pixel sizes of the input image. $crop_ratio_w is crop ratio width and $crop_ratio_h is crop ratio height.
So for my code vs. your code: $crop_ratio_w = $thumb_width and $crop_ratio_h = $thumb_height
//do this if we can start cropping by width (there's enough space on height)
if (($imagewidth * $crop_ratio_h / $crop_ratio_w) < $imageheight){
//count new res
$new_width = $imagewidth;
$new_height = ($imagewidth * $crop_ratio_h / $crop_ratio_w);
//count the height difference, so that new image is cropped in HEIGHT center
$difference = ($imageheight - $new_height);
$y_offset = ($difference / 2);
//create new empty image
$croppedImage = imagecreatetruecolor($new_width, $new_height);
//copy wanted area to the new empty image
imagecopy($croppedImage, $originalImage, 0, 0, 0, $y_offset, $new_width, $new_height);
}
//else on previous condition -- do this if we have to start cropping by height (there's not enough space on height)
else{
//count new res
$new_width = ($imageheight * $crop_ratio_w / $crop_ratio_h);
$new_height = $imageheight;
//count the height difference, so that new image is cropped in WIDTH center
$difference = ($imagewidth - $new_width);
$x_offset = ($difference / 2);
//create new empty image
$croppedImage = imagecreatetruecolor($new_width, $new_height);
//copy wanted area to the new empty image
imagecopy($croppedImage, $originalImage, 0, 0, $x_offset, 0, $new_width, $new_height);
}

php gd: when i crop images through php some images come out smushed

here is the website im talking about
http://makeupbyarpi.com/portfolio.php
you'll notice some of the images are smushed width-wise.
the code i used is this:
$width="500";
$height="636";
$img_src = $_FILES['galleryimg']['tmp_name'];
$thumb = "../gallery/".rand(0,100000).".jpg";
//Create image stream
$image = imagecreatefromjpeg($img_src);
//Gather and store the width and height
list($image_width, $image_height) = getimagesize($img_src);
//Resample/resize the image
$tmp_img = imagecreatetruecolor($width, $height);
imagecopyresampled($tmp_img, $image, 0, 0, 0, 0, $width, $height, $image_width, $image_height);
//Attempt to save the new thumbnail
if(is_writeable(dirname($thumb))){
imagejpeg($tmp_img, $thumb, 100);
}
//Free memory
imagedestroy($tmp_img);
imagedestroy($image);
the images that get uploaded are huge sometimes 3000px by 2000px and i have php crop it down to 500 x 536 and some landscape based images get smushed. is there a formula i can use to crop it carefully so that the image comes out good?
thanks
You could resize and add a letterbox if required. You simply need to resize the width and then calculate the new height (assuming width to height ratio is same as original) then if the height is not equal to the preferred height you need to draw a black rectangle (cover background) and then centre the image.
You could also do a pillarbox, but then you do the exact same as above except that width becomes height and height becomes width.
Edit: Actually, you resize the one that is the biggest, if width is bigger, you resize that and if height is bigger then you resize that. And depending on which one you resize, your script should either letterbox or pillarbox.
EDIT 2:
<?php
// Define image to resize
$img_src = $_FILES['galleryimg']['tmp_name'];
$thumb = "../gallery/" . rand(0,100000) . ".jpg";
// Define resize width and height
$width = 500;
$height = 636;
// Open image
$img = imagecreatefromjpeg($img_src);
// Store image width and height
list($img_width, $img_height) = getimagesize($img_src);
// Create the new image
$new_img = imagecreatetruecolor($width, $height);
// Calculate stuff and resize image accordingly
if (($width/$img_width) < ($height/$img_height)) {
$new_width = $width;
$new_height = ($width/$img_width) * $img_height;
$new_x = 0;
$new_y = ($height - $new_height) / 2;
} else {
$new_width = ($height/$img_height) * $img_width;
$new_height = $height;
$new_x = ($width - $new_width) / 2;
$new_y = 0;
}
imagecopyresampled($new_img, $img, $new_x, $new_y, 0, 0, $new_width, $new_height, $img_width, $img_height);
// Save thumbnail
if (is_writeable(dirname($thumb))) {
imagejpeg($new_img, $thumb, 100);
}
// Free up resources
imagedestroy($new_img);
imagedestroy($img);
?>
Sorry it took a while, I ran across a small bug in the calculation part which I was unable to fix for like 10 minutes =/ This should work.

Categories