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" />
Related
I am using EasyImage library to take pictures.
I then convert those Files to Bitmap and then I convert Bitmap to Base64 and upload it to server.
I know, it's not a good way to do it, but that's how I currently do it.
When a picture is taken:
#Override
public void onImagePicked(File imageFile, EasyImage.ImageSource source) {
uploadImage(imageFile);
}
This is the first line inside "uploadImage" method:
Image image = new Image(LoginManager.getInstance(getApplicationContext()).getUsername(), file);
This is the constructor:
public Image(String userName, File imageFile) {
this.userName = userName;
this.imageFile = imageFile;
createBase64(getBitmap());
}
Inside "getBitmap" is where the problem begins. These 2 lines in particular:
bitmap = BitmapFactory.decodeFile(imageFile.getPath());
bitmap = Bitmap.createScaledBitmap(bitmap, 100, 100, false);
imageFile is never null.
I checked with debugger at least a 100 times and it is never null. It also always has path.
getPath() is never null.
However, it still often fails to create bitmap.
Sometimes it is successful and everything is OK, but most of the times, the bitmap is null.
I don't know why.
File (the picture taken) is always created successfully and is never null, but it just fails to create the Bitmap for some reason.
From the documentation
Returns
the resulting decoded bitmap, or null if it could not be decoded.
This can have various reasons, most of the times the bitmap is too large and the space could not be allocated.
Check that the path to the image exists and that you have read / write permissions to the URI specified.
If you do have access but it is still failing you should add BitmapFactory.Options to the method call and set inSampleSize to load a smaller version of the image.
If set to a value > 1, requests the decoder to subsample the original image, returning a smaller image to save memory.
Also you should always check for null returned when working with bitmaps, since memory can always be an issue.
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?
I am trying to process a bmp image obtained from Android's camera intent through the following steps:
Obtain bmp image from intent
Convert bmp image to Mat object for OpenCV processing (problem starts here)
Do needed OpenCV processing (through sending Mat object, obj, as obj.getNativeObjAddr() to native processing, or perform it locally in java).
Convert Mat object back to bmp
The problem is indeed not novel. I have found countless similar questions online, none of which seem to resolve the situation however.
Results (problem)
The intention is to display the processed image (that undergoes the above 4 steps) in an ImageView object. After running, the ImageView however remains unchanged and logcat emits the following warning on reaching the line calling Utils.bitmapToMat()
W/System.err(3872): java.lang.IllegalArgumentException: mat == null
Code
Below is the code's outline that is used in the onActivityResult method (resultant_bmp is the acquired bmp from the camera intent. It displays successfully on its own).
filePath is the file path, name and extension included, of resultant_bmp.
The first 3 lines following the starting if condition are from here, where its use seems to work fine in the mentioned question.
Bitmap resultant_bmp /*image from camera*/,
bmp /*image after opencv processing*/;
Mat rgb_img, gray_img;
if (OpenCVLoader.initDebug()) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Config.RGB_565;
resultant_bmp= BitmapFactory.decodeFile(filePath, options);
/****************** Problem starts HERE ******************
Last point reachable before Logcat states:
W/System.err(4460):java.lang.IllegalArgumentException: mat == null
After this point, the program doesn't crash, but expected results
in the imageView (last line of code) do not result.
**********************************************************/
Utils.bitmapToMat(resultant_bmp, rgb_img);
Imgproc.cvtColor(rgb_img, gray_img, Imgproc.COLOR_RGBA2GRAY);
/*Do opencv processing (on gray_img) here*/
Utils.matToBitmap(gray_img, bmp);
imageView.setImageBitmap(bmp);
}
Previous attempts& research
I found a similar problem here and tried, as recommended, to push the file libopencv_java.so to system/lib on the device, using adb in command line and received the error:
failed to copy 'libopencv_java.so' to 'system/lib/libopencv_java.so': Read-only file system
This question considers the same problem domain in the current question; the code provided above follows a similar pattern as that suggested there, which still doesn't work.
Based on this answer (as well as this aforementioned one), I added the following lines to the code:
System.loadLibrary("opencv_java");
System.loadLibrary("libopencv_java");
I have added the OpenCV library to the project properties; as well as the NDKROOT variable indicating where the NDK root path lies, as explained further here.
I've tried the image processing required (in step 3 above) in another working sample of OpenCV's, so the problem definitely lies within step 2 (above); conversion of a bmp to a Mat object.
There should be a simple solution around this, but I cannot seem to find it. Help would be much appreciated if possible.
Thank you for your time.
Have you initialized your mat variable ? I couldnt find it in provided code.
Add this before you try to convert to mat.
Mat rgb_img = new Mat();
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 am working on a file manager kind of application in android in which i want to create thumbnails of the images.Thumbnails are getting created but the application often force closes giving out Out Of Memory Exception...
i tried out following code
icon.setImageURI(Uri.parse(path));
icon.setScaleType(ScaleType.FIT_XY);
icon.setLayoutParams(new LinearLayout.LayoutParams(30,30));
addView(icon);
Make sure that when you load the images you specify a sample rate to BitmapFactory.Options. This will keep your bitmaps from getting too big:
BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inSampleSize = 4;
... use a BitmapFactory method, passing opts ...
I did like this it worked
Bitmap imagethumbnail=BitmapFactory.decodeFile(path); //complete file path
imagethumbnail=Bitmap.createScaledBitmap(imagethumbnail, 40, 40, true);