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

我用這種方法來旋轉設備相機拍攝的原始照片。如今相機可能比8MPix更大(三星Galaxy S4擁有13萬像素相機)。即使使用較少的MPix相機(我的5 MP,2592 x 1944像素與ARGB_888結合需要19Mb根據官方文檔)我已經得到了OutOfMemory。所以問題是如何旋轉照片而不損失它的初始分辨率和質量?如何在旋轉圖像時避免OutOfMemory ex?

+0

你解決了這個問題嗎? @斯坦 – bentzy

+0

嘿斯坦我需要這個問題的答案。如果可以的話幫我一把!謝謝 – therealprashant

回答

2

由於沒有答案,我假設沒有答案,或者我剛纔問了一下這個問題有點不正確。它看起來像唯一的選擇,這裏是to increase the app's heap size
UPDATE:
還有另一種選擇 - 通過NDK/JNI位圖工作像here或使用Android Image-Magic lib。 Image Magic lib非常酷,旋轉圖像只需要:

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

MagickImage還有許多其他圖像處理選項。模糊,啞光,比例,木炭等等。但是,它的庫大小是顯而易見的。作者做得很好,他們涵蓋了所有可能的平臺:arm64-v8a,armeabi,armeabi-v7a,mips,mips64,x86,x86_64,所有這些庫的最終大小都超過36Mb。因此,在將所有庫添加到一個apk之前,您應該考慮使用清單來打包6個不同版本,以便通過芯片組/平臺過濾是正確的方法。
UPDATE
另一種選擇是convert Immutable Bitmap into Mutable (wrap bitmaps into MappedByteBuffer)

+1

您的使用案例似乎沒有理由首先解碼/編碼JPEG。這不僅是內存問題(正如您接受的答案指出的,有很多方法可以避免OOM),它還會影響性能和圖像質量。您可以根據EXIF標誌執行JPEG圖像的無損旋轉,如[演示] [這裏](http://stackoverflow.com/questions/706665/lossless-jpeg-rotate-90-180-270-degrees-in-java) 。可以在** [GitHub](https://github.com/bkhall/AndroidMediaUtil)上找到Android庫** –

+1

我嘗試了LLJTran/AndroidMediaUtil解決方案,並且失敗!我試圖旋轉一個非常大的JPEG圖像(2400x4200)。它的運行速度很慢,它不會產生JPEG格式,而會導致OOM。 – Stan

+0

順便說一下,AndroidMediaUtil具有惱人的「功能」 - 它們在資源中包含了一個xml文件(makernote.xml),因此他們在@ss cuz中創建了一個痛苦,lib/jar項目不能包含任何資源(不包括aar格式)。即使您將它作爲AndroidStudio中的模塊導入 - 這也無濟於事。所以我不得不將這個xml中的信息硬編碼爲字符串以使其工作。 2400x4200也不是那麼大,因爲我的手機相機拍攝了2400x3200。 – Stan

-1

製作方法名的解碼文件:

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

然後調用此方法是這樣的(你可以調用按鈕,點擊收聽此方法)

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

哪裏路徑是圖像的路徑,您保存您的圖像.. 在我的情況它是

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

如有任何問題 - 問:)希望這會有所幫助。

+0

這個錯誤是由於內存不足導致的,所以你必須設置它的高度和寬度,在這個方法中傳遞它 –

+1

你讀過這個:所以問題是如何旋轉照片而不損失它的初始尺寸和質量? – Stan

+0

你可以在此設置相同的圖像大小。 –