60

我正在尝试控制 Android 相机在纵向应用程序中拍照,但是当我保存图片时,它是横向的。我已经用 setCameraDisplayOrientation()方法将图像旋转了 90 级,但不起作用。

然后我找到了这篇文章,但是TAG_ORIENTATION0(未定义)。如果我抓住这个值并应用一个旋转值,也不起作用。

如何拍摄纵向照片并以良好的方向保存?

    /** Initializes the back/front camera */
private boolean initPhotoCamera() {
    try {
        camera = getCameraInstance(selected_camera);

        Camera.Parameters parameters = camera.getParameters();
   //           parameters.setPreviewSize(width_video, height_video);
   //           parameters.set("orientation", "portrait");
   //           parameters.set("rotation", 1);
   //           camera.setParameters(parameters);


        checkCameraFlash(parameters);

   //            camera.setDisplayOrientation( 0);
        setCameraDisplayOrientation(selected_camera, camera);


        surface_view.getHolder().setFixedSize(width_video, height_video);


        LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(width_video, height_video);
        surface_view.setLayoutParams(lp);

        camera.lock();

        surface_holder = surface_view.getHolder();
        surface_holder.addCallback(this);
        surface_holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

        setPreviewCamera();

    } catch (Exception e) {
        Log.v("RecordVideo", "Could not initialize the Camera");
        return false;
    }
    return true;
}

public void setCameraDisplayOrientation(int cameraId, Camera camera) {
     Camera.CameraInfo info = new Camera.CameraInfo();
     Camera.getCameraInfo(cameraId, info);
     int rotation = getWindowManager().getDefaultDisplay().getRotation();
     int degrees = 0;
     switch (rotation) {
         case Surface.ROTATION_0: degrees = 0; break;
         case Surface.ROTATION_90: degrees = 90; break;
         case Surface.ROTATION_180: degrees = 180; break;
         case Surface.ROTATION_270: degrees = 270; break;
     }

     int result;
     if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
         result = (info.orientation + degrees) % 360;
         result = (360 - result) % 360;  // compensate the mirror
     } else {  // back-facing
         result = (info.orientation - degrees + 360) % 360;
     }
     camera.setDisplayOrientation(result);
 }

     public static Bitmap rotate(Bitmap bitmap, int degree) {
    int w = bitmap.getWidth();
    int h = bitmap.getHeight();

    Matrix mtx = new Matrix();
   //       mtx.postRotate(degree);
    mtx.setRotate(degree);

    return Bitmap.createBitmap(bitmap, 0, 0, w, h, mtx, true);
}

@Override
public void onPictureTaken(byte[] data, Camera camera) {



    String timeStamp = Calendar.getInstance().getTime().toString();
    output_file_name = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM) + File.separator + timeStamp + ".jpeg";

    File pictureFile = new File(output_file_name);
    if (pictureFile.exists()) {
        pictureFile.delete();
    }

    try {
        FileOutputStream fos = new FileOutputStream(pictureFile);
        fos.write(data);

        Bitmap realImage = BitmapFactory.decodeFile(output_file_name);

        ExifInterface exif=new ExifInterface(pictureFile.toString());

        Log.d("EXIF value", exif.getAttribute(ExifInterface.TAG_ORIENTATION));
        if(exif.getAttribute(ExifInterface.TAG_ORIENTATION).equalsIgnoreCase("6")){
            realImage= rotate(realImage, 90);
        } else if(exif.getAttribute(ExifInterface.TAG_ORIENTATION).equalsIgnoreCase("8")){
            realImage= rotate(realImage, 270);
        } else if(exif.getAttribute(ExifInterface.TAG_ORIENTATION).equalsIgnoreCase("3")){
            realImage= rotate(realImage, 180);
        } else if(exif.getAttribute(ExifInterface.TAG_ORIENTATION).equalsIgnoreCase("0")){
            realImage= rotate(realImage, 45);
        }

        boolean bo = realImage.compress(Bitmap.CompressFormat.JPEG, 100, fos);

        fos.close();

        Log.d("Info", bo + "");

    } catch (FileNotFoundException e) {
        Log.d("Info", "File not found: " + e.getMessage());
    } catch (IOException e) {
        Log.d("TAG", "Error accessing file: " + e.getMessage());
    }
}
4

8 回答 8

59

问题是当我保存图像时我做得不好。

@Override
public void onPictureTaken(byte[] data, Camera camera) {

    String timeStamp = new SimpleDateFormat( "yyyyMMdd_HHmmss").format( new Date( ));
    output_file_name = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM) + File.separator + timeStamp + ".jpeg";

    File pictureFile = new File(output_file_name);
    if (pictureFile.exists()) {
        pictureFile.delete();
    }

    try {
        FileOutputStream fos = new FileOutputStream(pictureFile);

        Bitmap realImage = BitmapFactory.decodeByteArray(data, 0, data.length);

        ExifInterface exif=new ExifInterface(pictureFile.toString());

        Log.d("EXIF value", exif.getAttribute(ExifInterface.TAG_ORIENTATION));
        if(exif.getAttribute(ExifInterface.TAG_ORIENTATION).equalsIgnoreCase("6")){
            realImage= rotate(realImage, 90);
        } else if(exif.getAttribute(ExifInterface.TAG_ORIENTATION).equalsIgnoreCase("8")){
            realImage= rotate(realImage, 270);
        } else if(exif.getAttribute(ExifInterface.TAG_ORIENTATION).equalsIgnoreCase("3")){
            realImage= rotate(realImage, 180);
        } else if(exif.getAttribute(ExifInterface.TAG_ORIENTATION).equalsIgnoreCase("0")){
            realImage= rotate(realImage, 90);
        }

        boolean bo = realImage.compress(Bitmap.CompressFormat.JPEG, 100, fos);

        fos.close();

        ((ImageView) findViewById(R.id.imageview)).setImageBitmap(realImage);

        Log.d("Info", bo + "");

    } catch (FileNotFoundException e) {
        Log.d("Info", "File not found: " + e.getMessage());
    } catch (IOException e) {
        Log.d("TAG", "Error accessing file: " + e.getMessage());
    }
}

public static Bitmap rotate(Bitmap bitmap, int degree) {
    int w = bitmap.getWidth();
    int h = bitmap.getHeight();

    Matrix mtx = new Matrix();
   //       mtx.postRotate(degree);
    mtx.setRotate(degree);

    return Bitmap.createBitmap(bitmap, 0, 0, w, h, mtx, true);
}
于 2013-04-04T13:29:48.953 回答
54

setCameraDisplayOrientation()方法允许您更改预览的显示方式,而不会影响图像的记录方式 ( source )。

为了改变实际记录的图像,您需要设置Camera的旋转参数。你这样做:

//STEP #1: Get rotation degrees
Camera.CameraInfo info = new Camera.CameraInfo();
Camera.getCameraInfo(Camera.CameraInfo.CAMERA_FACING_BACK, info);
int rotation = mActivity.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 rotate = (info.orientation - degrees + 360) % 360;

//STEP #2: Set the 'rotation' parameter
Camera.Parameters params = mCamera.getParameters();
params.setRotation(rotate); 
mCamera.setParameters(params);

您的解决方案是一种解决方法,因为您在已记录图像之后对其进行了修改。此解决方案更简洁,并且在保存图像之前不需要所有这些“if”语句。

于 2013-09-18T14:04:36.800 回答
24

使用前置摄像头时,您可以使用以下方法正确生成预览。

此代码进入相机预览的 surfaceChanged 方法

@Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
     int angleToRotate=CommonMethods.getRoatationAngle(mActivity, Camera.CameraInfo.CAMERA_FACING_FRONT);
     mCamera.setDisplayOrientation(angleToRotate);
}

这段代码可以放到静态类中

 /**
     * Get Rotation Angle
     * 
     * @param mContext
     * @param cameraId
     *            probably front cam
     * @return angel to rotate
     */
    public static int getRoatationAngle(Activity mContext, int cameraId) {
        android.hardware.Camera.CameraInfo info = new android.hardware.Camera.CameraInfo();
        android.hardware.Camera.getCameraInfo(cameraId, info);
        int rotation = mContext.getWindowManager().getDefaultDisplay().getRotation();
        int degrees = 0;
        switch (rotation) {
        case Surface.ROTATION_0:
            degrees = 0;
            break;
        case Surface.ROTATION_90:
            degrees = 90;
            break;
        case Surface.ROTATION_180:
            degrees = 180;
            break;
        case Surface.ROTATION_270:
            degrees = 270;
            break;
        }
        int result;
        if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
            result = (info.orientation + degrees) % 360;
            result = (360 - result) % 360; // compensate the mirror
        } else { // back-facing
            result = (info.orientation - degrees + 360) % 360;
        }
        return result;
    }

您可以通过这种方式旋转图像。这仅在拍摄图像并且我们即将保存图像时使用

public static Bitmap rotate(Bitmap bitmap, int degree) {
        int w = bitmap.getWidth();
        int h = bitmap.getHeight();

        Matrix mtx = new Matrix();
        mtx.postRotate(degree);

        return Bitmap.createBitmap(bitmap, 0, 0, w, h, mtx, true);
    }

将用于拍照的方法

  @Override
    public void onPictureTaken(byte[] data, Camera camera) {
        int angleToRotate = getRoatationAngle(MainActivity.this, Camera.CameraInfo.CAMERA_FACING_FRONT);
        // Solve image inverting problem
        angleToRotate = angleToRotate + 180;
        Bitmap orignalImage = BitmapFactory.decodeByteArray(data, 0, data.length);
        Bitmap bitmapImage = rotate(orignalImage, angleToRotate);
    }

bitmapImage包含正确的图像。

于 2014-10-01T12:21:20.313 回答
7

这个应该可以,ExifInterface 不适用于所有制造商,因此请改用 CameraInfo,只需让相机以其默认旋转捕获图像,然后在 PictureCallback 上旋转结果数据

private PictureCallback mPicture = new PictureCallback() {
    @Override
    public void onPictureTaken(byte[] data, Camera camera) {
        File dir = new File(Constant.SDCARD_CACHE_PREFIX);
        if (!dir.exists()) {
            dir.mkdirs();
        }
        File pictureFile = new File(Constant.SDCARD_TAKE_PHOTO_CACHE_PREFIX);                       
        try {
            Bitmap realImage = BitmapFactory.decodeByteArray(data, 0, data.length);
            android.hardware.Camera.CameraInfo info = new android.hardware.Camera.CameraInfo();
            android.hardware.Camera.getCameraInfo(mCurrentCameraId, info);
            Bitmap bitmap = rotate(realImage, info.orientation);

            FileOutputStream fos = new FileOutputStream(pictureFile);               
            bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos);
            fos.close();                
        } catch (FileNotFoundException e) {
            Log.d(TAG, "File not found: " + e.getMessage());
        } catch (IOException e) {
            Log.d(TAG, "Error accessing file: " + e.getMessage());
        }

        resultFileUri = Uri.fromFile(pictureFile);
        startEffectFragment();
    }
};

public static Bitmap rotate(Bitmap bitmap, int degree) {
    int w = bitmap.getWidth();
    int h = bitmap.getHeight();

    Matrix mtx = new Matrix();
    mtx.postRotate(degree);

    return Bitmap.createBitmap(bitmap, 0, 0, w, h, mtx, true);
}
于 2013-09-20T11:17:36.670 回答
2

当您的布局固定为纵向模式时,这是最好的方法(下面提到)。

@Override
protected void onResume() {
    super.onResume();
    if (!openCamera(CameraInfo.CAMERA_FACING_BACK)) {
        alertCameraDialog();
    }
    if (cOrientationEventListener == null) {
        cOrientationEventListener = new OrientationEventListener(this, SensorManager.SENSOR_DELAY_NORMAL) {


            public void onOrientationChanged(int orientation) {

                // determine our orientation based on sensor response
                int lastOrientation = mOrientation;


                    if (orientation == ORIENTATION_UNKNOWN) return;
                    Camera.CameraInfo info =
                            new android.hardware.Camera.CameraInfo();
                    android.hardware.Camera.getCameraInfo(cameraId, info);
                    orientation = (orientation + 45) / 90 * 90;
                    int rotation = 0;
                    if (info.facing == CameraInfo.CAMERA_FACING_FRONT) {
                        rotation = (info.orientation - orientation + 360) % 360;
                    } else {  // back-facing camera
                        rotation = (info.orientation + orientation) % 360;
                    }
                        Parameters params = camera.getParameters();
                        params.setRotation(rotation);
                        camera.setParameters(params);




            }

            };


        }


    if (cOrientationEventListener.canDetectOrientation()) {
        cOrientationEventListener.enable();
    }
    }

您将使用 OrientEventListener 并实现此回调方法。每当方向发生变化时都会调用 onOrientationChanged,因此您的相机旋转将被设置,并且图片将在您保存时旋转。

      private PictureCallback myPictureCallback_JPG = new PictureCallback() 

       { 

   @Override
   public void onPictureTaken(byte[] arg0, Camera arg1) {
    try {  
               File pictureFile = getOutputMediaFile();
           if (pictureFile == null) {
               return;
           }
               FileOutputStream fos = new FileOutputStream(pictureFile);
               fos.write(arg0);
               fos.close();     
              camera.startPreview();
       } catch (Exception e) {
           e.printStackTrace();
       }
   } 
 };

获取输出媒体文件

  private static File getOutputMediaFile() {
            File mediaStorageDir = new File(
               Environment


         .getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),
            "MyCameraApp");
         if (!mediaStorageDir.exists()) {
        if (!mediaStorageDir.mkdirs()) {
            Log.d("MyCameraApp", "failed to create directory");
            return null;
        }
    }
    // Create a media file name
    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss")
            .format(new Date());
    File mediaFile;
    mediaFile = new File(mediaStorageDir.getPath() + File.separator
            + "IMG_" + timeStamp + ".jpg");

    return mediaFile;
  }

来源 这里

于 2015-05-13T14:23:03.810 回答
2

我没有代表发表评论,所以我不得不留下另一个答案,尽管 Nvhausid 的答案很棒并且值得称赞。简单、优雅,它适用于三星设备上的前置和后置摄像头,而 Exif 和 Media Cursor 不适用。

对我来说,唯一缺少的答案是处理来自面向用户的相机的镜像。

这是代码更改:

Bitmap bitmap = rotate(realImage, info.orientation, info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT);

以及新的旋转方法:

public static Bitmap rotate(Bitmap bitmap, int degree, boolean mirror) {
    int w = bitmap.getWidth();
    int h = bitmap.getHeight();

    Matrix mtx = new Matrix();
    if(mirror)mtx.setScale(1,-1);
    mtx.postRotate(degree);

    return Bitmap.createBitmap(bitmap, 0, 0, w, h, mtx, true);
}
于 2016-10-30T03:37:15.470 回答
1

我为您找到了有力的答案,我只是遇到了同样的问题并在不保存文件的情况下解决了它。解决方案是注册一个 OrientationEventListener 以在它发生变化时获取方向。http://www.androidzeitgeist.com/2013/01/fixing-rotation-camera-picture.html这里给出细节。我的代码如下:

private CameraOrientationListener myOrientationListener;
private int rotation;    

protected void onCreate(Bundle savedInstanceState) {
  setListeners();
  rotation = setCameraDisplayOrientation(CameraActivity.this, Camera.getNumberOfCameras()-1, mCamera);
}

public void setListeners(){
    myOrientationListener = new CameraOrientationListener(this);
    if(myOrientationListener.canDetectOrientation())
        myOrientationListener.enable();
}

public static int setCameraDisplayOrientation(Activity activity, int cameraId, Camera camera) {
     CameraInfo info = new CameraInfo();
     Camera.getCameraInfo(cameraId, info);
     int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
     int degrees = 0;
     switch (rotation) {
         case Surface.ROTATION_0: degrees = 0; break;
         case Surface.ROTATION_90: degrees = 90; break;
         case Surface.ROTATION_180: degrees = 180; break;
         case Surface.ROTATION_270: degrees = 270; break;
     }

     int result;
     if (info.facing == CameraInfo.CAMERA_FACING_FRONT) {
         result = (info.orientation + degrees) % 360;
         result = (360 - result) % 360;  // compensate the mirror
     } else {  // back-facing
         result = (info.orientation - degrees + 360) % 360;
     }
     camera.setDisplayOrientation(result);

     return result;
 }

/*
 * record the rotation when take photo
 */
public void takePhoto(){
    myOrientationListener.rememberOrientation();
    rotation += myOrientationListener.getRememberedOrientation();
    rotation = rotation % 360;

    mCamera.takePicture(null, null, mPicture);
}    

class CameraOrientationListener extends OrientationEventListener {
    private int currentNormalizedOrientation;
    private int rememberedNormalizedOrientation;

    public CameraOrientationListener(Context context) {
        super(context, SensorManager.SENSOR_DELAY_NORMAL);
    }

    @Override
    public void onOrientationChanged(int orientation) {
        // TODO Auto-generated method stub
        if (orientation != ORIENTATION_UNKNOWN) {
            currentNormalizedOrientation = normalize(orientation);
        }
    }

    private int normalize(int degrees) {
         if (degrees > 315 || degrees <= 45) {
            return 0;
        }

        if (degrees > 45 && degrees <= 135) {
            return 90;
        }

        if (degrees > 135 && degrees <= 225) {
            return 180;
        }

        if (degrees > 225 && degrees <= 315) {
            return 270;
        }

        throw new RuntimeException("The physics as we know them are no more. Watch out for anomalies.");
    }

    public void rememberOrientation() {
        rememberedNormalizedOrientation = currentNormalizedOrientation;
    }

    public int getRememberedOrientation() {
        return rememberedNormalizedOrientation;
    }
}

希望能帮助到你:)

于 2014-03-02T08:16:25.023 回答
0

我使用新的 camera2 api 来获取传感器方向,然后相应地旋转它:

  private void detectSensorOrientation()
  {
    CameraManager manager = (CameraManager) getSystemService(CAMERA_SERVICE);
    try
    {
      for (String cameraId : manager.getCameraIdList())
      {
        CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId);

        // We don't use a front facing camera in this sample.
        Integer facing = characteristics.get(CameraCharacteristics.LENS_FACING);
        if (facing != null && facing == CameraCharacteristics.LENS_FACING_FRONT)
        {
          continue;
        }

        cameraOrientaion = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
      }
    } catch (CameraAccessException e)
    {
      e.printStackTrace();
    }
  }

然后在 cameraOrientation 参数的帮助下,我旋转了我的 cameraPhoto:

  private void generateRotatedBitmap()
  {
    if (cameraOrientaion != 0)
    {
      Matrix matrix = new Matrix();
      matrix.postRotate(cameraOrientaion);
      rotatedPhoto =
          Bitmap.createBitmap(cameraPhoto, 0, 0, cameraPhoto.getWidth(), cameraPhoto.getHeight(),
              matrix, true);
      cameraPhoto.recycle();
    }
  }
于 2017-03-23T09:22:24.070 回答