web-dev-qa-db-fra.com

Android: largeur et hauteur maximales autorisées du bitmap

Je crée une application qui doit décoder des images volumineuses en bitmaps pour pouvoir les afficher dans un ImageView.

Si j'essaie juste de les décoder directement en bitmap, l'erreur suivante s'affiche: "Bitmap trop volumineux pour être chargé dans une texture (1944x2592, max = 2048x2048)"

Pour pouvoir afficher des images avec une résolution trop élevée, utilisez: 

Bitmap bitmap = BitmapFactory.decodeFile(path);

if(bitmap.getHeight()>=2048||bitmap.getWidth()>=2048){
    DisplayMetrics metrics = new DisplayMetrics();
    getWindowManager().getDefaultDisplay().getMetrics(metrics);
    int width = metrics.widthPixels;
    int height = metrics.heightPixels;
    bitmap =Bitmap.createScaledBitmap(bitmap, width, height, true);             
}

Cela fonctionne mais je ne veux pas vraiment coder en dur la valeur maximale de 2048 comme je l’ai indiqué dans l’instruction if, mais je ne peux pas trouver comment obtenir la taille maximale autorisée du bitmap pour un périphérique

Des idées? 

28
Fredkr

Cette limite devrait provenir de l'implémentation OpenGL sous-jacente. Si vous utilisez déjà OpenGL dans votre application, vous pouvez utiliser quelque chose comme ceci pour obtenir la taille maximale:

int[] maxSize = new int[1];
gl.glGetIntegerv(GL10.GL_MAX_TEXTURE_SIZE, maxSize, 0);
// maxSize[0] now contains max size(in both dimensions)

Cela montre que mon Galaxy Nexus et mon Galaxy S2 ont un maximum de 2048x2048.

Malheureusement, si vous ne l'utilisez pas déjà, le seul moyen d'obtenir un contexte OpenGL à partir duquel vous appelez cette méthode est d'en créer un (y compris la vue de surface, etc.), ce qui représente beaucoup de travail supplémentaire simplement pour demander une taille maximale.

9
Geobits

Pour obtenir la taille maximale autorisée, vous pouvez également parcourir toutes les configurations EGL10 et garder la trace de la taille la plus grande.

public static int getMaxTextureSize() {
    // Safe minimum default size
    final int IMAGE_MAX_BITMAP_DIMENSION = 2048;

    // Get EGL Display
    EGL10 egl = (EGL10) EGLContext.getEGL();
    EGLDisplay display = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);

    // Initialise
    int[] version = new int[2];
    egl.eglInitialize(display, version);

    // Query total number of configurations
    int[] totalConfigurations = new int[1];
    egl.eglGetConfigs(display, null, 0, totalConfigurations);

    // Query actual list configurations
    EGLConfig[] configurationsList = new EGLConfig[totalConfigurations[0]];
    egl.eglGetConfigs(display, configurationsList, totalConfigurations[0], totalConfigurations);

    int[] textureSize = new int[1];
    int maximumTextureSize = 0;

    // Iterate through all the configurations to located the maximum texture size
    for (int i = 0; i < totalConfigurations[0]; i++) {
        // Only need to check for width since opengl textures are always squared
        egl.eglGetConfigAttrib(display, configurationsList[i], EGL10.EGL_MAX_PBUFFER_WIDTH, textureSize);

        // Keep track of the maximum texture size
        if (maximumTextureSize < textureSize[0])
            maximumTextureSize = textureSize[0];
    }

    // Release
    egl.eglTerminate(display);

    // Return largest texture size found, or default
    return Math.max(maximumTextureSize, IMAGE_MAX_BITMAP_DIMENSION);
}

D'après mes tests, c'est assez fiable et vous n'avez pas besoin de créer une instance ..__ Pour ce qui est des performances, cela a pris 18 millisecondes pour s'exécuter sur mon Note 2 et seulement 4 millisecondes sur mon G3.

13
Pkmmte

cela décodera et redimensionnera l'image avant de la charger en mémoire, il suffit de changer le paysage et le portrait à la taille souhaitée

BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(path, options);
int imageHeight = options.outHeight;
int imageWidth = options.outWidth;
String imageType = options.outMimeType;
if(imageWidth > imageHeight) {
    options.inSampleSize = calculateInSampleSize(options,512,256);//if landscape
} else{
    options.inSampleSize = calculateInSampleSize(options,256,512);//if portrait
}
options.inJustDecodeBounds = false;
bitmap = BitmapFactory.decodeFile(path,options);

méthode de calcul de la taille

public static int calculateInSampleSize(
        BitmapFactory.Options options, int reqWidth, int reqHeight) {
   // Raw height and width of image
   final int height = options.outHeight;
   final int width = options.outWidth;
   int inSampleSize = 1;

   if (height > reqHeight || width > reqWidth) {

      // Calculate ratios of height and width to requested height and width
      final int heightRatio = Math.round((float) height / (float) reqHeight);
      final int widthRatio = Math.round((float) width / (float) reqWidth);

      // Choose the smallest ratio as inSampleSize value, this will guarantee
      // a final image with both dimensions larger than or equal to the
      // requested height and width.
      inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
   }

   return inSampleSize;
}
2
JRowan

Si vous êtes au niveau API 14+ (ICS), vous pouvez utiliser les fonctions getMaximumBitmapWidth et getMaximumBitmapHeight sur la classe Canvas. Cela fonctionnerait à la fois sur les couches accélérées par le matériel et les couches logicielles.

Je crois que le matériel Android doit au moins prendre en charge 2048x2048, ce qui serait une valeur minimale sûre. Sur les couches logicielles, la taille maximale est 32766x32766.

1

La limite 2048 * 2048 est pour GN. GN est un périphérique xhdpi et peut-être placez-vous l'image dans le mauvais compartiment de densité. J'ai déplacé une image 720 * 1280 de drawable à drawable-xhdpi et cela a fonctionné. 

Merci pour la réponse de Romain Guy. Voici le lien de sa réponse. 

0
jedichen