Android drawing scaled Bitmap without OutOfMemory error - android

I need scale my bitmap to screenSizeAverage / 3. When I do it like this, I have sometimes OutOfMemory error.
screenWidth = size.x;
screenHeight = size.y;
screenSizeAverage = (screenWidth + screenHeight) / 2;
Bitmap b2 = BitmapFactory.decodeResource(getResources(), R.drawable.logoqrtz);
logoqrtz = Bitmap.createScaledBitmap(b2, screenSizeAverage / 3,screenSizeAverage / 3, true);
protected void onDraw(Canvas canvas) {
canvas.drawBitmap(logoqrtz, (int) (screenWidth / 2, (int) (screenHeight /2), p);
}
What is the best way to do this without OutOfMemory error?

From developer.android.com
private Bitmap setPic() {
// Get the dimensions of the View
int targetW = size.x;
int targetH = size.y;
int size = ((screenWidth + screenHeight) / 2) / 3;
// Get the dimensions of the bitmap
BitmapFactory.Options bmOptions = new BitmapFactory.Options();
bmOptions.inJustDecodeBounds = true;
BitmapFactory.decodeFile(mCurrentPhotoPath, bmOptions);
int photoW = bmOptions.outWidth;
int photoH = bmOptions.outHeight;
// Determine how much to scale down the image
int scaleFactor = Math.min(photoW/size, photoH/size);
// Decode the image file into a Bitmap sized to fill the View
bmOptions.inJustDecodeBounds = false;
bmOptions.inSampleSize = scaleFactor;
bmOptions.inPurgeable = true;
return BitmapFactory.decodeResource(getResources(), R.drawable.logoqrtz, bmOptions);
}
Modified for your case.

Related

NullPointerException Cant find bitmap from drawable on oppo device

im trying to get imageview from drawable and resize it my current code is working on all devices except on oppo devices it crash inside crop() method
the crash im getting is on the first line in crop() method you can find below
Caused by: java.lang.NullPointerException:
my current code is:
public Bitmap getTileBitmap(int id, int size) {
String string = tileUrls.get(id);
if (string.contains(Themes.URI_DRAWABLE)) {
String drawableResourceName = string.substring(Themes.URI_DRAWABLE.length());
int drawableResourceId = Shared.context.getResources().getIdentifier(drawableResourceName, "drawable", Shared.context.getPackageName());
Bitmap bitmap = Utils.scaleDown(drawableResourceId, size, size);
return Utils.crop(bitmap, size, size);
}
return null;
}
public static Bitmap crop(Bitmap source, int newHeight, int newWidth) {
int sourceWidth = source.getWidth();
int sourceHeight = source.getHeight();
float xScale = (float) newWidth / sourceWidth;
float yScale = (float) newHeight / sourceHeight;
float scale = Math.max(xScale, yScale);
float scaledWidth = scale * sourceWidth;
float scaledHeight = scale * sourceHeight;
float left = (newWidth - scaledWidth) / 2;
float top = (newHeight - scaledHeight) / 2;
RectF targetRect = new RectF(left, top, left + scaledWidth, top + scaledHeight);
Bitmap dest = Bitmap.createBitmap(newWidth, newHeight, source.getConfig());
Canvas canvas = new Canvas(dest);
canvas.drawBitmap(source, null, targetRect, null);
return dest;
}
EDIT: added scale method which may cause the issue
public static Bitmap scaleDown(int resource, int reqWidth, int reqHeight) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(Shared.context.getResources(), resource);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeResource(Shared.context.getResources(), resource, options);
}
and so far im not sure what is causing the crash only on oppo devices
Try this:
options.inJustDecodeBounds = true;
options.inScaled = false;
options.inDensity = 0;
options.inMutable = true; //API 11. Pass to canvas? Might crash without this.
//Load the image here... BitmapFactory.decodeResource()...
... //Some calculations.
options.inJustDecodeBounds = false;
options.inPreferredConfig = Bitmap.Config.ARGB_8888;

Resizing Bitmap maintaining aspect ratio and without distortion and cropping

Is there any way to resize a Bitmap without distortion so that it does not exceed 720*1280 ? Smaller height and width is completely fine (blank canvas in case of smaller width or height is fine) I tried this https://stackoverflow.com/a/15441311/6848469 but it gives distorted image. Can anybody suggest a better solution?
Here is the method for downscaling bitmap not to exceed MAX_ALLOWED_RESOLUTION. In you case MAX_ALLOWED_RESOLUTION = 1280. It will downscale without any distortion and losing quality:
private static Bitmap downscaleToMaxAllowedDimension(String photoPath) {
BitmapFactory.Options bitmapOptions = new BitmapFactory.Options();
bitmapOptions.inJustDecodeBounds = true;
BitmapFactory.decodeFile(photoPath, bitmapOptions);
int srcWidth = bitmapOptions.outWidth;
int srcHeight = bitmapOptions.outHeight;
int dstWidth = srcWidth;
float scale = (float) srcWidth / srcHeight;
if (srcWidth > srcHeight && srcWidth > MAX_ALLOWED_RESOLUTION) {
dstWidth = MAX_ALLOWED_RESOLUTION;
} else if (srcHeight > srcWidth && srcHeight > MAX_ALLOWED_RESOLUTION) {
dstWidth = (int) (MAX_ALLOWED_RESOLUTION * scale);
}
bitmapOptions.inJustDecodeBounds = false;
bitmapOptions.inDensity = bitmapOptions.outWidth;
bitmapOptions.inTargetDensity = dstWidth;
return BitmapFactory.decodeFile(photoPath, bitmapOptions);
}
In case if you already have BITMAP object and not path use this:
private static Bitmap downscaleToMaxAllowedDimension(Bitmap bitmap) {
int MAX_ALLOWED_RESOLUTION = 1024;
int outWidth;
int outHeight;
int inWidth = bitmap.getWidth();
int inHeight = bitmap.getHeight();
if(inWidth > inHeight){
outWidth = MAX_ALLOWED_RESOLUTION;
outHeight = (inHeight * MAX_ALLOWED_RESOLUTION) / inWidth;
} else {
outHeight = MAX_ALLOWED_RESOLUTION;
outWidth = (inWidth * MAX_ALLOWED_RESOLUTION) / inHeight;
}
Bitmap resizedBitmap = Bitmap.createScaledBitmap(bitmap, outWidth, outHeight, false);
return resizedBitmap;
}

How to scale background image on canvas according to device size in android

All I have used to get the image as the background on canvas
canvas.drawBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.help_4, 0, 0, null);
And I get a large image. So can anyone pls. provide me a solution to get the Image set according to the Device size. As I'm new to coding a detailed explanation would be appreciated :)
Thank You
You're almost there. You just need to configure the BitmapFactory.Options variable by setting the output width and height (based on the screen size):
BitmapFactory.Options options = new BitmapFactory.Options();
Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
options.outHeight = size.x;
options.outWidth = size.y;
canvas.drawBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.help_4, options));
Determine the device width and height and scale it:
int deviceWidth = getWindowManager().getDefaultDisplay()
.getWidth();
int deviceHeight = getWindowManager().getDefaultDisplay()
.getHeight();
So in complete you can use the following ready-to-use snippet taken from here:
public Bitmap scaleToActualAspectRatio(Bitmap bitmap) {
if (bitmap != null) {
boolean flag = true;
int deviceWidth = getWindowManager().getDefaultDisplay()
.getWidth();
int deviceHeight = getWindowManager().getDefaultDisplay()
.getHeight();
int bitmapHeight = bitmap.getHeight();
int bitmapWidth = bitmap.getWidth();
if (bitmapWidth > deviceWidth) {
flag = false;
// scale According to WIDTH
int scaledWidth = deviceWidth;
int scaledHeight = (scaledWidth * bitmapHeight) / bitmapWidth;
try {
if (scaledHeight > deviceHeight)
scaledHeight = deviceHeight;
bitmap = Bitmap.createScaledBitmap(bitmap, scaledWidth,
scaledHeight, true);
} catch (Exception e) {
e.printStackTrace();
}
}
if (flag) {
if (bitmapHeight > deviceHeight) {
// scale According to HEIGHT
int scaledHeight = deviceHeight;
int scaledWidth = (scaledHeight * bitmapWidth) / bitmapHeight;
try {
if (scaledWidth > deviceWidth)
scaledWidth = deviceWidth;
bitmap = Bitmap.createScaledBitmap(bitmap, scaledWidth,
scaledHeight, true);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
return bitmap;
}
So finaly use:
myCanvas.drawBitmap(scaleToActualAspectRatio(myBitmap), X, Y, null)
The process would look something like this:
Get screen size
Calculate new image size (keeping aspect ratio)
Decode bitmap to new size.
Get screen size
To get the exact screen size of a device, use DisplayMetrics...
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
The metrics variable will now contain the screen dimensions in pixels. You can get the values by using metrics.widthPixels and metrics.heightPixels.
Calculate new image size (keeping aspect ratio)
To calculate new image size, we can use BitmapFactory.Options and tell it to scale the image down by a factor of x. To calculate that factor (also referred as inSampleSize), use the following method...
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;
}
Decode Bitmap to new size
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(getResources(), R.drawable.help_4, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, metrics.widthPixels, metrics.heightPixels);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeResource(getResources(), R.drawable.help_4, options);
The inJustDecodeBounds option tells the framework to null out the Bitmap to prevent OOM exceptions, since we are only interested in the dimensions, and not the actual image.
This method will ensure that the Bitmap is scaled efficiently. Read more here: http://developer.android.com/training/displaying-bitmaps/load-bitmap.html

OutOfMemoryError when loading my gridview with images

having trouble with handling a java.lang.OutOfMemoryError: bitmap size exceeds VM budget error. The original pictures are never bigger then 250x250px. and loaded from the drawable folder. I found some solutions across the internet talking about 'inJustDecodeBounds' but I just can't get it to work.. Any ideas on how to fix this issue? It's causing me a headache for two days now...
Right now I am rescaling the image by a factor which I calculate based on the parent width..
#Override
public View getView(int position, View v, ViewGroup parent) {
View mView = v;
this.parent = parent;
if (mView == null) {
LayoutInflater vi = (LayoutInflater) getContext().getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
mView = vi.inflate(R.layout.caa_xml, null);
}
ImageView image = (ImageView) mView.findViewById(R.id.iv_caarow);
String name = getItem(position).getFile();
int resId = C.getResources().getIdentifier(name, "drawable",
"com.test.com");
int imageWidth = (int) calculateImageWidth();
// load the origial BitMap (250 x 250 px)
Bitmap bitmapOrg = BitmapFactory
.decodeResource(C.getResources(), resId);
int width = bitmapOrg.getWidth();
int height = bitmapOrg.getHeight();
int newWidth = imageWidth;
int newHeight = imageWidth;
float scaleWidth = ((float) newWidth) / width;
float scaleHeight = ((float) newHeight) / height;
// create a matrix for the manipulation
Matrix matrix = new Matrix();
// resize
matrix.postScale(scaleWidth, scaleHeight);
// recreate the new Bitmap
Bitmap resizedBitmap = Bitmap.createBitmap(bitmapOrg, 0, 0, width,
height, matrix, true);
BitmapDrawable bmd = new BitmapDrawable(resizedBitmap);
image.setImageDrawable(bmd);
if (mView != null) {
//additional code here
}
return mView;
}
private float calculateImageWidth() {
// TODO Auto-generated method stub
int parentW = parent.getWidth() - parent.getPaddingLeft()
- parent.getPaddingRight();
Resources r = C.getResources();
float pxPaddingBetweenItem = TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, 2, r.getDisplayMetrics());
float pxPaddingInItem = TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, 10, r.getDisplayMetrics());
int totalImageWidth = (parentW - (int) (3 * pxPaddingBetweenItem) - (int) (8 * pxPaddingInItem)) / 4;
float imageWidth = (float) totalImageWidth;
return imageWidth;
}
the problem is, that you create a scaled Bitmap by using the old big one. After that you have two Bitmaps in your Memory and you don't even recycle the old one.
Anyway, there is a better way:
ImageView imageView = (ImageView) findViewById(R.id.some_id);
String pathToImage = "path";
BitmapFactory.Options bmOptions = new BitmapFactory.Options();
bmOptions.inJustDecodeBounds = true;
BitmapFactory.decodeFile(pathToImage, bmOptions);
int photoW = bmOptions.outWidth;
int photoH = bmOptions.outHeight;
// Determine how much to scale down the image
int scaleFactor = Math.min(photoW/50, photoH/50);
// Decode the image file into a Bitmap sized to fill the View
bmOptions.inJustDecodeBounds = false;
bmOptions.inSampleSize = scaleFactor;
bmOptions.inPurgeable = true;
Bitmap bitmap = BitmapFactory.decodeFile(pathToFile, bmOptions);
imageView.setImageBitmap(bitmap);
Edit:
When you want to use a resource Id instead of the file path, use decodeResource and do the last part like this:
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), resourceId, bmOptions);
imageView.setImageBitmap(bitmap);
Hope that piece of code helps you out!

How to resize Image in Android?

I am creating an application and want to setup a gallery view. I do not want the images in the gallery view to be full size. How do I resize images in Android?
Try:
Bitmap yourBitmap;
Bitmap resized = Bitmap.createScaledBitmap(yourBitmap, newWidth, newHeight, true);
or:
resized = Bitmap.createScaledBitmap(yourBitmap,(int)(yourBitmap.getWidth()*0.8), (int)(yourBitmap.getHeight()*0.8), true);
public Bitmap resizeBitmap(String photoPath, int targetW, int targetH) {
BitmapFactory.Options bmOptions = new BitmapFactory.Options();
bmOptions.inJustDecodeBounds = true;
BitmapFactory.decodeFile(photoPath, bmOptions);
int photoW = bmOptions.outWidth;
int photoH = bmOptions.outHeight;
int scaleFactor = 1;
if ((targetW > 0) || (targetH > 0)) {
scaleFactor = Math.min(photoW/targetW, photoH/targetH);
}
bmOptions.inJustDecodeBounds = false;
bmOptions.inSampleSize = scaleFactor;
bmOptions.inPurgeable = true; //Deprecated API 21
return BitmapFactory.decodeFile(photoPath, bmOptions);
}
Capture the image and resize it.
Bitmap image2 = (Bitmap) data.getExtras().get("data");
img.setImageBitmap(image2);
String incident_ID = IncidentFormActivity.incident_id;
imagepath="/sdcard/RDMS/"+incident_ID+ x + ".PNG";
File file = new File(imagepath);
try {
double xFactor = 0;
double width = Double.valueOf(image2.getWidth());
Log.v("WIDTH", String.valueOf(width));
double height = Double.valueOf(image2.getHeight());
Log.v("height", String.valueOf(height));
if(width>height){
xFactor = 841/width;
}
else{
xFactor = 595/width;
}
Log.v("Nheight", String.valueOf(width*xFactor));
Log.v("Nweight", String.valueOf(height*xFactor));
int Nheight = (int) ((xFactor*height));
int NWidth =(int) (xFactor * width) ;
bm = Bitmap.createScaledBitmap( image2,NWidth, Nheight, true);
file.createNewFile();
FileOutputStream ostream = new FileOutputStream(file);
bm.compress(CompressFormat.PNG, 100, ostream);
ostream.close();
You can use Matrix to resize your camera image ....
BitmapFactory.Options options=new BitmapFactory.Options();
InputStream is = getContentResolver().openInputStream(currImageURI);
bm = BitmapFactory.decodeStream(is,null,options);
int Height = bm.getHeight();
int Width = bm.getWidth();
int newHeight = 300;
int newWidth = 300;
float scaleWidth = ((float) newWidth) / Width;
float scaleHeight = ((float) newHeight) / Height;
Matrix matrix = new Matrix();
matrix.postScale(scaleWidth, scaleHeight);
Bitmap resizedBitmap = Bitmap.createBitmap(bm, 0, 0,Width, Height, matrix, true);
BitmapDrawable bmd = new BitmapDrawable(resizedBitmap);
//photo is bitmap image
Bitmap btm00 = Utils.getResizedBitmap(photo, 200, 200);
setimage.setImageBitmap(btm00);
And in Utils class :
public static Bitmap getResizedBitmap(Bitmap bm, int newHeight, int newWidth) {
int width = bm.getWidth();
int height = bm.getHeight();
float scaleWidth = ((float) newWidth) / width;
float scaleHeight = ((float) newHeight) / height;
Matrix matrix = new Matrix();
// RESIZE THE BIT MAP
matrix.postScale(scaleWidth, scaleHeight);
// RECREATE THE NEW BITMAP
Bitmap resizedBitmap = Bitmap.createBitmap(bm, 0, 0, width, height,
matrix, false);
return resizedBitmap;
}
bm = Bitmap.createScaledBitmap(bitmapSource, width, height, true);
:)
BitmapFactory.Options options=new BitmapFactory.Options();
options.inSampleSize=2; //try to decrease decoded image
Bitmap bitmap=BitmapFactory.decodeStream(is, null, options);
bitmap.compress(Bitmap.CompressFormat.JPEG, 70, fos); //compressed bitmap to file
Following is the function to resize bitmap by keeping the same Aspect Ratio. Here I have also written a detailed blog post on the topic to explain this method. Resize a Bitmap by Keeping the Same Aspect Ratio.
public static Bitmap resizeBitmap(Bitmap source, int maxLength) {
try {
if (source.getHeight() >= source.getWidth()) {
int targetHeight = maxLength;
if (source.getHeight() <= targetHeight) { // if image already smaller than the required height
return source;
}
double aspectRatio = (double) source.getWidth() / (double) source.getHeight();
int targetWidth = (int) (targetHeight * aspectRatio);
Bitmap result = Bitmap.createScaledBitmap(source, targetWidth, targetHeight, false);
if (result != source) {
}
return result;
} else {
int targetWidth = maxLength;
if (source.getWidth() <= targetWidth) { // if image already smaller than the required height
return source;
}
double aspectRatio = ((double) source.getHeight()) / ((double) source.getWidth());
int targetHeight = (int) (targetWidth * aspectRatio);
Bitmap result = Bitmap.createScaledBitmap(source, targetWidth, targetHeight, false);
if (result != source) {
}
return result;
}
}
catch (Exception e)
{
return source;
}
}
resized = Bitmap.createScaledBitmap(yourImageBitmap,(int)(yourImageBitmap.getWidth()*0.9), (int)(yourBitmap.getHeight()*0.9), true);
BitmapFactory.Options options=new BitmapFactory.Options();
options.inSampleSize = 10;
FixBitmap = BitmapFactory.decodeFile(ImagePath, options);
//FixBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.gv);
byteArrayOutputStream = new ByteArrayOutputStream();
FixBitmap.compress(Bitmap.CompressFormat.JPEG, 80, byteArrayOutputStream); //compress to 50% of original image quality
byteArray = byteArrayOutputStream.toByteArray();
ConvertImage = Base64.encodeToString(byteArray, Base64.DEFAULT);

Categories

Resources