Bitmap fuera de problemas de memoria
Mi problema
Tomo una foto con mi dispositivo Android. Entonces decodifico esa imagen del archivo.
- La cámara no funciona en Nougat 7.0
- Cómo devolver un mapa de bits con onPictureTaken en Android?
- Galaxy S3: tomar fotos en modo retrato destruye actividad
- Matriz int a la textura opengl en android
- Android MediaRecorder se bloquea
Bitmap photo = BitmapFactory.decodeFile(EXTERNAL_IMAGE_PATH+File.separator+this._currentPhotoName+JPEG_FILE_SUFFIX); if (photo == null && data != null) photo = (Bitmap) data.getExtras().get("data"); else if (data == null && photo == null) Log.e("CCPhotoManager","Can't find image from file or from intent data.");
A continuación, compruebo que la imagen y ver si es necesario girar a la orientación correcta.
try { ExifInterface exif = new ExifInterface(EXTERNAL_IMAGE_PATH+File.separator+this._currentPhotoName+JPEG_FILE_SUFFIX); int rotation = CCDataUtils.exifToDegrees(exif.getAttributeInt(ExifInterface.TAG_ORIENTATION,ExifInterface.ORIENTATION_NORMAL)); Log.v("CCPhotoManager", "Rotation:"+rotation); if (rotation > 0) { photo = this.convertSavedImageToCorrectOrientation(EXTERNAL_IMAGE_PATH+File.separator+this._currentPhotoName+JPEG_FILE_SUFFIX, photo, rotation); } } catch (IOException e1) { // TODO Auto-generated catch block e1.printStackTrace(); }
Si tiene que girar llamo a este método.
public Bitmap convertSavedImageToCorrectOrientation(String filePath,Bitmap photo,int rotation) { Log.d("CCPhotoManager", "Changing Orientation of photo located at: "+filePath+" Rotating by:"+rotation); int width = photo.getWidth(); int height = photo.getHeight(); Matrix matrix = new Matrix(); matrix.preRotate(rotation); Bitmap adjusted = Bitmap.createBitmap(photo, 0, 0, width, height, matrix, true); try { FileOutputStream out = new FileOutputStream(filePath); adjusted.compress(Bitmap.CompressFormat.JPEG, 100, out); } catch (Exception e) { e.printStackTrace(); } return adjusted; }
Estoy recibiendo quejas de memoria si se convertSavedImageToCorrectOrientation
en la línea Bitmap adjusted = Bitmap.createBitmap(photo,0,0,width,height,matrix,true);
Esto es sólo el caso en el Samsung Galaxy S3
. Funciona bien en el Samsung Galaxy Ace
, HTC Hero
y el Sony Xperia U
Aquí está el error.
10-17 14:33:33.950: E/AndroidRuntime(12556): java.lang.OutOfMemoryError 10-17 14:33:33.950: E/AndroidRuntime(12556): at android.graphics.Bitmap.nativeCreate(Native Method) 10-17 14:33:33.950: E/AndroidRuntime(12556): at android.graphics.Bitmap.createBitmap(Bitmap.java:605) 10-17 14:33:33.950: E/AndroidRuntime(12556): at android.graphics.Bitmap.createBitmap(Bitmap.java:551)
Es una enorme cantidad de memoria también.
10-17 14:33:33.945: E/dalvikvm-heap(12556): Out of memory on a 31961104-byte allocation.
Creo que es algo que ver con la cantidad de mapas de bits alrededor, pero no estoy seguro de cómo detener este error de pasar.
Sé que puedes llamar .recycle();
En ellos, pero no parece funcionar.
Mi pregunta
¿Cómo manejo correctamente mis mapas de bits para que no tenga este problema de MOO?
Gracias por adelantado
- ¿Cómo encontrar la longitud focal de la cámara Android?
- Android: ¿Cómo retrasar la captura de un marco específico tomado por la cámara?
- Obtener el ángulo de visión del dispositivo de la cámara Android
- ¿Cómo medir la altura, el ancho y la distancia del objeto usando la cámara?
- ¿Cómo hacer que la luz de la cámara parpadee en una secuencia específica?
- LibGDX - Camera.update () llamada no hace nada
- ¿Cómo mostrar la vista previa de 2 cámaras una al lado de la otra?
- Parte del objeto de cámara del tiempo es nulo durante la inicialización
Para problemas de memoria insuficiente
// decodifica la imagen y la escala para reducir el consumo de memoria
private Bitmap decodeFile(File f){ try { //Decode image size BitmapFactory.Options o = new BitmapFactory.Options(); o.inJustDecodeBounds = true; BitmapFactory.decodeStream(new FileInputStream(f),null,o); //The new size we want to scale to final int REQUIRED_SIZE=70; //Find the correct scale value. It should be the power of 2. int scale=1; while(o.outWidth/scale/2>=REQUIRED_SIZE && o.outHeight/scale/2>=REQUIRED_SIZE) scale*=2; //Decode with inSampleSize BitmapFactory.Options o2 = new BitmapFactory.Options(); o2.inSampleSize=scale; return BitmapFactory.decodeStream(new FileInputStream(f), null, o2); } catch (FileNotFoundException e) {} return null; }
Este es un ejemplo más completo de cómo redimensionar / rotar, tomado en parte de la guía de desarrolladores de Android (cambiar REQ_WIDTH y REQ_HEIGHT):
private static final int REQ_WIDTH = 450; private static final int REQ_HEIGHT = 450; /** * Resize, crop, rotate and Inserts the picture on the layout. * * @param mImageView to insert the bitmap. * @param imageURI from wich to obtain the bitmap. * */ private void setPic(ImageView mImageView, String imageURI) { // Get the original bitmap dimensions BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeFile(imageURI, options); // Calculate inSampleSize options.inSampleSize = calculateInSampleSize(options, REQ_HEIGHT, REQ_WIDTH); // Decode bitmap with inSampleSize set options.inJustDecodeBounds = false; Bitmap bitmap = BitmapFactory.decodeFile(imageURI, options); //need rotation? float rotation = rotationForImage(getActivity(), Uri.fromFile(new File(imageURI))); if (rotation != 0) { //rotate Matrix matrix = new Matrix(); matrix.preRotate(rotation); mImageView.setImageBitmap(Bitmap.createBitmap(bitmap, 0, 0, REQ_HEIGHT, REQ_WIDTH, matrix, true)); } else { //use the original mImageView.setImageBitmap(BitmapFactory.decodeFile(imageURI, options)); } } 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) { if (width > height) { inSampleSize = Math.round((float) height / (float) reqHeight); } else { inSampleSize = Math.round((float) width / (float) reqWidth); } } return inSampleSize; } public static float rotationForImage(Context context, Uri uri) { try { if (uri.getScheme().equals("content")) { String[] projection = { Images.ImageColumns.ORIENTATION }; Cursor c = context.getContentResolver().query(uri, projection, null, null, null); if (c.moveToFirst()) { return c.getInt(0); } } else if (uri.getScheme().equals("file")) { ExifInterface exif = new ExifInterface(uri.getPath()); int rotation = (int) exifOrientationToDegrees(exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL)); return rotation; } return 0; } catch (IOException e) { Log.e(TAG, "Error checking exif", e); return 0; } } private static float exifOrientationToDegrees(int exifOrientation) { if (exifOrientation == ExifInterface.ORIENTATION_ROTATE_90) { return 90; } else if (exifOrientation == ExifInterface.ORIENTATION_ROTATE_180) { return 180; } else if (exifOrientation == ExifInterface.ORIENTATION_ROTATE_270) { return 270; } return 0; }
Yo tenía exactamente el mismo problema, haciendo exactamente lo mismo en el mismo dispositivo! Desafortunadamente en mi caso la imagen necesitaba ser enviada a un webservice, usando el tamaño completo, original. Lo que funcionó para mí fue activar largeHeap en el elemento de aplicación del manifiesto.
Esto no solucionará el problema permanentemente – es posible que un dispositivo vaya junto con una cámara aún más grande y las imágenes no encajarán en la memoria incluso con la función grande habilitada. Para capturar este caso extrema borde también puse un try catch alrededor del código que gira la imagen, y acaba de mostrar un error agradable para el usuario.
Una solución más completa sería escribir su propio código de manipulación jpeg que puede rotar un jpeg utilizando un enfoque basado en la secuencia de modo que la imagen nunca necesita ser cargado en la memoria.
- Ruta de dibujo en Google Maps con Google Maps Android API v2
- Configurar el tema Programmactically causa el fondo negro