My requirement is to upload camera captured image to the server, but it should be less than 500 KB. In case, if it is greater than 500 KB, it needs to be reduced to the size less than 500 KB (but somewhat closer to it)
For this, I am using the following code -
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
try {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == getActivity().RESULT_OK) {
if (requestCode == REQUEST_CODE_CAMERA) {
try {
photo = MediaStore.Images.Media.getBitmap(
ctx.getContentResolver(), capturedImageUri);
String selectedImagePath = getRealPathFromURI(capturedImageUri);
img_file = new File(selectedImagePath);
Log.d("img_file_size", "file size in KBs (initially): " + (img_file.length()/1000));
if(CommonUtilities.isImageFileSizeGreaterThan500KB(img_file)) {
photo = CommonUtilities.getResizedBitmapLessThan500KB(photo, 500);
}
photo = CommonUtilities.getCorrectBitmap(photo, selectedImagePath);
// // CALL THIS METHOD TO GET THE URI FROM THE BITMAP
img_file = new File(ctx.getCacheDir(), "image.jpg");
img_file.createNewFile();
//Convert bitmap to byte array
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
photo.compress(Bitmap.CompressFormat.JPEG, 100, bytes);
//write the bytes in file
FileOutputStream fo = new FileOutputStream(img_file);
fo.write(bytes.toByteArray());
// remember close de FileOutput
fo.close();
Log.d("img_file_size", "file size in KBs after image manipulations: " + (img_file.length()/1000));
} catch (Exception e) {
Logs.setLogException(class_name, "onActivityResult(), when captured from camera", e);
}
}
}
} catch (Exception e) {
Logs.setLogException(class_name, "onActivityResult()", e);
} catch (OutOfMemoryError e) {
Logs.setLogError(class_name, "onActivityResult()", e);
}
}
And
public static Bitmap getResizedBitmapLessThan500KB(Bitmap image, int maxSize) {
int width = image.getWidth();
int height = image.getHeight();
float bitmapRatio = (float)width / (float) height;
if (bitmapRatio > 0) {
width = maxSize;
height = (int) (width / bitmapRatio);
} else {
height = maxSize;
width = (int) (height * bitmapRatio);
}
Bitmap reduced_bitmap = Bitmap.createScaledBitmap(image, width, height, true);
if(sizeOf(reduced_bitmap) > (500 * 1000)) {
return getResizedBitmap(reduced_bitmap, maxSize);
} else {
return reduced_bitmap;
}
}
To rotate the image, if needed.
public static Bitmap getCorrectBitmap(Bitmap bitmap, String filePath) {
ExifInterface ei;
Bitmap rotatedBitmap = bitmap;
try {
ei = new ExifInterface(filePath);
int orientation = ei.getAttributeInt(ExifInterface.TAG_ORIENTATION,
ExifInterface.ORIENTATION_NORMAL);
Matrix matrix = new Matrix();
switch (orientation) {
case ExifInterface.ORIENTATION_ROTATE_90:
matrix.postRotate(90);
break;
case ExifInterface.ORIENTATION_ROTATE_180:
matrix.postRotate(180);
break;
case ExifInterface.ORIENTATION_ROTATE_270:
matrix.postRotate(270);
break;
}
rotatedBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return rotatedBitmap;
}
Here is the output of the image file size initially and after all the operations to reduce file size.
img_file_size﹕ file size in KBs (initially): 3294
img_file_size﹕ file size in KBs after image manipulations: 235
See the difference above (in the output). The initial file size without those operations, and after those compression and other operations. I need that size to be somewhat closer to 500 kb.
The above code is working somewhat fine for me, as it is reducing the image file size to make it less than 500 KB.
But, the following are the issues with the above code -
This code is reducing the file size even if its less than 500 KB
In case it is more than 500 KB, the reduced file size becomes too less from 500 KB, , though I need it somewhat closer.
I need to get rid off above 2 issues. So, need to know what should I manipulate in the above code.
As I also want to correct the EXIF-orientation (rotated images), along with my above mentioned requirement.
Another issue you have is that you're measuring the size of the bitmap (which isn't compressed), and then converting it to JPG and measuring that. The JPG is probably always going to be smaller, and how well it compresses is going to be a factor of what the image is. Lots of big areas of the same color? Great! An extremely "busy" pattern? Compression won't be as great.
OK, so further clarification:
If you're targeting a certain file size, you can't do that by looking at the size BEFORE compression. You could get a general idea (e.g. JPEG compresses by a factor of ~15 for these photos), so then you could target 500k * 15 for the bitmap. But depending on what's in the photo, you might not hit that target exactly. So you probably want to do this:
You could have some steps on #5 to figure out how close you were and try to take that into account.
Please check if this code is helpful:
you can try this method
its helpful for you.
You can check size before resizing it. If the bitmap is larger than 500kb in size then resize it .
Also for making larger bitmap nearer to 500kb size, check the difference between size and compress accordingly .
and in resize Bitmap calculate the difference in size and compress accordingly
I assume you want to use the gallery or system camera to get the image. Please note that there is a upper limit bound for the maximum data transferred via
Intent
and that's why you always get downsized version of images.You can refer to https://developer.android.com/training/camera/photobasics.html for the standard solution. In summary, you should acquire the access to external storage and generate an
URI
for camera or get theURI
from gallery app. Then use theContentResolver
to get the image.You may want to implement content resolver for other application to access your data and that's the standard practice.
This is not the solution for your problem but the bug why you get very small files.
In
getResizedBitmapLessThan500KB(photo, 500)
the 500 is the max with/height in pixel of the image not the max size in kb.So all compressed files are less 500x500 pixels