BitmapFactory.decodeStream always returning null value - android

Here I am fetching value from Cursor :
if (mProfileCursor.moveToFirst()) {
byte[] blob = mProfileCursor.getBlob(
mProfileCursor.getColumnIndex(ContactsContract.Profile.PHOTO_URI));
ByteArrayInputStream inputStream = new ByteArrayInputStream(blob);
BufferedInputStream bis = new BufferedInputStream(inputStream,1024);
bitmap = BitmapFactory.decodeStream(bis);
}
} finally {
if (mProfileCursor != null) {
mProfileCursor.close();
}
}
I am trying to change byte[] into a bitmap but I am getting always null, according to answers in following post Android: bitmapfactory.decodestream returns null I tried BufferedInputStream but it is not working for me.
Also Romain Guy here said that this is a known defect in android but answer is very old, please let me know if there is way for getting bitmap correct.

public static final String PHOTO_URI
Added in API level 11
A URI that can be used to retrieve the contact's full-size photo. If PHOTO_FILE_ID is not null, this will be populated with a URI based off CONTENT_URI. Otherwise, this will be populated with the same value as PHOTO_THUMBNAIL_URI. A photo can be referred to either by a URI (this field) or by ID (see PHOTO_ID). If either PHOTO_FILE_ID or PHOTO_ID is not null, PHOTO_URI and PHOTO_THUMBNAIL_URI shall not be null (but not necessarily vice versa). Thus using PHOTO_URI is a more robust method of retrieving contact photos.
Type: TEXT
Constant Value: "photo_uri"
This is what the doc says, pskink is right, it returns a String. Also to add decodeStream returns null if it is not able to decode the image data and it would not generate any exception as well, so be carefull, check the values before using this.

Related

Using mp4parser , how can I handle videos that are taken from Uri and ContentResolver?

Background
We want to let the user choose a video from any app, and then trim a video to be of max of 5 seconds.
The problem
For getting a Uri to be selected, we got it working fine (solution available here) .
As for the trimming itself, we couldn't find any good library that has permissive license, except for one called "k4l-video-trimmer" . The library "FFmpeg", for example, is considered not permission as it uses GPLv3, which requires the app that uses it to also be open sourced. Besides, as I've read, it takes quite a lot (about 9MB).
Sadly, this library (k4l-video-trimmer) is very old and wasn't updated in years, so I had to fork it (here) in order to handle it nicely. It uses a open sourced library called "mp4parser" to do the trimming.
Problem is, this library seems to be able to handle files only, and not a Uri or InputStream, so even the sample can crash when selecting items that aren't reachable like a normal file, or even have paths that it can't handle. I know that in many cases it is possible to get a path of a file, but in many other cases, it's not, and I also know it's possible to just copy the file (here), but this isn't a good solution, as the file could be large and take a lot of space even though it's already accessible.
What I've tried
There are 2 places that the library uses a file:
In "K4LVideoTrimmer" file, in the "setVideoURI" function, which just gets the file size to be shown. Here the solution is quite easy, based on Google's documentation:
public void setVideoURI(final Uri videoURI) {
mSrc = videoURI;
if (mOriginSizeFile == 0) {
final Cursor cursor = getContext().getContentResolver().query(videoURI, null, null, null, null);
if (cursor != null) {
int sizeIndex = cursor.getColumnIndex(OpenableColumns.SIZE);
cursor.moveToFirst();
mOriginSizeFile = cursor.getLong(sizeIndex);
cursor.close();
mTextSize.setText(Formatter.formatShortFileSize(getContext(), mOriginSizeFile));
}
}
...
In "TrimVideoUtils" file, in "startTrim" which calls "genVideoUsingMp4Parser" function. There, it calls the "mp4parser" library using :
Movie movie = MovieCreator.build(new FileDataSourceViaHeapImpl(src.getAbsolutePath()));
It says that they use FileDataSourceViaHeapImpl (from "mp4parser" library) to avoid OOM on Android, so I decided to stay with it.
Thing is, there are 4 CTORS for it, all expect some variation of a file: File, filePath, FileChannel , FileChannel+fileName .
The questions
Is there a way to overcome this?
Maybe implement FileChannel and simulate a real file, by using ContentResolver and Uri ? I guess it might be possible, even if it means re-opening the InputStream when needed...
In order to see what I got working, you can clone the project here. Just know that it doesn't do any trimming, as the code for it in "K4LVideoTrimmer" file is commented:
//TODO handle trimming using Uri
//TrimVideoUtils.startTrim(file, getDestinationPath(), mStartPosition, mEndPosition, mOnTrimVideoListener);
Is there perhaps a better alternative to this trimming library, which is also permissive (meaning of Apache2/MIT licences , for example) ? One that don't have this issue? Or maybe even something of Android framework itself? I think MediaMuxer class could help (as written here), but I think it might need API 26, while we need to handle API 21 and above...
EDIT:
I thought I've found a solution by using a different solution for trimming itself, and wrote about it here, but sadly it can't handle some input videos, while mp4parser library can handle them.
Please let me know if it's possible to modify mp4parser to handle such input videos even if it's from Uri and not a File (without a workaround of just copying to a video file).
First of all a caveat: I am not familiar with the mp4parser library but your question looked interesting so I took a look.
I think its worth you looking at one of the classes the code comments say is "mainly for testing". InMemRandomAccessSourceImpl. To create a Movie from any URI, the code would be as follows:
try {
InputStream inputStream = getContentResolver().openInputStream(uri);
Log.e("InputStream Size","Size " + inputStream);
int bytesAvailable = inputStream.available();
int bufferSize = Math.min(bytesAvailable, MAX_BUFFER_SIZE);
final byte[] buffer = new byte[bufferSize];
int read = 0;
int total = 0;
while ((read = inputStream.read(buffer)) !=-1 ) {
total += read;
}
if( total < bytesAvailable ){
Log.e(TAG, "Read from input stream failed")
return;
}
//or try inputStream.readAllBytes() if using Java 9
inputStream.close();
ByteBuffer bb = ByteBuffer.wrap(buffer);
Movie m2 = MovieCreator.build(new ByteBufferByteChannel(bb),
new InMemRandomAccessSourceImpl(bb), "inmem");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
But I would say, there looks to be somewhat of a conflict between what you want to achieve and the approach the parser takes. It is depending on local files to avoid large memory overheads, and random access to bytes can only be done if the entire set of data is available, which differs from a streaming approach.
It will require buffering at least the amount of data required for your clip in one go before the parser is given the buffer. That might be workable for you if you are looking to grab short sections and the buffering is not too cumbersome. You may be subject to IO exceptions and the like if the read from the InputStream has issues, especially if it is remote content, whereas you really aren't expecting that with a file on a modern system.
There is also MemoryFile to consider which provides an ashmem backed file-like object. I think somehow that could be worked in.
Next a snipped shows how to open a MediaStore Uri with IsoFile from Mp4Parser. So, you can see how to get a FileChannel from a Uri.
public void test(#NonNull final Context context, #NonNull final Uri uri) throws IOException
{
ParcelFileDescriptor fileDescriptor = null;
try
{
final ContentResolver resolver = context.getContentResolver();
fileDescriptor = resolver.openFileDescriptor(uri, "rw");
if (fileDescriptor == null)
{
throw new IOException("Failed to open Uri.");
}
final FileDescriptor fd = fileDescriptor.getFileDescriptor();
final FileInputStream inputStream = new FileInputStream(fd);
final FileChannel fileChannel = inputStream.getChannel();
final DataSource channel = new FileDataSourceImpl(fileChannel);
final IsoFile isoFile = new IsoFile(channel);
... do what you need ....
}
finally
{
if (fileDescriptor != null)
{
fileDescriptor.close();
}
}
}

Why is BitmapFactory.decodeStream returning null?

Basically I am parsing some JSON that has an image with it and trying to load it into a ImageView. However mBitmap is returning null. I have no idea why and further research has not helped..
Here is an example url I am working with:
http://b.thumbs.redditmedia.com/ivBAJzLMJEkEy9jgTy3z4n-mO7gIGt5mQFU1Al5kJ-I.jpg
Here is all relevant code:
public static Bitmap LoadImageFromUrl(String url){
try {
mBitmap = BitmapFactory.decodeStream((InputStream)new URL(url).getContent());
return mBitmap;
}catch (Exception e){
Log.d(TAG,"Error getting image");
return null;
}
}
Here is where the method is called:
mListingModel.setmImageView(LoadImageFromUrl(data.getString(JSON_THUMBNAIL)));
Here is where I set the ImageView:
if(mItem.getmImageView() != null) {
holder.imageView.setImageBitmap(mItem.getmImageView());
}
Note: I am calling the method in an AsyncTask so that is not the problem.
The javadoc for Bitmap.decodeStream() states that:
If the input stream is null, or cannot be used to decode a bitmap, the
function returns null
You're passing it the results of URL.getContent(), which states in its javadoc:
By default this returns an InputStream, or null if the content type of
the response is unknown.
So maybe you should check to see if getContent() returns null before passing it on to the decoder.
i had in the past stupid problems like having my stream reached the end before i decoded it, so ensure to set it's position to 0 before decoding the stream
eg.
stream.Position = 0;
var bmp = BitmapFactory.DecodeStream(stream);
Can you check if this works for you:
InputStream in = new java.net.URL(downloadURL).openStream();
Bitmap avatarBmp = BitmapFactory.decodeStream(in);
in.close();
Also a reminder to add this in your Manifest
<uses-permission android:name="android.permission.INTERNET" />
I had the same problem.
I tried to find decode fail reason.. but I couldn't find.
I just confirmed that InputStream and BufferedInputStream are not null.
After restarting my AVD.. the problem was resolved even though I didn't change any code.

android Blob image not loading

here i want to display a image logo which i am receiving from a sqlite as blob database when i dont have internet, though i know its a not a good practice but i want to make it simpler this way.
Problem i am facing is i am able to receive image in log but some warning (link below) is coming because of which it is not loading it into imageView.
Here's the warning i am getting in log !!
I am unable to figure out why it still running DownloadImageTask which is a async task even when not online that is isOnline()==false !!
ImageView logo = (ImageView)findViewById(R.id.Logo);
Bundle extras = getIntent().getExtras();
if(isOnline(this)==true);
{
String link = extras.getString("Logo1");
new DownloadImageTask(logo).execute(link);
}
if(isOnline(this)==false){
Log.d("offline","image");
Log.d("offline",extras.getByteArray("Logo2").toString());
//getting these ^^ in log
byte[] outImage=(byte[]) extras.getByteArray("Logo2");
if(outImage!=null)
{
ByteArrayInputStream imageStream = new ByteArrayInputStream(outImage);
Bitmap theImage = BitmapFactory.decodeStream(imageStream);
logo.setImageBitmap(theImage);
}
}
}
if(isOnline(this)==true)//you Superfluous add a ";" in this
{
String link = extras.getString("Logo1");
new DownloadImageTask(logo).execute(link);
}
i am a newbie,hope can help you

Android ImageManager Google Game Services

We are trying to download avatars from Google Play Game Services at URIs like content :/ / ... through android-class ImageManager, but for unknown reasons, the class stops loading on same avatars, simply ceases to come in response OnImageLoadedListener. Each picture is a separate instance of the manager.
All avatars are valid (for the tests, each at least once loaded) no exceptions catch, the context in create manager is valid, tried everything, from the current Activity to getApplicationContext().
Tried to make loading and asynchronously and synchronously.
What is remarkable: after the last loader's action is always line in log with garbage collector and then do not continue to load (the application continues its work), although all references to objects are stored.
More often than not finish loading the last avatar.
Has anyone encountered a similar problem? Appears on versions from 2.3 to 4.2
Code in the alternate boot:
static ImageManager imageManager = null;
static int id = 0;
static Uri uri = null;
...
// ...
// change id & uri
// ...
imageManager = ImageManager.create(context);
Log.v("app", "LoadImageFromGoogle Manager created for Image #" + id);
imageManager.loadImage(new OnImageLoadedListener() {
#Override
public void onImageLoaded(Uri arg0, Drawable arg1) {
try {
Log.v("app", "LoadImageFromGoogle Image loaded #" + id);
Bitmap bm = ((BitmapDrawable)arg1).getBitmap();
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bm.compress(Bitmap.CompressFormat.PNG, 100, stream);
byte[] byteArray = stream.toByteArray();
// ... some code
Log.v("app", "LoadImageFromGoogle Image added #" + id);
} catch (Exception e) {
Log.v("app", "LoadImageFromGoogle after loading Exception = " + e.toString());
}
}
}, uri, android.R.drawable.btn_star);
the last line in the log is always the case:
Log.v("app", "LoadImageFromGoogle Manager created for Image #" + id);
and the following message GC.
Hmm.... I've never seen this issue. Are you sure you are feeding it a valid URI? My first guess would be that it might be an off-by-one error somewhere in your code where you're passing an invalid URI the last time you call imageManager.loadImage(). I'd try making the above code print the URIs it's trying to load as well as the image numbers, to see if something weird comes up.
If not, can you make a simple repro case and post it to our public bug tracker?
http://code.google.com/p/play-games-platform
Thanks!
I had the same problem. It looks like garbage collector can "clean" the listener before it can retrieve the image. The way to solve the problem is to implement the ImageManager.OnImageLoadedListener directly on your activity and not creating a new object on the moment.
Here you can find a related issue on google code:
https://code.google.com/p/play-games-platform/issues/detail?id=14&can=1&sort=-status&colspec=ID%20Type%20Status%20Priority%20Platform%20Summary%20Stars
Never is to late ;)

Uri.toString() returns a reference instead of the String

When attempting to execute this code in an Android Activity:
Uri testurl = Uri.parse("http://www.google.com");
Log.v("HTTPGet", "testurl.toString == " + testurl.toString());
the only output in Logcat is a reference to a string, but not the string itself:
HTTPGet(23045): testurl.toString == [Landroid.net.Uri;#4056e398
How can I print the actual string?
ORIGINAL ANSWER (Scratch it)
Uri.toString writes out a description of the URI object from the class Uri.
Documentation is here: http://developer.android.com/reference/android/net/Uri.html
To get the human readable version, invoke the getter methods defined for the class.
THE REAL ANSWER
The OP has clarified and provided the actual code. Here is the actual context:
#Override
protected Document doInBackground(Uri... arg0) {
Document ret = null;
Log.v("HTTPGet", "Uri.toString == " + arg0.toString());
try {
ret = Jsoup.connect(arg0.toString()).get();
} catch (IOException e) {
e.printStackTrace();
}
return ret;
}
What is happening here is that the parameter arg0 has type Uri[], namely an array of Uri. The dot-dot-dot syntax is Java's "varargs". It means the parameter is actually an array, but rather than passing an array in the call, you can pass any number of arguments that Java will bundle up into an array.
Because you are using a third party library, you have to override this method which takes in one or more Uris. You are assuming that only one will be used. If this is the case, you should instead write
Log.v("HTTPGet", "Uri.toString == " + arg0[0].toString());
If you really will be processing multiple uris, use a for-loop to go through and log all of them.
Make sure to fix your Jsoup.connect line too. It doesn't want a messy array string. :)
Invoke getEncodedPath() on Uri to get the string in it.
Something like below
// imageUri is an Uri extracted from Intent
String filePath = imageUri.getEncodedPath();
This filePath will have string content as defined in Uri. i.e. content:/media.../id
Shash

Categories

Resources