“Mapa de bits demasiado grande para ser cargado en una textura”

Estoy cargando un bitmap en un ImageView y viendo este error. Entiendo que este límite se relaciona con un límite de tamaño para texturas de hardware OpenGL (2048×2048). La imagen que necesito cargar es una imagen de zoom de aproximadamente 4000 pixeles de alto.

Intenté apagar la aceleración de hardware en el manifiesto, pero no alegría.

 

¿Es posible cargar una imagen de más de 2048 píxeles en un ImageView?

Toda la representación se basa en OpenGL, por lo que no puede superar este límite ( GL_MAX_TEXTURE_SIZE depende del dispositivo, pero el mínimo es 2048×2048, por lo que cualquier imagen inferior a 2048×2048 se ajustará).

Con imágenes tan grandes, si desea acercarse o alejarse, y en un dispositivo móvil, debe configurar un sistema similar al que ve en google maps, por ejemplo. Con la imagen dividida en varias piezas, y varias definiciones.

O puede reducir la imagen antes de mostrarla (consulte la respuesta del usuario1352407 sobre esta pregunta).

Y también, tenga cuidado de en qué carpeta colocar la imagen, Android puede ampliar automáticamente las imágenes. Eche un vistazo a la respuesta de Pilot_51 a continuación sobre esta pregunta.

Esta no es una respuesta directa a la pregunta (cargar imágenes> 2048), sino una posible solución para cualquiera que experimente el error.

En mi caso, la imagen era más pequeña que 2048 en ambas dimensiones (1280×727 para ser exactos) y el problema se experimentó específicamente en un Galaxy Nexus. La imagen estaba en la carpeta drawable y ninguna de las carpetas calificadas. Android asume que los elementos extraíbles sin un calificador de densidad son mdpi y los escala hacia arriba o hacia abajo para otras densidades, en este caso ampliados 2x para xhdpi. Mover la imagen culpable a drawable-nodpi para evitar escamas resolvió el problema.

He reducido la imagen de esta manera:

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

En lugar de pasar horas y horas tratando de escribir / depurar todo este código de reducción de muestreo manualmente, ¿por qué no utilizar Picasso ? Fue hecho para tratar con bitmaps de todos los tipos y / o tamaños.

He utilizado esta única línea de código para eliminar mi problema de “bitmap demasiado grande …” :

 Picasso.with(context).load(resourceId).fit().centerCrop().into(imageView); 

Cambiar el archivo de imagen a la carpeta drawable-nodpi carpeta drawable-nodpi funcionó para mí.

Usé Picasso y tuve el mismo problema. La imagen era demasiado grande al menos en tamaño, ancho o alto. finalmente encontré la solución aquí. puede escalar la imagen grande de acuerdo con el tamaño de visualización y también mantener la relación de aspecto:

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

y use este método para cargar imágenes de 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); 

también para un mejor rendimiento puede descargar la imagen de acuerdo con el ancho y alto de la pantalla, no toda la imagen:

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

y entonces:

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

EDITAR: getDisplaySize ()

display.getWidth()/getHeight() está en desuso. En lugar de Display usa DisplayMetrics .

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

La adición de los siguientes 2 atributos en ( AndroidManifest.xml ) funcionó para mí:

 android:largeHeap="true" android:hardwareAccelerated="false" 

BitmapRegionDecoder hace el truco.

Puede anular onDraw(Canvas canvas) , iniciar un nuevo Thread y decodificar el área visible para el usuario.

Como señala Larcho, a partir del nivel 10 de la API, puede usar BitmapRegionDecoder para cargar regiones específicas de una imagen y con eso, puede lograr mostrar una imagen grande en alta resolución asignando en memoria solo las regiones necesarias. Recientemente he desarrollado una lib que proporciona la visualización de imágenes grandes con manejo de gestos táctiles. El código fuente y las muestras están disponibles aquí .

Me encontré con el mismo problema, aquí está mi solución. establece el ancho de la imagen igual que el ancho de la pantalla de Android y luego escala la altura

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

Esto es mejor para cualquier tamaño de pantalla de Android. avísame si te funciona.

Reducir la imagen:

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

La imagen se reducirá al tamaño de reqHeight y reqWidth. Como entiendo en SamplingSize solo tomo una potencia de 2 valores.

Nivel de vista

Puede desactivar la aceleración de hardware para una vista individual en tiempo de ejecución con el siguiente código:

myView.setLayerType (View.LAYER_TYPE_SOFTWARE, null);

Probé todas las soluciones anteriores, una después de la otra, durante bastantes horas, ¡y ninguna parecía funcionar! Finalmente, decidí buscar un ejemplo oficial sobre capturar imágenes con la cámara de Android y mostrarlas. El ejemplo oficial ( aquí ), finalmente me dio el único método que funcionó. A continuación, presento la solución que encontré en esa aplicación de ejemplo:

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

NOTA PARA LOS QUE QUIERAN PONER IMÁGENES DE PEQUEÑO TAMAÑO:

La solución Pilot_51 (moviendo sus imágenes a la carpeta drawable-nodpi ) funciona, pero tiene otro problema: hace que las imágenes sean DEMASIADO PEQUEÑAS en la pantalla a menos que las imágenes cambien de tamaño a una resolución muy grande (como 2000 x 3800) para adaptarse a la pantalla. tu aplicación más pesada

SOLUCIÓN : coloque sus archivos de imagen en drawable-hdpi . Funcionó como un amuleto para mí.

Usando la subcarpeta dibujable correcta resolvió para mí. Mi solución fue poner mi imagen de resolución completa (1920×1200) en la carpeta drawable-xhdpi , en lugar de la carpeta dibujable .

También puse una imagen reducida (1280×800) en la carpeta drawable-hdpi .

Estas dos resoluciones coinciden con las tabletas Nexus 7 2013 y 2012 que estoy progtwigndo. También probé la solución en algunas otras tabletas.

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

Este código es trabajo

Use la biblioteca Glide en lugar de cargar directamente en imageview

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

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