159

I'm loading a bitmap into an ImageView, and seeing this error. I gather this limit relates to a size limit for OpenGL hardware textures (2048x2048). The image I need to load is a pinch-zoom image of about 4,000 pixels high.

I've tried turning off hardware acceleration in the manifest, but no joy.

    <application
        android:hardwareAccelerated="false"
        ....
        >

Is it possible to load an image larger than 2048 pixels into an ImageView?

Jonik
  • 80,077
  • 70
  • 264
  • 372
Ollie C
  • 28,313
  • 34
  • 134
  • 217
  • 1
    For anyone looking here, don't forget to put your image in a scroll view if you want it to be scrollable. That will get rid of the error. I wasted some time before realising that was my problem. – Jason Ridge Nov 03 '14 at 12:35
  • For anyone looking to display large images still keeping the image quality, refer to the library in @stoefln answer below. I used it and is worth giving a try. Definitely better than `inSampleSize` approach. – Mahendra Liya Feb 26 '15 at 12:09
  • For me,, working with a thumbnail of the original image is what got rid of the warning: http://stackoverflow.com/a/6228188/1617737 – ban-geoengineering Aug 26 '16 at 21:47
  • 1
    @Joe Blow current answer didn't work in your case? If no then please elaborate regarding issue you faced in context of this question? – Pravin Divraniya Nov 30 '16 at 09:33
  • @JoeBlow, Explain your specific issue. What image size, what device? etc. _"This question has not received enough attention"_ really? After 4 years and 15 Answers and nearly 74k views?? If you are trying to give Bounty to older accepted Answer, they need to re-post (after Bounty started) to qualify. – VC.One Dec 02 '16 at 18:06
  • 1
    hey @VC.One - it's a strange thing to get worked up about my man. I should have clicked "Reward existing answer". Nobody bothers tediously pressing the "best" button on that SO popup, because it's silly :) It's all resolved now as I clicked the bounty. Cheers!! – Fattie Dec 02 '16 at 18:09
  • @JoeBlow no worries. It's good to reward a deserving Answer. Didn't know if your specific issue had a unique twist... I've seen the system "eat up" rep into nothing if not awarded correctly. Didn't know about any SO pop-up (have not yet to set my own bounty)... All good. – VC.One Dec 02 '16 at 20:01
  • I am sorry I clicked the wrong button and caused a timewaste! @VC.One Cheers man!! – Fattie Dec 02 '16 at 21:08
  • 1
    I try to always pay out bounties (I don't like gathering up points). I guess, if you click to my profile, then bounties, @VC.One you'll see many really great QA from SO over the years !!!!!!!!!!!!!!! – Fattie Dec 02 '16 at 21:09
  • Here we are, 7 years later and Bitmap loading still generates issues on the Android platform... I ended up using either Glide ou Picasso on my project since no simple solution exists in the official SDK. – mbritto Oct 24 '19 at 15:06

18 Answers18

412

This isn't a direct answer to the question (loading images >2048), but a possible solution for anyone experiencing the error.

In my case, the image was smaller than 2048 in both dimensions (1280x727 to be exact) and the issue was specifically experienced on a Galaxy Nexus. The image was in the drawable folder and none of the qualified folders. Android assumes drawables without a density qualifier are mdpi and scales them up or down for other densities, in this case scaled up 2x for xhdpi. Moving the culprit image to drawable-nodpi to prevent scaling solved the problem.

Pilot_51
  • 7,337
  • 3
  • 29
  • 26
  • 3
    I was having memory issues trying to load drawables. Spent 2 hrs trying to understand why this was happening. Thanks for the indirect answer. – TrueCoke Dec 17 '13 at 04:08
  • 3
    About three and a half months now I have been programming almost full time on Android and I just now realized this. Seems dumb to make `drawable` essentially a hidden `drawable-mdpi` folder. This also explained why my custom map markers looked awful (they were being upscaled, then downscaled). – theblang Feb 07 '14 at 21:57
  • 10
    yeah what the hell! i think 99% of android programmers think "drawable" means "don't scale this". – Matt Logan Apr 29 '14 at 02:44
  • But I'm clicking image from a camera and using `setImageBitmap` to set an image. What to do in this case? – Tushar Gogna Apr 06 '15 at 06:12
  • I did put the troubled image on `drawable`. I move it to `drawable-hdpi` and it works. Thanks! –  Oct 09 '15 at 07:52
  • @JoeBlow Wow, thanks! I didn't expect my answer to be such a huge deal way back when I posted it. Glad I could help so many people! – Pilot_51 Dec 08 '16 at 11:05
108

I have scaled down the image in this way:

ImageView iv  = (ImageView)waypointListView.findViewById(R.id.waypoint_picker_photo);
Bitmap d = new BitmapDrawable(ctx.getResources() , w.photo.getAbsolutePath()).getBitmap();
int nh = (int) ( d.getHeight() * (512.0 / d.getWidth()) );
Bitmap scaled = Bitmap.createScaledBitmap(d, 512, nh, true);
iv.setImageBitmap(scaled);
user1352407
  • 1,091
  • 1
  • 7
  • 5
51

All rendering is based on OpenGL, so no you can't go over this limit (GL_MAX_TEXTURE_SIZE depends on the device, but the minimum is 2048x2048, so any image lower than 2048x2048 will fit).

With such big images, if you want to zoom in out, and in a mobile, you should setup a system similar to what you see in google maps for example. With the image split in several pieces, and several definitions.

Or you could scale down the image before displaying it (see user1352407's answer on this question).

And also, be careful to which folder you put the image into, Android can automatically scale up images. Have a look at Pilot_51's answer below on this question.

Jonik
  • 80,077
  • 70
  • 264
  • 372
jptsetung
  • 9,064
  • 3
  • 43
  • 55
  • 23
    If this is the case, how does the Gallery app allow the display and manipulation of images taken with the camera? 2048x2048 is only a 4MP image, and many Android phones take photos much larger than this and the Gallery app seems to have no problems. – Ollie C Apr 22 '12 at 19:42
  • 3
    Because GL_MAX_TEXTURE_SIZE depends on the device. – jptsetung Apr 23 '12 at 10:06
  • 24
    This really does not make any sense. I encountered the same problem now - with an image of 1286x835 pixels. AND: only on a Galaxy Nexus I get this error message and no image! It just seems ridiculous that a top-of-the-edge smartphone cannot display such a small image! My HTC Hero is capable of displaying that! What can I do? – Zordid Apr 26 '12 at 19:34
  • 1
    See Romain's answer here: http://stackoverflow.com/questions/7428996/hw-accelerated-activity-how-to-get-opengl-texture-size-limit – Ben Lee Sep 05 '12 at 13:31
  • 4
    @OllieC I would also like to know how the gallery apps do it. So if anyone knows, or has an example for showing large images, that would be great. – Innova May 23 '13 at 13:55
  • @innova I guess you found out, but they probably resize it to fit the screen since the image is bigger than the screen. – Mathijs Segers Apr 30 '14 at 14:44
  • How do you get the real limit, without using an ImageView ? – android developer Jul 29 '15 at 09:06
34

Instead of spending hours upon hours trying to write/debug all this downsampling code manually, why not use Picasso? It was made for dealing with bitmaps of all types and/or sizes.

I have used this single line of code to remove my "bitmap too large...." problem:

Picasso.load(resourceId).fit().centerCrop().into(imageView);
GabrielBB
  • 2,479
  • 1
  • 35
  • 49
Phileo99
  • 5,581
  • 2
  • 46
  • 54
  • Using centerCrop() without calling resize() will result in an IllegalStateException. Library forces to call resize when center crop is used. – Zsolt Boldizsar Apr 14 '15 at 11:46
  • That makes perfect sense, because cropping implies that you are resizing the image. – Phileo99 Apr 15 '15 at 02:45
  • 2
    Fast, easy and simple solution. Not sure if it is the best, but I got what I wanted. Thank you very much – Nabin Mar 05 '16 at 15:53
  • still getting the same error when used target with Picasso, for the bigger sized images :( – Narendra Singh Aug 16 '16 at 08:19
  • Try to use version 2.5.3-SNAPSHOT, seems it's now work correctly with big images – Anton Malmygin Aug 19 '16 at 10:28
  • Awesome, +1 for pointing out that Picasso has ready-made methods for these! For future readers, note that `centerCrop()` isn't the only option; for my needs, `.fit().centerInside()` solved the problem without distorting the end result. – Jonik Nov 02 '17 at 11:53
  • I would suggest using Fresco instead of Picasso. it does caching better – Armen Hovhannisian Mar 23 '18 at 22:03
23

Addition of the following 2 attributes in (AndroidManifest.xml) worked for me:

android:largeHeap="true"
android:hardwareAccelerated="false"
Aks4125
  • 4,522
  • 4
  • 32
  • 48
Sachin Lala
  • 715
  • 1
  • 8
  • 18
16

Changing the image file to drawable-nodpi folder from drawable folder worked for me.

Emzor
  • 1,380
  • 17
  • 28
Asha Antony
  • 441
  • 5
  • 8
  • This will prevent Android from trying to auto-scale the image based on the device's dimensions and screen density; this is why this solution works. Android will try to auto-scale anything in the `drawable` folder. – Chris Cirefice Jun 30 '17 at 15:58
9

I used Picasso and had the same problem. image was too large at least in on size, width or height. finally I found the solution here. you can scale the large image down according to display size and also keep the aspect ratio:

    public Point getDisplaySize(Display display) {
    Point size = new Point();

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) {
        display.getSize(size);
    } else {
        int width = display.getWidth();
        int height = display.getHeight();
        size = new Point(width, height);
    }

    return size;
}

and use this method for loading image by Picasso:

    final Point displySize = getDisplaySize(getWindowManager().getDefaultDisplay());
        final int size = (int) Math.ceil(Math.sqrt(displySize.x * displySize.y));
        Picasso.with(this)
                .load(urlSource)
                .resize(size, size)
                .centerInside()
                .into(imageViewd);

also for better performance you can download the image according to width and height of the display screen, not whole the image:

    public String reviseImageUrl(final Integer displayWidth,     final Integer displayHeight,
        final String originalImageUrl) {
    final String revisedImageUrl;

    if (displayWidth == null && displayHeight == null) {
        revisedImageUrl = originalImageUrl;
    } else {
        final Uri.Builder uriBuilder = Uri.parse(originalImageUrl).buildUpon();

        if (displayWidth != null && displayWidth > 0) {
            uriBuilder.appendQueryParameter(QUERY_KEY_DISPLAY_WIDTH, String.valueOf(displayWidth));
        }

        if (displayHeight != null && displayHeight > 0) {
            uriBuilder.appendQueryParameter(QUERY_KEY_DISPLAY_HEIGHT, String.valueOf(displayHeight));
        }

        revisedImageUrl = uriBuilder.toString();
    }

    return revisedImageUrl;
}

    final String newImageUlr = reviseImageUrl(displySize.x, displySize.y, urlSource);

and then:

    Picasso.with(this)
                .load(newImageUlr)
                .resize(size, size)
                .centerInside()
                .into(imageViewd);

EDIT: getDisplaySize()

display.getWidth()/getHeight() is deprecated. Instead of Display use DisplayMetrics.

public Point getDisplaySize(DisplayMetrics displayMetrics) {
        int width = displayMetrics.widthPixels;
        int height = displayMetrics.heightPixels;
        return new Point(width, height);
}
Vijay Vankhede
  • 3,018
  • 1
  • 26
  • 46
Sherry
  • 336
  • 3
  • 8
6

BitmapRegionDecoder does the trick.

You can override onDraw(Canvas canvas), start a new Thread and decode the area visible to the user.

Stephen Kennedy
  • 20,585
  • 22
  • 95
  • 108
Larcho
  • 536
  • 5
  • 10
5

As pointed by Larcho, starting from API level 10, you can use BitmapRegionDecoder to load specific regions from an image and with that, you can accomplish to show a large image in high resolution by allocating in memory just the needed regions. I've recently developed a lib that provides the visualisation of large images with touch gesture handling. The source code and samples are available here.

Emzor
  • 1,380
  • 17
  • 28
diegocarloslima
  • 1,346
  • 14
  • 16
4

View level

You can disable hardware acceleration for an individual view at runtime with the following code:

myView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);

marveson
  • 41
  • 1
3

I ran through same problem, here is my solution. set the width of image same as android screen width and then scales the height

Bitmap myBitmap = BitmapFactory.decodeFile(image.getAbsolutePath());
Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
int width = size.x;
int height = size.y;
Log.e("Screen width ", " "+width);
Log.e("Screen height ", " "+height);
Log.e("img width ", " "+myBitmap.getWidth());
Log.e("img height ", " "+myBitmap.getHeight());
float scaleHt =(float) width/myBitmap.getWidth();
Log.e("Scaled percent ", " "+scaleHt);
Bitmap scaled = Bitmap.createScaledBitmap(myBitmap, width, (int)(myBitmap.getWidth()*scaleHt), true);
myImage.setImageBitmap(scaled);

This is better for any size android screen. let me know if it works for you.

Luka Jacobowitz
  • 22,795
  • 5
  • 39
  • 57
Abhijit Gujar
  • 433
  • 6
  • 15
2

Scale down image:

BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;

// Set height and width in options, does not return an image and no resource taken
BitmapFactory.decodeStream(imagefile, null, options);

int pow = 0;
while (options.outHeight >> pow > reqHeight || options.outWidth >> pow > reqWidth)
    pow += 1;
options.inSampleSize = 1 << pow; 
options.inJustDecodeBounds = false;
image = BitmapFactory.decodeStream(imagefile, null, options);

The image will be scaled down at the size of reqHeight and reqWidth. As I understand inSampleSize only take in a power of 2 values.

vtlinh
  • 1,427
  • 3
  • 11
  • 16
2

Use Glide library instead of directly loading into imageview

Glide : https://github.com/bumptech/glide

Glide.with(this).load(Uri.parse(filelocation))).into(img_selectPassportPic);
saigopi.me
  • 14,011
  • 2
  • 83
  • 54
1

I tried all the solutions above, one-after-the-other, for quite many hours, and none seemed to work! Finally, I decided to look around for an official example concerning capturing images with Android's camera, and displaying them. The official example (here), finally gave me the only method that worked. Below I present the solution I found in that example app:

public void setThumbnailImageAndSave(final ImageView imgView, File imgFile) {

            /* There isn't enough memory to open up more than a couple camera photos */
    /* So pre-scale the target bitmap into which the file is decoded */

    /* Get the size of the ImageView */
    int targetW = imgView.getWidth();
    int targetH = imgView.getHeight();

    /* Get the size of the image */
    BitmapFactory.Options bmOptions = new BitmapFactory.Options();
    bmOptions.inJustDecodeBounds = true;
    BitmapFactory.decodeFile(imgFile.getAbsolutePath(), bmOptions);
    int photoW = bmOptions.outWidth;
    int photoH = bmOptions.outHeight;

    /* Figure out which way needs to be reduced less */
    int scaleFactor = 1;
    if ((targetW > 0) || (targetH > 0)) {
        scaleFactor = Math.min(photoW/targetW, photoH/targetH);
    }

    /* Set bitmap options to scale the image decode target */
    bmOptions.inJustDecodeBounds = false;
    bmOptions.inSampleSize = scaleFactor;
    bmOptions.inPurgeable = true;

    /* Decode the JPEG file into a Bitmap */
    Bitmap bitmap = BitmapFactory.decodeFile(imgFile.getAbsolutePath(), bmOptions);

    /* Associate the Bitmap to the ImageView */
    imgView.setImageBitmap(bitmap);
    imgView.setVisibility(View.VISIBLE);
}
Lucifer
  • 29,392
  • 25
  • 90
  • 143
JWL
  • 13,591
  • 7
  • 57
  • 63
0

NOTE FOR THOSE WHO WANT TO PUT IMAGES OF SMALL SIZE:

Pilot_51's solution (moving your images to drawable-nodpi folder) works, but has another problem: It makes images TOO SMALL on screen unless the images are resized to a very large (like 2000 x 3800) resolution to fit screen -- then it makes your app heavier.

SOLUTION: put your image files in drawable-hdpi -- It worked like a charm for me.

makeasy
  • 907
  • 1
  • 6
  • 15
  • 1
    You are just masking your image density problem. On hardware with low density your images will look bigger. – rupps Nov 14 '16 at 14:40
  • i also do not think that Pilot_51's solution has any issues, you should use appropriate image sizes as per your needs – Nilabja Jan 30 '17 at 09:31
0

Using the correct drawable subfolder solved it for me. My solution was to put my full resolution image (1920x1200) into the drawable-xhdpi folder, instead of the drawable folder.

I also put a scaled down image (1280x800) into the drawable-hdpi folder.

These two resolutions match the 2013 and 2012 Nexus 7 tablets I'm programming. I also tested the solution on some other tablets.

steveputz
  • 9
  • 4
0
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {

    super.onActivityResult(requestCode, resultCode, data);
    ///*
    if (requestCode == PICK_FROM_FILE && resultCode == RESULT_OK && null != data){



        uri = data.getData();

        String[] prjection ={MediaStore.Images.Media.DATA};

        Cursor cursor = getContentResolver().query(uri,prjection,null,null,null);

        cursor.moveToFirst();

        int columnIndex = cursor.getColumnIndex(prjection[0]);

        ImagePath = cursor.getString(columnIndex);

        cursor.close();

        FixBitmap = BitmapFactory.decodeFile(ImagePath);

        ShowSelectedImage = (ImageView)findViewById(R.id.imageView);

      //  FixBitmap = new BitmapDrawable(ImagePath);
        int nh = (int) ( FixBitmap.getHeight() * (512.0 / FixBitmap.getWidth()) );
        FixBitmap = Bitmap.createScaledBitmap(FixBitmap, 512, nh, true);

       // ShowSelectedImage.setImageBitmap(BitmapFactory.decodeFile(ImagePath));

        ShowSelectedImage.setImageBitmap(FixBitmap);

    }
}

This code is work

Alobaidi
  • 29
  • 1
  • 3
0

Add this code in manifest

<activity
        android:name="com.yalantis.ucrop.UCropActivity"
        android:screenOrientation="portrait"
        android:hardwareAccelerated="false"
        android:theme="@style/Theme.AppCompat.Light.NoActionBar" />