Prevent bitmap too large to be uploaded into a texture android - android

I need to display original image in full screen in gallery form. For thumb it will be work perfectly and when I try to display that image in full screen with original source it will not be able to display. In most cases if the image resolution is greater then 2000 then it will display error bitmap too large to be uploaded into a texture android.
I want to prevent this, I have search google but not getting any answer regarding this.

I came across the same problem and came up with a one liner solution for this problem here:
Picasso.with(context).load(new File(path/to/File)).fit().centerCrop().into(imageView);

i just created a if else function to check if the image is bigger than 1M pixels here's the sample code:
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == RESULT_OK) {
if (requestCode == SELECT_PICTURE) {
Uri selectedImageUri = data.getData();
selectedImagePath = getPath(selectedImageUri);
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 4;
Bitmap bitmap = BitmapFactory.decodeFile(selectedImagePath);
int height = bitmap.getHeight(), width = bitmap.getWidth();
if (height > 1280 && width > 960){
Bitmap imgbitmap = BitmapFactory.decodeFile(selectedImagePath, options);
imageView.setImageBitmap(imgbitmap);
System.out.println("Need to resize");
}else {
imageView.setImageBitmap(bitmap);
System.out.println("WORKS");
}

Google provided a training how to do that. Download the sample from Displaying Bitmaps Efficiently
Take a look to ImageResizer class.
ImageResizer.decodeSampledBitmapFrom* use this method to get downscaled image.

This is the code I used to rectify my problem of fitting an image of size 3120x4196 resolution in an image view of 4096x4096 resolution. Here ImageViewId is the id of the image view created in the main layout and ImageFileLocation is the path of the image which is to be resized.
ImageView imageView=(ImageView)findViewById(R.id.ImageViewId);
Bitmap d=BitmapFactory.decodeFile(ImageFileLcation);
int newHeight = (int) ( d.getHeight() * (512.0 / d.getWidth()) );
Bitmap putImage = Bitmap.createScaledBitmap(d, 512, newHeight, true);
imageView.setImageBitmap(putImage);

You don't need to load the whole image, cause it's too large and probably your phone won't able to show the full bitmap pixels.
You need to scale it first according to your device screen size.
This is the best method that I found and it works pretty good:
Android: Resize a large bitmap file to scaled output file

I found a way to do this without using any external libraries:
if (bitmap.getHeight() > GL10.GL_MAX_TEXTURE_SIZE) {
// this is the case when the bitmap fails to load
float aspect_ratio = ((float)bitmap.getHeight())/((float)bitmap.getWidth());
Bitmap scaledBitmap = Bitmap.createBitmap(bitmap, 0, 0,
(int) ((GL10.GL_MAX_TEXTURE_SIZE*0.9)*aspect_ratio),
(int) (GL10.GL_MAX_TEXTURE_SIZE*0.9));
imageView.setImageBitmap(scaledBitmap);
}
else{
// for bitmaps with dimensions that lie within the limits, load the image normally
if (Build.VERSION.SDK_INT >= 16) {
BitmapDrawable ob = new BitmapDrawable(getResources(), bitmap);
imageView.setBackground(ob);
} else {
imageView.setImageBitmap(bitmap);
}
}
Basically, the maximum image dimensions are a system-imposed limit. The above approach will correctly resize bitmaps that exceed this limit. However, only a portion of the entire image will be loaded. To change the region displayed, you can alter the x and y parameters of the createBitmap() method.
This approach handles bitmaps of any size, including pictures taken with professional cameras.
References:
Android Universal Image Loader.

Related

Does anyone know if there is a limitation on the size of the file BitmapFactory.decodeFile can decode?

I use the following code. With large image files it returns null, small ones display. Does anyone know if there is a size limitation with BitmapFactory.decodeFile?
File imgFile = new File(path);
if(imgFile.exists())
{
Bitmap myBitmap=null;
myBitmap = BitmapFactory.decodeFile(imgFile.getAbsolutePath());
ImageView imageView=(ImageView)findViewById(R.id.imageView1);
if(myBitmap!=null) {
imageView.setImageBitmap(myBitmap);
}
else {
Toast.makeText(MainActivity.this, "NULL", Toast.LENGTH_LONG).show();
}
} else Toast.makeText(MainActivity.this, "NO FILE", Toast.LENGTH_LONG).show();
how large is it? how many MBs?
do you get an OutOfMemoryException because each mobile app have specific amount of memory (heap size) and a large bitmap might exceed this limit, so u get a null
EDIT:
unless the big bitmap by chance, is corrupted of some weird format that the app could not decode? try another large bitmap
From experience there is a limit and when you hit that resolution limit for openGL you will see the following type of error message:
Bitmap too large to be uploaded into a texture (4128x2322, max=4096x4096)
You may also get a OutOfMemoryException error like many have noted.
First of all you should do this:
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeStream(inputStream, null, options);
final int width = options.outWidth;
final int height = options.outHeight;
Now that you have the width and height, it's time to make an intelligent decision about how to rescale it.
I would at this point look at the full code example (really only two methods to copy/paste) from Google at Loading Large Bitmaps Efficiently.

Universal Image Loader: Crop center image loading synchronously (no imageview) (Android, UIL)

I'm using Universal Image Loader to:
Load image synchronously
Fix orientation
Crop center (this is not working)
Do all this with a low memory footprint
I don't want to scale a bitmap by myself if I can do it with Universal Image Loader. The reason I ask this question is because I don't know wether this is possible or not with Universal Image Loader.
I don't want (or need) to use an ImageView to load the bitmap I simply need a bitmap, but crop center it on the fly. Is this possible with UIL? I have gone through the issues on GH, through questions on SO and can't find an example for it.
This is the code:
private Bitmap getBitmap(Uri uri, int width, int height) {
DisplayImageOptions options = new DisplayImageOptions.Builder()
.considerExifParams(true)
.cacheOnDisk(true)
.build();
ImageSize size = new ImageSize(width, height);
return mImageLoader.loadImageSync(uri.toString(), size, options);
}
Thank you all!
I think that that's what BitmapProcessors are for (although I haven't used the lib myself).
Here's what I would do:
// preProcessor gets to work before image gets cached, so cache will contain the cropped
// version
[...Builder...].preProcessor(new BitmapProcessor() {
public Bitmap process (Bitmap src) {
// Roughly assuming that the bitmap is bigger than the needed dimensions
// but you get the idea
int xOffset = (src.getWidth() - width) / 2;
int yOffset = (src.getHeight() - height) / 2;
Bitmap result = Bitmap.createBitmap(src, xOffset, yOffset, width, height);
// not sure whether this is necessary or the calling logic does it
// my guess is it does 'cause it's a simple check [if (src != result) src.recycle();]
// and the lib is rather smart altogether. Check the docs, they probably mention this
src.recycle();
return result;
}
})

BitmapFactory.decodeFile causes outOfMemoryError

BitmapFactory.decodeFile causes outOfMemoryError only when I choose the image from the phone gallery, not when I choose the image from taking the photo with the camera intent. I actually avoid using decodeFile when using the camera intent. Can I use that same approach when choosing from the gallery (getting data from the intent)? Here is my code for getting the image in both ways:
If image was chosen from the device' gallery:
if (requestCode == 1)
{
if (intent != null && resultcode == RESULT_OK)
{
ImageHelper ih = new ImageHelper();
mProfilePicPath = ih.getSelectedImageFilePathFromGallery(this, intent);
Bitmap portraitPhoto = ih.getChosenImageFromGallery(mProfilePicPath);
try{
ih.saveImage("Profile pics", portraitPhoto, this);
ImageHelper.getChosenImageFromGallery:
public Bitmap getChosenImageFromGallery(String imagePath) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(imagePath, options);
options.inSampleSize = DressingRoomActivity.calculateInSampleSize(options, 500, 500);
options.inJustDecodeBounds = false;
Bitmap portraitPhoto = ImageHelper.convertToPortraitOrientation(options, imagePath);
return portraitPhoto;
}
If image was chosen by taking photo using camera:
else if ((requestCode == CAMERA_REQUEST)&& (resultcode == Activity.RESULT_OK)){
Bundle extras = intent.getExtras();
Uri selectedImage = intent.getData();
if (extras != null) {
ImageHelper ih = new ImageHelper();
mProfilePicPath = ih.getFilePathFromCameraPhoto(this, selectedImage);
Bitmap photo = (Bitmap) intent.getExtras().get("data");
try{
ih.saveImage("Profile pics", photo, this);
As you can see, to grab the image from the gallery and get the Bitmap from it, I have to create the Bitmap to be only 500 x 500 pixels with this code options.inSampleSize = DressingRoomActivity.calculateInSampleSize(options, 500, 500); Otherwise it causes an outOfMemoryError on the line Bitmap bmp = BitmapFactory.decodeFile(path, options); Which is in the ImageHelper.convertToPortraitOrientation(options, imagePath); method. This means the user gets AS IS quality in their image from the camera, and 500px quality from their image in the gallery.
My questions: 1) Is there any way to not make my image quality 500px when choosing from gallery? Like avoid this line somehow: Bitmap bmp = BitmapFactory.decodeFile(path, options); or some other way?
2) With the gallery I had to convert to portrait which is only a minor annoyance but why is that? It flips the photo sideways if I don't.
Here is a complete tuto on how to Display Bitmaps Efficiently from the official doc. I had the same problem as you. What i did was to read and understand all the lessons from the given page before returning back to my codes. Try that, you will get things clearer in your head.
Edit
Your app is crashing because you are running the Bitmap.decode() method in the main thread. Use another thread (with a simple AsyncTask) to do that.
As i said before, there is a nice tuto on how to handle bitmap off UI Thread
There is 2 possible solutions to overcome outOfMemory exception:
Solution 1: you should use weakReference variables like.
WeakReference<Bitmap> weakReferenceBitmap=new
WeakReference<Bitmap>(bitmap);
GC clear weakReference variable more efficient as compare to other.
Solution2: you can use largeHeap property in your manifest to require more heap space then normal.
<application
android:largeHeap="true">
</application>
I will not recommend you the 2nd solution, but it works :)
Hope it will help :)

creating scaled bitmap leads to invalid image

I've created a function that scales a bitmap directly to a specific surface area. The function first gets the width and height of the bitmap and then finds the sample size closest to the required size. Lastly the image is scaled to the exact size. This is the only way I could find to decode a scaled bitmap. The problem is that the bitmap returned from BitmapFactory.createScaledBitmap(src,width,height,filter) always comes back with a width and height of -1. I've already implemented other functions that use the createScaledBitmap() method with out this error and I can not find any reason why creating a scaled bitmap would produce invalid output. I've also found that if I create a copy of the image bitmap that is mutable causes the same error. Thanks
public static Bitmap load_scaled_image( String file_name, int area) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(file_name, options);
double ratio = (float)options.outWidth / (float)options.outHeight;
int width, height;
if( options.outWidth > options.outHeight ) {
width = (int)Math.sqrt(area/ratio);
height = (int)(width*ratio);
}
else {
height = (int)Math.sqrt(area/ratio);
width = (int)(height*ratio);
}
BitmapFactory.Options new_options = new BitmapFactory.Options();
new_options.inSampleSize = Math.max( (options.outWidth/width), (options.outHeight/height) );
Bitmap image = BitmapFactory.decodeFile(file_name, new_options);
return Bitmap.createScaledBitmap(image, width, height, true);
}
I added this function to scale large camera images to a specific number of mega pixels. So a typical area passed in would be 1000000 for 1 megapixel. The camera image after being decoded yields a outWidth of 1952 and a outHieght of 3264. I then calculate the ratio this way I can keep the same height to width ratio with the scaled image, in this case the ratio is 0.598... Using the ratio and the new surface area I can find the new width which is 773 and a height of 1293. 773x1293=999489 which is just about 1 megapixel. Next I calculate the sample size for which to decode the new image, in this case the sample size is 4 and the image is decoded to 976x1632. So I'm passing in a width of 773 a height of 1293.
I was having a similar problem (getting -1 for height and width of the scaled bitmap).
Following this stackOverflow thread:
Android how to create runtime thumbnail
I've tried to use the same bitmap twice while calling the function:
imageBitmap = Bitmap.createScaledBitmap(imageBitmap, THUMBNAIL_SIZE,
THUMBNAIL_SIZE, false);
For some reason, this solved my problem, perhaps it would solve yours too.

Bitmap resizing and rotating: linear noise

I am resizing image and rotating it using Matrix:
Matrix mtx = new Matrix();
if(orientation>0) {
mtx.postRotate(orientation);
Log.d(TAG,"image rotated: "+orientation);
}
if(scale<1) {
mtx.postScale(scale,scale);
Log.d(TAG,"image scaled: "+scale);
}
bmp = Bitmap.createBitmap(bm_orig, 0, 0, width, height, mtx, true);
bm_orig.recycle();
bmp.compress(Bitmap.CompressFormat.JPEG,95,output);
bmp.recycle();
When bmp_orig is taken, used 3.2 Mpx Camera, image resized and rotated looks normal.
But when source is 4 Mpx or bigger, result after resizing has barely-noticeable linear noise
I dont know, why does this noise appear, and how to remove it.
Any idea?
May be another way to resize and rotate?
Found that this problem is related with source and resulting image size.
Solved it, when check image size before loading it, and then load halfsized image, if source image size is more than 2 times bigger than resulting size is needed.
BitmapFactory.Options options_to_get_size = new BitmapFactory.Options();
options_to_get_size.inJustDecodeBounds = true;
BitmapFactory.decodeStream(input, null, options_to_get_size);
int load_scale = 1; // load 100% sized image
int width_tmp=options_to_get_size.outWidth
int height_tmp=options_to_get_size.outHeight;
while(width_tmp/2>maxW && height_tmp/2>maxH){
width_tmp/=2;//load half sized image
height_tmp/=2;
load_scale*=2;
}
Log.d(TAG,"load inSampleSize: "+ load_scale);
//Now load image with precalculated scale. scale must be power of 2 (1,2,4,8,16...)
BitmapFactory.Options option_to_load = new BitmapFactory.Options();
option_to_load.inSampleSize = load_scale;
((FileInputStream)input).getChannel().position(0); # reset input stream to read again
Bitmap bm_orig = BitmapFactory.decodeStream(input,null,option_to_load);
input.close();
//now you can resize and rotate image using matrix as stated in question

Categories

Resources