My code:
BitmapFactory.Options opt = new BitmapFactory.Options();
opt.inJustDecodeBounds = true;
Bitmap rotateBmp = BitmapFactory.decodeFile("/storage/sdcard0/FastBurstCamera/2014-09-15 05-24-07-461.jpg", opt);
The file /storage/sdcard0/FastBurstCamera/2014-09-15 05-24-07-461.jpg exists, but the rotateBmp is null, why?
The file /storage/sdcard0/FastBurstCamera/2014-09-15 05-24-07-461.jpg exists, but the rotateBmp is null, why?
Because that's what you asked for.
Quoting the documentation for decodeFile() (emphasis added):
The decoded bitmap, or null if the image data could not be decoded, or, if opts is non-null, if opts requested only the size be returned (in opts.outWidth and opts.outHeight)
Quoting the documentation for inJustDecodeBounds:
If set to true, the decoder will return null (no bitmap), but the out... fields will still be set, allowing the caller to query the bitmap without having to allocate the memory for its pixels.
The reason may be the image size is big. Check this question.
Another reason may be not adding READ_EXTERNAL_STORAGE and/or WRITE_EXTERNAL_STORAGE permissions to your manifest file. Did you add?
Related
I'm going to compress image with Bitmap.compress() method.
But when I get Bitmap using bitmap = BitmapFactory.decodeFile() I get a null object, and the method didn't thow any exception.
Here's my code
public static File compressImage(String imagePath) throws IOException {
// Get bitmap
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
Bitmap bitmap = BitmapFactory.decodeFile(imagePath, options);
// Get bitmap output stream
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, byteArrayOutputStream);
......
When the code runs at the last line I get a NullPointerException :
java.lang.NullPointerException: Attempt to invoke virtual method 'boolean android.graphics.Bitmap.compress(android.graphics.Bitmap$CompressFormat, int, java.io.OutputStream)' on a null object reference
Then I run my code in debug mode, it turns out I got a null object from BitmapFactory.decodeFile method.
The parameter imagePath is
/storage/emulated/0/DCIM/Camera/IMG_20160610_195633.jpg
which seems ok.
This piece of code works well in another activity, but when i copy it to a async thread which I attempt to compress and upload images, it crashed. Is there any possibilities that this is because the async thread thing? Or something else I didn't notice?
Remove the following from your code:
options.inJustDecodeBounds = true;
From the documentation of inJustDecodeBounds:
If set to true, the decoder will return null (no bitmap), but the
out... fields will still be set, allowing the caller to query the
bitmap without having to allocate the memory for its pixels.
inJustDecodeBounds is useful to load large Bitmaps efficiently, since you can read their dimensions without having to allocate the memory for them, although it has no purpose in your code.
This answer applies if you are using your phone connected via USB to debug your code. My phone indicates Android version 6.0.1.
I read all of the posts about setting my "Uses-permission" fields and my code still didn't work. I found, however, that I needed to go into my device under "settings->device->applications->application manager" and then click on the application I was debugging and navigate to "Permissions" and manually enable the requested permissions.
The following permissions must be in your AndroidManifest.xml
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
By following this link, I have written the following code to show a large image bitmap from sdcard.
try {
InputStream lStreamToImage = context.getContentResolver().openInputStream(Uri.parse(imagePath));
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeStream(lStreamToImage, null, options);
options.inSampleSize = 8; //Decrease the size of decoded image
options.inPreferredConfig = Bitmap.Config.ARGB_4444;
options.inJustDecodeBounds = false;
bitmap = BitmapFactory.decodeStream(lStreamToImage, null, options);
} catch(Exception e){}
image.setImageBitmap(bitmap);
But it is not returning the bitmap(I mean it returns null). In logcat it is showing the below message repeatedly
08-02 17:21:04.389: D/skia(19359): --- SkImageDecoder::Factory returned null
If I will comment the options.inJustDecodeBounds line and rerun it, it works fine but slowly. The developer guide link I provided above says to use inJustDecodeBounds to load bitmaps efficiently.
Please tell me where I am doing wrong.
inJustDecodeBounds does not load bitmaps. That's the point of it. It loads the dimensions of the bitmap without loading the actual bitmap so you can do any pre-processing or checking on the bitmap before you actually load it. This is helpful is you, say, were having memory issues and you needed to check if loading a bitmap would crash you program.
The reason your bitmap might be loading slowly is because it's probably very large and SD cards are very slow.
EDIT:
From the documentation:
If set to true, the decoder will return null (no bitmap), but the out... fields will still be set, allowing the caller to query the bitmap without having to allocate the memory for its pixels.
Edit 2:
Looking at your code with the example provided by Google, it looks like you are doing relatively the same thing. The reason it's returning null is possibly your InputStream has been modified in the first decoding and thus not starting at the beginning of the bitmap's memory address (they use a resource ID rather than InputStream.
From the code you supplied here, here's what I've figured. You are ALWAYS setting a sample size to 8 regardless of what the first decoding gives you. The reason Google decodes the first time is to figure out what the actual size of the bitmap is versus what they want. They determine that the bitmap is ZxZ dimensions and they want YxY dimensions, so they calculate the samplesize that they should use from the second decoding. You are not doing this. You are simply retrieving the dimensions of the bitmap and not using them. THEN, you set the sample size to a hard-coded 8, swapping it to a hard-coded ARGB_4444 bitmap, then decoding the full bitmap in to memory. In other words, these three lines are not being used:
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeStream(lStreamToImage, null, options);
Setting inJustDecodeBounds merely gives you the bitmap's dimensions without putting the bitmap in to memory. It doesn't make it more efficient. It's meant to allow you to load bitmaps in a smaller memory space if they are too big because you can pre-decide what size it should be without decoding the whole thing).
The reason decoding the bitmap is slow might merely be a CPU thing. Depending on the size of your bitmap, you're loading the bitmap from an InputStream from the SDcard which is a slow operation in itself.
I try to load jpeg resource image to Bitmap of ARGB_8888 format:
BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inPreferredConfig = Bitmap.Config.ARGB_8888;
Bitmap b = BitmapFactory.decodeResource(resources, resId, opts);
Log.d("test", b.getConfig().toString());
Here resId is the id of a jpeg image resource.
And the output is "RGB_565".
Tried this in emulators of android 2.2 and 2.3.
Docs of 'inPreferredConfig' say:
If this is non-null, the decoder will try to decode into this internal
configuration. If it is null, or the request cannot be met, the
decoder will try to pick the best matching config based on the
system's screen depth, and characteristics of the original image such
as if it has per-pixel alpha (requiring a config that also does).
Image are loaded with the ARGB_8888 config by default.
So am I hitting the case of "the request cannot be met"? :)
But I honestly can't see how it is very difficult to decode RGB_565 into an ARGB_8888.
So I thought maybe I am doing wrong or this is a bug in Android...
When loading jpeg you must set alpha channel to true:
bitmap.setHasAlpha(true);
After looking through the source I can only tell that the decision to follow the defined inPreferredConfig is done in native code. ref: source
I would assume because a jpg cannot have an alpha channel that it is decoding it RGB_565 because it is the most efficient config for a non-alpha image. If you really want it to be decoded to ARGB_8888 convert the image into a png.
I'm making several calls to BitmapFactory.decodeFile() and BitmapFactory.decodeResource(), and I'd like to specify the format the bitmaps are decoded to, such as RGB_565 or RGBA_8888.
Currently, the decoded bitmap format seems to depend on the incoming image. Alternatively, is there a way to convert an existing bitmap to a specific format?
The reason this is important is that when I try to decode the image using jnigraphics, some images return an AndroidBitmapFormat of type ANDROID_BITMAP_FORMAT_NONE, which I assume is useless. Does anyone have more insight into why the format would be none of the known values? When this happens, the built-in image picker correctly displays images that are decoded this way, so I assume there has to be a way to deal with them.
Thanks for your input!
This might be what you are looking for:
BitmapFactory.Options op = new BitmapFactory.Options();
op.inPreferredConfig = Bitmap.Config.ARGB_8888;
bitmap = BitmapFactory.decodeFile(path, op);
When you have bitmap you can call copy method on it specifying BitmapConfig which is basically what you want.
http://developer.android.com/reference/android/graphics/Bitmap.html#copy(android.graphics.Bitmap.Config,boolean)
I used the BitmapFactory.decodeFile method to decode an image file in Android.
About the output bitmap, what is the property of the Bitmap.Config ?
(ALPHA_8 , ARGB_4444, ARGB_8888 or RGB_565 ?)
Thanks
If you're asking for more information on these values you must read this blog entry: http://www.curious-creature.org/2010/12/08/bitmap-quality-banding-and-dithering/
edit: You're asking what the value of Bitmap.Config will be after using the Bitmap.decodeFile():Bitmap method.
According to API you can use either decodeFile with param pathName:String or with params pathName:String and opts:Bitmap.Options. That second method accepts options for decoding. One of these is a Bitmap.Config param with this information (again from API):
public Bitmap.Config inPreferredConfig If this is non-null, the decoder will try to decode into this internal configuration.