【问题标题】:Android: Bitmaps loaded from gallery are rotated in ImageViewAndroid:从图库加载的位图在 ImageView 中旋转
【发布时间】:2011-04-08 13:26:12
【问题描述】:

当我将媒体库中的图像加载到位图中时,一切正常,除了在垂直握住手机时用相机拍摄的照片会被旋转,因此即使出现,我也总是得到水平照片在画廊垂直。 为什么会这样?如何正确加载?

【问题讨论】:

标签: android bitmap rotation gallery


【解决方案1】:

所以,举个例子……

首先你需要创建一个ExifInterface:

ExifInterface exif = new ExifInterface(filename);

然后您可以抓取图像的方向:

orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 1);

以下是方向值的含义: http://sylvana.net/jpegcrop/exif_orientation.html

因此,最重要的值是 3、6 和 8。 例如,如果方向是ExifInterface.ORIENTATION_ROTATE_90(即6),您可以像这样旋转图像:

Matrix matrix = new Matrix();
matrix.postRotate(90);
rotatedBitmap = Bitmap.createBitmap(sourceBitmap, 0, 0, sourceBitmap.getWidth(), sourceBitmap.getHeight(), matrix, true);

不过,这只是一个简单的示例。我确信还有其他方法可以执行实际旋转。但是您也可以在 StackOverflow 上找到它们。

【讨论】:

  • 以下是不同方向的所有旋转值:3:180、6:90、8:270
  • 可以使用命名常量时不要使用幻数:ExifInterface.ORIENTATION_NORMAL、ExifInterface.ORIENTATION_ROTATE_90、ExifInterface.ORIENTATION_ROTATE_180、ExifInterface.ORIENTATION_ROTATE_270。
  • 在内存中同时保存两个位图时,请注意OutOfMemoryError
  • 另一个完整的例子...stackoverflow.com/questions/14066038/…
【解决方案2】:

这是一个完整的解决方案(可在 Facebook SDK 的 Hackbook 示例中找到)。它的优点是不需要访问文件本身。如果您从内容解析器加载图像(例如,如果您的应用正在响应共享照片意图),这将非常有用。

public static int getOrientation(Context context, Uri photoUri) {
    /* it's on the external media. */
    Cursor cursor = context.getContentResolver().query(photoUri,
            new String[] { MediaStore.Images.ImageColumns.ORIENTATION }, null, null, null);

    if (cursor.getCount() != 1) {
        return -1;
    }

    cursor.moveToFirst();
    return cursor.getInt(0);
}

然后你可以得到一个旋转的Bitmap,如下所示。此代码还将图像(不幸的是)缩小到 MAX_IMAGE_DIMENSION。否则你可能会耗尽内存。

public static Bitmap getCorrectlyOrientedImage(Context context, Uri photoUri) throws IOException {
    InputStream is = context.getContentResolver().openInputStream(photoUri);
    BitmapFactory.Options dbo = new BitmapFactory.Options();
    dbo.inJustDecodeBounds = true;
    BitmapFactory.decodeStream(is, null, dbo);
    is.close();

    int rotatedWidth, rotatedHeight;
    int orientation = getOrientation(context, photoUri);

    if (orientation == 90 || orientation == 270) {
        rotatedWidth = dbo.outHeight;
        rotatedHeight = dbo.outWidth;
    } else {
        rotatedWidth = dbo.outWidth;
        rotatedHeight = dbo.outHeight;
    }

    Bitmap srcBitmap;
    is = context.getContentResolver().openInputStream(photoUri);
    if (rotatedWidth > MAX_IMAGE_DIMENSION || rotatedHeight > MAX_IMAGE_DIMENSION) {
        float widthRatio = ((float) rotatedWidth) / ((float) MAX_IMAGE_DIMENSION);
        float heightRatio = ((float) rotatedHeight) / ((float) MAX_IMAGE_DIMENSION);
        float maxRatio = Math.max(widthRatio, heightRatio);

        // Create the bitmap from file
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inSampleSize = (int) maxRatio;
        srcBitmap = BitmapFactory.decodeStream(is, null, options);
    } else {
        srcBitmap = BitmapFactory.decodeStream(is);
    }
    is.close();

    /*
     * if the orientation is not 0 (or -1, which means we don't know), we
     * have to do a rotation.
     */
    if (orientation > 0) {
        Matrix matrix = new Matrix();
        matrix.postRotate(orientation);

        srcBitmap = Bitmap.createBitmap(srcBitmap, 0, 0, srcBitmap.getWidth(),
                srcBitmap.getHeight(), matrix, true);
    }

    return srcBitmap;
}

【讨论】:

  • MAX_IMAGE_DIMENDION 是什么意思?
  • 这是你得到的图像的最大宽度或高度。 IE。假设您只需要一张 512x512 的图像,如果您打开一张 24 兆像素的图像,那么打开已经过二次采样的图像要比打开整个图像然后按比例缩小要高效得多 - 无论如何这可能会耗尽您所有的内存。
  • 在我的程序中,我发现将活动/片段中的位图变量定义为私有静态并在函数中将其设置为 null 很有用。那时的记忆问题较少。
  • 将 MAX_IMAGE_DIMENDION 替换为 MAX_IMAGE_WIDTH 和 MAX_IMAGE_HEIGHT 更智能
  • 节省了我很多时间 :) 非常感谢。对于那些获得空光标的人,您可以尝试ExifInterface exif = new ExifInterface(photoUri.getPath()); 然后exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 1) 来获取方向(例如ORIENTATION_ROTATE_90ORIENTATION_ROTATE_180
【解决方案3】:

在这篇文章的帮助下用这段代码解决了这个问题:

            Bitmap myBitmap = getBitmap(imgFile.getAbsolutePath());

            try {
                ExifInterface exif = new ExifInterface(imgFile.getAbsolutePath());
                int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 1);
                Log.d("EXIF", "Exif: " + orientation);
                Matrix matrix = new Matrix();
                if (orientation == 6) {
                    matrix.postRotate(90);
                }
                else if (orientation == 3) {
                    matrix.postRotate(180);
                }
                else if (orientation == 8) {
                    matrix.postRotate(270);
                }
                myBitmap = Bitmap.createBitmap(myBitmap, 0, 0, myBitmap.getWidth(), myBitmap.getHeight(), matrix, true); // rotating bitmap
            }
            catch (Exception e) {

            }
            ImageView img = (ImageView) findViewById(R.id.imgTakingPic);
            img.setImageBitmap(myBitmap);

希望它能节省别人的时间!

【讨论】:

  • 编辑建议:方向 6、3、8 是否没有正确命名的常量?如果不需要旋转,我们可以不跳过新的位图吗?
  • 正如@d60402 之前在评论中所说,您可以使用命名常量:ExifInterface.ORIENTATION_NORMAL、ExifInterface.ORIENTATION_ROTATE_90、ExifInterface.ORIENTATION_ROTATE_180、ExifInterface.ORIENTATION_ROTATE_270。
【解决方案4】:

使用实用程序来完成繁重的工作。

9re 创建了一个简单的实用程序来处理处理 EXIF 数据和将图像旋转到正确方向的繁重工作。

您可以在此处找到实用程序代码:https://gist.github.com/9re/1990019

只需下载此文件,将其添加到项目的 src 目录并使用 ExifUtil.rotateBitmap() 即可获得正确的方向,如下所示:

String imagePath = photoFile.getAbsolutePath();             // photoFile is a File class.
Bitmap myBitmap  = BitmapFactory.decodeFile(imagePath);

Bitmap orientedBitmap = ExifUtil.rotateBitmap(imagePath, myBitmap);

【讨论】:

  • 为我工作!我只是将位图的大小调整为高清格式,然后将其传递给 ExifUtil.rotateBitmap() 以避免像这样的 OutOfMemoryError :Bitmap resized = Bitmap.createScaledBitmap(myBitmap, 720, 1280, true); photo = ExifUtil.rotateBitmap(picturePath, resized);
  • @Phil 不错的补充。我没有遇到过这种情况(我使用的是更旧、更糟糕的 Android 设备),但知道这一点真的很好。
  • 你是英雄我的朋友 :)
  • @klutch 你让我很开心。 :) 公平地说,9re made 编写了实用程序代码,所以他是真正的英雄。
  • @SreekanthKarumanaghat 好问题!当我深入研究时,我可能知道为什么这是有道理的,但现在对我来说似乎也是多余的。也许在 React Native 上花费了太多时间。
【解决方案5】:

您查看过图片的 EXIF 数据吗?它可能知道拍照时相机的方向。

【讨论】:

  • 你是对的,这当然是解决方案。稍后,我将在单独的答案中发布我的代码作为示例,但我将此标记为已接受,因为它让我走上了正确的轨道。
【解决方案6】:

这是因为画廊正确显示旋转图像但不是 ImageView 看这里:

                    myBitmap = BitmapFactory.decodeFile(imgFile.getAbsolutePath(),optionss);
                    ExifInterface exif = new ExifInterface(selectedImagePath);
                    int rotation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
                    int rotationInDegrees = exifToDegrees(rotation);
                    deg = rotationInDegrees;
                    Matrix matrix = new Matrix();
                    if (rotation != 0f) {
                        matrix.preRotate(rotationInDegrees);
                        myBitmap = Bitmap.createBitmap(myBitmap, 0, 0, myBitmap.getWidth(), myBitmap.getHeight(), matrix, true);
                    }

你需要这个:

private static int exifToDegrees(int exifOrientation) {        
    if (exifOrientation == ExifInterface.ORIENTATION_ROTATE_90) { return 90; } 
    else if (exifOrientation == ExifInterface.ORIENTATION_ROTATE_180) {  return 180; } 
    else if (exifOrientation == ExifInterface.ORIENTATION_ROTATE_270) {  return 270; }            
    return 0;    
} 

【讨论】:

    【解决方案7】:

    Kotlin 代码:

    if (file.exists()){
        val bitmap = BitmapFactory.decodeFile(file.absolutePath)
    
        val exif = ExifInterface(file.absoluteFile.toString())
        val orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL)
        val matrix = Matrix()
    
        when(orientation){
            ExifInterface.ORIENTATION_ROTATE_90 -> matrix.postRotate(90F)
            ExifInterface.ORIENTATION_ROTATE_180 -> matrix.postRotate(180F)
            ExifInterface.ORIENTATION_ROTATE_270 -> matrix.postRotate(270F)
        }
    
        val rotatedBitmap = Bitmap.createBitmap(bitmap, 0,0 , bitmap.width, bitmap.height, matrix, true)
        bitmap.recycle()
        iv_capture.setImageBitmap(rotatedBitmap)
    }
    

    【讨论】:

    • 像魅力一样工作!我只是想知道为什么您将结果存储在不同的位图中而不是将其分配给同一个变量。它会提高性能吗?
    【解决方案8】:

    多亏了我再也找不到的帖子,经过多次尝试后让它工作了:-(

    Exif 似乎总是有效,困难在于获取文件路径。我发现的代码在早于 4.4 和 4.4 之后的 API 之间有所不同。基本上 4.4+ 的图片 URI 包含“com.android.providers”。对于此类 URI,代码使用 DocumentsContract 获取图片 id,然后使用 ContentResolver 运行查询,而对于旧版 SDK,代码直接使用 ContentResolver 查询 URI。

    这是代码(对不起,我不能相信是谁发布的):

    /**
     * Handles pre V19 uri's
     * @param context
     * @param contentUri
     * @return
     */
    public static String getPathForPreV19(Context context, Uri contentUri) {
        String res = null;
    
        String[] proj = { MediaStore.Images.Media.DATA };
        Cursor cursor = context.getContentResolver().query(contentUri, proj, null, null, null);
        if(cursor.moveToFirst()){;
            int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
            res = cursor.getString(column_index);
        }
        cursor.close();
    
        return res;
    }
    
    /**
     * Handles V19 and up uri's
     * @param context
     * @param contentUri
     * @return path
     */
    @TargetApi(Build.VERSION_CODES.KITKAT)
    public static String getPathForV19AndUp(Context context, Uri contentUri) {
        String wholeID = DocumentsContract.getDocumentId(contentUri);
    
        // Split at colon, use second item in the array
        String id = wholeID.split(":")[1];
        String[] column = { MediaStore.Images.Media.DATA };
    
        // where id is equal to
        String sel = MediaStore.Images.Media._ID + "=?";
        Cursor cursor = context.getContentResolver().
                query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                        column, sel, new String[]{ id }, null);
    
        String filePath = "";
        int columnIndex = cursor.getColumnIndex(column[0]);
        if (cursor.moveToFirst()) {
            filePath = cursor.getString(columnIndex);
        }
    
        cursor.close();
        return filePath;
    }
    
    public static String getRealPathFromURI(Context context,
            Uri contentUri) {
        String uriString = String.valueOf(contentUri);
        boolean goForKitKat= uriString.contains("com.android.providers");
    
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && goForKitKat) {
                Log.i("KIKAT","YES");
                return getPathForV19AndUp(context, contentUri);
            } else {
    
                return getPathForPreV19(context, contentUri);
            }
    }
    

    【讨论】:

    • 非常感谢您。经过数小时的游标和 exif 工作后,这节省了可能的一天。正如您所说,实际上 exif 具有真实可靠的数据,而不是游标返回。只要给它正确的路径就可以了。
    【解决方案9】:

    你可以从 sd 卡读取路径并执行以下代码...它会在旋转后替换现有照片..

    不是:Exif 在大多数设备上都不起作用,它提供了错误的数据,因此最好在保存到您想要的任何角度之前对旋转进行硬编码,您只需将 postRotate 中的角度值更改为您想要的任何角度值到。

        String photopath = tempphoto.getPath().toString();
        Bitmap bmp = BitmapFactory.decodeFile(photopath);
    
        Matrix matrix = new Matrix();
        matrix.postRotate(90);
        bmp = Bitmap.createBitmap(bmp, 0, 0, bmp.getWidth(), bmp.getHeight(), matrix, true);
    
        FileOutputStream fOut;
        try {
            fOut = new FileOutputStream(tempphoto);
            bmp.compress(Bitmap.CompressFormat.JPEG, 85, fOut);
            fOut.flush();
            fOut.close();
    
        } catch (FileNotFoundException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    
    }
    

    【讨论】:

    • 这是要旋转但我们不知道图像是否需要旋转。
    【解决方案10】:

    我改进了 Teo Inke 的回答。除非确实有必要,否则它不再旋转图像。它也更容易阅读,并且应该运行得更快。

    // Load Image
    Bitmap bitmap = BitmapFactory.decodeFile(filePath);
    
    // Rotate Image if Needed
    try
    {
        // Determine Orientation
        ExifInterface exif = new ExifInterface(filePath);
        int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 1);
    
        // Determine Rotation
        int rotation = 0;
        if      (orientation == 6)      rotation = 90;
        else if (orientation == 3)      rotation = 180;
        else if (orientation == 8)      rotation = 270;
    
        // Rotate Image if Necessary
        if (rotation != 0)
        {
            // Create Matrix
            Matrix matrix = new Matrix();
            matrix.postRotate(rotation);
    
            // Rotate Bitmap
            Bitmap rotated = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true); 
    
            // Pretend none of this ever happened!
            bitmap.recycle();
            bitmap = rotated;
            rotated = null;
         }
    }
    catch (Exception e)
    {
        // TODO: Log Error Messages Here
    }
    
    // TODO: Use Result Here
    xxx.setBitmap(bitmap);
    

    【讨论】:

      【解决方案11】:

      首先你需要的是真实的文件路径 如果你做得很好,如果你使用的是 URI,那么使用这个方法 获取真正的路径:

       public static String getRealPathFromURI(Uri contentURI,Context context) {
          String path= contentURI.getPath();
          try {
              Cursor cursor = context.getContentResolver().query(contentURI, null, null, null, null);
              cursor.moveToFirst();
              String document_id = cursor.getString(0);
              document_id = document_id.substring(document_id.lastIndexOf(":") + 1);
              cursor.close();
      
              cursor = context.getContentResolver().query(
                      android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                      null, MediaStore.Images.Media._ID + " = ? ", new String[]{document_id}, null);
              cursor.moveToFirst();
              path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
              cursor.close();
          }
          catch(Exception e)
          {
              return path;
          }
          return path;
      }
      

      例如提取您的位图:

        try {
                                  Bitmap bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), selectedImage);
      
                              }
                              catch (IOException e)
                              {
                                  Log.e("IOException",e.toString());
                              }
      

      如果你愿意,你可以使用 decodeFile() 代替。

      现在您已经有了位图,并且真正的路径得到了图像的方向:

       private static int getExifOrientation(String src) throws IOException {
              int orientation = 1;
      
              ExifInterface exif = new ExifInterface(src);
              String orientationString=exif.getAttribute(ExifInterface.TAG_ORIENTATION);
              try {
                  orientation = Integer.parseInt(orientationString);
              }
              catch(NumberFormatException e){}
      
              return orientation;
          }
      

      最后像这样将它旋转到正确的位置:

      public static Bitmap rotateBitmap(String src, Bitmap bitmap) {
              try {
                  int orientation = getExifOrientation(src);
      
                  if (orientation == 1) {
                      return bitmap;
                  }
      
                  Matrix matrix = new Matrix();
                  switch (orientation) {
                      case 2:
                          matrix.setScale(-1, 1);
                          break;
                      case 3:
                          matrix.setRotate(180);
                          break;
                      case 4:
                          matrix.setRotate(180);
                          matrix.postScale(-1, 1);
                          break;
                      case 5:
                          matrix.setRotate(90);
                          matrix.postScale(-1, 1);
                          break;
                      case 6:
                          matrix.setRotate(90);
                          break;
                      case 7:
                          matrix.setRotate(-90);
                          matrix.postScale(-1, 1);
                          break;
                      case 8:
                          matrix.setRotate(-90);
                          break;
                      default:
                          return bitmap;
                  }
      
                  try {
                      Bitmap oriented = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
                      bitmap.recycle();
                      return oriented;
                  } catch (OutOfMemoryError e) {
                      e.printStackTrace();
                      return bitmap;
                  }
              } catch (IOException e) {
                  e.printStackTrace();
              }
      
              return bitmap;
          }
      

      就是这样,您现在已将位图旋转到正确的位置。

      干杯。

      【讨论】:

        【解决方案12】:

        这可行,但可能不是最好的方法,但它可能对某人有所帮助。

        String imagepath = someUri.getAbsolutePath();
        imageview = (ImageView)findViewById(R.id.imageview);
        imageview.setImageBitmap(setImage(imagepath, 120, 120));    
        
        public Bitmap setImage(String path, final int targetWidth, final int targetHeight) {
            Bitmap bitmap = null;
        // Get exif orientation     
            try {
                ExifInterface exif = new ExifInterface(path);
                int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 1);
                if (orientation == 6) {
                    orientation_val = 90;
                }
                else if (orientation == 3) {
                    orientation_val = 180;
                }
                else if (orientation == 8) {
                    orientation_val = 270;
                }
            }
                catch (Exception e) {
                }
        
                try {
        // First decode with inJustDecodeBounds=true to check dimensions
                    final BitmapFactory.Options options = new BitmapFactory.Options();
                    options.inJustDecodeBounds = true;
                    BitmapFactory.decodeFile(path, options);
        
        // Adjust extents
                    int sourceWidth, sourceHeight;
                    if (orientation_val == 90 || orientation_val == 270) {
                        sourceWidth = options.outHeight;
                        sourceHeight = options.outWidth;
                    } else {
                        sourceWidth = options.outWidth;
                        sourceHeight = options.outHeight;
                    }
        
        // Calculate the maximum required scaling ratio if required and load the bitmap
                    if (sourceWidth > targetWidth || sourceHeight > targetHeight) {
                        float widthRatio = (float)sourceWidth / (float)targetWidth;
                        float heightRatio = (float)sourceHeight / (float)targetHeight;
                        float maxRatio = Math.max(widthRatio, heightRatio);
                        options.inJustDecodeBounds = false;
                        options.inSampleSize = (int)maxRatio;
                        bitmap = BitmapFactory.decodeFile(path, options);
                    } else {
                        bitmap = BitmapFactory.decodeFile(path);
                    }
        
        // Rotate the bitmap if required
                    if (orientation_val > 0) {
                        Matrix matrix = new Matrix();
                        matrix.postRotate(orientation_val);
                        bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
                    }
        
        // Re-scale the bitmap if necessary
                    sourceWidth = bitmap.getWidth();
                    sourceHeight = bitmap.getHeight();
                    if (sourceWidth != targetWidth || sourceHeight != targetHeight) {
                        float widthRatio = (float)sourceWidth / (float)targetWidth;
                        float heightRatio = (float)sourceHeight / (float)targetHeight;
                        float maxRatio = Math.max(widthRatio, heightRatio);
                        sourceWidth = (int)((float)sourceWidth / maxRatio);
                        sourceHeight = (int)((float)sourceHeight / maxRatio);
                        bitmap = Bitmap.createScaledBitmap(bitmap, sourceWidth,     sourceHeight, true);
                    }
                } catch (Exception e) {
                }
                return bitmap;
            }
        

        【讨论】:

          【解决方案13】:

          也许这会有所帮助(旋转 90 度)(这对我有用)

          private Bitmap rotateBitmap(Bitmap image){
                  int width=image.getHeight();
                  int height=image.getWidth();
          
                  Bitmap srcBitmap=Bitmap.createBitmap(width, height, image.getConfig());
          
                  for (int y=width-1;y>=0;y--)
                      for(int x=0;x<height;x++)
                          srcBitmap.setPixel(width-y-1, x,image.getPixel(x, y));
                  return srcBitmap;
          
              }
          

          【讨论】:

          【解决方案14】:

          以下方法根据方向缩放和旋转位图:

          public Bitmap scaleAndRotateImage(String path, int orientation, final int targetWidth, final int targetHeight)
          {
              Bitmap bitmap = null;
          
              try
              {
                  // Check the dimensions of the Image
                  final BitmapFactory.Options options = new BitmapFactory.Options();
                  options.inJustDecodeBounds = true;
                  BitmapFactory.decodeFile(path, options);
          
                  // Adjust the Width and Height
                  int sourceWidth, sourceHeight;
                  if (orientation == 90 || orientation == 270)
                  {
                      sourceWidth = options.outHeight;
                      sourceHeight = options.outWidth;
                  }
                  else
                  {
                      sourceWidth = options.outWidth;
                      sourceHeight = options.outHeight;
                  }
          
                  // Calculate the maximum required scaling ratio if required and load the bitmap
                  if (sourceWidth > targetWidth || sourceHeight > targetHeight)
                  {
                      float widthRatio = (float)sourceWidth / (float)targetWidth;
                      float heightRatio = (float)sourceHeight / (float)targetHeight;
                      float maxRatio = Math.max(widthRatio, heightRatio);
                      options.inJustDecodeBounds = false;
                      options.inSampleSize = (int)maxRatio;
                      bitmap = BitmapFactory.decodeFile(path, options);
                  }
                  else
                  {
                      bitmap = BitmapFactory.decodeFile(path);
                  }
          
                  // We need to rotate the bitmap (if required)
                  int orientationInDegrees = exifToDegrees(orientation);
                  if (orientation > 0)
                  {
                      Matrix matrix = new Matrix();
                      if (orientation != 0f)
                      {
                          matrix.preRotate(orientationInDegrees);
                      };
          
                      bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
                  }
          
                  // Re-scale the bitmap if necessary
                  sourceWidth = bitmap.getWidth();
                  sourceHeight = bitmap.getHeight();
          
                  if (sourceWidth != targetWidth || sourceHeight != targetHeight)
                  {
                      float widthRatio = (float)sourceWidth / (float)targetWidth;
                      float heightRatio = (float)sourceHeight / (float)targetHeight;
                      float maxRatio = Math.max(widthRatio, heightRatio);
                      sourceWidth = (int)((float)sourceWidth / maxRatio);
                      sourceHeight = (int)((float)sourceHeight / maxRatio);
                      bitmap = Bitmap.createScaledBitmap(bitmap, sourceWidth, sourceHeight, true);
                  }
              }
              catch (Exception e)
              {
                  Logger.d("Could not rotate the image");
                  Logger.d(e.getMessage());
              }
              return bitmap;
          }
          

          例子:

          public void getPictureFromDevice(Uri Uri,ImageView imageView)
          {
              try
              {
                  ExifInterface exifInterface = new ExifInterface(Uri.getPath());
                  int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
          
                  Bitmap bitmap = scaleAndRotateImage(Uri.getPath(), orientation, imageView.getWidth(), imageView.getHeight());
                  imageView.setImageBitmap(bitmap);
              }
              catch (OutOfMemoryError outOfMemoryError)
              {
                  Logger.d(outOfMemoryError.getLocalizedMessage());
                  Logger.d("Failed to load image from filePath (out of memory)");
                  Logger.d(Uri.toString());
              }
              catch (Exception e)
              {
                  Logger.d("Failed to load image from filePath");
                  Logger.d(Uri.toString());
              }
          }
          

          【讨论】:

            【解决方案15】:

            光标打开后应该是关闭的。

            这是一个例子。

             public static int getOrientation(Context context, Uri selectedImage)
            {
                int orientation = -1;
                Cursor cursor = context.getContentResolver().query(selectedImage,
                        new String[] { MediaStore.Images.ImageColumns.ORIENTATION }, null, null, null);
                if (cursor.getCount() != 1)
                   return orientation;
            
                cursor.moveToFirst();
                orientation = cursor.getInt(0);
                cursor.close(); // ADD THIS LINE
               return orientation;
            }
            

            【讨论】:

              【解决方案16】:

              我已经融化了@Timmmm 答案和@Manuel。如果您执行此解决方案,您将不会收到 Run Out Of Memory 异常。

              此方法检索图像方向:

              private static final int ROTATION_DEGREES = 90;
              // This means 512 px
              private static final Integer MAX_IMAGE_DIMENSION = 512;
              
              public static int getOrientation(Uri photoUri) throws IOException {
              
                  ExifInterface exif = new ExifInterface(photoUri.getPath());
                  int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 1);
              
                  switch (orientation) {
                      case ExifInterface.ORIENTATION_ROTATE_90:
                          orientation = ROTATION_DEGREES;
                          break;
                      case ExifInterface.ORIENTATION_ROTATE_180:
                          orientation = ROTATION_DEGREES * 2;
                          break;
                      case ExifInterface.ORIENTATION_ROTATE_270:
                          orientation = ROTATION_DEGREES * 3;
                          break;
                      default:
                          // Default case, image is not rotated
                          orientation = 0;
                  }
              
                  return orientation;
              }
              

              因此,您可以使用此方法在将图像加载到内存之前调整其大小。这样,您将不会收到内存异常。

              public static Bitmap getCorrectlyOrientedImage(Context context, Uri photoUri) throws IOException {
                  InputStream is = context.getContentResolver().openInputStream(photoUri);
                  BitmapFactory.Options dbo = new BitmapFactory.Options();
                  dbo.inJustDecodeBounds = true;
                  BitmapFactory.decodeStream(is, null, dbo);
                  is.close();
              
                  int rotatedWidth, rotatedHeight;
                  int orientation = getOrientation(photoUri);
              
                  if (orientation == 90 || orientation == 270) {
                      rotatedWidth = dbo.outHeight;
                      rotatedHeight = dbo.outWidth;
                  } else {
                      rotatedWidth = dbo.outWidth;
                      rotatedHeight = dbo.outHeight;
                  }
              
                  Bitmap srcBitmap;
                  is = context.getContentResolver().openInputStream(photoUri);
                  if (rotatedWidth > MAX_IMAGE_DIMENSION || rotatedHeight > MAX_IMAGE_DIMENSION) {
                      float widthRatio = ((float) rotatedWidth) / ((float) MAX_IMAGE_DIMENSION);
                      float heightRatio = ((float) rotatedHeight) / ((float) MAX_IMAGE_DIMENSION);
                      float maxRatio = Math.max(widthRatio, heightRatio);
              
                      // Create the bitmap from file
                      BitmapFactory.Options options = new BitmapFactory.Options();
                      options.inSampleSize = (int) maxRatio;
                      srcBitmap = BitmapFactory.decodeStream(is, null, options);
                  } else {
                      srcBitmap = BitmapFactory.decodeStream(is);
                  }
                  is.close();
              
                  // if the orientation is not 0, we have to do a rotation.
                  if (orientation > 0) {
                      Matrix matrix = new Matrix();
                      matrix.postRotate(orientation);
              
                      srcBitmap = Bitmap.createBitmap(srcBitmap, 0, 0, srcBitmap.getWidth(),
                              srcBitmap.getHeight(), matrix, true);
                  }
              
                  return srcBitmap;
              }
              

              这对我来说非常有效。我希望这对其他人有帮助

              【讨论】:

                【解决方案17】:

                Timmmm 对上述解决方案进行了改进,在最后添加了一些额外的缩放,以确保图像符合边界:

                public static Bitmap loadBitmap(String path, int orientation, final int targetWidth, final int targetHeight) {
                    Bitmap bitmap = null;
                    try {
                        // First decode with inJustDecodeBounds=true to check dimensions
                        final BitmapFactory.Options options = new BitmapFactory.Options();
                        options.inJustDecodeBounds = true;
                        BitmapFactory.decodeFile(path, options);
                
                        // Adjust extents
                        int sourceWidth, sourceHeight;
                        if (orientation == 90 || orientation == 270) {
                            sourceWidth = options.outHeight;
                            sourceHeight = options.outWidth;
                        } else {
                            sourceWidth = options.outWidth;
                            sourceHeight = options.outHeight;
                        }
                
                        // Calculate the maximum required scaling ratio if required and load the bitmap
                        if (sourceWidth > targetWidth || sourceHeight > targetHeight) {
                            float widthRatio = (float)sourceWidth / (float)targetWidth;
                            float heightRatio = (float)sourceHeight / (float)targetHeight;
                            float maxRatio = Math.max(widthRatio, heightRatio);
                            options.inJustDecodeBounds = false;
                            options.inSampleSize = (int)maxRatio;
                            bitmap = BitmapFactory.decodeFile(path, options);
                        } else {
                            bitmap = BitmapFactory.decodeFile(path);
                        }
                
                        // Rotate the bitmap if required
                        if (orientation > 0) {
                            Matrix matrix = new Matrix();
                            matrix.postRotate(orientation);
                            bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
                        }
                
                        // Re-scale the bitmap if necessary
                        sourceWidth = bitmap.getWidth();
                        sourceHeight = bitmap.getHeight();
                        if (sourceWidth != targetWidth || sourceHeight != targetHeight) {
                            float widthRatio = (float)sourceWidth / (float)targetWidth;
                            float heightRatio = (float)sourceHeight / (float)targetHeight;
                            float maxRatio = Math.max(widthRatio, heightRatio);
                            sourceWidth = (int)((float)sourceWidth / maxRatio);
                            sourceHeight = (int)((float)sourceHeight / maxRatio);
                            bitmap = Bitmap.createScaledBitmap(bitmap, sourceWidth, sourceHeight, true);
                        }
                    } catch (Exception e) {
                    }
                    return bitmap;
                }
                

                【讨论】:

                  【解决方案18】:

                  使用以下代码正确旋转图像:

                  private Bitmap rotateImage(Bitmap bitmap, String filePath)
                  {
                      Bitmap resultBitmap = bitmap;
                  
                      try
                      {
                          ExifInterface exifInterface = new ExifInterface(filePath);
                          int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, 1);
                  
                          Matrix matrix = new Matrix();
                  
                          if (orientation == ExifInterface.ORIENTATION_ROTATE_90)
                          {
                              matrix.postRotate(ExifInterface.ORIENTATION_ROTATE_90);
                          }
                          else if (orientation == ExifInterface.ORIENTATION_ROTATE_180)
                          {
                              matrix.postRotate(ExifInterface.ORIENTATION_ROTATE_180);
                          }
                          else if (orientation == ExifInterface.ORIENTATION_ROTATE_270)
                          {
                              matrix.postRotate(ExifInterface.ORIENTATION_ROTATE_270);
                          }
                  
                          // Rotate the bitmap
                          resultBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
                      }
                      catch (Exception exception)
                      {
                          Logger.d("Could not rotate the image");
                      }
                      return resultBitmap;
                  }
                  

                  【讨论】:

                  • 您可以将所有的 if 条件合并在一起,以获得更小的代码。
                  【解决方案19】:

                  我通过以下解决方法解决了这个问题。请注意,我也在缩放图像,这是避免 OutOfMemoryExceptions 所必需的。

                  请注意,此解决方案不适用于纵向图像或倒置图像(感谢 Timmmm 的注意)。如果需要,Timmmm 的上述解决方案可能是更好的选择,而且它看起来也更优雅:https://stackoverflow.com/a/8914291/449918

                  File path = // ... location of your bitmap file
                  int w = 512; int h = 384; // size that does not lead to OutOfMemoryException on Nexus One
                  Bitmap b = BitmapFactory.decodeFile(path);
                  
                  
                  // Hack to determine whether the image is rotated
                  boolean rotated = b.getWidth() > b.getHeight();
                  
                  Bitmap resultBmp = null;
                  
                  // If not rotated, just scale it
                  if (!rotated) {
                      resultBmp = Bitmap.createScaledBitmap(b, w, h, true);
                      b.recycle();
                      b = null;
                  
                  // If rotated, scale it by switching width and height and then rotated it
                  } else {
                      Bitmap scaledBmp = Bitmap.createScaledBitmap(b, h, w, true);
                      b.recycle();
                      b = null;
                  
                      Matrix mat = new Matrix();
                      mat.postRotate(90);
                      resultBmp = Bitmap.createBitmap(scaledBmp, 0, 0, h, w, mat, true);
                  
                      // Release image resources
                      scaledBmp.recycle();
                      scaledBmp = null;
                  }
                  
                  // resultBmp now contains the scaled and rotated image
                  

                  干杯

                  【讨论】:

                  • 这将无法正常工作。肖像图像呢?颠倒的图像?使用 exif 数据要好得多。
                  • 它在我的一个应用程序中正常工作,但当然我还没有测试所有类型的场景。 @Timmmm 您能否更具体地说明它在哪些情况下不起作用?我也很困惑你投票否决我的帖子。这似乎是对诚实尝试分享潜在解决方案的一种相当严厉的回应。
                  • 我不是故意的;对不起!我只是不想让任何人复制您的解决方案,希望它会起作用。正如我所说,它不适用于纵向或倒置图像。我将添加正确的解决方案作为答案。
                  • 我明白了。我将添加一条评论,突出显示您在上面的解决方案作为首选解决方案。
                  猜你喜欢
                  • 2019-11-06
                  • 1970-01-01
                  • 2015-07-22
                  • 1970-01-01
                  • 2016-05-24
                  • 1970-01-01
                  • 2016-07-13
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多