web-dev-qa-db-fra.com

"Bitmap trop volumineux pour être chargé dans une texture"

Je charge un bitmap dans un ImageView et voir cette erreur. Je suppose que cette limite concerne une taille limite pour les textures matérielles OpenGL (2048x2048). L’image que je dois charger est une image avec un zoom d’environ 4 000 pixels.

J'ai essayé de désactiver l'accélération matérielle dans le manifeste, mais pas de joie.

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

Est-il possible de charger une image plus grande que 2048 pixels dans un ImageView?

148
Ollie C

Tous les rendus sont basés sur OpenGL, vous ne pouvez donc pas dépasser cette limite (GL_MAX_TEXTURE_SIZE dépend du périphérique, mais le minimum est de 2048x2048, donc toute image inférieure à 2048x2048 convient).

Avec de telles images de grande taille, si vous souhaitez effectuer un zoom avant et dans un mobile, vous devez configurer un système similaire à celui que vous voyez dans Google Maps, par exemple. Avec l'image divisée en plusieurs morceaux et plusieurs définitions.

Vous pouvez également réduire l’image avant de l’afficher (voir réponse de l'utilisateur 1352407 à cette question).

Et aussi, faites attention au dossier dans lequel vous avez mis l'image, Android peut automatiquement redimensionner les images. Jetez un œil à réponse de Pilot_51 ci-dessous pour cette question.

46
jptsetung

Ce n'est pas une réponse directe à la question (chargement d'images> 2048), mais une solution possible pour toute personne rencontrant l'erreur.

Dans mon cas, l'image était plus petite que 2048 dans les deux dimensions (1280x727 pour être exact) et le problème a été spécifiquement rencontré sur un Nexus Galaxy. L'image était dans le dossier drawable et aucun des dossiers qualifiés. Android suppose que les éléments dessinables sans qualificateur de densité sont des mdpi et les redimensionne vers le haut ou le bas pour d'autres densités, en l'occurrence deux fois plus pour xhdpi. Déplacer l'image coupable vers drawable-nodpi pour éviter la mise à l'échelle a résolu le problème.

395
Pilot_51

J'ai réduit l'image de cette façon:

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);
103
user1352407

Au lieu de passer des heures et des heures à écrire/déboguer tout ce code de sous-échantillonnage manuellement, pourquoi ne pas utiliser Picasso? Il a été conçu pour traiter avec bitmaps de tout type et/ou de toute taille.

J'ai utilisé cette seule ligne de code pour supprimer mon "bitmap too large ...." problème:

Picasso.load(resourceId).fit().centerCrop().into(imageView);
34
Phileo99

Changer le fichier image dans le dossier drawable-nodpi à partir du dossier drawable a fonctionné pour moi.

16
Asha Antony

L'ajout des 2 attributs suivants dans (AndroidManifest.xml) a fonctionné pour moi:

Android:largeHeap="true"
Android:hardwareAccelerated="false"
12
Sachin Lala

J'ai utilisé Picasso et j'ai eu le même problème. l'image était trop grande au moins en taille, largeur ou hauteur. enfin j'ai trouvé la solution ici. vous pouvez réduire la taille de la grande image en fonction de la taille d'affichage tout en conservant le rapport de format:

    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;
}

et utilisez cette méthode pour charger l'image par 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);

aussi pour de meilleures performances, vous pouvez télécharger l'image en fonction de la largeur et de la hauteur de l'écran, mais pas l'intégralité de l'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);

puis:

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

EDIT: getDisplaySize ()

display.getWidth()/getHeight() est obsolète. Au lieu de Display, utilisez DisplayMetrics.

public Point getDisplaySize(DisplayMetrics displayMetrics) {
        int width = displayMetrics.widthPixels;
        int height = displayMetrics.heightPixels;
        return new Point(width, height);
}
9
Sherry

BitmapRegionDecoder fait le tour.

Vous pouvez remplacer onDraw(Canvas canvas), démarrer un nouveau thread et décoder la zone visible par l'utilisateur.

6
Larcho

Comme l'a souligné Larcho, à partir du niveau 10 de l'API, vous pouvez utiliser BitmapRegionDecoder pour charger des régions spécifiques à partir d'une image. Vous pouvez ainsi afficher une grande image en haute résolution en allouant en mémoire uniquement les régions nécessaires. J'ai récemment développé une librairie qui permet de visualiser de grandes images avec la gestion des gestes tactiles. Le code source et les exemples sont disponibles ici .

5
diegocarloslima

J'ai rencontré le même problème, voici ma solution. définir la largeur de l'image identique à Android largeur de l'écran, puis redimensionner la hauteur

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);

Ceci est préférable pour tout écran Android de taille. Dites-moi si cela marche pour vous.

3
Abhijit Gujar

Voir le niveau

Vous pouvez désactiver l'accélération matérielle pour une vue individuelle au moment de l'exécution à l'aide du code suivant:

myView.setLayerType (View.LAYER_TYPE_SOFTWARE, null);

2
marveson

Utilisez la bibliothèque Glide au lieu de charger directement dans imageview

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

Glide.with(this).load(Uri.parse(filelocation))).into(img_selectPassportPic);
1
saigopi

Réduire l'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);

L'image sera réduite à la taille de reqHeight et de reqWidth. Si je comprends bien, inSampleSize ne prend qu'une puissance de 2 valeurs.

1
vtlinh

J'ai essayé toutes les solutions ci-dessus, l'une après l'autre, pendant de nombreuses heures et aucune ne semblait fonctionner! Enfin, j'ai décidé de chercher un exemple officiel concernant la capture d'images avec la caméra Android et leur affichage. L'exemple officiel ( ici ), m'a finalement donné la seule méthode qui a fonctionné. Ci-dessous, je présente la solution trouvée dans cet exemple d'application:

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);
}
1
nemesisfixx
@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);

    }
}

Ce code est travail

0
Alobaidi

NOTE POUR CEUX QUI VOULENT METTRE DES IMAGES DE PETITE TAILLE:

La solution de Pilot_51 (déplacer vos images dans le dossier drawable-nodpi] fonctionne, mais présente un autre problème: elle crée des images TROP PETITES à l'écran, à moins que les images ne soient redimensionnées à une très grande taille (comme 2000 x 3800). résolution adaptée à l'écran - votre application sera alors plus lourde.

SOLUTION: mettez vos fichiers image dans drawable-hdpi - Cela a fonctionné comme un charme pour moi.

0
makeasy

Utiliser le bon sous-dossier dessinable l'a résolu pour moi. Ma solution a été de placer mon image en pleine résolution (1920x1200) dans le dossier drawable-xhdpi, au lieu du dossier drawable.

J'ai également mis une image réduite (1280x800) dans le dossier drawable-hdpi.

Ces deux résolutions correspondent aux tablettes Nexus 7 2013 et 2012 que je programme. J'ai également testé la solution sur d'autres tablettes.

0
steveputz