I have a project on Android and iOS, there is a section where it shows a 360 view of a car, in iOS I just get the 60 images from internal storage that were previously downloaded from the internet, and these images are showed when the user starts to swipe the car to the right or to the left. And this process takes just 200ms to be ready to interact with the user.
But in Android I have to take first the 60 images and convert them in bitmaps, and then the process is similar to the iOS process. Nevertheless, this first process, convert all of them to bitmap takes about 3 seconds o more. I have read the process to show an image in Android in many sources of information and seems like is necessary use a bitmap for this task, so is possible to reduce the time to get all bitmaps?, or could I save a bitmap to avoid converting the PNG file again to a new bitmap when the users open the same view again?
The code that I'm using to convert png file to a bitmap object is the same that Android developers documentation recommend:
https://developer.android.com/topic/performance/graphics/load-bitmap
My source code for get bitmap is:
public static Bitmap decodeSampledBitmapFromFile(String filePath, int reqWidth, int reqHeight) {
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(filePath, options);
options.inSampleSize = 1;
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
Bitmap bitmap =BitmapFactory.decodeFile(filePath, options);
Log.d("img360","bitmap res "+bitmap.getWidth()+ " h "+bitmap.getHeight());
return bitmap;
}
I'm really thankful for your help and support.
If you want to download images from Internet and display them on android
Just put an imageview and use picaso or glide library
It is faster and easier
Related
So, I'm updating an old e-book reader. The problem I'm facing is the size of the bitmaps (the pages). The way it works is: the app downloads a file, extract it, decode it with our DRM then I can access all pages. The thing is, each page its a 35mb bitmap.
I need to reduce this by a lot. I can't convert the file to any other format.
I tried this:
byte[] rawBytes = intToByteArray(b.getByteCount());
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 4;
Bitmap bit = BitmapFactory.decodeByteArray(rawBytes, 0,rawBytes.length, options);
But the Bitmap keeps returning null, and for what I gathered its when the Bitmap facorty can't decode the bitmap.
So, there is any other way to reduce the impact of this big bitmaps ?
I have a question that I seem to find the answer nowhere.
Does this lines of code:
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeStream(is, null, options);
actually mean that, that file is being downloaded? Android docs say something like this:
decode with inJustDecodeBounds=true to check dimensions
and
Does:
options.inSampleSize = calculateInSampleSize(options, reqWidth,
reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
BitmapFactory.decodeStream(is, null, options);
means that it will actually download the file smaller (not downloaded as original size and copied after that to a smaller size bitmap).
Clear example: I have some url's that point to many 2000 x 1500 images. By decoding those files and loading them to bitmaps, do I need to have enough memory for downloading the file at its full resolution (2000 x 1500), if I only need thumbnails of (200 x 150)?
I know another answer has already been accepted as the right one but for clarity...
This line options.inJustDecodeBounds = true; means that the call to BitmapFactory.decodeStream(is, null, options); doesn't get the bitmap information but does get bounding information and the MimeType.
You can then use these returned values, outWidth, outHeight and outMimeType to get a 'resampled' version of the bitmap data by setting options.inJustDecodeBounds = false; and setting the sample size to a given ratio determined by your desired output dimensions options. inSampleSize = [int].
See this very informative page for more information: Loading Large Bitmaps Efficiently
Indeed looks like the file is being downloaded, and the effiency part comes where the bitmap being loaded in memory is the smaller one ( the one being decoded with inSampleSize options).
I have 3 or 4 image paths that I use to load an image so I set it to an imageview. Why does it take long? Or better asking is there a way to make it faster? At the end of the day I am loading to fit an imageview of less than 60 dp hight and width
Uri mainImgeUri = Uri.parse(imagePath);
InputStream imageStream;
try {
imageStream = mActiviy.getContentResolver().openInputStream(mainImgeUri);
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 8;
Bitmap yourSelectedImage = BitmapFactory.decodeStream(imageStream, null, options);
mainImageIV.setImageBitmap(yourSelectedImage);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
USE CASE:
What happens is that a user will add 5 images (and he get to choose them from Gallery which is mostly taken by phone camera). He hit save and my app stores the path to them in an sqlite database. Then when the user opens the app again to see them, my app query the db to get the paths to all the images and executes the code above x number of times so all the image views are loaded with the intended images
Take a look at http://developer.android.com/training/displaying-bitmaps/load-bitmap.html
It explains how to calculate the correct inSampleSize based on the required dimensions of the output image. It also explains how to reference large bitmaps without having to load all their pixel data into memory.
The idea is that you resample bigger images and only load the smaller ones into memory making the whole process much more efficient. The example code is accessing a bitmap from resources, but this can easily be modified for your needs.
The important things to look out for in the example are inJustDecodeBounds and calculateInSampleSize.
How to solve OOM issue in android . I have tried almost every things like scaling bitmap,inPurgeable in BitmapOption,releasing all resources etc. but still getting OOM issue.
This is basically in images taken by camera or any image i.e. larger then 1.5 mb. I have also images 15-20 mb size in my app.
this is what i´m doing to avoid OOM errors, Using some of the code of the android training. This is in my class "ScaledFactor"
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);
options.inPurgeable = true; // I aded this to the android training code, without this I still have OOM errors. so try using inPurgeable = true
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeResource(res, resId, options);
}
In my Activity I use
background = ScaledFactor.decodeSampledBitmapFromResource(getResources(), R.drawable.menu, screenheight, screenwidth); // screeenhieght is the output height , screenwidth is the output width
Then in the on destroy method, or after calling an other intent I use background.recycle();
I´m not using the hdpi, ldpi and so folders... I just use the drawable with large bitmaps, and do the scalling. this way you save some mb on the final apk file
The android training code is here for more info http://developer.android.com/training/displaying-bitmaps/load-bitmap.html#load-bitmap
C ya ! Hope this helps, I spent a hole day trying to figure this out and reading all the questions and answers in this forum. This is just the example of the background image but i have more than 20 images in my game all loaded this way but with smaller output size, and it works very smooth.
Have you tried Bitmap.recycle(); ?
It once solved my Out of Memory issue.
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.