Can I convert PNG or jpeg to 25% size of original image by using php GD library?
I can't install extra php extension.
If you're wanting to reduce the file size to 25% of that of the original image, you may need some trial-and-error, which can be costly from a computational and memory standpoint, as in GD the only way to do this is as follows:
$old_bytes=filesize($original_file_path);
$image=imagecreatefromjpeg($original_file_path);
imagejpeg($image, $new_file_path, $quality_guess);
$new_bytes=filesize($new_file_path);
$ratio=$old_bytes/$new_bytes;
The tricky thing is: how accurate do you want to get? You will have to encapsulate the above code, or something like it, in some sort of loop and carry it out multiple times, and then make the subjective judgment call of deciding when to stop. Ideally you want $ratio close to 4.
If your source images are all roughly similar in terms of quality settings, you might find it much better to manually test things out for a single file, and just decide on a fixed quality setting that achieves the reduction in filesize that you're looking for.
In my experience though, it is generally a bad idea to aim for consistent filesize or consistent reduction in filesize, so you might want to rethink your end goal here. Usually I approach image compression based on quality, i.e. I take a sample of images and then I compress them with different quality settings (75 is often a good starting point) and send them around to a few different users on different devices (after looking at them myself on different devices) and I pick the lowest quality setting at which no one can notice a decrease in quality. Often it is surprisingly low, but it will also be heavily dependent on the specifics of the image. Certain images are just more compressable than others, based on the structure of their content.
So if you're aiming for a fixed size-reduction, you might find that much of the time you're compressing a lot less than you could (i.e. you could lower the quality even more without users noticing) but you might also find that some of the time you are actually reducing quality to terrible levels. Like, imagine one user who leaves the quality settings on 100, and then another user that had mindfully optimized the quality settings based on perception. If your code reduces both of them to 25% file size, you'll probably produce far fewer savings than you could have on that originally-100-quality image, but you're probably going to end up with a visibly terrible image on that carefully-optimized image.
So...yes, you could do what you want, but it will be computationally intensive and I am having trouble imagining a scenario where it would be a good idea.
Related
I'm currently trying to speed up the websites we develop. The part I'm working on now is to optimise the images so that they are as small (filesize, not dimensions) as possible without losing quality.
Our customers can upload their own images to the website through our custom CMS, but images aren't being compressed or optimised at all. My superior explained this is because the customers can upload their own images, and these images could be optimised beforehand through Photoshop or tools like it. If you optimise already optimised images, the quality would get worse. ...right?
We're trying to find a solution that won't require us to install a module or anything. We already use imagejpeg(), imagepng() and imagegif(), but we don't use the $quality parameter because of reasons previously explained. I've seen some snippets, but they all use imagejpg() and the like.
That being said, is there a sure-fire way of optimising images without the risk of optimising previously optimised images? Or would it be no problem at all to use imagejpeg(), imagepng() and imagegif(), even if it would mean optimising already optimised images?
Thank you!
"If you optimise already optimised images, the quality would get worse. "
No if you use a method without loose.
I don't know for method directly in php but if you are on linux server you can use jpegtran or jpegoptim ( with --strip-all) for jpeg and OptiPNG or PNGOUT for png.
Going from your title, I am going to assume compression
So, lets say a normal jpg of 800x600 is uploaded by your customers.
The customers jpg is 272kb because it has full details and everything.
You need to set tresholds for filesizes at dimensions what is acceptable.
Like:
if $dimensions->equals(800,600) and file_type($image) =='jpg' and file_size($image) > 68kb
then schedule_for_compression($image)
and that way you set up parameters for what is acceptable as an upper limit of file size. If the dimensions match, and the filesize is bigger, then its not optimised.
But without knowing more details what exactly is understood about optimising, this is the only thing I can think of.
If you are using a low number of images to compress, you might find an external service, such as: https://tinypng.com/developers might be of assistance.
I've used their on-line tools for reducing filesize on both JPG and PNG file manually but they do appaear to offer a free API service for the first 500 images per month.
Apologies if this would be better as a comment than an answer, I'm fairly new to stackoverflow and haven't got enough points yet, but felt this may be a handy alternative solution.
Saving a JPEG with the same or higher quality setting will not result in a noticeable loss in quality. Just re-save with your desired quality setting. If the file ends up larger, just discard it and keep the original. Remove metadata using jpegran or jpegoptim before you optimize so it doesn't affect the file size when you compare to the original.
PNG and GIF wont't lose any quality unless you reduce the number of colors. Just use one of the optimizers Gyncoca mentioned.
I am working at the moment on an issue where we are seeing CPU Usage issues on a particular host when converting images using iMagick. The issue is pretty perfectly described here:
https://github.com/ResponsiveImagesCG/wp-tevko-responsive-images/issues/150 (I don't use that particular library, but I DO use the same responsive images classes they do, and I am timing out on that particular line, only for some images).
They seem to suggest that removing the call to ->posterizeImage() will fix their issue, and in my tests it does, I can't even tell any difference in the converted images. But this worries me because I wonder if there is a difference that I am not seeing, or one that only comes up in certain scenarios (I mean if posterizing an image didn't do anything there wouldn't be a method for it, right?). I see online that it 'Reduces the image to a limited number of color level' (136 levels in the case causing an issue for me, for what it's worth). I'm having some difficulty parsing that though, which I think is related to a poor grasp of the way various image formats store data (really it doesn't go past the idea that an image is broken up into pixels, which are broken up into proportions of red green and blue).
What actual visual differences could I expect to see if we stop posterizing images? Is it something that I would only expect in certain types of image (like, would it be more visible in transparent over non-transparent, or warmer coloured images)? Or that would be more evident in certain display styles (like print, or the warmer colour temp in iPhone displays)?
Basically I am looking for the info to make an informed choice on whether it's safe to comment out. I'm not worried if it means some images might be x Kb larger, but if it will make them look poor quality, or distort them in some way (even in corner cases) then I need to consider other options.
From the ImageMagick command line documentation:
-posterize levels
reduce the image to a limited number of color levels per channel.
Very low values of levels, e.g., 2, 3, 4, have the most visible effect.
There is a bit more info in the Color Quantization examples - it also has some example images:
The operators original purpose (using an argument of '2') is to re-color images using just 8 basic colors, as if the image was generated using a simple and cheap poster printing method using just the basic colors. Thus the operator gets its name.
...
An argument of '3' will map image colors based on a colormap of 27 colors, including mid-tone colors. While an argument of '4' will generate a 64 color colortable, and '5' generates a 125 color colormap.
Essentially it reduces the number of colors used in the image - and by extension the size. Using a level of 136 would not have much visible affect, as this translates to a 2,515,456 color colortable (136^3).
It is also worth noting from the commit for the issue you linked is that this isn't even always an effective way of reducing image size:
... it turns out that posterization only improves file sizes
for PNGs and can actually lead to slightly larger file sizes for
JPG images.
Posterisation is a reduction of the amount of colour information stored in an image - as such, it is really a decrease in quality. It's hard to imagine how stopping doing this could be detrimental. And, if it turns out later that there is/was a legitimate reason for doing it, you can always do it later because if you stop doing it now, you will still have all the original information.
If it was the other way around, and you started to introduce posterisation and later found out it was undesirable for some reason, you would no longer be able to get the original information back.
So, I would see no harm in stopping posterising. And the fact that I have written that, kind of challenges anyone who knows better to speak up and tell me I am wrong :-)
I've been doing some speed optimization on my site using Page Speed and it gives recommendations like so:
Optimizing the following images could reduce their size by 35.3KiB (21% reduction).
Losslessly compressing http://example.com/.../some_image.jpg could save 25.3KiB (55% reduction).
How are the calculations done to get the file size reduction numbers? How can I determine if an image is optimized in PHP?
As I understand it, they seem to base this on the image quality (so saving at 60% in Photoshop or so is considered optimized?).
What I would like to do is once an image is uploaded, check if the image is fully optimized, if not, then optimize it using a PHP image library such as GD or ImageMagick. If I'm right about the number being based on quality, then I will just reduce the quality as needed.
How can I determine if an image is fully optimized in the standards that Page Speed uses?
Chances are they are simply using a standard compression or working on some very simple rules to calculate image compression/quality. It isn't exactly what you were after but what I often use on uploaded images etc etc dynamic content is a class called SimpleImage:
http://www.white-hat-web-design.co.uk/blog/resizing-images-with-php/
this will give you the options to resize & adjust compression, and I think even change image type (by which I mean .jpg to .png or .gif anything you like). I worked in seo and page optimization was a huge part of my Job I generally tried to make the images the size the needed to be no smaller or bigger. compress JS & CSS and that's really all most people need to worry about.
It looks like you could use the PageSpeed Insights API to get the compressions scores: https://developers.google.com/speed/docs/insights/v1/reference, though I'm guessing you'd want to run a quality check/compression locally, rather than sending everything through this API.
It also looks like they've got a standalone image optimizer available at http://code.google.com/p/page-speed/wiki/DownloadPageSpeed?tm=2, though this appears to be a Windows binary. They've got an SDK there as well, though I haven't looked into what it entails, or how easy it would be to integrate into an existing site.
I have one basic question. I have project where I need more sizes of one picture.
Yes... During uploading you make thumbnails... and so on... I know this story ... performance vs. storing possibilities.
So I save original img, a make 2 thumbnails copies for example max width 100px and maxwidht 200px with respect to ratio.
Now I need show image in 150px max width so I take saved img(200px) and .....
I use getimagesize() for calculating showing width and height respected to ratio,
or I set max-widht and max-height and I leave it for browser (browser make it for me),
or I set width a keep height: auto (but I want also limit max height)
So actualy I use php and getimagesize() but this function every time work with file and I am little scared. When you process 1 img it is OK but what about 20 or 100.
And... another idea, while uploading I save to DB also size information, for this I have to save data for 3 img (now only original one) this complicate everything.
So ... any ideas? What is your practice? THX.
Two images, at a maximum: A thumbnail, and the original image are sufficient. Make sure that your upload page is well-secured, because I've seen a website taken down through DoS (abusing an unprotected image-resizing page). Also limit the maximum upload size, to prevent abuse.
You can use the max-width and max-height CSS properties to limit the size of your images.
My approach
I wrote a pretty simple gallery application in php a while ago and this is how it works:
The images are stored in a folder with subfolders representing albums (and subalbums). They are uploaded via FTP and the webserver only has read-permissions on them.
For each image there are three versions:
a full one (the original)
a "mid" one (1024x768px max)
a "thumb" one (250x250px max)
All requests for images by the browser are served by php, and not-yet-existing versions are generated on the fly. The actual data is served through X-Sendfile, but that's an implementation detail.
I store the smaller versions in separate directories. When given a path to an original image, it is trivial to find the corresponding downscaled files (and check for existence and modification times).
Thoughts on your problem
Scaling images using HTML / CSS is considered bad practice for two simple reasons: if you are scaling up, you have a blurred image. If you are scaling down, you waste bandwidth and make your page slower for no good reason. So don't do it.
It should be possible to determine a pretty small set of required versions of each file (for example those used in a layout as in my case). Depending on the size and requirements of your project there are a few possibilities for creating those versions:
on the fly: generate / update them, when they are requested
during upload: have the routine that is called during the upload-process do the work
in the background: have the upload-routine add a job to a queue that is worked on in the background (probably most scalable but also fairly complex to implement and deploy)
Scaling down large images is a pretty slow operation (taking a few seconds usually). You might want to throttle it somehow to prevent abuse / DoS. Also limit dimensions and file size. A 100 MP (or even bigger) plain white (or any color) JPG might be very small when compressed, but will use an awful lot of RAM during scaling. Also big PNGs take really long to decompress (and even more to compress).
For a small website it doesn't matter, which approach you choose. Something that works (even if it doesn't scale) will do. If you plan on getting a good amount of traffic and a steady stream of uploads, then choose wisely and benchmark carefully.
A certain site I know recently upgraded their bandwith from 2,5 TB monthly to 3,5 TB.
Reason is they went over the 2,5 limit recently. They're complaining they don't know how to get down the bandwidth usage.
One thing I haven't seen them consider is the fact that JPEG and other images that are displayed on the site(and it is an image-heavy site) can contain metadata. Where the picture was taken and such.
Fact of the matter is, this information is of no importance whatsoever on that site. It's not gonna be used, ever. Yet it's still adding to the bandwidth, since it increases the filesize of every images from a few bytes to a few kilobytes.
On a site that uses up more then 2,5 TB per month, stripping the several thousands images of their metadata will help decrease the bandwidth usage at least by a few Gigabytes per month I think, if not more.
So is there a way to do this in PHP? And also, for the allready existing files, does anybody know a good automatic metadata remover? I know of JPEG & PNG Stripper, but that's not very good... Might be usefull for initial cleaning though...
It's trivial with GD:
$img = imagecreatefromjpeg("myimg.jpg");
imagejpeg($img, "newimg.jpg", $quality);
imagedestroy($img);
This won't transfer EXIF data. Don't know how much bandwidth it will actually save, though, but you could use the code above to increase the compression of the images. That would save a lot of bandwidth, although it possibly won't be very popular.
I seriously doubt image metadata is the root of all evil here.
Some questions to take into consideration:
How is the webserver configured?
Does it issue http 304 responses properly?
Isn't there some kind of hand-made caching/streaming of data through php scripting that prevents said data from being cached by the browser? (in which case, url rewriting and http redirections should be considered).
Check out Smush.it! It will strip all un-necs info from an image. They have an API you can use to crunch the images.
Note: By Design, it may change the filetype on you. This is on purpose. If another filetype can display the same image with the same quality, with less bytes it will give you a new file.
I think you need to profile this. You might be right about it saving a few GB but thats relatively little on 2.5TB of bandwidth. You need real data about what is being served most and work on that. If you do find it is images that send your bandwidth usage so high you first should check your caching headers and 304 responses, you also might want to investigate using something like amazon S3 to serve your images. I have managed to reduce bandwidth costs a lot by doing this.
That said, if the EXIF data is really making that much of a difference then you can use the GD library to copy a jpeg image using the imagejpeg function. This won't copy EXIF data.
Emil H's probably addresses the question the best.
But I wanted to add that this will almost certainly not save you as much as you may think. This type of metadata takes up very little space; I would think that
Re-compressing the images to a smaller file size, and
Cropping or resizing to reduce the resolution of the images
are both going to have a much greater effect. With point one alone you could probably drop bandwidth 50% and with both, you could drop bandwidth 80% - that is if you are willing to sacrifice some image size.
If not, you could always have the default view at a smaller size, with an 'enlarge' link. Most people just browsing will see the smaller image, and only those who want the largest size will click to enlarge it, so you'll still get almost all the bandwidth saving. This is what Flickr does, for example.
Maybe some sort of hex data manipulation would help here. I'm facing the same problem and investigating on some sort of automated solution.
Just wondering if that can be done and if possible, I'll write a php class for this.
Might be smart to do all the image manipulation on the client side (using a java applet such as facebook does) and then when the image is compressed, resized and fully stripped of unnecessary pixels and content, it can be uploaded at it's optimal size, saving you bandwidth and server side performance! (at the cost of initial development)