I'm trying to compress uploaded images down to a specific size of 200Kb. I don't want to compress them any more than they need to be and using lossless compression like PNG isn't enough. Simply setting it to imagejpeg($image, null, 40) creates different compressed sizes for different images. Is there a way to set the desired compression size in bytes or at least have some algorithm that can find out the compression output without looping through imagejpeg() from 100 to 0 quality?
            Asked
            
        
        
            Active
            
        
            Viewed 505 times
        
    0
            
            
        
        user9391457
        
- 21
 - 3
 
- 
                    You don't need to loop through all sizes from 100 to 0, you can use a binary search like this... https://stackoverflow.com/a/52281257/2836621 – Mark Setchell Jul 14 '19 at 21:27
 - 
                    Or you can *"shell out"* to **ImageMagick** and do this... https://stackoverflow.com/a/29549024/2836621 – Mark Setchell Jul 14 '19 at 21:29
 - 
                    You can probably use Imagick (the PHP binding to ImageMagick) and then use `$imagick->setOption('jpeg:extent', 200000);` – Mark Setchell Jul 14 '19 at 22:19
 
2 Answers
1
            
            
        I found a way to use ob to view the file size of the image before it is uploaded so I used it in a loop
// Get get new image data
    ob_start();
    // Build image with minimal campression
    imagejpeg($newImage, NULL, 100);
    // Get the size of the image file in bytes
    $size = ob_get_length();
    // Save new image into a variable
    $compressedImage = addslashes(ob_get_contents());
    // Clear memory
    ob_end_clean();
    // If image is larger than 200Kb
    if ($size > 200000) {
      // This variable will decrease by 2 every loop to try most combinations 
      // from least compressed to most compressed
      $compressionValue = 100;
      for ($i=0; $i < 50; $i++) {
        $compressionValue = $compressionValue - 2;
        ob_start();
        imagejpeg($newImage, NULL, $compressionValue);
        $size = ob_get_length();
        // Overwrite old compressed image with the new compressed image
        $compressedImage = addslashes(ob_get_contents());
        // Clear memory
        ob_end_clean();
        // If image is less than or equal to 200.5Kb stop the loop
        if ($size <= 200500) {
          break;
        }
      }
    }
This is incredibly well optimized on its own too. The whole process only takes a few milliseconds with a 1.5Mb starting image even when it is trying 50 combinations.
        user9391457
        
- 21
 - 3
 
0
            
            
        There really isn't any way to predict the level of compression beforehand. The effect of compression depends upon the image source. One of the problems is that there is a myriad of JPEG compression settings.
- The quantization tables (up to 3) with 64 different values.
 - Sub sampling.
 - Spectral selection in progressive scans.
 - Successive Approximation in progressive scans.
 - Optimize huffman tables.
 
So there are billions upon billions of parameters that you can set.
There are JPEG optimization applications out there that will look at the compressed data.
        user3344003
        
- 20,574
 - 3
 - 26
 - 62