Android调用照相机展示高清图片及展示图片时图片倾斜问题
一、概述
由于需要做一个调用Android原生照相机并展示出清楚的图片的demo,在网上查找了很多资料,没有找到一个我希望的完整文章。包括:调用照相机、调用手机图片、照相机拍出的图片展示清楚的图片、部分手机(如:小米、华为等)在展示图片时图片是倾斜的如何调正的问题。这里做一个总结,之后自己再遇到这样的问题也可以快速查看。
二、配置权限
首先需要在AndroidManifest.xml 文件添加需要的权限
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_CONTACTS" />
由于Android 6.0以上的手机需要动态获取权限所以以上权限需要在代码中做判断API level 23以上版本需要在代码中动态获取
if(currentapiVersion>23){
if (HasPermission(mActivity,Manifest.permission.WRITE_EXTERNAL_STORAGE) && HasPermission(mActivity,Manifest.permission.READ_EXTERNAL_STORAGE)) {
//具体操作
}else{
ActivityCompat.requestPermissions(mActivity, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE,Manifest.permission.READ_EXTERNAL_STORAGE}, 2);
}
}
/**检查有没有sd卡写入权限*/
private boolean HasPermission(Context context,String permission){//Manifest.permission.WRITE_EXTERNAL_STORAGE
int result= ContextCompat.checkSelfPermission(context,permission);
return result ==PackageManager.PERMISSION_GRANTED;
}
同时要在application中配置
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
三、封装CameraUtil工具类
1、Android调用照相机
调用照相机时,设置照片存储路径,自定义照片名称(这里是根据时间命名),判断手机当前版本号,如果在API level 23以上则判断是否获取权限,如果没有则动态获取权限,如果已经获取权限了,则打开照相机。
/**打开照相机*/
public void OpenCamera(){
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
//设置自定义存储路径
mFilePath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/systemCemer";
File outFilePath = new File(mFilePath);
//判断是否有该文件夹,没有则创建文件夹
if (!outFilePath.exists()) {
outFilePath.mkdirs();
}
//设置自定义照片的名字
String fileName = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
mFilePath = mFilePath + "/" + fileName + ".jpg";
File outFile = new File(mFilePath);
//获取手机当前版本号
int currentapiVersion = Build.VERSION.SDK_INT;
if (currentapiVersion >23) {//currentapiVersion >23
//判断是否有照相机权限
if (HasPermission(mActivity,Manifest.permission.CAMERA)) {
//判断是否有读取和写入的权限
if (HasPermission(mActivity,Manifest.permission.WRITE_EXTERNAL_STORAGE) && HasPermission(mActivity,Manifest.permission.READ_EXTERNAL_STORAGE)) {
Uri uri = Uri.fromFile(outFile);
intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
//打开照相机
mActivity.startActivityForResult(intent, REQUEST_CODE_TAKE_PICTURE);
} else {//无储存权限
ActivityCompat.requestPermissions(mActivity, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE,Manifest.permission.READ_EXTERNAL_STORAGE}, 0);
}
} else {//无相机权限
ActivityCompat.requestPermissions(mActivity, new String[]{Manifest.permission.CAMERA}, 1);
}
}else{
imageUri = Uri.fromFile(outFile);
intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
//打开照相机
mActivity.startActivityForResult(intent, REQUEST_CODE_TAKE_PICTURE);
}
}
/** 检查有没有sd卡写入权限*/
private boolean HasPermission(Context context,String permission){//Manifest.permission.WRITE_EXTERNAL_STORAGE
int result= ContextCompat.checkSelfPermission(context,permission);
return result ==PackageManager.PERMISSION_GRANTED;
}
2、调用系统相册
打开系统相册,同样在调用系统相册前先判读是否获取权限。
/**打开相册前的权限判断各种*/
public void OpenPhotoStrat(){
int currentapiVersion = Build.VERSION.SDK_INT;
if(currentapiVersion>23){
if (HasPermission(mActivity,Manifest.permission.WRITE_EXTERNAL_STORAGE) && HasPermission(mActivity,Manifest.permission.READ_EXTERNAL_STORAGE)) {
OpenPhoto();
}else{
ActivityCompat.requestPermissions(mActivity, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE,Manifest.permission.READ_EXTERNAL_STORAGE}, 2);
}
}else{
OpenPhoto();
}
}
/**打开相册*/
private void OpenPhoto(){
Intent intent = new Intent("android.intent.action.GET_CONTENT");
intent.setType("image/*");
// 打开相册
mActivity.startActivityForResult(intent, CHOOSE_PHOTO);
}
3、拍摄完毕或在相册选取好照片后处理图片
因为这里写的是一个工具类,所以需要创建一个回调接口
public interface ReturnBitmap {
void returnBitmap(Bitmap bitmap);
}
这里是根据Activity里面的回调方法onActivityResult,在工具类里面进行处理之后再返回给Activity处理好的Bitmap图片。其中有相册里获取图片(case CHOOSE_PHOTO:)和从照相机里获取的图片(case REQUEST_CODE_TAKE_PICTURE:)。
//在CameraUtil里处理返回的结果
public void onActivityResult(int requestCode, int resultCode, Intent data,ReturnBitmap returnBitmaps) {
returnBitmap = returnBitmaps;
switch (requestCode) {
case CHOOSE_PHOTO:
if (resultCode == mActivity.RESULT_OK) {
handleImage(data);
}
break;
//-----获取高清图片
case REQUEST_CODE_TAKE_PICTURE:
if (BuildConfig.DEBUG) Log.d("SystemCemerActivity", mFilePath);
final Bitmap bitmap = loadingImageBitmap(mFilePath);
if (bitmap!=null) {
//picture.setImageBitmap(bitmap);
returnBitmap.returnBitmap(bitmap);
}
break;
default:
break;
}
}
下面部分是相册返回的处理代码
// 只在Android4.4及以上版本使用
@TargetApi(19)
private void handleImage(Intent data) {
String imagePath = null;
Uri uri = data.getData();
if (DocumentsContract.isDocumentUri(mActivity, uri)) {
// 通过document id来处理
String docId = DocumentsContract.getDocumentId(uri);
if ("com.android.providers.media.documents".equals(uri.getAuthority())) {
// 解析出数字id
String id = docId.split(":")[1];
String selection = MediaStore.Images.Media._ID + "=" + id;
imagePath = getImagePath(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, selection);
}
else if ("com.android.providers.downloads.documents".equals(uri.getAuthority())) {
Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"),
Long.valueOf(docId));
imagePath = getImagePath(contentUri, null);
}
}
else if ("content".equals(uri.getScheme())) {
// 如果不是document类型的Uri,则使用普通方式处理
imagePath = getImagePath(uri, null);
}
// 根据图片路径显示图片
displayImage(imagePath);
}
/***
* 如果不是document类型的Uri,则使用普通方式处理
* @param uri
* @param selection
* @return
*/
private String getImagePath(Uri uri, String selection) {
String path = null;
// 通过Uri和selection来获取真实图片路径
Cursor cursor = mActivity.getContentResolver().query(uri, null, selection, null, null);
if (cursor != null) {
if (cursor.moveToFirst()) {
path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
}
cursor.close();
}
return path;
}
/***
* 根据图片路径显示图片
* @param imagePath
*/
private void displayImage(String imagePath) {
if (imagePath != null) {
Bitmap bitmap = BitmapFactory.decodeFile(imagePath);
//旋转图片
bitmap = rotateBitmapByDegree(bitmap,getBitmapDegree(imagePath));
//picture.setImageBitmap(bitmap);
returnBitmap.returnBitmap(bitmap);
}
else {
Toast.makeText(mActivity, "failed to get image", Toast.LENGTH_SHORT).show();
}
}
下面的是照相机返回图片处理代码
//整理高清图片
public Bitmap loadingImageBitmap(String imagePath) {
/**
* 获取图片位置的宽与高
*/
final int width = mActivity.getWindowManager().getDefaultDisplay().getWidth();
final int height = mActivity.getWindowManager().getDefaultDisplay().getHeight();
/**
* 通过设置optios来只加载大图的尺寸
*/
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
Bitmap bitmap = null;
try {
bitmap = BitmapFactory.decodeFile(imagePath, options);
/**
* 计算手机宽高与显示大图的宽高,然后确定缩放有比例
*/
int widthRaio = (int) Math.ceil(options.outWidth/(float)width);
int heightRaio = (int) Math.ceil(options.outHeight/(float)height);
if (widthRaio>1&&heightRaio>1){
if (widthRaio>heightRaio){
options.inSampleSize = widthRaio;
}else {
options.inSampleSize = heightRaio;
}
}
/**
* 设置加载缩放后的图片
*/
options.inJustDecodeBounds = false;
bitmap = BitmapFactory.decodeFile(imagePath, options);
//旋转图片
bitmap = rotateBitmapByDegree(bitmap,getBitmapDegree(imagePath));
} catch (Exception e) {
e.printStackTrace();
}
return bitmap;
}
下面照片和照相机公用代码,主要作用是处理图片倾斜问题(如:小米、华为等会遇到这样的问题)。
/**
* 读取图片的旋转的角度
*
* @param path 图片绝对路径
* @return 图片的旋转角度
*/
public static int getBitmapDegree(String path) {
int degree = 0;
try {
// 从指定路径下读取图片,并获取其EXIF信息
ExifInterface exifInterface = new ExifInterface(path);
// 获取图片的旋转信息
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;
}
/**
* 将图片按照某个角度进行旋转
*
* @param bm 需要旋转的图片
* @param degree 旋转角度
* @return 旋转后的图片
*/
public static Bitmap rotateBitmapByDegree(Bitmap bm,int degree) {
Bitmap returnBm = null;
//根据旋转角度,生成旋转矩阵
Matrix matrix = new Matrix();
matrix.postRotate(degree);
try {
//将原始图片按照旋转矩阵进行旋转,并得到新的图片
returnBm = Bitmap.createBitmap(bm, 0, 0, bm.getWidth(), bm.getHeight(), matrix, true);
} catch (OutOfMemoryError e) {
}
if (returnBm == null) {
returnBm = bm;
}
if (bm != returnBm) {
bm.recycle();
}
return returnBm;
}
}
这样一个CameraUtil工具类就封装完成了。
四、MainActivity如何调用
下面是调用CameraUtil工具类的方法,其中6.0以上需要配置
//6.0以上配置
StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
StrictMode.setVmPolicy(builder.build());
builder.detectFileUriExposure();
这些方法否则显示不出来图片
package com.wzp.mycamera;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.os.Build;
import android.os.Bundle;
import android.os.StrictMode;
import android.support.annotation.RequiresApi;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
public class MainActivity extends Activity {
private Button takePhoto;
private ImageView picture;
private Button chooseFromAlbum;
private CameraUtil cameraUtil;
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main);
//6.0以上配置
StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
StrictMode.setVmPolicy(builder.build());
builder.detectFileUriExposure();
takePhoto = (Button) findViewById(R.id.take_photo);
picture = (ImageView) findViewById(R.id.picture);
chooseFromAlbum = (Button) findViewById(R.id.choose_from_album);
//-----创建CameraUtil实例
cameraUtil = new CameraUtil(this);
takePhoto.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//-----从CameraUtil中调用相机
cameraUtil.OpenCamera();
}
});
chooseFromAlbum.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//-----从CameraUtil中调用相机
cameraUtil.OpenPhotoStrat();
}
});
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
cameraUtil.onActivityResult(requestCode, resultCode, data, new CameraUtil.ReturnBitmap() {
@Override
public void returnBitmap(Bitmap bitmap) {
picture.setImageBitmap(bitmap);
}
});
}
}
五、Layout布局文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<Button
android:id="@+id/take_photo"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="启动相机" />
<Button
android:id="@+id/choose_from_album"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="从相册中选择图片" />
<ImageView
android:id="@+id/picture"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center_horizontal"
android:layout_margin="10dp"/>
</LinearLayout>
以上就是关于Android照相机调用的全部内容
查看源码
链接: 源码连接.