2013-07-14 15 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; 
} 

Używam tej metody do obracania oryginalnych zdjęć wykonanych aparatem urządzenia. W dzisiejszych czasach aparat może być większy niż 8MPix (Samsung Galaxy S4 ma 13 Mega pikseli aparatu). I nawet z mniejszą kamerą MPix (moja jest 5 MP, 2592 x 1944 pikseli, które w połączeniu z ARGB_888 pobiera 19Mb pamięci RAM zgodnie z oficjalnymi dokumentami) Mam już OutOfMemory. Pytanie więc, jak obrócić zdjęcie BEZ jego początkowej rozdzielczości, a tym samym jakości?Jak uniknąć OutOfMemory ex podczas obracania obrazu?

+0

Czy rozwiązałeś ten problem? @Stan – bentzy

+0

Hej Stan Potrzebuję odpowiedzi na te pytania. Pomóż mi, jeśli możesz! dzięki – therealprashant

Odpowiedz

2

Ponieważ nie było odpowiedzi, zakładam, że nie ma odpowiedzi, a może właśnie zadałem pytanie nieco niepoprawnie. Wygląda na to jedyna opcja tutaj jest to increase the app's heap size
UPDATE:
Jest też inna opcja - do pracy z bitmapami poprzez NDK/JNI jak here lub użyć Android Image-Magic lib. Obraz Magia lib jest całkiem fajny, aby obrócić obraz wszystko czego potrzebujesz to:

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

MagickImage posiada wiele innych opcji graficznych manipulacji, jak również. Rozmycie, mat, skala, węgiel drzewny i wiele innych. Jednak rozmiar jego bibliotek jest zauważalny. Autorzy wykonali świetną robotę i objęli wszystkie możliwe plaformy: arm64-v8a, armeabi, armeabi-v7a, mips, mips64, x86, x86_64 i ostateczny rozmiar wszystkich tych bibliotek wynosi ponad 36Mb. Więc powinieneś pomyśleć zanim dodasz wszystkie biblioteki do jednej aplikacji, może opakowanie 6 różnych wersji przy użyciu manifestu do filtrowania przez chipset/platformę jest właściwą drogą.
UPDATE
Inną opcją jest convert Immutable Bitmap into Mutable (wrap bitmaps into MappedByteBuffer)

+1

Twój przypadek użycia nie wydaje się usprawiedliwiać dekodowania/kodowania JPEG w pierwszej kolejności. To nie tylko problem z pamięcią (jak wskazuje zaakceptowana odpowiedź, istnieje wiele sposobów na uniknięcie OOM), wpływa również na wydajność i jakość obrazu. Możesz bezstratnie obracać obraz JPEG zgodnie z flagą EXIF, jak pokazano [tutaj] (http://stackoverflow.com/questions/706665/lossless-jpeg-rotate-90-180-270-degrees-in-java) . Biblioteka Androida znajduje się na ** [GitHub] (https://github.com/bkhall/AndroidMediaUtil) ** –

+1

Próbowałem rozwiązania LLJTran/AndroidMediaUtil i nie udało się! Próbowałem obrócić naprawdę duży obraz JPEG (2400 x 4200). Działa powoli i zrzuca OOM bez wynikowego JPEG. – Stan

+0

Btw, AndroidMediaUtil ma irytującą "funkcję" - zawiera plik xml (makernote.xml) w zasobach, co spowodowało ból w @ss, ponieważ projekt lib/jar nie może zawierać żadnych zasobów (z wyjątkiem formatu aar). Nawet jeśli importujesz go jako moduł w AndroidStudio - to nie pomoże. Musiałem więc zakodować informacje z tego xml'a na String, aby działało. Również 2400x4200 nie jest aż tak duży, ponieważ moja kamera telefoniczna strzela 2400x3200. – Stan

-1

Zrób plik nazwa metody dekodowania:

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

następnie wywołać tę metodę tak (można wywołać tej metody w przycisk click słuchacza)

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

Gdzie ścieżka jest ścieżką obrazu, w której zapisujesz zdjęcie .. w moim przypadku to jest

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

W przypadku jakiegokolwiek problemu - zapytaj :) Mam nadzieję, że to pomaga.

+0

Ten błąd występuje z powodu braku pamięci, więc musisz ustawić jego wysokość i szerokość, przekazać ją w tej metodzie. –

+1

Czy przeczytałeś to: Więc pytanie brzmi, jak obrócić zdjęcie BEZ utraty jego początkowego rozmiaru, a tym samym jakości? – Stan

+0

można ustawić ten sam rozmiar obrazu w tym również koleś. –

Powiązane problemy