如何在 onPictureTaken 中旋转和翻转位图

Posted

技术标签:

【中文标题】如何在 onPictureTaken 中旋转和翻转位图【英文标题】:How to rotate and flip bitmap in onPictureTaken 【发布时间】:2013-04-20 04:02:23 【问题描述】:

我在onPictureTaken 中发现保存的位图围绕 y 轴镜像并顺时针旋转 90 度,即使相机预览不是。这是在我运行 2.3.6 的 Nexus S 上。在我的 Nexus 4 和 4.2 上运行的相同程序生成的位图围绕 y 轴镜像并顺时针旋转 180 度。

这是我在onPictureTaken中运行的代码:

@Override
public void onPictureTaken(final byte[] data, Camera camera) 
    Bitmap picture = BitmapFactory.decodeByteArray(data, 0, data.length);
    String path = MediaStore.Images.Media.insertImage(getContentResolver(), picture, "name" , "description");
    Log.e("tag", "path: " + path); // prints something like "path: content://media/external/images/media/819"

    try 
        ExifInterface exif = new ExifInterface(path); // prints this error: "04-25 21:28:21.063: E/JHEAD(12201): can't open 'content://media/external/images/media/819'"
        int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
        Log.e("tag", "exif orientation: " + orientation); // this is outputting orientation unknown
     catch (IOException e) 
        e.printStackTrace();
    

鉴于我似乎从不同的设备得到不同的结果,谁能告诉我如何纠正这个问题?如何检测生成位图的方向,以便知道将其逆时针旋转 90 度或 180 度?

[编辑]

我使用我一直在阅读的 ExifInterface 资料添加了一些更多信息,但这些信息似乎没有成功...

【问题讨论】:

当我看到这个时我认为 ExifInterface,我不确定,只是一个评论,我从未使用过原始相机 等等,@JRowan 你用过相机吗?如果是这样,如何从相机中获取位图? onActivityResult() with new Intent(MediaStore.ACTION_IMAGE_CAPTURE); 啊,我明白了。我没有使用 Intent...我正在运行的相机预览被另一个视图覆盖...所以我认为我不能使用它,对吧? 我知道你所说的可以通过获取图片的 ExifInterface 属性来解决,你是怎么做的也许你可以设置 ExifInterface 属性,我不确定 【参考方案1】:

我为此付出了很多努力,并想,我会分享我的解决方案。 它在 Motorola Devy、Samsung Xcover 1 和 Samsung XCover 2 上进行了测试。

当我使用自定义相机预览时,该解决方案基本上有两个 部分。 1.照顾相机预览并根据设置预览的旋转 到设备旋转。 2.一旦拍照,即调用'onPictureTaken'回调 将图片旋转正确的角度,使其显示预览的内容 显示。

1


private void initPreview(int width, int height) 
    if (camera != null && holder.getSurface() != null) 
        try 
            camera.setPreviewDisplay(holder);
         catch (Throwable t) 
            Log.e("PreviewDemo-surfaceCallback",
              "Exception in setPreviewDisplay()", t);
            Toast.makeText(getContext(), t.getMessage(),
                       Toast.LENGTH_LONG).show();
        

        try 
            Camera.Parameters parameters=camera.getParameters();

            Camera.Size size=getBestPreviewSize(width, height, parameters);
            Camera.Size pictureSize=getSmallestPictureSize(parameters);

            Display display = windowManager.getDefaultDisplay();
            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.FROYO)  // for 2.1 and before
                if (isPortrait(display)) 
                    parameters.set(CAMERA_PARAM_ORIENTATION, CAMERA_PARAM_PORTRAIT);
                 else 
                    parameters.set(CAMERA_PARAM_ORIENTATION, CAMERA_PARAM_LANDSCAPE);
                
             else  // for 2.2 and later
                switch (display.getRotation()) 
                    case Surface.ROTATION_0: // This is display orientation
                        if (size.height > size.width) parameters.setPreviewSize(size.height, size.width);
                        else parameters.setPreviewSize(size.width, size.height);
                        camera.setDisplayOrientation(90);
                        break;
                    case Surface.ROTATION_90:
                        if (size.height > size.width) parameters.setPreviewSize(size.height, size.width);
                        else parameters.setPreviewSize(size.width, size.height);
                        camera.setDisplayOrientation(0);
                        break;
                    case Surface.ROTATION_180:
                        if (size.height > size.width) parameters.setPreviewSize(size.height, size.width);
                        else parameters.setPreviewSize(size.width, size.height);
                        camera.setDisplayOrientation(270);
                        break;
                    case Surface.ROTATION_270:
                        if (size.height > size.width) parameters.setPreviewSize(size.height, size.width);
                        else parameters.setPreviewSize(size.width, size.height);
                        camera.setDisplayOrientation(180);
                        break;
                
            

            parameters.setPictureSize(pictureSize.width, pictureSize.height);
            //parameters.setPictureFormat(ImageFormat.JPEG);
            camera.setParameters(parameters);
         catch (Exception e) 
            e.printStackTrace();
        
    


您的“surfaceChanged”方法,在您的相机预览 (SurfaceView) 中, 你应该看起来像这样:


public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) 
        stopPreview();
        initPreview(w, h);
        startPreview();
    

在哪里

停止预览:

private void stopPreview() 
    if (camera != null) 
        camera.stopPreview();
    

开始预览:

private void startPreview() 
    if (camera != null) 
        camera.startPreview();
    

2


在您的“onPictureTaken”回调中,使用以下代码旋转图片:

Display display = getWindowManager().getDefaultDisplay();
    int rotation = 0;
    switch (display.getRotation()) 
        case Surface.ROTATION_0: // This is display orientation
        rotation = 90;
        break;
    case Surface.ROTATION_90:
        rotation = 0;
        break;
    case Surface.ROTATION_180:
        rotation = 270;
        break;
    case Surface.ROTATION_270:
        rotation = 180;
            break;
     

     Bitmap bitmap = BitmapTools.toBitmap(data);
     bitmap = BitmapTools.rotate(bitmap, rotation);

BitmapTools.java

public class BitmapTools 

        public static Bitmap toBitmap(byte[] data) 
            return BitmapFactory.decodeByteArray(data , 0, data.length);
        

        public static Bitmap rotate(Bitmap in, int angle) 
            Matrix mat = new Matrix();
            mat.postRotate(angle);
            return Bitmap.createBitmap(in, 0, 0, in.getWidth(), in.getHeight(), mat, true);
        
    

【讨论】:

如果您这样做并使用后置摄像头,则必须在第 2 步中以不同方式进行旋转。 这是一个很好的详细答案。我没有完全使用您的代码,但它确实帮助我理解了问题,所以我将其标记为已接受的答案。我希望它可以帮助其他遇到此问题的开发人员。 在这个答案link 中解释得更好。【参考方案2】:

你去看看这个,保存图片,也许这会起作用,记住 if(bitmap.getWidth > bitmap.getHeight()) 作为另一个检查

public static int getExifRotation(String imgPath) 
    
        try 
        
            ExifInterface exif = new ExifInterface(imgPath);
            String rotationAmount = exif.getAttribute(ExifInterface.TAG_ORIENTATION);
            if (!TextUtils.isEmpty(rotationAmount)) 
            
                int rotationParam = Integer.parseInt(rotationAmount);
                switch (rotationParam) 
                
                    case ExifInterface.ORIENTATION_NORMAL:
                        return 0;
                    case ExifInterface.ORIENTATION_ROTATE_90:
                        return 90;
                    case ExifInterface.ORIENTATION_ROTATE_180:
                        return 180;
                    case ExifInterface.ORIENTATION_ROTATE_270:
                        return 270;
                    default:
                        return 0;
                
             
            else 
            
                return 0;
            
        
        catch (Exception ex) 
        
            return 0;
        
    

【讨论】:

我喜欢if(width &gt; height)检查,但如果另一部手机将图像旋转270度怎么办? 叹息 你试过这个方法,我用这个是因为当我拍照时,相机拍摄它并将它旋转 90 度,但是当它显示在画廊或任何它显示我如何拍照的地方时,所以打开它以编程方式我必须像这样检查 我在检查后使用 matrix.preRotate() 或 matrix.postRotate() 和 Bitmap.createBitmap()【参考方案3】:

您必须阅读有关 ExifInterface 的信息才能解决此问题。

我的应用程序中有这个功能来检查从相机拍摄的天气天气图像是否需要旋转。

      if(ExifNeedsRotate(GetPathFromUri(context, selectedImage)))
    // Rotate your bitmap using the Matrix
     


public static boolean ExifNeedsRotate(String paramString)

      if (android.os.Build.VERSION.SDK_INT >= 5)

          try
          

                Class localClass = Class.forName("android.media.ExifInterface");
                Class[] arrayOfClass1 = new Class[1];
                arrayOfClass1[0] = String.class;
                Constructor localConstructor = localClass.getConstructor(arrayOfClass1);
                Class[] arrayOfClass2 = new Class[1];
                arrayOfClass2[0] = String.class;
                Method localMethod = localClass.getMethod("getAttribute", arrayOfClass2);
                Object[] arrayOfObject1 = new Object[1];
                arrayOfObject1[0] = paramString;
                Object localObject1 = localConstructor.newInstance(arrayOfObject1);
                Object[] arrayOfObject2 = new Object[1];
                arrayOfObject2[0] = "Orientation";
                Object localObject2 = localMethod.invoke(localObject1, arrayOfObject2);
                if (localObject2 != null)
                      boolean bool = localObject2.equals("6");
                      if (bool)
                         return true;
                

          
          catch (Exception localException)
              return false;
          

    

    return false;


将 ImageUri 的路径作为输入传递。

 public static String GetPathFromUri(Context paramContext, Uri paramUri)
  
       String str;
       try
       
            if (paramUri.toString().startsWith("file:"))
                    str = paramUri.getPath();
            
            else
            
                    str = null;
                    String[] arrayOfString = new String[1];
                    arrayOfString[0] = "_data";
                    Cursor localCursor = paramContext.getContentResolver().query(paramUri, arrayOfString, null, null, null);
                    if (localCursor != null)
                    
                            localCursor.moveToFirst();
                            int i = localCursor.getColumnIndex(arrayOfString[0]);
                            if ((localCursor.getCount() >= 1) && (localCursor.getColumnCount() >= i + 1))
                                str = localCursor.getString(i);
                            localCursor.close();
                    
            

      
      catch (Exception localException)
          str = null;
      

      return str;
  

【讨论】:

【参考方案4】:

您可以将相机配置为在拍照时为您旋转图片,而不是在拍照回调中显式旋转图片。

camera.SetDisplayOrientation(degrees) //sets the orientation in the preview

同时

cameraParameters.SetRotation(degress) //rotates the actual captured image

【讨论】:

以上是关于如何在 onPictureTaken 中旋转和翻转位图的主要内容,如果未能解决你的问题,请参考以下文章

如何在 konvajs 中翻转旋转的图像

如何在wpf中翻转图像

如何在matlab中进行数据的平移和旋转

如何翻转或旋转 Word 中使用 m2doc 服务生成的图表图片

Metal渲染:实现旋转/翻转功能

如何只翻转变换矩阵的一个轴?