我正在尝试控制Android相机在肖像应用程序中拍照,但是当我保存图片时,它是在风景中。我用setCameraDisplayOrientation()
方法将图像旋转了90个等级,但不起作用。
然后我发现了这个post,但TAG_ORIENTATION
是0
(未定义)。如果我捕获此值并应用旋转值,则也不起作用。
如何拍摄肖像并以良好的方向保存?
/** 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());
}
}
答案 0 :(得分:55)
问题是当我保存图像时我做得不好。
@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);
}
答案 1 :(得分:51)
使用 setCameraDisplayOrientation()方法,您可以更改预览的显示方式,而不会影响图像的记录方式(source )。
要更改实际记录的图像,您需要设置相机的旋转参数。你这样做:
//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”语句。
答案 2 :(得分:23)
使用前置摄像头时,可以使用以下方法正确生成预览。
此代码进入相机预览的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
包含正确的图像。
答案 3 :(得分:6)
这个应该可以使用,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);
}
答案 4 :(得分: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);
}
答案 5 :(得分: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;
}
}
希望它有所帮助:)
答案 6 :(得分:1)
当您以纵向模式修复布局时,这是使用的最佳方法(下文提到)。
@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();
}
}
};
getOutputMediaFile
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;
}
来源Here
答案 7 :(得分: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();
}
}