I would like to reduce My Bitmap image size to maximum of 640px. For example I have Bitmap image of size 1200 x 1200 px .. How can I reduce it to 640px.
If you pass bitmap width and height then use:
public Bitmap getResizedBitmap(Bitmap image, int bitmapWidth, int bitmapHeight) {
return Bitmap.createScaledBitmap(image, bitmapWidth, bitmapHeight, true);
}
If you want to keep the bitmap ratio the same, but reduce it to a maximum side length, use:
public Bitmap getResizedBitmap(Bitmap image, int maxSize) {
int width = image.getWidth();
int height = image.getHeight();
float bitmapRatio = (float) width / (float) height;
if (bitmapRatio > 1) {
width = maxSize;
height = (int) (width / bitmapRatio);
} else {
height = maxSize;
width = (int) (height * bitmapRatio);
}
return Bitmap.createScaledBitmap(image, width, height, true);
}
Use this Method
/** getResizedBitmap method is used to Resized the Image according to custom width and height
* #param image
* #param newHeight (new desired height)
* #param newWidth (new desired Width)
* #return image (new resized image)
* */
public static Bitmap getResizedBitmap(Bitmap image, int newHeight, int newWidth) {
int width = image.getWidth();
int height = image.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(image, 0, 0, width, height,
matrix, false);
return resizedBitmap;
}
or you can do it like this:
Bitmap.createScaledBitmap(Bitmap src, int dstWidth, int dstHeight, boolean filter);
Passing filter = false will result in a blocky, pixellated image.
Passing filter = true will give you smoother edges.
Here is working code to reduce Bitmap image resolution (pixels) to desired value...
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.ImageView;
import android.widget.Toast;
public class ImageProcessActivity extends AppCompatActivity {
private static final String TAG = "ImageProcessActivity";
private static final String IMAGE_PATH = "/sdcard/DCIM/my_image.jpg";
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 halfHeight = height / 2;
final int halfWidth = width / 2;
// Calculate the largest inSampleSize value that is a power of 2 and keeps both
// height and width larger than the requested height and width.
while ((halfHeight / inSampleSize) >= reqHeight && (halfWidth / inSampleSize) >= reqWidth) {
inSampleSize *= 2;
}
}
return inSampleSize;
}
public static Bitmap decodeSampleDrawableFromFile(String file, int reqWidth, int reqHeight) {
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(file, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeFile(file, options);
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_image_process);
new AsyncTask<Object, Object, Bitmap>() {
#Override
protected Bitmap doInBackground(Object... objects) {
try {
return decodeSampleDrawableFromFile(IMAGE_PATH, 640, 640);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Bitmap bitmap) {
super.onPostExecute(bitmap);
((ImageView) findViewById(R.id.img)).setImageBitmap(bitmap);
}
}.execute();
}
}
Steps:
Get the Bitmap.Options (image info).
Sample the size to desired sample size.
Load to Bitmap with given options (desired resolution) from the image file into a bitmap object. But do this operation in a background thread.
Load Bitmap image into ImageView on UI thread (onPostExecute()).
Related
I have confusion between android bitmap scaling and sampling here may have two code one for scaling and another for sampling can anyone help me for identifying working of this two code and what is main differences between them.
Scaling :
public static Bitmap getScaleBitmap(Bitmap bitmap, int newWidth, int newHeight) {
int width = bitmap.getWidth();
int height = bitmap.getHeight();
float scaleWidth = ((float) newWidth) / width;
float scaleHeight = ((float) newHeight) / height;
Matrix matrix = new Matrix();
matrix.postScale(scaleWidth, scaleHeight);
return Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, false);
}
Sampling :
mImageView.setImageBitmap(decodeSampledBitmapFromResource(getResources(),R.id.myimage, 100, 100));
public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
int reqWidth, int reqHeight) {
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(res, resId, options);
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
options.inJustDecodeBounds = false;
return BitmapFactory.decodeResource(res, resId, options);
}
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 halfHeight = height / 2;
final int halfWidth = width / 2;
while ((halfHeight / inSampleSize) >= reqHeight
&& (halfWidth / inSampleSize) >= reqWidth) {
inSampleSize *= 2;
}
}
return inSampleSize;
}
here both code perform image resizing but different way so how I can identify which one is good and simple.
First code, takes bitmap and creates new smaller bitmap - you would use memmory for the bigger bitmap.
Second code takes resource. inJustDecodeBounds Makes it so you not load the whole bitmap into memmory just information for it. Then calculate how it should be sized, and then again when set inJustDecodeBounds to false load into memmory reduced version of the image. So you would use memmory only for the decoded image
Oficial docs
Scaling: First, you decode the whole bitmap in memory, then you scale it.
Sampling: You get the required scaled bitmap without loading the whole bitmap in memory.
This question already has answers here:
What is a NullPointerException, and how do I fix it?
(12 answers)
Closed 6 years ago.
From the logcat I understand that the Activity crashes because of NullPointerException causes by this line of code.
mImageView.setImageBitmap(decodeSampledBitmapFromResource(getResources(),
R.id.picture, imageWidth, imageHeight));
I have read articles about similar problem but still getting NullPointerException. I think that mistake right under my nose, but still I can't catch it.
Where should I put this line to avoid NullPointerException?
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
ImageView mImageView = (ImageView) findViewById(R.id.picture);
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(getResources(), R.id.picture, options);
int imageHeight = options.outHeight;
int imageWidth = options.outWidth;
mImageView.setImageBitmap(decodeSampledBitmapFromResource(getResources(),
R.id.picture, imageWidth, imageHeight));
}
public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
int reqWidth, int reqHeight) {
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(res, resId, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeResource(res, resId, options);
}
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) {
final int halfHeight = height / 2;
final int halfWidth = width / 2;
// Calculate the largest inSampleSize value that is a power of 2 and keeps both
// height and width larger than the requested height and width.
while ((halfHeight / inSampleSize) > reqHeight
&& (halfWidth / inSampleSize) > reqWidth) {
inSampleSize *= 2;
}
}
return inSampleSize;
}
and here is ImageView from layout.
<ImageView
android:layout_height="240dp"
android:layout_width="199dp"
android:src="#drawable/galaxy"
android:id="#+id/picture"
android:layout_gravity="center_horizontal"
android:scaleType="fitCenter"
android:layout_weight="0.19" />
There is a cleaner alternative to display a bitmap onto a imageview.
Try this:
private Bitmap bitmap_image;
Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//get image from resources
bitmap_image = BitmapFactory.decodeResource(getResources(), R.drawable.picture);
ImageView mImageView = (ImageView) findViewById(R.id.picture);
mImageView.setImageBitmap(bitmap_image);
}
-To retrieve a image from resources and store it into a bitmap, use BitmapFactory.decodeResource(getResources(), R.drawable.yourimagename);
-at this point you can directly set the image to a imageView. If you want to manipulate the size of the image here is a function that will resize a bitmap:
public 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;
// 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(bm, 0, 0, width, height, matrix, false);
return resizedBitmap;
}
-If you need clarification on the re-sizing of the bitmap, refer to this stackoverflow post:
How to Resize a Bitmap in Android?
-if you need a full working example, i have a activity that utilizes retrieving a image from resources and storing it into a bitmap and then displaying it on screen. The only part I do not have that you request, is displaying the bitmap in a imageView.
Github class link:
https://github.com/Rifat-Rashid/thePlatformer/blob/master/MainActivity.java
I am developing an android application in which i want to set a Banner image on top of the screen which will come from server, i need to resize it dynamically according to the device size programmatically.
try this,
int iWidth=bmp.getWidth();
int iHeight=bmp.getHeight();
Display display = getWindowManager().getDefaultDisplay();
DisplayMetrics dm = new DisplayMetrics();
display.getMetrics(dm);
int dWidth=dm.widthPixels;
int dHeight=dm.heightPixels;
float sWidth=((float) dWidth)/iWidth;
float sHeight=((float) dHeight)/iHeight;
if(sWidth>sHeight) sWidth=sHeight;
else sHeight=sWidth;
Matrix matrix=new Matrix();
matrix.postScale(sWidth,sHeight);
newImage=Bitmap.createBitmap(bmp, 0, 0, iWidth, iHeight, matrix, true);
imageview.setImageBitmap(newImage);
You could check out the scale attributes of the ImageView in xml first
And resize using this
public static Bitmap getResizedBitmap(Bitmap image)
{
return Bitmap.createScaledBitmap(image, x, y, true);
}
Assuming you want to set an ImageView declared in your layout (for example with properties android:layout_width="match_parent" android:layout_height="wrap_content") you can adapt the following code:
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true; // just compute size, don't create bitmap
BitmapFactory.decodeStream(stream, null, options); // stream is the InputStream representing the image you want to display
int imageHeight = options.outHeight;
int imageWidth = options.outWidth;
imageViewWidth = imageView.getWidth(); // imageView is the View container for the image you want to display
imageViewHeight = imageView.getHeight();
// Compute the sample size
double sampleSize = computePowerOfTwoInSampleSize(options, imageViewWidth, imageViewHeight);
if(sampleSize<1) {
options.inSampleSize = 1;
}
else {
options.inSampleSize = (int) sampleSize;
}
options.inJustDecodeBounds = false; // compute size and create bitmap
bitmap = BitmapFactory.decodeStream(stream, null, options);
imageView.setImageBitmap(bitmap);
try {
stream.close();
}
catch (IOException e) {
e.printStackTrace();
}
where the method computePowerOfTwoInSampleSize is something like this (take into consideration that resizing to power of 2 is more efficient compared to other values):
private double computePowerOfTwoInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
int height = options.outHeight;
int width = options.outWidth;
double inSampleSize = 1;
// compute the up-sample coefficient (power of 2)
if(height < reqHeight && width < reqWidth) {
while(height < reqHeight && width < reqWidth) {
height = height*2;
width = width*2;
if(height < reqHeight && width < reqWidth) {
inSampleSize = inSampleSize/2;
}
}
}
// compute the down-sample coefficient
else {
while(height > reqHeight || width > reqWidth) {
// Calculate ratios of height and width to requested height and width (power of 2)
height = Math.round((float)height/2);
width = Math.round((float)width/2);
inSampleSize = inSampleSize*2;
}
}
return inSampleSize;
}
im having problems with high resolution images.
Im using nodpi-drawable folder for 1280x720 images, and using this code to scale it.
public static Drawable scaleDrawable(Drawable d, int width, Activity cxt)
{
BitmapDrawable bd = (BitmapDrawable)d;
double oldWidth = bd.getBitmap().getWidth();
double scaleFactor = width / oldWidth;
int newHeight = (int) (d.getIntrinsicHeight() * scaleFactor);
int newWidth = (int) (oldWidth * scaleFactor);
Drawable drawable = new BitmapDrawable(cxt.getResources(),MainScreen.getResizedBitmap(bd.getBitmap(),newHeight,newWidth));
BitmapDrawable bd2 = (BitmapDrawable)drawable;
return drawable;
}
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;
// 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(bm, 0, 0, width, height, matrix, false);
return resizedBitmap;
}
I use that code to scale images to screen witdh so if the screen is 320x480 the image will scale to 320 and keep proportions, i dont care if image go out of screen from bottom.
All its working fine, but when trying in a xhdpi device specifically a Samsung Galaxy Note 2 with a screen of exactly 720x1280.
It crash with Out Of Memory Exception in the line:
Bitmap resizedBitmap = Bitmap.createBitmap(bm, 0, 0, width, height, matrix, false);
I cant understand why, the image should be scaled from 720 to 720 but my code must be really bad optimized or something.
I havent tried on a 1080x1920 device but it seems it will crash too.
Someone can see something bad when looking at the code?
use this method to resize your bitmap-
Bitmap bm=decodeSampledBitmapFromPath(src, reqWidth, reqHeight);
use this Defination-
public Bitmap decodeSampledBitmapFromPath(String path, int reqWidth,
int reqHeight) {
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(path, options);
options.inSampleSize = calculateInSampleSize(options, reqWidth,
reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
Bitmap bmp = BitmapFactory.decodeFile(path, options);
return bmp;
}
}
public 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) {
if (width > height) {
inSampleSize = Math.round((float) height / (float) reqHeight);
} else {
inSampleSize = Math.round((float) width / (float) reqWidth);
}
}
return inSampleSize;
}
If you are using resource then replace method with BitmapFactory's decodeResource method..
public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
int reqWidth, int reqHeight) {
....
.....
return BitmapFactory.decodeResource(res, resId, options);
}
You should use the utility class BitmapFactory for image-processing-operations. Also use BitmapFactory.Options to adjust the input/output sizes of the bitmaps. After a bitmap is not needed anymore, you should free the related memory.
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