Android如何修复相机方向

Posted

技术标签:

【中文标题】Android如何修复相机方向【英文标题】:Android how to fix camera orientation 【发布时间】:2013-12-02 14:34:12 【问题描述】:

注意相机的视图(不是捕获的图像)是如何向左翻转的(上图),Activity 的方向是正确的,但是相机视图是混乱的,请帮助我 :) 谢谢你。

这是 XML 布局文件:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_
    android:layout_
    android:orientation="vertical" >

    <LinearLayout
        android:layout_
        android:layout_
        android:orientation="vertical" >

        <LinearLayout
            android:layout_
            android:layout_
            android:gravity="center|top"
            android:orientation="vertical" >

            <SurfaceView
                android:id="@+id/camerapreview"
                android:layout_margin="10dp"
                android:layout_
                android:layout_ />
        </LinearLayout>
    </LinearLayout>

</LinearLayout>

这里是活动的代码:

public class CustomCameraActivity extends Activity implements SurfaceHolder.Callback 

    Camera camera;
    SurfaceView surfaceView;
    SurfaceHolder surfaceHolder;
    boolean previewing = false;

    @Override
    public void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.camera);

        surfaceView = (SurfaceView)findViewById(R.id.camerapreview);
        surfaceHolder = surfaceView.getHolder();
        surfaceHolder.addCallback(this);

    

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) 
        if(previewing)
            camera.stopPreview();
            previewing = false;
        

        if (camera != null)
            try 
                camera.setPreviewDisplay(surfaceHolder);
                camera.startPreview();
                previewing = true;
             catch (IOException e) 
                e.printStackTrace();
            
        
    

    @Override
    public void surfaceCreated(SurfaceHolder holder) 
        camera = Camera.open();
    

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) 
        camera.stopPreview();
        camera.release();
        camera = null;
        previewing = false;
    

【问题讨论】:

Check it out, it will guide you 我的意思是相机的视图而不是捕获的图像。 In your case, it will be help you tnx @RobinHood 生病检查一下 【参考方案1】:

我找到了解决方案here。 @Ed Jellard 的回答。

我只需在surfaceCreated(SurfaceHolder holder) 方法上添加camera.setDisplayOrientation(90);,现在显示在正确的角度。

看看快乐的 T-REX :)

【讨论】:

我不认为这只 T-REX 很高兴 :P 无论如何,它帮助了我。谢谢。 @AmitGupta 在我看来很开心。 :D 这仅在设备的相机以横向方式定向时才有效。虽然这适用于大多数人,但不适用于 Nexus 5X 等摄像头为反向横向的设备(您需要将方向设置为 180) 这仅适用于此设备,并且您已在其他设备上旋转图像。这可能是正确的解决方案:captechconsulting.com/blogs/…【参考方案2】:

这个问题很久以前就解决了,但是我遇到了一些困难,所以这是我的最终解决方案,希望这对其他人有帮助:

public void startPreview() 
        try 
            Log.i(TAG, "starting preview: " + started);

            // ....
            Camera.CameraInfo camInfo = new Camera.CameraInfo();
            Camera.getCameraInfo(cameraIndex, camInfo);
            int cameraRotationOffset = camInfo.orientation;
            // ...

            Camera.Parameters parameters = camera.getParameters();
            List<Camera.Size> previewSizes = parameters.getSupportedPreviewSizes();
            Camera.Size previewSize = null;
            float closestRatio = Float.MAX_VALUE;

            int targetPreviewWidth = isLandscape() ? getWidth() : getHeight();
            int targetPreviewHeight = isLandscape() ? getHeight() : getWidth();
            float targetRatio = targetPreviewWidth / (float) targetPreviewHeight;

            Log.v(TAG, "target size: " + targetPreviewWidth + " / " + targetPreviewHeight + " ratio:" + targetRatio);
            for (Camera.Size candidateSize : previewSizes) 
                float whRatio = candidateSize.width / (float) candidateSize.height;
                if (previewSize == null || Math.abs(targetRatio - whRatio) < Math.abs(targetRatio - closestRatio)) 
                    closestRatio = whRatio;
                    previewSize = candidateSize;
                
            

            int rotation = getWindowManager().getDefaultDisplay().getRotation();
            int degrees = 0;
            switch (rotation) 
            case Surface.ROTATION_0:
                degrees = 0;
                break; // Natural orientation
            case Surface.ROTATION_90:
                degrees = 90;
                break; // Landscape left
            case Surface.ROTATION_180:
                degrees = 180;
                break;// Upside down
            case Surface.ROTATION_270:
                degrees = 270;
                break;// Landscape right
            
            int displayRotation;
            if (isFrontFacingCam) 
                displayRotation = (cameraRotationOffset + degrees) % 360;
                displayRotation = (360 - displayRotation) % 360; // compensate
                                                                    // the
                                                                    // mirror
             else  // back-facing
                displayRotation = (cameraRotationOffset - degrees + 360) % 360;
            

            Log.v(TAG, "rotation cam / phone = displayRotation: " + cameraRotationOffset + " / " + degrees + " = "
                    + displayRotation);

            this.camera.setDisplayOrientation(displayRotation);

            int rotate;
            if (isFrontFacingCam) 
                rotate = (360 + cameraRotationOffset + degrees) % 360;
             else 
                rotate = (360 + cameraRotationOffset - degrees) % 360;
            

            Log.v(TAG, "screenshot rotation: " + cameraRotationOffset + " / " + degrees + " = " + rotate);

            Log.v(TAG, "preview size: " + previewSize.width + " / " + previewSize.height);
            parameters.setPreviewSize(previewSize.width, previewSize.height);
            parameters.setRotation(rotate);
            camera.setParameters(parameters);
            camera.setPreviewDisplay(mHolder);
            camera.startPreview();

            Log.d(TAG, "preview started");

            started = true;
         catch (IOException e) 
            Log.d(TAG, "Error setting camera preview: " + e.getMessage());
        
    

【讨论】:

我不知道如何处理变量。如果您添加有关其余部分的更多信息,那就太好了。代码中有很多红色变量。【参考方案3】:

Camera.CameraInfo 类中有一个属性,名为orientation。它返回整数。您可以获取当前方向,然后进行相应的更改。

请参阅此 answer 处理方向和 CameraInfo 类。

我相信这会对你有所帮助。

【讨论】:

【参考方案4】:

当您旋转手机时,相机会自动旋转,但是如果您希望相机或图库中的图像处于正确的方向,请使用:-

public void rotate(String filePath)
              Bitmap cameraBitmap = null;
            BitmapFactory.Options bmOptions = new BitmapFactory.Options();
            bmOptions.inJustDecodeBounds = false;
            bmOptions.inPurgeable = true;
            bmOptions.inBitmap = cameraBitmap; 
            bmOptions.inMutable = true; 

        cameraBitmap = BitmapFactory.decodeFile(filePath,bmOptions); 
        // Your image file path
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            cameraBitmap.compress(Bitmap.CompressFormat.JPEG, 100, bos);


        ExifInterface exif = new ExifInterface(filePath);
        float rotation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);  
        System.out.println(rotation);

        float rotationInDegrees = exifToDegrees(rotation);
        System.out.println(rotationInDegrees);

        Matrix matrix = new Matrix();
        matrix.postRotate(rotationInDegrees);

        Bitmap rotatedBitmap = Bitmap.createBitmap(cameraBitmap , 0, 0, cameraBitmap.getWidth(), cameraBitmap.getHeight(), matrix, true);
        FileOutputStream fos=new FileOutputStream(filePath);
        rotatedBitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos);
        fos.write(bos.toByteArray());
        cameraBitmap.recycle();
        System.gc();
        fos.flush();
        fos.close();


private static float exifToDegrees(float 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;    
 

【讨论】:

这不是一个实际的答案,阅读OP comment

以上是关于Android如何修复相机方向的主要内容,如果未能解决你的问题,请参考以下文章

如何在Android中修复相机预览(surfaceview)的正确纵横比?

如何实现 Android 相机以任何屏幕方向拍照?

打开相机意图时如何防止android应用程序方向

如何修复 Android 模拟器中的“无法连接到相机服务”异常

Android:编码的相机预览帧总是横向的。如何旋转?

如何使用 Cordova 相机插件拍摄多张照片