Reputation: 1605
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);
}
Upvotes: 16
Views: 24451
Reputation: 3833
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;
Upvotes: 52
Reputation: 13855
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
Upvotes: 1
Reputation: 157457
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)
Upvotes: 1