2012-06-21 20 views
6

Básicamente estoy intentando rotar un mapa de bits (desde una imagen) en una aplicación de Android. La razón por la que quiero hacer esto es que una imagen tomada desde la cámara (a través de un intento) se muestra horizontalmente, incluso si se captura verticalmente, y la orientación se mantiene como metadatos en la imagen. Corrígeme si está equivocado. Sin embargo, el problema es que la imagen ocupará mucha memoria cuando se carga, si se toma con un teléfono con una cámara razonablemente buena, y no he encontrado la manera de rotarla y guardarla sin el riesgo de obtener OutOfMemoryError . El código siguiente es donde i:Girar una imagen en Android sin OutOfMemoryError o downscaling

  1. de carga en la imagen
  2. Comprobar si necesita girarse
  3. Carga una versión a escala reducida para la visualización en un ImageView
  4. Gira la imagen pequeña, si es necesario
  5. En un hilo separado; cargar, girar y guardar la imagen, por lo que no es necesario en el futuro

Es importante que la aplicación mantenga las imágenes en la resolución, pero cualquier trucos con codificaciones son bienvenidos. He buscado en Internet por unos días, no he podido encontrar nada más de lo que ya he implementado. Aquí hay otro hilo sobre el tema, pero no parece haber soluciones. Espero que puedas ayudar.

public Bitmap getBitmap(final Context c) { 
    if (bitmap != null) 
     return bitmap; 

    final int rotate = necessaryRotation(c, file); 
    // if(rotate != 0) rotateImageFile(c, rotate); 

    try { 
     // Get scaled version 
     BitmapFactory.Options options = new BitmapFactory.Options(); 
     options.inJustDecodeBounds = true; 
     BitmapFactory.decodeFile(file, options); 
     options.inSampleSize = calcInSampleSize(options, 1024, 1024); 
     options.inJustDecodeBounds = false; 
     bitmap = BitmapFactory.decodeFile(file, options); 

     // rotate? 
     bitmap = rotateImage(c,bitmap,rotate); 

     System.out.println("Bitmap loaded from file: size=" 
       + bitmap.getWidth() + "," + bitmap.getHeight()); 

     System.gc(); 
    } catch (Exception e) { 
     System.err.println("Unable to load image file: " 
       + this.getFilename()); 
    } 

    // if rotation is needed, do it in worker thread for next time 
    if(rotate != 0){ 
     Thread t = new Thread(new Runnable(){ 

      public void run() { 
       // load entire image 
       try{ 
        File imageFile = new File(getFilename()); 
        Bitmap huge = Media.getBitmap(c.getContentResolver(), 
        Uri.fromFile(imageFile)); 

        huge = rotateImage(c,huge,rotate); 

        // save bitmap properly 
        FileOutputStream out = new FileOutputStream(imageFile); 
        huge.compress(Bitmap.CompressFormat.PNG, 100, out); 

        out.flush(); 
        out.close(); 
        huge.recycle(); 
        huge = null; 
        out = null; 
        System.gc(); 

       }catch(IOException e){ 
        e.printStackTrace(); 
       } 
      } 

     }); 
     t.start(); 
    } 

    return bitmap; 
} 

private Bitmap rotateImage(Context c, Bitmap bitmap, int rotate) { 
    if (rotate != 0) { 
     // rotate 
     Matrix m = new Matrix(); 
     m.postRotate(rotate); 
     Bitmap rotImage = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), 
       bitmap.getHeight(), m, true); 
     bitmap.recycle(); 

     System.out.println("Image (id=" + getId() 
       + ") rotated successfully"); 

     System.gc(); 

     return rotImage; 
    } 
    return bitmap; 
} 

private int necessaryRotation(Context c, String imageFile) { 
    int rotate = 0; 
    ExifInterface exif; 
    try { 
     exif = new ExifInterface(imageFile); 
     int orientation = exif.getAttributeInt(
       ExifInterface.TAG_ORIENTATION, 
       ExifInterface.ORIENTATION_NORMAL); 

     switch (orientation) { 
     case ExifInterface.ORIENTATION_ROTATE_270: 
      rotate = 270; 
      break; 
     case ExifInterface.ORIENTATION_ROTATE_180: 
      rotate = 180; 
      break; 
     case ExifInterface.ORIENTATION_ROTATE_90: 
      rotate = 90; 
      break; 
     } 
    } catch (IOException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } 

    return rotate; 
} 

private int calcInSampleSize(BitmapFactory.Options options, int reqWidth, 
     int reqHeight) { 
    int height = options.outHeight; 
    int width = options.outWidth; 
    int inSampleSize = 1; 
    while (height > reqHeight || width > reqWidth) { 
     height /= 2; 
     width /= 2; 
     inSampleSize *= 2; 
    } 

    return inSampleSize; 
} 

Si hay algo que necesita saber o tiene alguna optimizaciones que podría ser capaz de utilizar para reducir el uso de memoria, por favor escribir :) Gracias

+0

i He creado una buena solución JNI que evita la falta de memoria al eliminar la barrera de limitación de tamaño máximo de almacenamiento dinámico. [** aquí hay un enlace **] (http://stackoverflow.com/questions/14398670/android-rotating-a-bitmap-using-jni-ndk#comment20033361_14398670) en mi fragmento. algunas notas: - reemplace en el código cada instancia de "uint16_t" con "uint32_t" (ese es el error en mi código que he preguntado). - el mapa de bits de entrada y salida debe estar con la configuración 8888 (que es ARGB) - el mapa de bits de entrada se reciclará durante el proceso. - el código gira la imagen 90 grados en sentido antihorario. por supuesto puedes cambiarlo dependiendo –

Respuesta

0

Prueba este fragmento:

private Bitmap rotateImage(Context c, Bitmap bitmap, int rotate) { 
    .... 

    // reduce byte per pixel 
    bitmap = bitmap.copy(Bitmap.Config.RGB_565, false); 

    Bitmap.createBitmap(bitmap,... 
}