Android get image from path (gallery, pictures ect) - android

Need to get image from path. I have tried everything but don't seem to get the image.
My two image paths:
/storage/emulated/0/DCIM/Camera/20161025_081413.jpg
content://media/external/images/media/4828
How do i set my image from these paths?
I am using ImageView to display my image.
My code:
File imgFile = new File("/storage/emulated/0/DCIM/Camera/20161025_081413.jpg");
Bitmap myBitmap = BitmapFactory.decodeFile(imgFile.getAbsolutePath());
holder.myimage.setImageBitmap(myBitmap);
Thanks in advance

Regularly, you can just write BitmapFactory.decodeBitmap(....) etc, but the file can be huge and you can get the OutOfMemoryError in no time, especially, if you do decoding a few times in the row. So you need to compress the image before setting it to view, so you won't run out of memory. Here is the proper way to do it.
File f = new File(path);
if(file.exists()){
Bitmap myBitmap = ImageHelper.getCompressedBitmap(photoView.getMaxWidth(), photoView.getMaxHeight(), f);
photoView.setImageBitmap(myBitmap);
}
//////////////
/**
* Compresses the file to make a bitmap of size, passed in arguments
* #param width width you want your bitmap to have
* #param height hight you want your bitmap to have.
* #param f file with image
* #return bitmap object of sizes, passed in arguments
*/
public static Bitmap getCompressedBitmap(int width, int height, File f) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(f.getAbsolutePath(), options);
options.inSampleSize = calculateInSampleSize(options, width, height);
options.inJustDecodeBounds = false;
return BitmapFactory.decodeFile(f.getAbsolutePath(), 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;
}

I found my problem. I am using Android SDK 23.
From the Android documentation.
If the device is running Android 6.0 or higher, and your app's target SDK is 23 or higher: The app has to list the permissions in the manifest, and it must request each dangerous permission it needs while the app is running. The user can grant or deny each permission, and the app can continue to run with limited capabilities even if the user denies a permission request.
https://developer.android.com/training/permissions/requesting.html
Hopes this helps someone else

Related

Android Shadow is not showing in ActionBar

I have problem with shadow of ActionBar it doesn't show when i add this : android:hardwareAccelerated="false" in my AndroidManifest.xml but when i delete this line it show shadow well and show other problem in my Activity which has Recycleview with items of images(small size images) it be very slow when i scroll the Recycleview, but when add android:hardwareAccelerated="false" scrolling be normal.
Please anyone could help me with this?
According to google documentation
Beginning in Android 3.0 (API level 11), the Android 2D rendering pipeline supports hardware acceleration, meaning that all drawing operations that are performed on a View's canvas use the GPU. Because of the increased resources required to enable hardware acceleration, your app will consume more RAM.
So i guess writing android:hardwareAccelerated="false" stops the app from making use of the GPU, hence reducing GPU rendered effects like shadows.
A couple of things that you can do is
Add the android:hardwareAccelerated="false" for the specific activity where you want to load heavy images. Click here to check that.
Try and reduce the size of the images that you are loading. This can be done using the following two functions as documented in the developer documentation for android. Click here for the complete documentation.
Function 1
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;
}
Function 2
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);
}
Set Image in ImageView
mImageView.setImageBitmap(
decodeSampledBitmapFromResource(getResources(), R.id.myimage, 100, 100));
Also refer this link for a another reference about Image Resizing.

How are you supposed to "load large bitmaps efficiently" if you can't get the dimensions?

I am getting pretty frustrated with all these official Android docs that conveniently gloss over the fact that even when you apply a Bitmap to an ImageView, the ImageView's dimensions are 0, 0, and yet you can't get the dimensions prior to mapping, either!
https://developer.android.com/training/displaying-bitmaps/load-bitmap.html
All these methods assume you already know fixed dimensions for the ImageView's height and width in terms of pixels, but this is almost useless because in practice you're supposed to either use dp units or layout_weight so things scale to the viewable region so things look right on various phones.
The only way, it would seem, to get the dimensions is to go to the trouble of inefficiently mapping the bitmap and then getting the dimensions that way, but even if you do, the dimensions will show up as 0 if you do imageView.getWidth() or getHeight()! You have to do a bunch of weird async stuff to wait until the dimensions somehow "settle" and THEN you can finally get the dimensions, but at this stage, what's the point when you've already wasted time doing an inefficient mapping?
Is there some well known workaround to all this that Google isn't explaining in the docs? How are you supposed to know the ImageView dimensions when you're not working with pixels in the XML? It's mind-boggling to me that this isn't documented more.
Here is a sample of the problem:
<ImageView
android:id="#+id/my_imageview"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"/>
I have this ImageView inside a DialogFragment. The idea is that I can map a Bitmap to this ImageView and it will fit inside the DialogFragment by means of something like myImageView.setImageBitmap(BitmapFactory.decodeFile(path_to_file));, but this by itself is inefficient if the Bitmap is large.
However, in order to load the Bitmap efficiently, you need to already know the dimensions of the ImageView -- and in pixels! But you can't get the dimensions of the ImageView until you've already mapped the Bitmap inefficiently and waited for some kind of post-execute stage where the dimensions have settled in.
These are the methods I am using to do efficient mapping (assuming you already know the sizes -- it breaks if one of the dimensions is 0, so I added a fix). This code is from Google:
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 == 0 || width == 0) {
return 0; //my fix
}
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 decodeSampledBitmapFromFilePath(String pathName, int reqWidth, int reqHeight) {
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(pathName, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeFile(pathName, options);
}
And for example this does not work:
myImageView.post(new Runnable() {
#Override
public void run() {
int reqHeight = myImageView.getHeight(); //height = 0
int reqWidth = myImageView.getWidth(); //width = 528
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(picFullPath, options);
int realWidth = options.outWidth;
int realHeight = options.outHeight;
reqHeight = realHeight * reqWidth / realWidth; //reqHeight = 396, reqWidth = 528
Bitmap bm = decodeSampledBitmapFromFilePath(picFullPath, reqWidth, reqHeight);
myImageView.setImageBitmap(bm);
}
});
myImageView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
int finalHeight = myImageView.getHeight(); //480!
int finalWidth = myImageView.getWidth(); //608!
}
});
You Should get height and Width of view after inflate any view from XML or Dynamically and then use bellow code to get rendered view height and width :
imageView.measure(0,0);
imageView.getMeasuredHeight();
imageView.getMeasuredWidth();
But Above method may given 0 for height and width , if you are not passing any height and width from XML or you are not used any relative property in Relative layout
I use this approach when I need to load bitmap after I know ImageView size:
myImageView.post(new Runnable() {
#Override
public void run() {
int requiredHeight = myImageView.getHeight(); //height is ready, but is 0 - not calculated.
int requiredWidth = myImageView.getWidth(); //width ready
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(pathName, options);
int realWidth = option.outWidth;
int realHeight = option.outHeight;
//calculating required Height
requiredHeight = realHeight / realWidth * requiredWidth;
//now we have both - required height and width.
Bitmap bm = decodeSampledBitmapFromFilePath(pathName, requiredWidth, requiredHeight);
myImageView.setImageBitmap(bm);
}
});

Android Out of Memory error on drawable folder [duplicate]

This question already has an answer here:
Bitmap too large to be uploaded into a texture
(1 answer)
Closed 7 years ago.
In my android app, have all the images in the drawable folder. On most phones, we had no issue. But some phones have out of memory error. When the images copying for example to the drawable-xhdpi folder the issue is gone. What is the reason this problem, how can i fix it?
drawable is equivalent of drawable-mdpi
If you put your images in that folder they will get up-sampled for higher resolutions devices and that up-sampling can trigger OOM if images are large.
If you put same sized images in drawable-xhdpi you will have upsampled images only on larger xxhdpi devices, and downsampled on others.
If you want to avoid automatic up/down sampling of images put them in drawable-nodpi folder.
Different devices might have different size limits. Try using: drawable-xxhdpi
Helpful cheat sheet: http://i.stack.imgur.com/kV4Oh.png
For managing Out Of Memory Error one thing you may need to do is reduce the image size by compressing it and keep it in drawable folders.which is useful to reduce the app size and also memory consumption at runtime.
Or you may need to use the following class for reducing the image size aspect ratio.
ImageResizer
public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
int reqWidth, int reqHeight, boolean isLow) {
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
if (isLow) {
options.inPreferredConfig = Bitmap.Config.RGB_565;
}
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);
}
/**
* Calculate an inSampleSize for use in a {#link BitmapFactory.Options} object when decoding
* bitmaps using the decode* methods from {#link BitmapFactory}. This implementation calculates
* the closest inSampleSize that is a power of 2 and will result in the final decoded bitmap
* having a width and height equal to or larger than the requested width and height.
*
* #param options An options object with out* params already populated (run through a decode*
* method with inJustDecodeBounds==true
* #param reqWidth The requested width of the resulting bitmap
* #param reqHeight The requested height of the resulting bitmap
* #return The value to be used for inSampleSize
*/
public static int calculateInSampleSize(BitmapFactory.Options options,
int reqWidth, int reqHeight) {
// BEGIN_INCLUDE (calculate_sample_size)
// 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;
}
// This offers some additional logic in case the image has a strange
// aspect ratio. For example, a panorama may have a much larger
// width than height. In these cases the total pixels might still
// end up being too large to fit comfortably in memory, so we should
// be more aggressive with sample down the image (=larger inSampleSize).
long totalPixels = width * height / inSampleSize;
// Anything more than 2x the requested pixels we'll sample down further
final long totalReqPixelsCap = reqWidth * reqHeight * 2;
while (totalPixels > totalReqPixelsCap) {
inSampleSize *= 2;
totalPixels /= 2;
}
}
return inSampleSize;
// END_INCLUDE (calculate_sample_size)
}
Usage
private Bitmap mBackground;
private Drawable mBackgroundDrawable;
#Override
protected void onCreate(Bundle savedInstanceState) {
LinearLayout linearLayout = (LinearLayout) findViewById(R.id.parent);
final Resources res = getResources();
int[] dimensions = Util.getDisplayDimensions(this);
mBackground = ImageResizer.decodeSampledBitmapFromResource(res, R.drawable.bg, 100, 100, false);
mBackgroundDrawable = new BitmapDrawable(res, mBackground);
linearLayout.setBackground(mBackgroundDrawable);
}
#Override
protected void onDestroy() {
recycle();
super.onDestroy();
}
private void recycle() {
if (mBackground != null) {
mBackground.recycle();
mBackground = null;
if (mBackgroundDrawable != null)
mBackgroundDrawable = null;
}
}
Note : If your applying true as third argument which help you to reduce the image size effectively using Bitmap.Config.RGB_565.
if (isLow) {
options.inPreferredConfig = Bitmap.Config.RGB_565;
}
Finally, research about OOM.

How to make a bitmap take less memory on Android?

I have a set of image files stored in internal storage, each file size is about 750 KB. I need to create a 360 degrees animation like with this images, so, I load each image in a list, while I'm doing this process an out of memory exception appears.
I have been reading about bitmap processing on Android, but in this case is not about resize bitmap dimensions, the dimensions are OK (600, 450) because its a tablet application, is about image quality I think.
Is there a way to reduce the memory each bitmap takes?.
It is not possible without reducing image dimensions.
All images with the same dimensions require same amount of RAM, regardless it size on disk and compression. Graphics adapter don't understand different image types and compression and it needs only uncompressed raw array of pixels. And it size is constant
For example
size = width * height * 4; // for RGBA_8888
size = width * height * 2; // for RGB_565
So you should reduce image dimensions or use caching on the disk and remove bitmaps from the RAM that are currently invisible and reload from disk when needed.
There is a great resource on how to do this here:
http://developer.android.com/training/displaying-bitmaps/load-bitmap.html
Basically you need to load a bitmap at a different resolution using these two functions:
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;
}
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);
}
Then set the image as follows:
imageView.setImageBitmap(decodeSampledBitmapFromResource(getResources(),
R.drawable.my_image_resource,
imageView.getWidth(),
imageView.getHeight()));
Hope that helps!

How to avoid out of memory error? [duplicate]

This question already has answers here:
Strange OutOfMemory issue while loading an image to a Bitmap object
(44 answers)
Closed 8 years ago.
I am developing a game and I load 52 Bitmap files using BitmapFactory, and when running the App. I receive OutOfMemoryError. Is that because the images in the drawable folder are .JPG and not .PNG? Please let me know how to solve this issue.
JPG vs PNG doesn't matter, because when you load the bitmaps you uncompress them into raw data (basically the same as bmp). Uncompressed, each bitmap uses 4*width*height bytes. Depending on how big your images are, that can be very large. I would suggest using an LRUCache with a fixed size to hold only the images you actually need in memory and to kick out the unused ones.
I am dealing with 196 of png pictures in my app and ran into out of memory as well when I attempted to load all the images. My images are png, this means converting them from jpg to png didn't help.
I don't know if it's the optimum solution or not, but what I did is to start an IntentService from my main activity's OnCreate() method, first time it is called. Inside I check if a smaller version of the images is already stored on the internal storage. If the smaller versions are already created, I maintain a list of them and use them in my activities whenever I need to display them. If they are not present, which happens when the user installed the app for the first time, or the cache is cleared from the settings for this app, I create them by calling decodeSampledBitmapFromResource() with the desired width and height. The desired width and height can be store in an xml file and be specific for different screens. The functions I use for resizing while maintaining the image aspect are provided below.
/**
* Calculate in sample size.
*
* #param options the options
* #param reqWidth the req width
* #param reqHeight the req height
* #return the int
*/
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;
}
/**
* Decode sampled bitmap from resource.
*
* #param res the res
* #param resId the res id
* #param reqWidth the req width
* #param reqHeight the req height
* #return the bitmap
*/
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);
}

Categories

Resources