不同设备上,Android相机的 setDisplayOrientation(90) 失败

8
我有一个相机应用程序的问题。相机活动是以竖屏模式显示的。因此,我给了...
camera.setDisplayOrientation(90);

根据 SO 上不同的帖子,这在纵向模式下可以正常工作。

但是在不同的设备上却无法正常工作。问题是预览旋转了 90 度向左或向右。在 Htc 上没问题,但在 Galaxy 系列上无法正常工作。

有人能帮我吗?

4个回答

3

请按照以下不同方式设置方向和预览,根据需要使用:

第一种方式:

  public void surfaceChanged(SurfaceHolder holder, int format, int width, int height)
  {            
    if (isPreviewRunning)
    {
        mCamera.stopPreview();
    }

    Parameters parameters = mCamera.getParameters();
    Display display = ((WindowManager)getSystemService(WINDOW_SERVICE)).getDefaultDisplay();

    if(display.getRotation() == Surface.ROTATION_0)
    {
        parameters.setPreviewSize(height, width);                           
        mCamera.setDisplayOrientation(90);
    }

    if(display.getRotation() == Surface.ROTATION_90)
    {
        parameters.setPreviewSize(width, height);                           
    }

    if(display.getRotation() == Surface.ROTATION_180)
    {
        parameters.setPreviewSize(height, width);               
    }

    if(display.getRotation() == Surface.ROTATION_270)
    {
        parameters.setPreviewSize(width, height);
        mCamera.setDisplayOrientation(180);
    }

    mCamera.setParameters(parameters);
    previewCamera();                      
}

并且。
  public void previewCamera()
  {        
     try 
     {           
          mCamera.setPreviewDisplay(mSurfaceHolder);          
          mCamera.startPreview();
          isPreviewRunning = true;
     }
     catch(Exception e)
     {
         Log.d(APP_CLASS, "Cannot start preview", e);    
     }
 }

第二种方法:

  private Camera mCamera;
  private OrientationEventListener mOrientationEventListener;
  private int mOrientation =  -1;

 private static final int ORIENTATION_PORTRAIT_NORMAL =  1;
 private static final int ORIENTATION_PORTRAIT_INVERTED =  2;
 private static final int ORIENTATION_LANDSCAPE_NORMAL =  3;
 private static final int ORIENTATION_LANDSCAPE_INVERTED =  4;

 @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
         // force Landscape layout
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR |           ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
   /*
      Your other initialization code here
   */
   }

 @Override 
  protected void onResume() {
       super.onResume();

        if (mOrientationEventListener == null) {            
              mOrientationEventListener = new OrientationEventListener(this,  SensorManager.SENSOR_DELAY_NORMAL) {

        @Override
        public void onOrientationChanged(int orientation) {

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

            if (orientation >= 315 || orientation < 45) {
                if (mOrientation != ORIENTATION_PORTRAIT_NORMAL) {                          
                    mOrientation = ORIENTATION_PORTRAIT_NORMAL;
                }
            }
            else if (orientation < 315 && orientation >= 225) {
                if (mOrientation != ORIENTATION_LANDSCAPE_NORMAL) {
                    mOrientation = ORIENTATION_LANDSCAPE_NORMAL;
                }                       
            }
            else if (orientation < 225 && orientation >= 135) {
                if (mOrientation != ORIENTATION_PORTRAIT_INVERTED) {
                    mOrientation = ORIENTATION_PORTRAIT_INVERTED;
                }                       
            }
            else { // orientation <135 && orientation > 45
                if (mOrientation != ORIENTATION_LANDSCAPE_INVERTED) {
                    mOrientation = ORIENTATION_LANDSCAPE_INVERTED;
                }                       
            }   

            if (lastOrientation != mOrientation) {
                changeRotation(mOrientation, lastOrientation);
            }
        }
    };
}
if (mOrientationEventListener.canDetectOrientation()) {
    mOrientationEventListener.enable();
    }
 }

  @Override protected void onPause() {
       super.onPause();
       mOrientationEventListener.disable();
  }

    /**
     * Performs required action to accommodate new orientation
     * @param orientation
     * @param lastOrientation
    */
   private void changeRotation(int orientation, int lastOrientation) {
   switch (orientation) {
    case ORIENTATION_PORTRAIT_NORMAL:
        mSnapButton.setImageDrawable(getRotatedImage(android.R.drawable.ic_menu_camera, 270));
        mBackButton.setImageDrawable(getRotatedImage(android.R.drawable.ic_menu_revert, 270));
        Log.v("CameraActivity", "Orientation = 90");
        break;
    case ORIENTATION_LANDSCAPE_NORMAL:
        mSnapButton.setImageResource(android.R.drawable.ic_menu_camera);
        mBackButton.setImageResource(android.R.drawable.ic_menu_revert);
        Log.v("CameraActivity", "Orientation = 0");
        break;
    case ORIENTATION_PORTRAIT_INVERTED:
        mSnapButton.setImageDrawable(getRotatedImage(android.R.drawable.ic_menu_camera, 90));
        mBackButton.setImageDrawable(getRotatedImage(android.R.drawable.ic_menu_revert, 90));
        Log.v("CameraActivity", "Orientation = 270");
        break;
    case ORIENTATION_LANDSCAPE_INVERTED:
        mSnapButton.setImageDrawable(getRotatedImage(android.R.drawable.ic_menu_camera, 180));
        mBackButton.setImageDrawable(getRotatedImage(android.R.drawable.ic_menu_revert, 180));      
        Log.v("CameraActivity", "Orientation = 180");
        break;
     }
  } 

    /**
   * Rotates given Drawable
   * @param drawableId    Drawable Id to rotate
   * @param degrees       Rotate drawable by Degrees
   * @return              Rotated Drawable
   */
 private Drawable getRotatedImage(int drawableId, int degrees) {
    Bitmap original = BitmapFactory.decodeResource(getResources(), drawableId);
    Matrix matrix = new Matrix();
    matrix.postRotate(degrees);

   Bitmap rotated = Bitmap.createBitmap(original, 0, 0, original.getWidth(),  original.getHeight(),  matrix, true);
  return new BitmapDrawable(rotated);
}

然后在你的PictureCallback中设置元数据来指示旋转级别:

private Camera.PictureCallback mJpegCallback = new Camera.PictureCallback() {

@Override
public void onPictureTaken(byte[] data, Camera camera) {
    try {
        // Populate image metadata

        ContentValues image = new ContentValues();
        // additional picture metadata
        image.put(Media.DISPLAY_NAME, [picture name]);
        image.put(Media.MIME_TYPE, "image/jpg");
        image.put(Media.TITLE, [picture title]);
        image.put(Media.DESCRIPTION, [picture description]);
        image.put(Media.DATE_ADDED, [some time]);
        image.put(Media.DATE_TAKEN, [some time]);
        image.put(Media.DATE_MODIFIED, [some time]);

        // do not rotate image, just put rotation info in
        switch (mOrientation) {
            case ORIENTATION_PORTRAIT_NORMAL:
                image.put(Media.ORIENTATION, 90);
                break;
            case ORIENTATION_LANDSCAPE_NORMAL:
                image.put(Media.ORIENTATION, 0);
                break;
            case ORIENTATION_PORTRAIT_INVERTED:
                image.put(Media.ORIENTATION, 270);
                break;
            case ORIENTATION_LANDSCAPE_INVERTED:
                image.put(Media.ORIENTATION, 180);
                break;
        }

        // store the picture
        Uri uri = getContentResolver().insert(
                Media.EXTERNAL_CONTENT_URI, image);

        try {
            Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0,
                    data.length);
            OutputStream out = getContentResolver().openOutputStream(
                    uri);
            boolean success = bitmap.compress(
                    Bitmap.CompressFormat.JPEG, 75, out);
            out.close();
            if (!success) {
                finish(); // image output failed without any error,
                            // silently finish
            }

现在,随着横向设备的出现,OrientationEventListener需要进行额外的检查。
  Display display = ((WindowManager)getSystemService(WINDOW_SERVICE)).getDefaultDisplay();                                        
 if (display.getOrientation() == Surface.ROTATION_0) { 
    // landscape oriented devices
 } else { 
     // portrait oriented device
 }

完整代码(LC有点浪费,但很容易演示这种方法)

 @Override
 public void onOrientationChanged(int orientation) {

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

Display display = ((WindowManager)getSystemService(WINDOW_SERVICE)).getDefaultDisplay();                                        

if (display.getOrientation() == Surface.ROTATION_0) {   // landscape oriented devices
    if (orientation >= 315 || orientation < 45) {
        if (mOrientation != ORIENTATION_LANDSCAPE_NORMAL) {                         
            mOrientation = ORIENTATION_LANDSCAPE_NORMAL;
        }
    } else if (orientation < 315 && orientation >= 225) {
        if (mOrientation != ORIENTATION_PORTRAIT_INVERTED) {
            mOrientation = ORIENTATION_PORTRAIT_INVERTED;
        }                       
    } else if (orientation < 225 && orientation >= 135) {
        if (mOrientation != ORIENTATION_LANDSCAPE_INVERTED) {
            mOrientation = ORIENTATION_LANDSCAPE_INVERTED;
        }                       
    } else if (orientation <135 && orientation > 45) { 
        if (mOrientation != ORIENTATION_PORTRAIT_NORMAL) {
            mOrientation = ORIENTATION_PORTRAIT_NORMAL;
        }                       
    }                       
} else {  // portrait oriented devices
    if (orientation >= 315 || orientation < 45) {
        if (mOrientation != ORIENTATION_PORTRAIT_NORMAL) {                          
            mOrientation = ORIENTATION_PORTRAIT_NORMAL;
        }
    } else if (orientation < 315 && orientation >= 225) {
        if (mOrientation != ORIENTATION_LANDSCAPE_NORMAL) {
            mOrientation = ORIENTATION_LANDSCAPE_NORMAL;
 }                       
    } else if (orientation < 225 && orientation >= 135) {
        if (mOrientation != ORIENTATION_LANDSCAPE_INVERTED) {
            mOrientation = ORIENTATION_LANDSCAPE_INVERTED;
        }                       
    } else if (orientation <135 && orientation > 45) { 
        if (mOrientation != ORIENTATION_PORTRAIT_NORMAL) {
            mOrientation = ORIENTATION_PORTRAIT_NORMAL;
        }                       
    }                       
} else {  // portrait oriented devices
    if (orientation >= 315 || orientation < 45) {
        if (mOrientation != ORIENTATION_PORTRAIT_NORMAL) {                          
            mOrientation = ORIENTATION_PORTRAIT_NORMAL;
        }
    } else if (orientation < 315 && orientation >= 225) {
        if (mOrientation != ORIENTATION_LANDSCAPE_NORMAL) {
            mOrientation = ORIENTATION_LANDSCAPE_NORMAL;
        }                       
    } else if (orientation < 225 && orientation >= 135) {
        if (mOrientation != ORIENTATION_PORTRAIT_INVERTED) {
            mOrientation = ORIENTATION_PORTRAIT_INVERTED;
        }                       
    } else if (orientation <135 && orientation > 45) { 
        if (mOrientation != ORIENTATION_LANDSCAPE_INVERTED) {
            mOrientation = ORIENTATION_LANDSCAPE_INVERTED;
        }                       
    }
 }

  if (lastOrientation != mOrientation) {
    changeRotation(mOrientation, lastOrientation);
  }
 }

第三种方法:

 private Bitmap adjustImageOrientation(Bitmap image) {
    ExifInterface exif;
    try {
        exif = new ExifInterface(picturePath);
        int exifOrientation = exif.getAttributeInt(
                ExifInterface.TAG_ORIENTATION,
                ExifInterface.ORIENTATION_NORMAL);

        int rotate = 0;
        switch (exifOrientation) {
        case ExifInterface.ORIENTATION_ROTATE_90:
            rotate = 90;
            break;

        case ExifInterface.ORIENTATION_ROTATE_180:
            rotate = 180;
            break;

        case ExifInterface.ORIENTATION_ROTATE_270:
            rotate = 270;
            break;
        }

        if (rotate != 0) {
            int w = image.getWidth();
            int h = image.getHeight();

            // Setting pre rotate
            Matrix mtx = new Matrix();
            mtx.preRotate(rotate);

            // Rotating Bitmap & convert to ARGB_8888, required by tess
            image = Bitmap.createBitmap(image, 0, 0, w, h, mtx, false);

        }
    } catch (IOException e) {
             return null;
    }
    return image.copy(Bitmap.Config.ARGB_8888, true);
}

1

我只是想分享一个对我有用的新解决方案。

基本上,您可以从Camera.CameraInfo中获取方向值。这将告诉您需要在setDisplayOrientation上使用哪些度数才能正确显示图像。当使用后置摄像头时,您可以简单地使用检索到的值来设置setDisplayOrientation。但是,当使用前置摄像头时,您需要进行一些微调,因为Android系统会翻转图像,使其看起来像镜子。

以下代码适用于我,并已在包括Nexus6和Galaxy在内的4个不同设备上进行了测试。

Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
int cameraCount = Camera.getNumberOfCameras();
int camIdx = 0; // DO your logic to get front or back camera...or loop through all avaialable.
Camera.getCameraInfo(camIdx, cameraInfo);

try {
    mCamera = Camera.open(camIdx);
    // If using back camera then simply rotate what CameraInfo tells you.
    if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_BACK)
        mCamera.setDisplayOrientation(cameraInfo.orientation);
    else
        // If using front camera note that image might be flipped to give users the impresion the are looking at a mirror.
        mCamera.setDisplayOrientation( (360 - cameraInfo.orientation) % 360);
} catch (Exception e) {
    e.printStackTrace();
}

1

我之前在类似的问题中给出了答案,但是你说这个问题出现在HTC设备上。我建议你在旋转代码中添加断点,并在物理旋转设备时检查变量 - 这可能有助于确定Galaxy型号的不同之处。


1

检查手机设置中的“自动旋转屏幕”选项是否被勾选(设置 > 显示或屏幕 - 取决于Android版本)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接