Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Bitmap compressed with quality=100 bigger file size than original

I am trying to send an image to a server. Before sending it, I am reducing its size and quality, and then fixing any rotation issue. My problem is that, after rotating the image, when I save it, the file is bigger than before. Before rotation size was 10092 and after rotation is 54226

// Scale image to reduce it
Bitmap reducedImage = reduceImage(tempPhotoPath);

// Decrease photo quality
FileOutputStream fos = new FileOutputStream(tempPhotoFile);
reducedImage.compress(CompressFormat.JPEG, 55, fos);
fos.flush();
fos.close();

// Check and fix rotation issues
Bitmap fixed = fixRotation(tempPhotoPath);
if(fixed!=null)
{
    FileOutputStream fos2 = new FileOutputStream(tempPhotoFile);
    fixed.compress(CompressFormat.JPEG, 100, fos2);
    fos2.flush();
    fos2.close();
}

public Bitmap reduceImage(String originalPath)
{
    // Decode image size
    BitmapFactory.Options o = new BitmapFactory.Options();
    o.inJustDecodeBounds = true;
    o.inPurgeable = true;
    o.inInputShareable = true;
    BitmapFactory.decodeFile(originalPath, o);

    // The new size we want to scale to
    final int REQUIRED_SIZE = 320;

    // Find the correct scale value. It should be the power of 2.
    int width_tmp = o.outWidth, height_tmp = o.outHeight;
    int scale = 1;
    while (true) {
        if (width_tmp / 2 < REQUIRED_SIZE || height_tmp / 2 < REQUIRED_SIZE) {
            break;
        }
        width_tmp /= 2;
        height_tmp /= 2;
        scale *= 2;
    }

    // Decode with inSampleSize
    BitmapFactory.Options o2 = new BitmapFactory.Options();
    o2.inPurgeable = true;
    o2.inInputShareable = true;
    o2.inSampleSize = scale;
    Bitmap bitmapScaled = null;
    bitmapScaled = BitmapFactory.decodeFile(originalPath, o2);

    return bitmapScaled;
}

public Bitmap fixRotation(String path)
{
    Bitmap b = null;
    try
    {
        //Find if the picture is rotated
        ExifInterface exif = new ExifInterface(path);
        int degrees = 0;
        if(exif.getAttribute(ExifInterface.TAG_ORIENTATION).equalsIgnoreCase("6"))
            degrees = 90;
        else if(exif.getAttribute(ExifInterface.TAG_ORIENTATION).equalsIgnoreCase("8"))
            degrees = 270;
        else if(exif.getAttribute(ExifInterface.TAG_ORIENTATION).equalsIgnoreCase("3"))
            degrees = 180;

        if(degrees > 0)
        {
            BitmapFactory.Options o = new BitmapFactory.Options();
            o.inPurgeable = true;
            o.inInputShareable = true;
            Bitmap bitmap = BitmapFactory.decodeFile(path, o);

            int w = bitmap.getWidth();
            int h = bitmap.getHeight();

            Matrix mtx = new Matrix();
            mtx.postRotate(degrees);

            b = Bitmap.createBitmap(bitmap, 0, 0, w, h, mtx, true);
        }
    }
    catch(Exception e){e.printStackTrace();}

    return b;
}
like image 876
Pablo Moncunill Avatar asked Mar 04 '13 13:03

Pablo Moncunill


1 Answers

You're compressing it with different quality measures. After rotation, you're using quality 100, so it's going to be a larger file than the previous one, with quality 55.

When you compress an image, it doesn't matter what the current file size/quality is. That has no real impact on the outcome. Compressing at 55 quality, followed by 100 quality, does not result in a file with the same size as a simple 55 quality compression. It results in a file with the size of 100 quality compression, because that's the last thing done to it.


For your specific code, I'm not sure I see the reason behind compressing it twice anyway. Compression(file size) isn't what was causing your OOM problems when rotating, the image dimensions were most likely the culprit. Shrinking the image before rotating should fix that, no need for saving a temp file.

All you need to do is run reduceImage(), then follow it up with fixRotation(). Fix your rotation method so that it accepts a Bitmap instead of a path, so you don't need to save the file in between. Finally, save/compress it at whatever quality you desire.

If you do need the temp file for some reason, use PNG for the first compression. This way it's lossless, so when you recompress the final image, you won't have used JPG(lossy) twice at a low quality.

like image 138
Geobits Avatar answered Nov 12 '22 00:11

Geobits