Android拍照或从系统相册获取图片

遇到问题:有的手机拍摄的图片自动旋转90度,有的图片旋转了180度,有的手机是正常的,导致显示到界面的上的头像不准确。服务器要求的是正的,这样问题就来了,不能用户发个照片在微博上看到的是被旋转了的啊,另外一个项目里旋转了的图片直接匹配出现问题,这个更严重。

在做Android开发中还是会经常选择照片然后做上传操作的。但是其中选择照片系统的有两种方式,第一种是拍照、第二种是从相册中选择。这里分别介绍下。

解决思路:1.拿到照相机自带的返回的uri;2.根据uri获取到照片在手机上的绝对路径,根据路径获取获取照片的旋转角度(此处应该特别注意:一定要是照相机返回的原始的uri,不然获取到的旋转角度始终为0);3.根据uri获取到bitmap4.根据动态获取到旋转角度来旋转图片5.把图片设置到view上或传到服务器

其中拍照有两种方法,从系统相册选择有两种方法,会分别介绍和分析。

直接上代码:1.根据uri获取到照片在手机上的绝对路径,根据路径获取获取照片的旋转角度(此处应该特别注意:一定要是照相机返回的原始的uri,不然获取到的旋转角度始终为0);

刚才说过会介绍两种方法,其实无论几种方法原理都是一个。就是通过intent发出隐式意图调用系统的照相机,然后在获取到从相机返回的图片,这里的两种主要是返回方式有两种。

/** * 专为Android4.4及以上设计的从Uri获取文件绝对路径,以前的方法已不好使 */ @SuppressLint public static String getPath(final Context context, final Uri uri) { final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT; // DocumentProvider if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) { // ExternalStorageProvider if (isExternalStorageDocument { final String docId = DocumentsContract.getDocumentId; final String[] split = docId.split; final String type = split[0]; if ("primary".equalsIgnoreCase { return Environment.getExternalStorageDirectory() + "/" + split[1]; } // TODO handle non-primary volumes } // DownloadsProvider else if (isDownloadsDocument { final String id = DocumentsContract.getDocumentId; final Uri contentUri = ContentUris.withAppendedId( Uri.parse("content://downloads/public_downloads"), Long.valueOf; return getDataColumn(context, contentUri, null, null); } // MediaProvider else if (isMediaDocument { final String docId = DocumentsContract.getDocumentId; final String[] split = docId.split; final String type = split[0]; Uri contentUri = null; if ("image".equals { contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI; } else if ("video".equals { contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI; } else if ("audio".equals { contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI; } final String selection = "_id=?"; final String[] selectionArgs = new String[]{split[1]}; return getDataColumn(context, contentUri, selection, selectionArgs); } } // MediaStore (and general) else if ("content".equalsIgnoreCase(uri.getScheme { return getDataColumn(context, uri, null, null); } // File else if ("file".equalsIgnoreCase(uri.getScheme { return uri.getPath(); } return null; } /** * Get the value of the data column for this Uri. This is useful for * MediaStore Uris, and other file-based ContentProviders. * * @param context The context. * @param uri The Uri to query. * @param selection  Filter used in the query. * @param selectionArgs  Selection arguments used in the query. * @return The value of the _data column, which is typically a file path. */ public static String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) { Cursor cursor = null; final String column = "_data"; final String[] projection = {column}; try { cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null); if (cursor != null && cursor.moveToFirst { final int column_index = cursor.getColumnIndexOrThrow; return cursor.getString(column_index); } } finally { if (cursor != null) cursor.close(); } return null; } /** * @param uri The Uri to check. * @return Whether the Uri authority is ExternalStorageProvider. */ public static boolean isExternalStorageDocument { return "com.android.externalstorage.documents".equals(uri.getAuthority; } /** * @param uri The Uri to check. * @return Whether the Uri authority is DownloadsProvider. */ public static boolean isDownloadsDocument { return "com.android.providers.downloads.documents".equals(uri.getAuthority; } /** * @param uri The Uri to check. * @return Whether the Uri authority is MediaProvider. */ public static boolean isMediaDocument { return "com.android.providers.media.documents".equals(uri.getAuthority; }

1、直接返回图片。

2.根据图片的绝对路径获取默认的角度:

2、提前创建好存放图片的Uri然后拍照返回后存储起来。

/** * 读取图片的旋转的角度 * * @param path 图片绝对路径 * @return 图片的旋转角度 */ public static int getBitmapDegree(String path) { int degree = 0; try { // 从指定路径下读取图片,并获取其EXIF信息 ExifInterface exifInterface = new ExifInterface; // 获取图片的旋转信息 int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL); 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(); } return degree; }

第一种拍照方法:

 Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); startActivityForResult(intent, TAKE_PHOTO_REQUEST);

没错,简单的两行代码就可以调取摄像头进行拍照了,这时候我们是通过Intent指定activion:
MediaStore.ACTION_IMAGE_CAPTURE去查找符合条件的程序。相机里面会对这个action做处理,这一步属于intent的操作了,这里不再赘述。

case TAKE_PHOTO_REQUEST: if (resultCode == RESULT_CANCELED) { Toast.makeText(MainActivity.this, "取消了拍照", Toast.LENGTH_LONG).show(); return; } Bitmap photo = data.getParcelableExtra; iv_image.setImageBitmap; break;

上面的代码是onActivityResult中的处理,判断request后做拍照返回处理,其中data直接返回Bitmap,不过这里要注意一点就是,这个Bitmap会经过系统压缩。所以有时候可能看起来照片并没有那么清晰。也正是由于是系统压缩的原因,这个图片基本不会很大,基本不会OOM。

发表评论

电子邮件地址不会被公开。 必填项已用*标注