2012-06-21 4 views
6

Fondamentalmente sto provando a ruotare una Bitmap (da un'immagine) in un'app Android. Il motivo per cui voglio farlo è che un'immagine scattata dalla fotocamera (attraverso un intento) viene visualizzata orizzontalmente anche se è catturata verticalmente e l'orientamento viene mantenuto come metadata sull'immagine. Correggimi se sbaglio Il problema è, tuttavia, che l'immagine occuperà molta memoria quando caricata, se presa su un telefono con una fotocamera ragionevolmente buona, e non ho trovato il modo di ruotarla e salvarla senza il rischio di ottenere OutOfMemoryError . Il seguente codice è dove i:Rotazione di un'immagine in Android senza OutOfMemoryError o downscaling

  1. carico nell'immagine
  2. Verifica se deve essere ruotata
  3. carica una versione ridotta per la visualizzazione in un'ImageView
  4. Ruota piccola immagine se necessario
  5. In un thread separato; caricare, ruotare e salvare l'immagine, quindi non è necessario in futuro

È importante che l'applicazione mantenga le immagini nella risoluzione, ma i trucchi con le codifiche sono benvenuti. Ho cercato su Internet per alcuni giorni, non riuscendo a trovare nulla di più di quello che ho già implementato. C'è un'altra discussione sull'argomento qui, ma non sembrano esserci soluzioni. Spero che tu possa aiutare

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

Se c'è qualcosa che dovete sapere o avere ottimizzazioni potrei essere in grado di utilizzare per ridurre l'utilizzo della memoria, si prega di scrivere :) Grazie

+0

i Ho creato una buona soluzione JNI che evita l'esaurimento della memoria rimuovendo la barriera di limitazione della dimensione massima dell'heap. [** Ecco un collegamento **] (http://stackoverflow.com/questions/14398670/android-rotating-a-mapmap-using-jni-ndk#comment20033361_14398670) al mio snippet. alcune note: - sostituisci nel codice ogni istanza di "uint16_t" con "uint32_t" (questo è il bug sul mio codice che ti ho chiesto). - input e output bitmap deve essere con 8888 config (che è ARGB) - bitmap di input verrà riciclato durante il processo. - Il codice ruota l'immagine in senso anti-orario. ovviamente puoi cambiarlo a seconda –

risposta

0

Prova questo frammento:

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

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

    Bitmap.createBitmap(bitmap,... 
}