title: How to scale PNG image until reaches the target file size
body: <p>As the title says I'm trying to resize a PNG image in order to reach a target file size (in terms of MegaBytes).<br />
  I searched a lot on SO and over the web, found a lot of codes but all of them are not taking in consideration the final file size.<br />
  I've arranged some code but trying to optimize performance.</p>
  <hr />
  <p>Example:</p>
  <ul>
  <li>Source image dimensions = 30 MB</li>
  <li>Target file output size = 5 MB</li>
  </ul>
  <p>Current flow:</p>
  <ul>
  <li>1 - Load the PNG image as <code>BufferedImage</code></li>
  <li>2 - Recursively use <code>Scalr.resize(...)</code> in order to resize the image
  <ul>
  <li>2.1 - For each step use <code>ImageIO.write</code> to store the compressed PNG on a temporary file</li>
  <li>2.2 - Check the size using <code>File.length</code>, if size on disk is &gt; 5 MB return to step 2</li>
  </ul>
  </li>
  <li>3 - Save the image using <code>ImageIO.write(...)</code></li>
  </ul>
  <p>This method works, fine-tuning some parameters (such as scale factor) I'm able to accomplish the task.</p>
  <p>I'm trying to understand if I can improve all by calculating/guessing the final file size without storing the image on a temporary file.<br />
  There is a <code>byte[]</code> obj stored into the <code>BufferedImage</code> obj that I can get using <code>BufferedImage.getData().getDataBuffer()</code> that represents the content of the image but obviously the size of this array is 2x o 3x bigger than the final size of the file because of the PNG compression algo.</p>
  <p>I've tried some formula in order to calculate the value, something like:
  <code>w * h * bitDepth * 8 / 1024 / 1024</code> but I'm sure that I'm loosing a lot of data and the accounts do not add up!</p>
  <hr />
  <p>At the moment I'm using mainly this code:</p>
  <pre class="lang-java prettyprint-override"><code>static void resize(BufferedImage image, String outPath, int scalingFactor) throws Exception {
      image = Scalr.resize(image, image.getWidth() - scalingFactor);
  
      // image.getData().getDataBuffer() - the byteArray containing image
  
      File tempFile = File.createTempFile(&quot;&quot; + System.currentTimeMillis(), &quot;.png&quot;);
      ImageIO.write(image, &quot;png&quot;, tempFile);
  
      System.out.println(&quot;Calculated size in bytes is: &quot; + tempFile.length() + &quot; - factor: &quot; + scalingFactor);
  
      // MAX_SIZE defined in bytes
      if (tempFile.length() &gt; MAX_SIZE) {
          // recursion starts here
          resize(image, outPath, chooseFactor(tempFile, 4));
      } else {
          // break the recursive cycle
          ImageIO.write(image, &quot;png&quot;, new File(outPath));
      }
  }
  
  static int chooseFactor(File image, int scale) {
      // MEGABYTE is 1024*1024
      double mbSize = (double) image.length() / MEGABYTE;
      return (int) ((mbSize / scale) * 100);
  }
  </code></pre>
  <hr />
  <p><strong>There is a way to calculate/guess the final file size starting from <code>BufferedImage</code> object?</strong></p>
  <p>Please tell me if I have made myself clear or can I give additional information.<br />
  Also recommend a more appropriate title for the question if you think it is not explanatory enough.</p>
  <p>Thanks.</p>