1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > 关于Android手机拍照预览 剪裁界面出现照片九十度旋转的问题

关于Android手机拍照预览 剪裁界面出现照片九十度旋转的问题

时间:2023-09-23 03:19:46

相关推荐

关于Android手机拍照预览 剪裁界面出现照片九十度旋转的问题

案场还原:

最近做的项目,测试机小米6X及本人的努比亚Z11测试拍照环节均正常,但在领导的三星手机及Oppo FindX上就出现了奇葩现象,拍照完预览照片、剪裁照片出现了九十度的旋转,如果这时候你用模拟器,比如Genymotion也能发现此问题,预览及剪裁出现旋转。

原因排查:

通过搜索大量墙里墙内资料,原因大概总结为以下几点,自我理解,若有不对,还望指正:

Android原生系统设定的拍照界面是Landscape也就是横屏模式,因此即使你调用拍照的Activity是竖屏模式,拍照画面也是竖屏模式,但到了预览和剪裁就默认切换成了横屏的画面。可能是某些手机厂商深度定制系统的结果,比如三星反其道而行,系统设定拍照旋转,简直是反人类,反社会!有网友也反应可能与Activity启动模式有关,建议设置当前启动模式为Standard,但我不是这个原因,因为默认模式就是Standard。

对于以上原因,可是尝试在配置文件中设定:

<activity android:name=".activity.ProfileActivity"android:configChanges="keyboardHidden|orientation|screenSize"android:exported="true"android:launchMode="standard"android:screenOrientation="portrait" />

But,这些对我来说都不起作用

4 .代码问题

解决:

强制将旋转后的照片转回来

最重要的也就是从ExifInterface这个多媒体相关类中读取照片被旋转的角度,然后使用Matrix强制转回来。代码如下

/*** 获取原始图片的角度(***解决三星手机拍照后图片是横着的问题***)* 读取照片exif信息中的旋转角度** @param path 照片路径* @return角度*/private int getPictureDegree(String path) {int degree = 0;/*** 方法一*/// boolean hasRotation = false;// String[] orientationColumn = {MediaStore.Images.Media.ORIENTATION};// Cursor cursor = context.getContentResolver().query(cameraUri, orientationColumn, null, null, null);// Log.e(TAG, "cursor: " + cursor + " " );// if (cursor.getCount() != 1) {// cursor.close();// return -1;// }// if (cursor.moveToFirst()){// degree = cursor.getInt(cursor.getColumnIndex(orientationColumn[0]));// hasRotation = true;// }// cursor.close();// cursor = null;// Log.e(TAG, "getPictureDegree: " + degree );/*** 方法二*/try {ExifInterface exifInterface = new ExifInterface(path);int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);Log.e(TAG, "原图被旋转角度: ========== " + orientation );switch (orientation) {case ExifInterface.ORIENTATION_ROTATE_90:degree = 90;break;case ExifInterface.ORIENTATION_ROTATE_180:degree = 180;break;case ExifInterface.ORIENTATION_ROTATE_270:degree = 270;break;}} catch (IOException e) {e.printStackTrace();}/*** 方法三*/// int degree = 0;// android.hardware.Camera.CameraInfo info = new android.hardware.Camera.CameraInfo();// android.hardware.Camera.getCameraInfo(0, info);// degree = info.orientation;// Log.e(TAG, "CameraInfo: " + info.orientation );return degree;}

然后转回来:

Matrix matrix = new Matrix();int degree = getPictureDegree(cameraImagePath);matrix.postRotate(degree); /*翻转90度*/

这里需要说明一下获取照片被旋转角度getPictureDegree这个方法,有三种获取角度的方式

使用数据库Cursor读取信息context.getContentResolver().query(cameraUri, orientationColumn, null, null, null)但我读不到String[] orientationColumn = {MediaStore.Images.Media.ORIENTATION};相关的信息,报空指针异常,因此放弃。直接读取硬件摄像头CameraInfo相关信息再进行旋转,这个方法也有硬伤,在正常的测试机上预览剪裁本来不会旋转,结果你用你用摄像机竖屏拍照,得到的info.orientation是九十度,然后进行旋转,本来正常的拍照也被颠倒了,因此同样放弃该方式。使用ExifInterface读取,关于该类的详细说明请百度。国内多数开发者遇见此坑都推荐运用此方式读取旋转角度,但我遇见一个更奇葩的问题,通过int orientation=exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL)读取到的角度永远为0!!!!!!!!

此问题搞得我焦头烂额,欲哭无泪。经过一番Google,Stack Overflow上的开发者建议切换为第一种Cursor读取信息,但我刚才也讲了,方法报空指针,有待商榷。

现在所有的问题都集中在一点,明明旋转了的照片读取到的旋转角度却是0度!!

好吧,一天两天过去,终于找到了一种思路

还别说,之前我还真的是在读取角度信息之前做了图片压缩处理,然后才进行旋转操作

/*** 旋转* @return*/private Bitmap toturn() {BitmapFactory.Options options = new BitmapFactory.Options();options.inJustDecodeBounds = true;// 简单的压缩options.inSampleSize = 4; //把原图按1/4的比例压缩options.inJustDecodeBounds = false; // 压缩完后便可以将inJustDecodeBounds设置为false// 把流转化为Bitmap图片Bitmap bitmap = BitmapFactory.decodeFile(cameraImagePath, options);Matrix matrix = new Matrix();int degree = getPictureDegree(cameraImagePath);matrix.postRotate(degree); /*翻转90度*/int width = bitmap.getWidth();int height = bitmap.getHeight();Bitmap returnBm = Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true);if (returnBm == null) {returnBm = bitmap;}if (bitmap != returnBm) {bitmap.recycle();}Log.e(TAG, "returnBm: " + returnBm );return returnBm;}

好吧,皇天不负有心人,先旋转再压缩之后,运行,终于解决了,在这也要感谢链接的博主。

有时候我们找bug,就跟买房一样,大海捞针,也是看运气。

附上我所有的拍照相关代码

private Uri cameraUri;// 裁剪后图片的宽(X)和高(Y),480 X 480的正方形。private static int output_X = 480;private static int output_Y = 480;private Uri imageUriCrop; //剪裁后的图片uri/*** 拍照*/public void fromCamera(){if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {File dir = new File(ConstantManager.cameraPath);//创建文件夹if (!dir.exists()) dir.mkdirs();Intent openCameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);cameraFile = new File(dir, String.valueOf(System.currentTimeMillis()) + ".jpg");//指定照片路径if (!cameraFile.exists()) {try {cameraFile.createNewFile();} catch (IOException e) {e.printStackTrace();}}cameraImagePath = cameraFile.getPath();if (Build.VERSION.SDK_INT >= 24) {cameraUri = FileProvider.getUriForFile(context, context.getApplicationContext().getPackageName() + ".provider", cameraFile);} else {cameraUri = Uri.fromFile(cameraFile);}// Log.e(TAG, "cameraUri: " + cameraUri );openCameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, cameraUri);openCameraIntent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 0);((Activity) context).startActivityForResult(openCameraIntent, 0x008);} else {view.showMsg("没有储存卡");}}/*** 图片剪裁** @param system* @param in*/public void crop(boolean system, Intent in,@Nullable File cameraFile) {Intent intent = new Intent("com.android.camera.action.CROP");//设置数据源Uri uri;if (system) { //从系统相册选择if (in != null && in.getData() != null) {uri = createSingleCropUri("crop_image.jpg"); //剪裁后的图库图片名intent.setDataAndType(in.getData(), "image/*");} else {return;}} else { //从相机拍照选择if (Build.VERSION.SDK_INT >= 24) {//添加这一句表示对目标应用临时授权该Uri所代表的文件intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);/*** Android 7.0要求设置数据源使用ContentUri,输出使用正常的Uri*/Uri contentUri = getImageContentUri(context,cameraFile);intent.setDataAndType(contentUri,"image/*"); //设置剪裁后的图片数据源uri = createSingleCropUri(cameraFile.getName()); //剪裁后的照片名} else {intent.setDataAndType(Uri.fromFile(cameraFile), "image/*"); //设置剪裁后的图片数据源uri = createSingleCropUri(cameraFile.getName()); //剪裁后的照片名}}Log.e(TAG, "crop: " + uri );intent.putExtra("crop", "true");// 设置裁剪intent.putExtra("aspectX", 1);// aspectX , aspectY :宽高的比例,为浮点数则不会固定裁剪框比例intent.putExtra("aspectY", 1);intent.putExtra("outputX", output_X);// 定义输出图片大小,不定义则按裁剪框大小定义,但裁剪耗时会加长intent.putExtra("outputY", output_Y);intent.putExtra("return-data", true);intent.putExtra("scale", true);//保留比例intent.putExtra("return-data", false);//是否返回dataintent.putExtra(MediaStore.EXTRA_OUTPUT, uri);//输出路径,剪裁后的图片intent.putExtra("outputFormat", pressFormat.JPEG.toString());//编码格式intent.putExtra("noFaceDetection", true);((Activity) context).startActivityForResult(intent, 0x009);}private Uri createSingleCropUri(String fileName) {if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {File dir = new File(ConstantManager.cameraPath);//创建文件夹if (!dir.exists()) dir.mkdirs();File cropFile = new File(dir, fileName);//指定裁剪路径,多图情况下裁剪路径不能唯一,否则文件会被覆盖imageUriCrop = Uri.fromFile(cropFile);}return imageUriCrop;}/*** 安卓7.0裁剪根据文件路径获取uri*/public static Uri getImageContentUri(Context context, File imageFile) {String filePath = imageFile.getAbsolutePath();Cursor cursor = context.getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,new String[]{MediaStore.Images.Media._ID},MediaStore.Images.Media.DATA + "=? ",new String[]{filePath}, null);if (cursor != null && cursor.moveToFirst()) {int id = cursor.getInt(cursor.getColumnIndex(MediaStore.MediaColumns._ID));Uri baseUri = Uri.parse("content://media/external/images/media");return Uri.withAppendedPath(baseUri, "" + id);} else {if (imageFile.exists()) {ContentValues values = new ContentValues();values.put(MediaStore.Images.Media.DATA, filePath);return context.getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);} else {return null;}}}/*** 获取原始图片的角度(***解决三星手机拍照后图片是横着的问题***)* 读取照片exif信息中的旋转角度** @param path 照片路径* @return角度*/private int getPictureDegree(String path) {int degree = 0;/*** 方法一*/// boolean hasRotation = false;// String[] orientationColumn = {MediaStore.Images.Media.ORIENTATION};// Cursor cursor = context.getContentResolver().query(cameraUri, orientationColumn, null, null, null);// Log.e(TAG, "cursor: " + cursor + " " );// if (cursor.getCount() != 1) {// cursor.close();// return -1;// }// if (cursor.moveToFirst()){// degree = cursor.getInt(cursor.getColumnIndex(orientationColumn[0]));// hasRotation = true;// }// cursor.close();// cursor = null;// Log.e(TAG, "getPictureDegree: " + degree );/*** 方法二*/try {ExifInterface exifInterface = new ExifInterface(path);int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);Log.e(TAG, "原图被旋转角度: ========== " + orientation );switch (orientation) {case ExifInterface.ORIENTATION_ROTATE_90:degree = 90;break;case ExifInterface.ORIENTATION_ROTATE_180:degree = 180;break;case ExifInterface.ORIENTATION_ROTATE_270:degree = 270;break;}} catch (IOException e) {e.printStackTrace();}/*** 方法三*/// int degree = 0;// android.hardware.Camera.CameraInfo info = new android.hardware.Camera.CameraInfo();// android.hardware.Camera.getCameraInfo(0, info);// degree = info.orientation;// Log.e(TAG, "CameraInfo: " + info.orientation );return degree;}/*** 旋转* @return*/private Bitmap toturn() {Matrix matrix = new Matrix();int degree = getPictureDegree(cameraImagePath);matrix.postRotate(degree); /*翻转90度*/BitmapFactory.Options options = new BitmapFactory.Options();options.inJustDecodeBounds = true;// 简单的压缩options.inSampleSize = 4; //把原图按1/4的比例压缩options.inJustDecodeBounds = false; // 压缩完后便可以将inJustDecodeBounds设置为false// 把流转化为Bitmap图片Bitmap bitmap = BitmapFactory.decodeFile(cameraImagePath, options);int width = bitmap.getWidth();int height = bitmap.getHeight();Bitmap returnBm = Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true);// if (returnBm == null) {// returnBm = bitmap;// }// if (bitmap != returnBm) {// bitmap.recycle();// }// Log.e(TAG, "returnBm: " + returnBm );return returnBm;}/*** 保存旋转后的Bitmap图片在SD卡中* 如果没有SD卡则存在手机中* @return 保存成功时返回图片的路径,失败时返回null*/public String savePhotoToSD() {Bitmap mbitmap = toturn();FileOutputStream outStream = null;String fileName = String.valueOf(System.currentTimeMillis()) + ".jpg";File file = new File(ConstantManager.cameraPath );String filePath = file + "/" +fileName;// 判断文件是否已经存在,不存在则创建if ( !file.exists() ) {file.mkdirs();}try {outStream = new FileOutputStream(filePath);// 把数据写入文件,100表示不压缩press(pressFormat.JPEG, 100, outStream);Log.e(TAG, "旋转处理后的图片: " + filePath );return filePath;} catch (Exception e) {e.printStackTrace();return null;} finally {try {if (outStream != null) {outStream.close();}if (mbitmap != null) {mbitmap.recycle();}} catch (Exception e) {e.printStackTrace();}}}

Activity中回调处理:

@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) {Log.e(TAG, "resultCode: " + resultCode);if (resultCode == this.RESULT_OK) {Log.e(TAG, "requestcode: " + requestCode);switch (requestCode) {case 0x007:presenter.crop(true, data, null);break;case 0x008:File imageFile = new File(presenter.savePhotoToSD());presenter.crop(false, data, imageFile);break;case 0x009:presenter.uploadImage(userId, entity);break;default:break;}}}

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。