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照相机调用的全部内容

查看源码

链接: 源码连接.

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值