2013-07-14 11 views
6
public static boolean rotateBitmapByExifAndSave(File targetFile){ 

    if (targetFile==null || !targetFile.exists() || !targetFile.canRead() || !targetFile.canWrite()) 
     return false; 

    boolean isSucceed = false; 
    // detect if photo is need to be rotated 
    try { 
     final Matrix matrix = new Matrix(); 

     ExifInterface exifReader = new ExifInterface(targetFile.getAbsolutePath()); 

     int orientation = exifReader.getAttributeInt(ExifInterface.TAG_ORIENTATION, 1); 
     boolean isRotationNeeded = true; 

     switch (orientation) { 
     case ExifInterface.ORIENTATION_ROTATE_90: 
      matrix.postRotate(90); 
      break; 

     case ExifInterface.ORIENTATION_ROTATE_180: 
      matrix.postRotate(180); 
      break; 

     case ExifInterface.ORIENTATION_ROTATE_270: 
      matrix.postRotate(270); 
      break; 

     default: // ExifInterface.ORIENTATION_NORMAL 
      // Do nothing. The original image is fine. 
      isRotationNeeded = false; 
      isSucceed = true; 
      break; 
     } 

     if (isRotationNeeded){ 
      BitmapFactory.Options bmfOtions = new BitmapFactory.Options(); 
      Bitmap bitmap = null; 
      FileInputStream fileInputStream = null; 
      try { 
       fileInputStream = new FileInputStream(targetFile); 
       bitmap = BitmapFactory.decodeStream(fileInputStream,null,bmfOtions); 
      } catch (FileNotFoundException e){ 
       isSucceed = false; 
      } 
      finally { 
       if (fileInputStream != null) 
        try { 
         fileInputStream.close(); 
        } catch (IOException e) {} 
      } 
      if (bitmap!=null){ 
       bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true); 
       isSucceed = ImageUtils.saveBitmapToFile(bitmap, targetFile, 100); 
       bitmap.recycle(); 
      } 
     } 

    } catch (IOException e) { 
     Log.e("ImageUtils", e); 
    } catch (Exception e) { 
     // like there is no EXIF support? 
     Log.e("ImageUtils", e); 
    } catch (Throwable e) { 
     // stupid Out of VM's memory 
     Log.e("ImageUtils", e.toString()); 
    } 

    return isSucceed; 
} 

Uso questo metodo per ruotare le foto originali realizzate dalla fotocamera del dispositivo. Al giorno d'oggi la fotocamera potrebbe essere più grande di 8 MPix (Samsung Galaxy S4 ha una fotocamera da 13 megapixel). E anche con meno fotocamera MPix (il mio è 5 MP, 2592 x 1944 pixel che in congiunzione di ARGB_888 prende 19Mb di RAM in base ai documenti ufficiali) Ho già OutOfMemory. Quindi la domanda è come ruotare la foto SENZA perdere la sua risoluzione iniziale e quindi la qualità?Come evitare OutOfMemory ex mentre si ruota l'immagine?

+0

Hai risolto questo problema? @Stan – bentzy

+0

Hey Stan, ho bisogno di questa risposta alle domande. Aiutami se puoi! grazie – therealprashant

risposta

2

Dato che non c'era risposta presumo che non ci sia una risposta o forse ho appena fatto la domanda un po 'in modo errato. Sembra che l'unica opzione qui è to increase the app's heap size
UPDATE:
C'è anche un'altra opzione - a lavorare con le immagini bitmap tramite NDK/JNI come here o per utilizzare Android Image-Magic lib. L'immagine magica lib è piuttosto fresco, di ruotare un'immagine tutto ciò che serve è:

ImageInfo imageInfo = new ImageInfo(imageFile.getAbsolutePath()); 
MagickImage magickImage = new MagickImage(imageInfo); 
magickImage.setCompression(100); // to minimize loss 
magickImage.rotateImage(90.0f).writeImage(imageInfo); 

MagickImage ha molte altre opzioni di immagine manipolare pure. Sfocatura, opaco, scala, carbone di legna e molti altri. Tuttavia le sue dimensioni di librerie sono evidenti. Gli autori hanno fatto un ottimo lavoro e hanno coperto tutte le plaform possibili: arm64-v8a, armeabi, armeabi-v7a, mips, mips64, x86, x86_64 e la dimensione finale di tutte queste librerie è superiore a 36 Mb. Quindi dovresti pensare prima di aggiungere tutte le librerie in un apk, magari confezionare 6 versioni differenti usando manifest per filtrare per chipset/piattaforma è la giusta via.
UPDATE
Un'altra opzione è quella di convert Immutable Bitmap into Mutable (wrap bitmaps into MappedByteBuffer)

+1

Il tuo caso d'uso non sembra giustificare la decodifica/codifica di JPEG in primo luogo. Non è solo il problema della memoria (come indica la risposta accettata, ci sono diversi modi per evitare OOM), ma influisce anche sulle prestazioni e sulla qualità dell'immagine. È possibile eseguire la rotazione senza perdita di un'immagine JPEG in base al flag EXIF, come dimostrato [qui] (http://stackoverflow.com/questions/706665/lossless-jpeg-rotate-90-180-270-degrees-in-java) . La libreria Android può essere trovata su ** [GitHub] (https://github.com/bkhall/AndroidMediaUtil) ** –

+1

Ho provato la soluzione LLJTran/AndroidMediaUtil e fallisce! Ho provato a ruotare un'immagine JPEG molto grande (2400x4200). Funziona lentamente e genera OOM senza JPEG risultante. – Stan

+0

Btw, AndroidMediaUtil ha caratteristiche "fastidiose" - hanno incluso un file xml (makernote.xml) in risorse e quindi hanno creato un dolore nel @ss cuz il progetto lib/jar non può contenere alcuna risorsa (escluso il formato aar). Anche se lo si importa come modulo in AndroidStudio, questo non aiuta. Quindi ho dovuto inserire le informazioni hardcode da questo xml in String per farlo funzionare. Anche il 2400x4200 non è così grande da quando la mia fotocamera del telefono scatta 2400 x 3200. – Stan

-1

Fai un file di nome di metodo decode:

public static Bitmap decodeFile(File f,int WIDTH,int HIGHT){ 
     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_WIDTH=WIDTH; 
      final int REQUIRED_HIGHT=HIGHT; 
      //Find the correct scale value. It should be the power of 2. 
      int scale=1; 
      while(o.outWidth/scale/2>=REQUIRED_WIDTH && o.outHeight/scale/2>=REQUIRED_HIGHT) 
       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; 
    } 

poi chiamare questo metodo come questo (È possibile chiamare questo metodo in scatto del tasto ascoltatore)

Bitmap bi = decodeFile(new File(path),1280,800); 

Dove percorso è il percorso dell'immagine in cui si salva l'immagine .. nel mio caso è

String path = Environment.getExternalStorageDirectory().toString() + "/nature.jpg"; 

In caso di qualsiasi problema - chiedere :) Spero che questo aiuti.

+0

Questo errore si verifica a causa della memoria insufficiente, quindi devi impostarne l'altezza e la larghezza, passarlo in questo metodo –

+1

Hai letto questo: la domanda è come ruotare la foto SENZA perdere la sua dimensione iniziale e quindi la sua qualità? – Stan

+0

puoi impostare la stessa dimensione dell'immagine anche in questo caso. –

Problemi correlati