Crop image in Android using perfect aspect ratio - java

I have been working on an android application. There is feature in my application which requires an image with exact dimensions of device screen, for which i am using this code,
Intent cropIntent = new Intent("com.android.camera.action.CROP");
cropIntent.setDataAndType(picUri, "image/*");
cropIntent.putExtra("crop", "true");
cropIntent.putExtra("aspectX", 0);
cropIntent.putExtra("aspectY", 0);
cropIntent.putExtra("outputX", width);
cropIntent.putExtra("outputY", height);
cropIntent.putExtra("return-data", true);
but the problem with this code is that since aspect ratio has been set to zero, in some devices like samsung, the crop window is in square size and cannot be adjusted. So how could i set the aspect ratio in aspectX as well as aspectY field so that there is no problem in image cropping,
I have also written a java progrem to calculate aspect ratio but it doesnt seem to work nice with all resolutions.
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
class AspectRatio
{ public static void main(String args[])
{ BufferedReader buff=new BufferedReader(new InputStreamReader(System.in));
int width=0,height=0;
try
{ System.out.print("Enter the width of the screen:");
width=Integer.parseInt(buff.readLine());
System.out.println("Enter the height of the screen:");
height=Integer.parseInt(buff.readLine());
}
catch(IOException e)
{ e.printStackTrace();
}
int factor=0;
for(int i=2;i<new AspectRatio().minimum(width,height)/2;i++)
{ if(width%i==0&&height%1==0)
{ factor=i;
}
}
System.out.println("The aspect ratio is:"+width/factor+":"+height/factor);
}
public int minimum(int a,int b)
{ return (a<b?a:b);
}
}

you can get the Width and Height from the System using the next Class :
DisplayMetrics
check the link it will also give the example how to use this class..

this is my helper class to reduce any image with perfect ratio and it works with image taken from camera and img on the device:
public class ImageUtils {
private static final String TAG = "ImageUtils";
private static final float maxHeight = 1280.0f;
private static final float maxWidth = 1280.0f;
public static byte[] compressImage(String imagePath) {
Bitmap scaledBitmap = null;
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
Bitmap bmp = BitmapFactory.decodeFile(imagePath, options);
int actualHeight = options.outHeight;
int actualWidth = options.outWidth;
float imgRatio = (float) actualWidth / (float) actualHeight;
float maxRatio = maxWidth / maxHeight;
if (actualHeight > maxHeight || actualWidth > maxWidth) {
if (imgRatio < maxRatio) {
imgRatio = maxHeight / actualHeight;
actualWidth = (int) (imgRatio * actualWidth);
actualHeight = (int) maxHeight;
} else if (imgRatio > maxRatio) {
imgRatio = maxWidth / actualWidth;
actualHeight = (int) (imgRatio * actualHeight);
actualWidth = (int) maxWidth;
} else {
actualHeight = (int) maxHeight;
actualWidth = (int) maxWidth;
}
}
options.inSampleSize = ImageUtils.calculateInSampleSize(options, actualWidth, actualHeight);
options.inJustDecodeBounds = false;
options.inDither = false;
options.inPurgeable = true;
options.inInputShareable = true;
options.inTempStorage = new byte[16 * 1024];
try {
bmp = BitmapFactory.decodeFile(imagePath, options);
} catch (OutOfMemoryError exception) {
exception.printStackTrace();
}
try {
scaledBitmap = Bitmap.createBitmap(actualWidth, actualHeight, Bitmap.Config.ARGB_8888);
} catch (OutOfMemoryError exception) {
exception.printStackTrace();
}
float ratioX = actualWidth / (float) options.outWidth;
float ratioY = actualHeight / (float) options.outHeight;
float middleX = actualWidth / 2.0f;
float middleY = actualHeight / 2.0f;
Matrix scaleMatrix = new Matrix();
scaleMatrix.setScale(ratioX, ratioY, middleX, middleY);
Canvas canvas = new Canvas(scaledBitmap);
canvas.setMatrix(scaleMatrix);
canvas.drawBitmap(bmp, middleX - bmp.getWidth() / 2, middleY - bmp.getHeight() / 2, new Paint(Paint.FILTER_BITMAP_FLAG));
ExifInterface exif;
try {
exif = new ExifInterface(imagePath);
int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 0);
Matrix matrix = new Matrix();
if (orientation == 6) {
matrix.postRotate(90);
} else if (orientation == 3) {
matrix.postRotate(180);
} else if (orientation == 8) {
matrix.postRotate(270);
}
scaledBitmap = Bitmap.createBitmap(scaledBitmap, 0, 0, scaledBitmap.getWidth(), scaledBitmap.getHeight(), matrix, true);
} catch (IOException e) {
e.printStackTrace();
}
ByteArrayOutputStream out = new ByteArrayOutputStream();
scaledBitmap.compress(Bitmap.CompressFormat.JPEG, 85, out);
return out.toByteArray();
}
public static boolean compressImage(Bitmap image, FileOutputStream fos){
Bitmap scaledBitmap = null;
int actualHeight = image.getHeight();
int actualWidth = image.getWidth();
float imgRatio = (float) actualWidth / (float) actualHeight;
float maxRatio = maxWidth / maxHeight;
if (actualHeight > maxHeight || actualWidth > maxWidth) {
if (imgRatio < maxRatio) {
imgRatio = maxHeight / actualHeight;
actualWidth = (int) (imgRatio * actualWidth);
actualHeight = (int) maxHeight;
} else if (imgRatio > maxRatio) {
imgRatio = maxWidth / actualWidth;
actualHeight = (int) (imgRatio * actualHeight);
actualWidth = (int) maxWidth;
} else {
actualHeight = (int) maxHeight;
actualWidth = (int) maxWidth;
}
}
Log.d(TAG, "ActualHeight " + actualHeight);
Log.d(TAG, "ActualHidht " + actualWidth);
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = ImageUtils.calculateInSampleSize(options, actualWidth, actualHeight);
options.inJustDecodeBounds = false;
options.inDither = false;
options.inPurgeable = true;
options.inInputShareable = true;
options.inTempStorage = new byte[16 * 1024];
Bitmap bmp = null;
try {
// int bytes = byteSizeOf(image);
// //or we can calculate bytes this way. Use a different value than 4 if you don't use 32bit images.
// //int bytes = b.getWidth()*b.getHeight()*4;
// ByteBuffer buffer = ByteBuffer.allocate(bytes); //Create a new buffer
// image.copyPixelsToBuffer(buffer); //Move the byte data to the buffer
// byte[] array = buffer.array(); //Get the underlying array containing the data.
// bmp = BitmapFactory.decodeByteArray(array, 0, array.length, options);
ByteArrayOutputStream blob = new ByteArrayOutputStream();
image.compress(Bitmap.CompressFormat.PNG, 0 /*ignored for PNG*/, blob);
byte[] bitmapdata = blob.toByteArray();
bmp = BitmapFactory.decodeByteArray(bitmapdata , 0, bitmapdata.length);
} catch (OutOfMemoryError exception) {
exception.printStackTrace();
}
try {
scaledBitmap = Bitmap.createBitmap(actualWidth, actualHeight, Bitmap.Config.ARGB_8888);
} catch (OutOfMemoryError exception) {
exception.printStackTrace();
}
float ratioX = actualWidth / (float) options.outWidth;
float ratioY = actualHeight / (float) options.outHeight;
float middleX = actualWidth / 2.0f;
float middleY = actualHeight / 2.0f;
Matrix scaleMatrix = new Matrix();
scaleMatrix.setScale(ratioX, ratioY, middleX, middleY);
Canvas canvas = new Canvas(scaledBitmap);
canvas.setMatrix(scaleMatrix);
canvas.drawBitmap(bmp, middleX - bmp.getWidth() / 2, middleY - bmp.getHeight() / 2, new Paint(Paint.FILTER_BITMAP_FLAG));
// ExifInterface exif;
// try {
//// exif = new ExifInterface(imagePath);
//// int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 0);
//// Matrix matrix = new Matrix();
//// if (orientation == 6) {
//// matrix.postRotate(90);
//// } else if (orientation == 3) {
//// matrix.postRotate(180);
//// } else if (orientation == 8) {
//// matrix.postRotate(270);
//// }
//
// } catch (IOException e) {
// e.printStackTrace();
// }
scaledBitmap = Bitmap.createBitmap(scaledBitmap, 0, 0, scaledBitmap.getWidth(), scaledBitmap.getHeight(), null, true);
scaledBitmap.compress(Bitmap.CompressFormat.JPEG, 85, fos);
return true;
}
public static void compressImage(String imagePath, FileOutputStream fos) {
Bitmap scaledBitmap = null;
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
Bitmap bmp = BitmapFactory.decodeFile(imagePath, options);
int actualHeight = options.outHeight;
int actualWidth = options.outWidth;
float imgRatio = (float) actualWidth / (float) actualHeight;
float maxRatio = maxWidth / maxHeight;
if (actualHeight > maxHeight || actualWidth > maxWidth) {
if (imgRatio < maxRatio) {
imgRatio = maxHeight / actualHeight;
actualWidth = (int) (imgRatio * actualWidth);
actualHeight = (int) maxHeight;
} else if (imgRatio > maxRatio) {
imgRatio = maxWidth / actualWidth;
actualHeight = (int) (imgRatio * actualHeight);
actualWidth = (int) maxWidth;
} else {
actualHeight = (int) maxHeight;
actualWidth = (int) maxWidth;
}
}
options.inSampleSize = ImageUtils.calculateInSampleSize(options, actualWidth, actualHeight);
options.inJustDecodeBounds = false;
options.inDither = false;
options.inPurgeable = true;
options.inInputShareable = true;
options.inTempStorage = new byte[16 * 1024];
try {
bmp = BitmapFactory.decodeFile(imagePath, options);
} catch (OutOfMemoryError exception) {
exception.printStackTrace();
}
try {
scaledBitmap = Bitmap.createBitmap(actualWidth, actualHeight, Bitmap.Config.ARGB_8888);
} catch (OutOfMemoryError exception) {
exception.printStackTrace();
}
float ratioX = actualWidth / (float) options.outWidth;
float ratioY = actualHeight / (float) options.outHeight;
float middleX = actualWidth / 2.0f;
float middleY = actualHeight / 2.0f;
Matrix scaleMatrix = new Matrix();
scaleMatrix.setScale(ratioX, ratioY, middleX, middleY);
Canvas canvas = new Canvas(scaledBitmap);
canvas.setMatrix(scaleMatrix);
canvas.drawBitmap(bmp, middleX - bmp.getWidth() / 2, middleY - bmp.getHeight() / 2, new Paint(Paint.FILTER_BITMAP_FLAG));
ExifInterface exif;
try {
exif = new ExifInterface(imagePath);
int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 0);
Matrix matrix = new Matrix();
if (orientation == 6) {
matrix.postRotate(90);
} else if (orientation == 3) {
matrix.postRotate(180);
} else if (orientation == 8) {
matrix.postRotate(270);
}
scaledBitmap = Bitmap.createBitmap(scaledBitmap, 0, 0, scaledBitmap.getWidth(), scaledBitmap.getHeight(), matrix, true);
} catch (IOException e) {
e.printStackTrace();
}
//ByteArrayOutputStream out = new ByteArrayOutputStream();
scaledBitmap.compress(Bitmap.CompressFormat.JPEG, 85, fos);
}
public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
final int heightRatio = Math.round((float) height / (float) reqHeight);
final int widthRatio = Math.round((float) width / (float) reqWidth);
inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
}
final float totalPixels = width * height;
final float totalReqPixelsCap = reqWidth * reqHeight * 2;
while (totalPixels / (inSampleSize * inSampleSize) > totalReqPixelsCap) {
inSampleSize++;
}
return inSampleSize;
}
static protected int byteSizeOf(Bitmap data) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB_MR1) {
return data.getRowBytes() * data.getHeight();
} else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
return data.getByteCount();
} else {
return data.getAllocationByteCount();
}
}
}
/**
* reduces the size of the image
* #param image
* #param maxSize
* #return
*/
public Bitmap getResizedBitmap(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);
}
return Bitmap.createScaledBitmap(image, width, height, true);
}
private void setVideoViewRatio(VideoView vv, int maxSize, int cWidth, int cHeight){
int width = cWidth;
int height = cHeight;
float ratio = (float)cWidth / (float) height;
if (ratio > 0) {
width = maxSize;
height = (int) (width / ratio);
} else {
height = maxSize;
width = (int) (height * ratio);
}
vv.setMinimumWidth(width);
vv.setMinimumHeight(height);
}

Related

Crash in gallery due to java.lang.RuntimeException: android.os.TransactionTooLargeException: data parcel size 539544 bytes

When I open gallery and select a image app get crash with the exception "java.lang.RuntimeException: android.os.TransactionTooLargeException: data parcel size 539544 bytes"
The code is as follow
Intent intent = new Intent(Intent.ACTION_PICK);
intent.setType("image/*");
startActivityForResult(intent, SELECT_PHOTO_FROM_GALLERY);
and in On activity result method
openDialog.dismiss();
try {
if (data == null || data.getData() == null) {
Toast.makeText(getContext(), "Error getting image.", Toast.LENGTH_SHORT).show();
return;
}
mUri = data.getData();
createFile(mUri, null);
} catch (Exception e) {
Log.e(TAG, "GALLERY EXCEPTION " + e.toString());
} catch (OutOfMemoryError E) {
Log.e(TAG, "GALLERY MEMORY EXCEPTION " + E.toString());
}
I am not using onSavedInstancestate(). and
I've reffered
What to do on TransactionTooLargeException
and
http://nemanjakovacevic.net/blog/english/2015/03/24/yet-another-post-on-serializable-vs-parcelable/
You need to resize your image size before set into imageview (if you having very large image then you need to resize your image in thread).
So you need to call createFile(this,mUri) and it will return you bitmap. I already put height and width hardcoded for now so you can change yourself.
/**
* Loads a bitmap and avoids using too much memory loading big images (e.g.: 2560*1920)
*/
private static Bitmap createFile(Context context, Uri theUri) {
Bitmap outputBitmap = null;
AssetFileDescriptor fileDescriptor;
try {
fileDescriptor = context.getContentResolver().openAssetFileDescriptor(theUri, "r");
BitmapFactory.Options options = new BitmapFactory.Options();
outputBitmap = BitmapFactory.decodeFileDescriptor(fileDescriptor.getFileDescriptor(), null, options);
options.inJustDecodeBounds = true;
int actualHeight = options.outHeight;
int actualWidth = options.outWidth;
float maxHeight = 740.0f;
float maxWidth = 1280.0f;
float imgRatio = actualWidth / actualHeight;
float maxRatio = maxWidth / maxHeight;
if (actualHeight > maxHeight || actualWidth > maxWidth) {
if (imgRatio < maxRatio) {
imgRatio = maxHeight / actualHeight;
actualWidth = (int) (imgRatio * actualWidth);
actualHeight = (int) maxHeight;
} else if (imgRatio > maxRatio) {
imgRatio = maxWidth / actualWidth;
actualHeight = (int) (imgRatio * actualHeight);
actualWidth = (int) maxWidth;
} else {
actualHeight = (int) maxHeight;
actualWidth = (int) maxWidth;
}
}
options.inSampleSize = calculateInSampleSize(options, actualWidth, actualHeight);
options.inJustDecodeBounds = false;
options.inTempStorage = new byte[16 * 1024];
outputBitmap = BitmapFactory.decodeFileDescriptor(fileDescriptor.getFileDescriptor(), null, options);
if (outputBitmap != null) {
Log.d(TAG, "Loaded image with sample size " + options.inSampleSize + "\t\t"
+ "Bitmap width: " + outputBitmap.getWidth()
+ "\theight: " + outputBitmap.getHeight());
}
fileDescriptor.close();
} catch (IOException e) {
e.printStackTrace();
}
return outputBitmap;
}
private static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
final int heightRatio = Math.round((float) height / (float) reqHeight);
final int widthRatio = Math.round((float) width / (float) reqWidth);
inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
}
final float totalPixels = width * height;
final float totalReqPixelsCap = reqWidth * reqHeight * 2;
while (totalPixels / (inSampleSize * inSampleSize) > totalReqPixelsCap) {
inSampleSize++;
}
return inSampleSize;
}
Do not exchange huge data (>1MB) between services and application. We can't send image/data through intent size > 1MB. TransactionTooLargeException occurred when you tried to send large bitmap image/image/pojo from one activity to another via intent.
Solution : Use global variable for this.
You are getting exception because of this:
Intent intent = new Intent(Intent.ACTION_PICK);
intent.setType("image/*");
startActivityForResult(intent, SELECT_PHOTO_FROM_GALLERY);
If image size will < 1MB sure it will work, but I'm sure image size will be >1MB.

Error when selecting images from my custom gallery android

If i select some images it will work but when i select other images that maybe are more heavy in terms of size it gives me this error:
java.lang.OutOfMemoryError: Failed to allocate a 79629324 byte allocation with 16777120 free bytes and 46MB until OOM
I have this classes:
Main activity where i click to go to my custom gallery activity:
public class gallerygridselect extends BaseNavegationActivity implements View.OnClickListener{
private LinearLayout lnrImages;
private Button btnAddPhots,btnSaveImages;
private ArrayList<String> imagesPathList;
private Bitmap yourbitmap;
private final int PICK_IMAGE_MULTIPLE = 1;
ArrayList<String> a = new ArrayList<String>();
long imageSize = 0; // kb
ImageView imageView;
private String[] imagesPath;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.gallery_picker);
lnrImages = (LinearLayout) findViewById(R.id.lnrImages);
btnAddPhots = (Button) findViewById(R.id.btnAddPhots);
btnSaveImages = (Button) findViewById(R.id.btnSaveImages);
btnAddPhots.setOnClickListener(this);
btnSaveImages.setOnClickListener(this);
}
#Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.btnAddPhots:
Intent intent = new Intent(gallerygridselect.this, gallerygrid.class);
startActivityForResult(intent, PICK_IMAGE_MULTIPLE);
break;
case R.id.btnSaveImages:
if (imagesPathList != null) {
if (imagesPathList.size() > 0) {
Toast.makeText(gallerygridselect.this, imagesPathList.size() + " fotos selecionadas", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(gallerygridselect.this, imagesPathList.size() + " fotos selecionadas", Toast.LENGTH_SHORT).show();
}
} else {
Toast.makeText(gallerygridselect.this, "Selecione as fotos", Toast.LENGTH_SHORT).show();
}
break;
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK) {
if (requestCode == PICK_IMAGE_MULTIPLE) {
imagesPathList = new ArrayList<String>();
imagesPath = data.getStringExtra("data").split("\\|");
for (int i = 0; i < imagesPath.length; i++) {
System.out.println("imagesPath "+imagesPath[i]);
}
imageSize = this.getFileSize(String.valueOf(imagesPath));
Log.d("PATH", "" + imagesPath);
try {
lnrImages.removeAllViews();
} catch (Throwable e) {
e.printStackTrace();
}
for (int i = 0; i < imagesPath.length; i++) {
imagesPathList.add(imagesPath[i]);
Log.e("Pathlist", "" + imagesPathList);
yourbitmap = BitmapFactory.decodeFile(imagesPath[i]);
Log.i("BITMAP", "" + yourbitmap);
imageView = new ImageView(this);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
params.setMargins(5, 5, 5, 5);
imageView.setLayoutParams(params);
imageView.setImageBitmap(BitmapHelper.decodeFile(imagesPath[i], 320, 480, true));
imageView.setAdjustViewBounds(true);
lnrImages.addView(imageView);
}
}
}
}
private long getFileSize(String imagesPath) {
long length = 0;
try {
File file = new File(imagesPath);
length = file.length();
length = length / 1024;
} catch (Exception e) {
e.printStackTrace();
}
return length;
}
private String getPath(Uri uri) {
String[] projection = {MediaStore.Images.Media.DATA};
Cursor cursor = managedQuery(uri, projection, null, null, null);
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
}
}
My bitmap help class:
public class BitmapHelper {
//decodes image and scales it to reduce memory consumption
public static Bitmap decodeFile(String bitmapFile, int requiredWidth, int requiredHeight, boolean quickAndDirty)
{
try
{
//Decode image size
BitmapFactory.Options bitmapSizeOptions = new BitmapFactory.Options();
bitmapSizeOptions.inJustDecodeBounds = true;
BitmapFactory.decodeStream(new FileInputStream(bitmapFile), null, bitmapSizeOptions);
// load image using inSampleSize adapted to required image size
BitmapFactory.Options bitmapDecodeOptions = new BitmapFactory.Options();
bitmapDecodeOptions.inTempStorage = new byte[16 * 1024];
bitmapDecodeOptions.inSampleSize = computeInSampleSize(bitmapSizeOptions, requiredWidth, requiredHeight, false);
bitmapDecodeOptions.inPurgeable = true;
bitmapDecodeOptions.inDither = !quickAndDirty;
bitmapDecodeOptions.inPreferredConfig = quickAndDirty ? Bitmap.Config.RGB_565 : Bitmap.Config.ARGB_8888;
Bitmap decodedBitmap = BitmapFactory.decodeStream(new FileInputStream(bitmapFile), null, bitmapDecodeOptions);
// scale bitmap to mathc required size (and keep aspect ratio)
float srcWidth = (float) bitmapDecodeOptions.outWidth;
float srcHeight = (float) bitmapDecodeOptions.outHeight;
float dstWidth = (float) requiredWidth;
float dstHeight = (float) requiredHeight;
float srcAspectRatio = srcWidth / srcHeight;
float dstAspectRatio = dstWidth / dstHeight;
// recycleDecodedBitmap is used to know if we must recycle intermediary 'decodedBitmap'
// (DO NOT recycle it right away: wait for end of bitmap manipulation process to avoid
// java.lang.RuntimeException: Canvas: trying to use a recycled bitmap android.graphics.Bitmap#416ee7d8
// I do not excatly understand why, but this way it's OK
boolean recycleDecodedBitmap = false;
Bitmap scaledBitmap = decodedBitmap;
if (srcAspectRatio < dstAspectRatio)
{
scaledBitmap = getScaledBitmap(decodedBitmap, (int) dstWidth, (int) (srcHeight * (dstWidth / srcWidth)));
// will recycle recycleDecodedBitmap
recycleDecodedBitmap = true;
}
else if (srcAspectRatio > dstAspectRatio)
{
scaledBitmap = getScaledBitmap(decodedBitmap, (int) (srcWidth * (dstHeight / srcHeight)), (int) dstHeight);
recycleDecodedBitmap = true;
}
// crop image to match required image size
int scaledBitmapWidth = scaledBitmap.getWidth();
int scaledBitmapHeight = scaledBitmap.getHeight();
Bitmap croppedBitmap = scaledBitmap;
if (scaledBitmapWidth > requiredWidth)
{
int xOffset = (scaledBitmapWidth - requiredWidth) / 2;
croppedBitmap = Bitmap.createBitmap(scaledBitmap, xOffset, 0, requiredWidth, requiredHeight);
scaledBitmap.recycle();
}
else if (scaledBitmapHeight > requiredHeight)
{
int yOffset = (scaledBitmapHeight - requiredHeight) / 2;
croppedBitmap = Bitmap.createBitmap(scaledBitmap, 0, yOffset, requiredWidth, requiredHeight);
scaledBitmap.recycle();
}
if (recycleDecodedBitmap)
{
decodedBitmap.recycle();
}
decodedBitmap = null;
scaledBitmap = null;
return croppedBitmap;
}
catch (Exception ex)
{
ex.printStackTrace();
}
return null;
}
/**
* compute powerOf2 or exact scale to be used as {#link BitmapFactory.Options#inSampleSize} value (for subSampling)
*
// #param requiredWidth
// #param requiredHeight
* #param powerOf2
* weither we want a power of 2 sclae or not
* #return
*/
public static int computeInSampleSize(BitmapFactory.Options options, int dstWidth, int dstHeight, boolean powerOf2)
{
int inSampleSize = 1;
// Raw height and width of image
final int srcHeight = options.outHeight;
final int srcWidth = options.outWidth;
if (powerOf2)
{
//Find the correct scale value. It should be the power of 2.
int tmpWidth = srcWidth, tmpHeight = srcHeight;
while (true)
{
if (tmpWidth / 2 < dstWidth || tmpHeight / 2 < dstHeight)
break;
tmpWidth /= 2;
tmpHeight /= 2;
inSampleSize *= 2;
}
}
else
{
// Calculate ratios of height and width to requested height and width
final int heightRatio = Math.round((float) srcHeight / (float) dstHeight);
final int widthRatio = Math.round((float) srcWidth / (float) dstWidth);
// 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 drawableToBitmap(Drawable drawable)
{
if (drawable instanceof BitmapDrawable)
{
return ((BitmapDrawable) drawable).getBitmap();
}
Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
drawable.draw(canvas);
return bitmap;
}
public static Bitmap getScaledBitmap(Bitmap bitmap, int newWidth, int newHeight)
{
int width = bitmap.getWidth();
int height = bitmap.getHeight();
float scaleWidth = ((float) newWidth) / width;
float scaleHeight = ((float) newHeight) / height;
// CREATE A MATRIX FOR THE MANIPULATION
Matrix matrix = new Matrix();
// RESIZE THE BIT MAP
matrix.postScale(scaleWidth, scaleHeight);
// RECREATE THE NEW BITMAP
Bitmap resizedBitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, false);
return resizedBitmap;
}
}
Im newb at android development what can i do to fix this. Thanks in advance.
You need to pass file path with height and width. SO it will return you small image :-
Bitmap ShrinkBitmap(String file, int width, int height){
BitmapFactory.Options bmpFactoryOptions = new BitmapFactory.Options();
bmpFactoryOptions.inJustDecodeBounds = true;
Bitmap bitmap = BitmapFactory.decodeFile(file, bmpFactoryOptions);
int heightRatio = (int)Math.ceil(bmpFactoryOptions.outHeight/(float)height);
int widthRatio = (int)Math.ceil(bmpFactoryOptions.outWidth/(float)width);
if (heightRatio > 1 || widthRatio > 1)
{
if (heightRatio > widthRatio)
{
bmpFactoryOptions.inSampleSize = heightRatio;
} else {
bmpFactoryOptions.inSampleSize = widthRatio;
}
}
bmpFactoryOptions.inJustDecodeBounds = false;
bitmap = BitmapFactory.decodeFile(file, bmpFactoryOptions);
return bitmap;
}
for more info see link :-
http://voidcanvas.com/whatsapp-like-image-compression-in-android/

Need Java code to compress image below 500 KB in Android

I have tried by setting BitmapFactory.Options inSampleSize but its not reducing image below 500 KB.
Image might be any size and must be compressed because i'm storing it on database, Image below 500 KB is my primary requirement. Below is my code:
int inSampleSize = 1;
Bitmap bitmapImage;//= BitmapFactory.decodeFile(imageUri, options);
do {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = inSampleSize;
options.inScaled = true;
bitmapImage = BitmapFactory.decodeFile(imageUri, options);
inSampleSize++;
} while (bitmapImage != null && bitmapImage.getByteCount() > 500000);
Please help me on this.
Try this
public Bitmap compressImage(String imageUri) {
String filePath = getRealPathFromURI(imageUri);
Bitmap scaledBitmap = null;
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
Bitmap bmp = BitmapFactory.decodeFile(filePath,options);
int actualHeight = options.outHeight;
int actualWidth = options.outWidth;
ExifInterface exi;
int orien=0;
try {
exi = new ExifInterface(filePath);
orien = exi.getAttributeInt(ExifInterface.TAG_ORIENTATION, 0);
} catch (IOException e1) {
e1.printStackTrace();
}
float maxHeight = ScreenHeight;
float maxWidth = ScreenWidth;
float imgRatio = actualWidth / actualHeight;
float maxRatio = maxWidth / maxHeight;
if (actualHeight > maxHeight || actualWidth > maxWidth) {
if (imgRatio < maxRatio) {
imgRatio = maxHeight / actualHeight;
actualWidth = (int) (imgRatio * actualWidth);
actualHeight = (int) maxHeight;
} else if (imgRatio > maxRatio) {
imgRatio = maxWidth / actualWidth;
actualHeight = (int) (imgRatio * actualHeight);
actualWidth = (int) maxWidth;
} else {
actualHeight = (int) maxHeight;
actualWidth = (int) maxWidth;
}
}
options.inSampleSize =calculateInSampleSize(options, actualWidth, actualHeight);
options.inJustDecodeBounds = false;
options.inDither = false;
options.inPurgeable = true;
options.inInputShareable = true;
options.inTempStorage = new byte[16*1024];
try{
bmp = BitmapFactory.decodeFile(filePath,options);
}
catch(OutOfMemoryError exception){
}
try{
scaledBitmap = Bitmap.createBitmap(actualWidth, actualHeight, Bitmap.Config.ARGB_8888);
}
catch(OutOfMemoryError exception){
}
float ratioX = actualWidth / (float)options.outWidth;
float ratioY = actualHeight / (float)options.outHeight;
float middleX = actualWidth / 2.0f;
float middleY = actualHeight / 2.0f;
Matrix scaleMatrix = new Matrix();
scaleMatrix.setScale(ratioX, ratioY, middleX, middleY);
Canvas canvas = new Canvas(scaledBitmap);
canvas.setMatrix(scaleMatrix);
canvas.drawBitmap(bmp, middleX - bmp.getWidth()/2, middleY - bmp.getHeight() / 2, new Paint(Paint.FILTER_BITMAP_FLAG));
boolean isPorait=true;
if(((Activity)context).getResources().getConfiguration().orientation==Configuration.ORIENTATION_LANDSCAPE){
isPorait=false;
}
ExifInterface exif;
try {
exif = new ExifInterface(filePath);
int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 0);
Log.d("EXIF", "Exif: " + orientation);
Matrix matrix = new Matrix();
if (orientation == 6) {
if(isPorait)
matrix.postRotate(90);
Log.d("EXIF", "Exif: " + orientation);
} else if (orientation == 3) {
if(!isPorait)
matrix.postRotate(180);
else
matrix.postRotate(-90);
Log.d("EXIF", "Exif: " + orientation);
} else if (orientation == 8) {
if(isPorait)
matrix.postRotate(270);
else
matrix.postRotate(180);
Log.d("EXIF", "Exif: " + orientation);
}
scaledBitmap = Bitmap.createBitmap(scaledBitmap, 0, 0,scaledBitmap.getWidth(), scaledBitmap.getHeight(), matrix, true);
} catch (IOException e) {
}
bmp.recycle();
return scaledBitmap;
}

How to get better quality in fix resize image in Android?

I have 4608x3456 image that I want to adjust the size of. I want to adjust the resolution of the image to 640x480, yet when I do this the quality of the image drops. Is there a way to decrease image resolution and and still have a better image quality?
Resized Image 640x480 :
Bitmap temobitmpa = loadScaledBitmapFromUri(path,640,480);
return getImageUri(getApplicationContext(), temobitmpa);
public Bitmap loadScaledBitmapFromUri(String filePath, int width, int height) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
// calc aspect ratio
int[] retval = calculateAspectRatio(options.outWidth, options.outHeight);
options.inJustDecodeBounds = false;
options.inSampleSize = calculateSampleSize(options.outWidth,
options.outHeight, width, height);
Log.i("test", "sample size::" + options.inSampleSize);
Bitmap unscaledBitmap = BitmapFactory.decodeFile(filePath, options);
return Bitmap.createScaledBitmap(unscaledBitmap, retval[0], retval[1],
true);
}
private int[] calculateAspectRatio(int origWidth, int origHeight) {
int newWidth = 640;
int newHeight = 480;
// If no new width or height were specified return the original bitmap
if (newWidth <= 0 && newHeight <= 0) {
newWidth = origWidth;
newHeight = origHeight;
}
// Only the width was specified
else if (newWidth > 0 && newHeight <= 0) {
newHeight = (newWidth * origHeight) / origWidth;
}
// only the height was specified
else if (newWidth <= 0 && newHeight > 0) {
newWidth = (newHeight * origWidth) / origHeight;
}
// If the user specified both a positive width and height
// (potentially different aspect ratio) then the width or height is
// scaled so that the image fits while maintaining aspect ratio.
// Alternatively, the specified width and height could have been
// kept and Bitmap.SCALE_TO_FIT specified when scaling, but this
// would result in whitespace in the new image.
else {
double newRatio = newWidth / (double) newHeight;
double origRatio = origWidth / (double) origHeight;
if (origRatio > newRatio) {
newHeight = (newWidth * origHeight) / origWidth;
} else if (origRatio < newRatio) {
newWidth = (newHeight * origWidth) / origHeight;
}
}
int[] retval = new int[2];
retval[0] = newWidth;
retval[1] = newHeight;
return retval;
}
private int calculateSampleSize(int srcWidth, int srcHeight, int dstWidth,
int dstHeight) {
final float srcAspect = (float) srcWidth / (float) srcHeight;
final float dstAspect = (float) dstWidth / (float) dstHeight;
if (srcAspect > dstAspect) {
return srcWidth / dstWidth;
} else {
return srcHeight / dstHeight;
}
}
You can try this image scaling library, it gives a very good image quality.
https://github.com/thebuzzmedia/imgscalr

Getting Out of memory on a 3001616-byte allocation error for bitmap decoding

I'm actually getting this error on method Load image inside it i'm doing
i set options size to:
bmOptions.inSampleSize = 1;
the method in which the error points line decodeStream()..
private Bitmap LoadImage(String URL, BitmapFactory.Options options) {
Bitmap bitmap = null;
InputStream in = null;
try {
in = OpenHttpConnection(URL);
bitmap = BitmapFactory.decodeStream(in, null, options);
in.close();
} catch (IOException e1) {
return null;
}
return bitmap;
}
E/dalvikvm-heap(8627): Out of memory on a 3001616-byte allocation.
at decodeStream()
at loadImage()
This class scales an image in a memory effecient way to a precise size, it also does some auto rotation, you might want to disable that or pass in the angle. Is based on post here: http://zerocredibility.wordpress.com/2011/01/27/android-bitmap-scaling/
import java.io.IOException;
import java.io.InputStream;
import android.content.ContentResolver;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.net.Uri;
/**
* http://zerocredibility.wordpress.com/2011/01/27/android-bitmap-scaling/
*
*/
public final class
BitmapScaler {
/**
*
* #param uri
* #param context
* #param newWidth
* Image will not exceed this width
* #param newHeight
* Image will not exceed this height
* #return
* #throws IOException
*/
public static Bitmap ScaleBitmap(Uri uri, Context context,
int newWidth, int newHeight, int targetWidth, int targetHeight)
throws IOException {
final ContentResolver contentResolver = context.getContentResolver();
int sample = 1;
{
InputStream is = contentResolver.openInputStream(uri);
try {
sample = getRoughSize(is, newWidth, newHeight);
} finally {
is.close();
}
}
{
InputStream is = contentResolver.openInputStream(uri);
try {
Bitmap temp = roughScaleImage(is, sample);
try {
return scaleImage(temp, newWidth, newHeight, targetWidth,
targetHeight);
} finally {
temp.recycle();
}
} finally {
is.close();
}
}
}
private static Bitmap scaleImage(final Bitmap source, final int maxWidth,
final int maxHeight, final int targetWidth, final int targetHeight) {
int newWidth = maxWidth;
int newHeight = maxHeight;
final int sourceHeight = source.getHeight();
final int sourceWidth = source.getWidth();
final int angle = sourceHeight > sourceWidth ? -90 : 0;
final boolean rotate = angle != 0;
final boolean nintey = (angle == 90) || (angle == -90);
final int width = nintey ? sourceHeight : sourceWidth;
final int height = nintey ? sourceWidth : sourceHeight;
final float scaleByWidth = ((float) newWidth / width);
int testNewHeight = (int) (height * scaleByWidth);
float scale;
if (testNewHeight > newHeight) { // then we must scale to match
// newHeight instead of new width
final float scaleByHeight = ((float) newHeight / height);
newWidth = (int) (width * scaleByHeight);
scale = scaleByHeight;
} else {
// accept the scale
newHeight = testNewHeight;
scale = scaleByWidth;
}
Matrix matrix = new Matrix();
matrix.postScale(scale, scale);
if (rotate) {
matrix.postRotate(angle);
matrix.postTranslate(0, newHeight);
}
matrix.postTranslate((maxWidth - newWidth) / 2,
(maxHeight - newHeight) / 2);
Bitmap b = Bitmap.createBitmap(targetWidth, targetHeight,
Bitmap.Config.ARGB_8888);
Paint p = new Paint(Paint.FILTER_BITMAP_FLAG);
Canvas c = new Canvas(b);
c.drawBitmap(source, matrix, p);
return b;
}
private static Bitmap roughScaleImage(InputStream is, int sample) {
BitmapFactory.Options scaledOpts = new BitmapFactory.Options();
scaledOpts.inSampleSize = sample;
return BitmapFactory.decodeStream(is, null, scaledOpts);
}
private static int getRoughSize(InputStream is, int newWidth, int newHeight) {
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeStream(is, null, o);
return getRoughSize(o.outWidth, o.outHeight, newWidth, newHeight);
}
private static int getRoughSize(int width, int height, int newWidth,
int newHeight) {
int sample = 1;
while (true) {
if (width / 2 < newWidth || height / 2 < newHeight) {
break;
}
width /= 2;
height /= 2;
sample *= 2;
}
return sample;
}
}
Following is the code which Decode file into specified scale.
File f = new File(StringfileName);
Bitmap bm = decodeFile(f);
private static Bitmap decodeFile(File f) {
try {
// Decode image size
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeStream(new FileInputStream(f), null, o);
// The new size we want to scale to
final int REQUIRED_SIZE = 150;
// Find the correct scale value. It should be the power of 2.
int scale = 1;
while (o.outWidth / scale / 2 >= REQUIRED_SIZE
&& o.outHeight / scale / 2 >= REQUIRED_SIZE)
scale *= 2;
// Decode with inSampleSize
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize = scale;
o.inJustDecodeBounds = false;
return BitmapFactory.decodeStream(new FileInputStream(f), null, o2);
} catch (FileNotFoundException e) {
}
return null;
}
take a look at this docs http://developer.android.com/training/displaying-bitmaps/load-bitmap.html . I was having the same problem before as well.

Categories

Resources