Search code examples
androidimageimage-scaling

Scale image on android file to file


I'm trying to scale image down before sending them to the back-end in my android app. Currently I'm doing this with BitmapFactory.decodeFile() and inJustDecodeBounds option. but it skips sensor information and as a result I'm getting rotated image. I'm fixing it by setting transformation matrix. Here is my code:

        File image = new File(uri.getPath());

        int angle = 0;
        ExifInterface exif = null;
        try {
            exif = new ExifInterface(image.getPath());
            int orientation = exif.getAttributeInt(TAG_ORIENTATION, ORIENTATION_NORMAL);

            switch (orientation) {
                case ORIENTATION_ROTATE_90:
                    angle = 90;
                    break;

                case ORIENTATION_ROTATE_180:
                    angle = 180;
                    break;
                case ORIENTATION_ROTATE_270:
                    angle = 270;
                    break;
            }
        } catch (IOException e) {
            if (DEBUG) e.printStackTrace();
        }

        Matrix mat = new Matrix();
        mat.postRotate(angle);

        final BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(image.getAbsolutePath(), options);

        options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);

        options.inJustDecodeBounds = false;
        Bitmap bitmap = BitmapFactory.decodeFile(image.getAbsolutePath(), options);

        if (angle != 0) {
            bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), mat, true);
        }

        if (DEBUG) {
            Log.d("COMPRESS", "scaled bitmap size: " + bitmap.getWidth() + "x" + bitmap.getHeight());
        }
        ByteArrayOutputStream buffer = new ByteArrayOutputStream();
        bitmap.compress(Bitmap.CompressFormat.JPEG, 40, buffer);
        bitmap.recycle();
        return buffer.toByteArray();

But this approach leads to OOM exceptions as it do everything in the memory and each non 0 degree image is loaded to memory twice.

Much better approach could be a direct scaling with saving sensor and other metadata information directly to file. I tried ffmpeg libarary for this but it is hanging.

I tried to google some other library but for all my requests it gives me an answers how to scale image in ImageView, Canvas etc.

So is there any other way to scale image on android in efficient way ? Thanks.


Solution

  • I would use Picasso: http://square.github.io/picasso/ as it is able to handle orientation, resizing, and out of memory in one nice fluent API.

    Bitmap smaller = Picasso.with(context)
       .load(new File(uri.getPath()))
       .resize(800, 800) // this is max size
       .centerInside()
       .get();
    
    ... carry on with compress code
    

    https://github.com/square/picasso/issues/226