How to optimize images in PHP? - php

I've a website where users can save their profile image (avatar).
I'd like to make some optimization to the image when they load it.
I mean, it's an avatar image, doesn't need full resolution, nor great size.
What can i do? I've been thinking:
Resize it
Low the quality
Possible:
convert it to GIF
Color fill to transparent PNGs
There are some library better (simpler) than GD to do this?
Thanks a lot!

GD is how this is done. It sounds like a simple operation, but there are a number of factors that you really want to get right if you're going to do this. All in all, this winds up being several hundred lines of code to take care of everything.
My recommendation is that although you may wish to resize an image (which requires a lossy recompression if using JPEG), converting it to a GIF is a bad idea. You don't know what the source type is, so doing that is problematic.
Here's my recommended flow:
1) Resize the image to your output format. You can force a cropping aspect ratio here as well, if you want.
2) Determine original source mode:
8 bit indexed (GIF/PNG8): Save as PNG8 (format tends to be smaller than GIF).
16-24 bit: Save as JPG. Quality is up to you, but 70% is a good baseline.
32 bit (PNG24): Save as PNG24, taking care to maintain the transparency.
Note, this solution pretty much destroys any 'animated' gifs, but... that's what happens when you try to resize an animated gif.
Although... I also highly recommend to NOT do this as a single stage process and removing the original files. This is the kind of thing that will only come back to bite you later.
Disk space is cheap these days... far better to store the original in a high quality format (even at 2K x 2K resolution), then create an image service which will serve the resolution/quality you need and cache the result.

You could use the Asido imaging library for PHP to resize your images. This library makes use of GD though. Here is some example usage code.
The resizing and other imaging operations are preferably done after the uploading of new images (except if you want to save the higher resolution for some other purpose).

<p>
//This function will proportionally resize image
function resizeImage($CurWidth,$CurHeight,$MaxSize,$DestFolder,$SrcImage,$Quality,$ImageType)
{
//Check Image size is not 0
if($CurWidth <= 0 || $CurHeight <= 0)
{
return false;
}
//Construct a proportional size of new image
$ImageScale = min($MaxSize/$CurWidth, $MaxSize/$CurHeight);
$NewWidth = ceil($ImageScale*$CurWidth);
$NewHeight = ceil($ImageScale*$CurHeight);
$NewCanves = imagecreatetruecolor($NewWidth, $NewHeight);
// Resize Image
if(imagecopyresampled($NewCanves, $SrcImage,0, 0, 0, 0, $NewWidth, $NewHeight, $CurWidth, $CurHeight))
{
switch(strtolower($ImageType))
{
case 'image/png':
imagepng($NewCanves,$DestFolder);
break;
case 'image/gif':
imagegif($NewCanves,$DestFolder);
break;
case 'image/jpeg':
case 'image/pjpeg':
imagejpeg($NewCanves,$DestFolder,$Quality);
break;
default:
return false;
}
//Destroy image, frees memory
if(is_resource($NewCanves)) {imagedestroy($NewCanves);}
return true;
}
}
</p>

I'd pick some standard avatar image sizes you'll need for your page, like
medium size for a profile page, if you have one and
small size which appears next to the user's post
you get the idea, just what you need
And when the user uploads a new avatar, you convert it to the formats you'll need with a reasonable quality setting. I'm assuming you're going for JPEGs, because this is a good catch-all format for this use case. PNGs do poor with photographic content, JPEGs are not so great for drawings, but then most avatars you see are photos. I wouldn't use GIFs any more these days, they limit to 256 colors and have only a 1-bit alpha channel.

Related

Optimize PNG when resizing with GD/PHP - How to determine color palette?

I had troubles resizing a PNG and maintaining small file sizes. Solution found here.
When resizing the PNG, however, I ran into problems regarding image quality. As far as I could see, GD uses indexed 8-bit-color palette which distorts text and colors get lost, see:
Original Image
Resized Image with solution given above
Resized Image with a tweak²
²The idea for the tweak I found here in stackoverflow: Create truecolor-image, resize it, and copy it to a new image, so the palette is determined based on the resampled result and the image quality is better as you can see in the image above.
// create new image
$newImageTmp = imagecreatetruecolor($newwidth,$newheight);
// we create a temporary truecolor image
// do the image resizing by copying from the original into $newImageTmp image
imagecopyresampled($newImageTmp,$src,0,0,0,0,$newwidth,$newheight,$width,$height);
// create output image
$newImage = imagecreate($newwidth,$newheight);
// copy resized truecolor image onto index-color image
imagecopy($newImage,$newImageTmp,0,0,0,0,$newwidth,$newheight);
// write image to buffer and save in variable
ob_start(); // stdout --> buffer
imagepng($newImage,NULL,6);
$newImageToSave = ob_get_contents(); // store stdout in $newImageToSave
ob_end_clean(); // clear buffer
// remove images from php buffer
imagedestroy($src);
imagedestroy($newImageTmp);
imagedestroy($newImage);
Problem: None of both results are satisfactory.
I am quite sure that there must be a way to 1. determine the color palette, and 2. maintain most of the image's colors, so that 3. the PNG looks similar to the original and has an acceptable file size.
Now, I only see going for JPG instead of PNG. But if you know a solution, it would greatly be appreciated if you let me/us know.
Thank you!
All you need is to replace
$newImage = imagecreate($newwidth,$newheight);
With
$newImage = imagecreatetruecolor($newwidth, $newheight);
Output $maxImgWidth = 200;
PHP's fork of GD doesn't have usable palette generation, so you only get PNG32 with vanialla libpng compression.
For small PNG8 with palette use pngquant, e.g. http://pngquant.org/php.html
And then compress it further with advpng or zopfli-png.

Server-side image resizing performance

I have been noticing more and more from the big sites (Google, Facebook, Youtube and co) that they are resizing images "close" to their desired measurements client side and I am wondering whether this is a shift in the way people are thinking or them being lazy.
Take a scenario of adding a new image size to a standard set of images at particular sizes for a set of products (e-commerce) which number into the 100's of thousands, maybe millions.
Imagine I have a copy of my original image that is 300x350 or whatever and client side, resize it to 200x250. I do this for each product for 20 products on a page.
Is the work and problems server-side of accomodating this new size really worth the benefit client side?
If not then what is a good way to judge when you should pre-process a certain size?
If yes, is there ever a time where server-side processing and caching might become overkill (i.e. housing 8 images of 110x220, 120x230, 150x190 etc)?
Consider following:
Image resizing is heavy process for server. It first of all costly itself. Secondly it is harddrive IO operations which ARE quite slow. SO it all depends on how loaded your server is.
For client it matters in two ways:
1) Thumbnails are smaller in file size and hence are much faster to download. SO they will appear way faster. But that all depends on speed of Internet connection, which day by day is increasing. Have you seen how large images are loaded? They will not be displayed whole at once, but rather by 'lines'
2) If you try to display large image in small size, the quality will be much much much lower. It is because of how browsers process it. They do not have capabilities of Photoshop and cannot do proper quality resizing.
3) Many large images on single page will increase memory usage by that page. On some not so powerful computers that may give terrible lags while scrolling opening it.
As a solution to this question i more tend to do what i have seen in one of Drupal modules (imagecache if i am right).
It does not create thumbnails on image upload. Instead it creates them on request time using .htaccess and mod_rewrite capabilities. It checks if requested file does not exist and if no it redirects request to small and light-weight PHP script which will create the thumbnail, write it to filesystem and then output to client.
So next visitor will already get previously created thumbnail.
Thus you implement postponed/lazy image resizing, which will make the load smoother (stretch it in time).
I decided to test this first on a single image on a page and did some multiplication math to anticipate multiple images. I should note:
I was using pngs for this test however pngs seem pretty standard.
I was using a particular function which apative resizes the image so that the width and height would always fit the original aspect ratio of the image I resized.
I got an image which was 450x450 (roughly) and decided to resize it down, client side, to 200x200 (all measurements in this answer are pixels). I found very little CPU jump by it despite the resize being more than half of the images total size.
The quality was also good across all modern browsers, Chrome, Opera, Firefox and IE all showed the image as clear as if it was done in Photoshop or GD.
On on IE7 I didn't notice much of a CPU jump and the quality was good provided I used a percentile resize based upon the images size constraints.
Overall the additional storage, computation and coding required to make even this size cache server side seemed to be at a disadvantage to the power that can be implied on the user end.
That being said, if I were to start doing multiples of this type of resizing (say 20, as in my question) I would probably start to hit problems.
After some tweaking around I found that anything under 1/3 of the original images size, provided the image was under 1000px in width or height, seemed to be negliable to CPU and general computer performance.
With the added function I was using I got just as good quality from resizing client side as I did server side. The specific function I used (for interested parties) was:
function pseudoResize($maxWidth = 0, $maxHeight = 0){
$width = $this->org_width;
$height = $this->org_height;
$maxWidth = intval($maxWidth);
$maxHeight = intval($maxHeight);
$newWidth = $width;
$newHeight = $height;
// Ripped from the phpthumb library in GdThumb.php under the resize() function
if ($maxWidth > 0)
{
$newWidthPercentage = (100 * $maxWidth) / $width;
$newHeight = ($height * $newWidthPercentage) / 100;
$newWidth = intval($maxWidth);
$newHeight = intval($newHeight);
if ($maxHeight > 0 && $newHeight > $maxHeight)
{
$newHeightPercentage = (100 * $maxHeight) / $newHeight;
$newWidth = intval(($newWidth * $newHeightPercentage) / 100);
$newHeight = ceil($maxHeight);
}
}
if ($maxHeight > 0)
{
$newHeightPercentage = (100 * $maxHeight) / $height;
$newWidth = ($width * $newHeightPercentage) / 100;
$newWidth = ceil($newWidth);
$newHeight = ceil($maxHeight);
if ($maxWidth > 0 && $newWidth > $maxWidth)
{
$newWidthPercentage = (100 * $maxWidth) / $newWidth;
$newHeight = intval(($newHeight * $newWidthPercentage) / 100);
$newWidth = intval($maxWidth);
}
}
return array(
'width' => $newWidth,
'height' => $newHeight
);
}
So it does seem from my own testing that housing every size of every image your going to use, i.e. as I asked in my question:
If yes, is there ever a time where server-side processing and caching might become overkill (i.e. housing 8 images of 110x220, 120x230, 150x190 etc)?
Does seem to be overkill in modern computing and rather you should go for close measurements if you intend to use many different size of many images.
I have found, however, that if you have a standard set of sizes and they are small then the advantage is actually to server side resize and storage of all sizes since forcing the client to resize will always slow their computer down a little but scaling under 1/3 of it's original size seems to not make too much of a difference.
So I believe that the reason why sites such as FB and Google and Youtube don't worry too much about storing exact measurements of all their images is because "close-to-measurement" scaling can be more performant overall.

Image uploading concept in PHP

how to take image from one folder and rename and re-size the images and move to another folder?
I need to get image from one folder and rename and re-size the same image and move into another folder using php
You will most likely be using gd for resizing the images.
Here is a pretty crappy, but hopefully useful code sample. In this case, $originalName is the name given in the $_FILES array's tmp_name position. I am resizing to a width of 1200 in this case, with the height adapting according to such width. You might (and most likely will) not desire this behavior. This is just some ugly code I used in some courses I taught about 3 years ago, I don't have the newer samples in this computer so you will have to get used to the idea :)
$newDir is where the file will be located. by calling imagejpeg or imagepng and passing the filename as second argument, it means to the function that you wish to save the image in that location.
if ($type == 'image/jpeg') {
$original = imagecreatefromjpeg($originalName);
}
else {
$original = imagecreatefrompng($originalName);
}
$width = imagesx($original);
$height = imagesy($original);
//prepare for creation of image with width of 1000
$new_height = floor($height * (1200 / $width));
// create the 1200 width image
$tmp_img = imagecreatetruecolor(1200, $new_height);
// copy and resize old image into new image
imagecopyresized($tmp_img, $original, 0, 0, 0, 0,
1200, $new_height, $width, $height);
//create a random and unique name to identify (here it isn't that random ;)
$newDir = '/this/is/some/directory/and/filename.';
if ($type == 'image/jpeg') {
imagejpeg($tmp_img, $newDir."jpg");
}
else {
imagepng($tmp_img, $newDir."png");
}
Many file system functions are already built-in with PHP (e.g. rename), and you'll find most of what you need to resize images by using the GD library here.
There are libraries available in PHP for image resize.
Here are some useful links you may like.
http://www.fliquidstudios.com/2009/05/07/resizing-images-in-php-with-gd-and-imagick/
http://php.net/manual/en/book.image.php
PHP/GD - Cropping and Resizing Images
http://net.tutsplus.com/tutorials/php/image-resizing-made-easy-with-php/
Use imagick http://php.net/manual/en/imagick.resizeimage.php
If I were you I would write a PE using a diffent language (one that you might be best used to) to adjust anything of the given image then just feel free to phpexec it to do all the steps you mentioned, you can sit relax and wait for the end result. HHAHAHHA :-)
Use imagick library to resize; it's good.

Image filesize after resizing with Imagick and Gmagick

While resizing an image, I have noticed that Imagick and Gmagick produce images with different filesize on HDD with the same options:
$image = new Imagick("c.jpg");
$image->thumbnailImage(260,195);
$image->writeImage("c_imagick.jpg");
outputs an Image with 88kb
$image = new Gmagick("c.jpg");
$image->thumbnailImage(260,195);
$image->writeImage("c_gmagick.jpg");
outputs an Image with 15kb
Does someone have any idea, why the difference is so huge?
Try setting the image compression settings prior to resizing.
$image->setImageCompression(Imagick::COMPRESSION_JPEG);
$image->setImageCompressionQuality(80);
Additionally, check the size of the resulting image. Comments in the PHP documentation lead me to believe that the automatic fit portion of thumbnailImage does not work as you would expect in IMagick.
From PHP Docs:
The fit functionality of thumbnailImage doesn't work as one would anticipate. Instead, use >this to make a thumbnail that has max of 200x82:
// Create thumbnail max of 200x82
$width=$im->getImageWidth();
if ($width > 200) { $im->thumbnailImage(200,null,0); }
$height=$im->getImageHeight();
if ($height > 82) { $im->thumbnailImage(null,82,0); }

kohana 3.0 resize image before uploading?

I want to upload some images to the server, but first of all i want them croped, and resized to some certain dimensions.
Now i am doing the simple upload and save like that:
$header_image = Upload::save($_FILES['sale_picture_header'],NULL,APPPATH.'media'.'/');
$image_header = Model::factory('image');
$image_header->name = basename($header_image);
$image_header->save();
(excluding the validation).
How can i crop or resize the image to some desired dimensions, in Kohana 3.0? I couldn't find any relevant documentation regarding that.
Thank you!
Did you try with the image package:
// Resize to 200 pixels on the shortest side
$image->resize(200, 200);
// Resize to 200x200 pixels, keeping aspect ratio
$image->resize(200, 200, Image::INVERSE);
// Resize to 500 pixel width, keeping aspect ratio
$image->resize(500, NULL);
// Resize to 500 pixel height, keeping aspect ratio
$image->resize(NULL, 500);
// Resize to 200x500 pixels, ignoring aspect ratio
$image->resize(200, 500, Image::NONE);
source:
http://kohanaframework.org/3.0/guide/api/Image#resize
You can use the ImageMagick library, or the GD library for image manipulation.
Also note that these are strictly server-side, and will not happen before upload. For that you'd need some client-side plugin capable of image manipulation such as Flash or Java.
I found something very interesting. The question was, how to perform this action, "resize then crop" an image to fit perfectly a determined box, and this is the solution:
Image::factory($file)
->resize(128, 149, Image::PRECISE)
->crop(128, 149)
->save(DOCROOT.$filename);
Note that you must use Image::PRECISE, instead of IMAGE::AUTO.
Hope this helps someone.

Categories