16

I need to send an image from a file to a server. The server request the image in a resolution of 2400x2400.

What I'm trying to do is:

1) Get a Bitmap using BitmapFactory.decodeFile using the correct inSampleSize.

2) Compress the image in JPEG with a quality of 40%

3) Encode the image in base64

4) Sent to the server

I cannot achieve the first step, it throws an out of memory exception. I'm sure the inSampleSize is correct but I suppose even with inSampleSize the Bitmap is huge (around 30 MB in DDMS).

Any ideas how can do it? Can I do these steps without created a bitmap object? I mean doing it on filesystem instead of RAM memory.

This is the current code:

// The following function calculate the correct inSampleSize
Bitmap image = Util.decodeSampledBitmapFromFile(imagePath, width,height);   
// compressing the image
ByteArrayOutputStream baos = new ByteArrayOutputStream();
image.compress(Bitmap.CompressFormat.JPEG, 40, baos);
// encode image
String encodedImage = Base64.encodeToString(baos.toByteArray(),Base64.DEFAULT));


public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
    // Raw height and width of image
    final int height = options.outHeight;
    final int width = options.outWidth;
    int inSampleSize = 1;

    if (height > reqHeight || width > reqWidth) {

        // Calculate ratios of height and width to requested height and width
        final int heightRatio = Math.round((float) height / (float) reqHeight);
        final int widthRatio = Math.round((float) width / (float) reqWidth);

        // Choose the smallest ratio as inSampleSize value, this will guarantee
        // a final image with both dimensions larger than or equal to the
        // requested height and width.
        inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
    }

    return inSampleSize;
}

public static Bitmap decodeSampledBitmapFromFile(String path,int reqWidth, int reqHeight) {

    // First decode with inJustDecodeBounds=true to check dimensions
    final BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeFile(path, options);

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

    // Decode bitmap with inSampleSize set
    options.inJustDecodeBounds = false;
    return BitmapFactory.decodeFile(path,options);
}
alasarr
  • 1,565
  • 3
  • 16
  • 32

3 Answers3

52

you can skip ARGB_8888, and use RGB_565 instead, and then dither then images to preserve good quality

 BitmapFactory.Options options = new BitmapFactory.Options();
 options.inJustDecodeBounds = false;
 options.inPreferredConfig = Config.RGB_565;
 options.inDither = true;
Nicholas Ng
  • 1,428
  • 18
  • 23
Björn Hallström
  • 3,775
  • 9
  • 39
  • 50
1

you have to use BitmapFactory.Options with inJustDecodeBounds set to true. This way you can load information about the bitmap and calculate the value for downsampling it (inSampleSize for instance)

Blackbelt
  • 156,034
  • 29
  • 297
  • 305
1

Do NOT load the image as a bitmap, convert it to an array, then send it.

instead:

Read it as a file, in JPG format. Use the files byte array, to encode it, and send the file across.

Loading it to bitmap, is going to cause huge memory issues unnecessarily. An image, reperesented in Bitmap format, will take ~20x or more memory than neccessary.

On the server side, you will need to treat it as a file too. rather than a bitmap.

Here is a link to loading a file to byte[] : Elegant way to read file into byte[] array in Java

Community
  • 1
  • 1
IAmGroot
  • 13,760
  • 18
  • 84
  • 154
  • I need a Bitmap, because I need to resize it and compress it. The original image size is 12MB and I'd like sent to the server around 700KB not the 12MB of the original image. – alasarr Oct 30 '13 at 09:59
  • @alasarr Ah my mistake. you must be sampling it wrong. See http://developer.android.com/training/displaying-bitmaps/load-bitmap.html – IAmGroot Oct 30 '13 at 10:01
  • @alasarr Just so you are aware. A `2400x2400` image, in bitmap format, using `2 bytes` per pixel, is `11MB` in size. regardless of whether the jpg format is `700KB`. Or in `4 byte` representation is `22MB` – IAmGroot Oct 30 '13 at 10:03