2

I have a php script where the user can upload images. I want to make the script lower the image quality (jpeg) if the file size is bigger than 'X' kbytes.

Something like this:

if( $_FILES['uploaded_img']['size'] > $file_size_limit ){
     // code that lowers the quality of the uploaded image but keeps the image width and height
}

What is the best approach for this?

ps: I don't want to change image width and height.

user1091856
  • 3,032
  • 6
  • 31
  • 42
  • Read up on the image functions: http://php.net/manual/en/ref.image.php You could use `imagejpeg` to save the image in another quality, but you wouldn't know the original quality though. – Cyclonecode Sep 24 '12 at 00:04
  • yeah, i figured i couldn't tell the image quality. That's why I will only run this code when the file size exceeds a certain limit. – user1091856 Sep 24 '12 at 00:06

2 Answers2

4

Sure you can. Do something like this.

$upload = $_FILES['uploaded_img'];
$uploadPath = 'new/path/for/upload/';
$uploadName = pathinfo($upload['name'], PATHINFO_FILENAME);
$restrainedQuality = 75; //0 = lowest, 100 = highest. ~75 = default
$sizeLimit = 2000;

if($upload['size'] > $sizeLimit) {
    //open a stream for the uploaded image
    $streamHandle = @fopen($upload['tmp_name'], 'r');
    //create a image resource from the contents of the uploaded image
    $resource = imagecreatefromstring(stream_get_contents($streamHandle));

    if(!$resource)
        die('Something wrong with the upload!');

    //close our file stream
    @fclose($streamHandle);

    //move the uploaded file with a lesser quality
    imagejpeg($resource, $uploadPath . $uploadName . '.jpg', $restrainedQuality); 
    //delete the temporary upload
    @unlink($upload['tmp_name']);
} else {
    //the file size is less than the limit, just move the temp file into its appropriate directory
    move_uploaded_file($upload['tmp_name'], $uploadPath . $upload['name']);
}

This will accept any image format supported by PHP GD (Assuming that it's installed on your server. Most likely is). If the image is less than the limit, it will just upload the original image to the path you specify.

Austin Brunkhorst
  • 20,704
  • 6
  • 47
  • 61
  • WOW never thought this could be so simple in PHP. Thanks. – user1091856 Sep 24 '12 at 01:02
  • I know this isn't directly related to my question, but is it necessary to 'unlink' the temporary file??? Wont the server do it automatically for me? – user1091856 Sep 24 '12 at 01:47
  • Yes, the server will do it automatically. But why have two instances of the image on the server at once when you have the option to that script execution? – Austin Brunkhorst Sep 24 '12 at 02:07
  • This script seems OK except that it doesn't address the problem it tries to solve. The original may be too big simply because the image is large, in which case the resampling doesn't solve the problem and may even worsen it. In the very least, after the resampling, the new byte size should be compared to the original, and only used if it is better. – entonio Jan 08 '14 at 23:31
4

Your basic approach (which is implemented in Austin's answer) will work some of the time, but it's important to keep in mind that quality != file size. While they are generally correlated, it is perfectly possible (even common) that reducing the quality of a jpeg file will actually result in a LARGER file. This is because any JPEG uploaded to your system has already been run through the JPEG compression formula (often with a quality of 79 or 80). Depending on the original image, this process will create artifacts/alter the resulting image. When you run this already optimized image through the jpeg compression algorithm a second time it doesn't "know" what the original image looked like... so it treats the incoming jpeg as if it's a brand new lossless file and tries to copy it as closely as possible... including any artifacts created in the original process. Couple this with the fact that the original jpeg compression already took advantage of most of the "easy" compression tricks, it ends up being quite likely that compressing a second time results in a crappier looking image (copy of a copy problem) but not smaller file.

I did a few tests to see where the cutoff was, and unsurprisingly if the original image had a low compression ratio (q=99) a lot of space was saved re-compressing to q=75. If the original was compressed at q=75 (pretty common for graphic program defaults) then the secondary q=75 compression looked worse but resulted in virtually the same file-size as the original. If the original had a lower compression level (q=50) then the secondary q=75 compression resulted in a significantly larger file (for these tests I used three complex photos... obviously images with specific palates/compositions will have different performances going through these compressions). Note: I'm using Fireworks cs4 for this test... I realize that these quality indicators have no standardization between platforms

As noted in the comments below, moving from file formats like PNG to JPEG will usually end up significantly smaller (though without any transparency), but from JPEG -> JPEG (or GIF->JPEG, especially for simple or small-palate images) will often not help.

Regardless, you can still try using the compression method described by Austin, but make sure you compare the file-sizes of the two images when you're done. If there is only a small incremental gain or the new file is larger, then default back to the original image.

Community
  • 1
  • 1
Ben D
  • 14,321
  • 3
  • 45
  • 59
  • Well, my only objective here is to prevent the user from uploading heavy image files, and this is the only solution I found for this so far – user1091856 Sep 24 '12 at 01:11
  • You are right about instances of JPEGs, but converting a png -> jpg will generally yield a lot of difference in size. – Austin Brunkhorst Sep 24 '12 at 01:13
  • True. Not only that but I tried using this code with a png that has transparent background, the new jpeg came all messed up. But yet this is still better than simply telling the user they will have to compress the image and not doing anything. – user1091856 Sep 24 '12 at 01:15
  • 1
    Yeah, jpegs can't support transparency, but moving from PNG->jpeg will generally result in savings... Just make sure that you're checking the compressed result to make sure it gives you significant enough savings to justify the lossiness. – Ben D Sep 24 '12 at 01:19