As the title says I'm trying to resize a PNG image in order to reach a target file size (in terms of MegaBytes).
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.
I've arranged some code but trying to optimize performance.
Example:
- Source image dimensions = 30 MB
- Target file output size = 5 MB
Current flow:
- 1 - Load the PNG image as
BufferedImage - 2 - Recursively use
Scalr.resize(...)in order to resize the image- 2.1 - For each step use
ImageIO.writeto store the compressed PNG on a temporary file - 2.2 - Check the size using
File.length, if size on disk is > 5 MB return to step 2
- 2.1 - For each step use
- 3 - Save the image using
ImageIO.write(...)
This method works, fine-tuning some parameters (such as scale factor) I'm able to accomplish the task.
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.
There is a byte[] obj stored into the BufferedImage obj that I can get using BufferedImage.getData().getDataBuffer() 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.
I've tried some formula in order to calculate the value, something like:
w * h * bitDepth * 8 / 1024 / 1024 but I'm sure that I'm loosing a lot of data and the accounts do not add up!
At the moment I'm using mainly this 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("" + System.currentTimeMillis(), ".png");
ImageIO.write(image, "png", tempFile);
System.out.println("Calculated size in bytes is: " + tempFile.length() + " - factor: " + scalingFactor);
// MAX_SIZE defined in bytes
if (tempFile.length() > MAX_SIZE) {
// recursion starts here
resize(image, outPath, chooseFactor(tempFile, 4));
} else {
// break the recursive cycle
ImageIO.write(image, "png", 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);
}
There is a way to calculate/guess the final file size starting from BufferedImage object?
Please tell me if I have made myself clear or can I give additional information.
Also recommend a more appropriate title for the question if you think it is not explanatory enough.
Thanks.