Android实现拍照(兼容7.0)

在7.0以前,调用相机拍照

 /**
     * 拍照
     *
     * @param view
     */
    @Event(R.id.btn_photo)
    private void takePhoto(View view) {
        //启动照相机拍照
        Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        photoPath = Environment.getExternalStorageDirectory() + "/xyh.jpg";
        intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(new File(photoPath)));
        startActivityForResult(intent, PHOTO_REQUEST);
    }

在用Android 7.0版本时,出现了异常 FileUriExposedException,就是在传递uri时出错

百度了一下,说是Android 7.0后又修改了文件权限,可以使用FileProvider解决

1.在 res 目录下新建文件夹 xml 然后创建资源文件 filepaths(随意名字)

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <!--external-path:代表的根目录: Environment.getExternalStorageDirectory()-->
    <external-path
        name="images"
        path="拍照/" /> //存放照片文件夹
</resources>
<files-path/> //代表的根目录: Context.getFilesDir()
<external-path/> //代表的根目录: Environment.getExternalStorageDirectory()
<cache-path/> //代表的根目录: getCacheDir()

2.在manifest中添加provider


        <provider
            android:name="android.support.v4.content.FileProvider"
            android:authorities="com.xiaoyehai.takephoto.fileprovider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/filepaths" />
        </provider>

exported:要求必须为false,为true则会报安全异常。grantUriPermissions:true,表示授予 URI 临时访问权限。

3.调用相机拍照,图片得存储吧,存储图片又需要权限,因此动态申请权限
AndroidManifest.xml文件中:

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

4.java代码



/**
 * android7.0拍照
 */
public class MainActivity extends AppCompatActivity {

    private static final int REQUEST_PERMISSION_CODE = 559;

    private static final int REQUEST_CAMERA = 648;

    private ImageView mImageView;

    private String[] permissions = {Manifest.permission.WRITE_EXTERNAL_STORAGE};

    private File mFile;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mImageView = (ImageView) findViewById(R.id.iv);
    }

    public void doclick(View view) {
        if (Build.VERSION.SDK_INT >= 23) {
            if (ContextCompat.checkSelfPermission(this, permissions[0]) != PackageManager.PERMISSION_GRANTED) {
                ActivityCompat.requestPermissions(this, permissions, REQUEST_PERMISSION_CODE);
            } else {
                takePhoto();
            }
        } else {
            takePhoto();
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);

        if (requestCode == REQUEST_PERMISSION_CODE && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            takePhoto();
        } else {
            // 没有获取 到权限,从新请求,或者关闭app
            Toast.makeText(this, "需要存储权限", Toast.LENGTH_SHORT).show();
        }
    }

    private void takePhoto() {
        Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        mFile = new File(Environment.getExternalStorageDirectory().getAbsolutePath()
                + "/拍照/" + System.currentTimeMillis() + ".jpg");
        if (!mFile.getParentFile().exists()) {
            mFile.getParentFile().mkdirs();
        }

        //改变Uri com.xiaoyehai.takephoto.fileprovider注意和清单文件中一致中的一致
        Uri uri = FileProvider.getUriForFile(this, "com.xiaoyehai.takephoto.fileprovider", mFile);
        //添加权限
        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);

        intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
        startActivityForResult(intent, REQUEST_CAMERA);
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        if (requestCode == REQUEST_CAMERA && resultCode == RESULT_OK) {
            Uri uri = FileProvider.getUriForFile(this, "com.xiaoyehai.takephoto.fileprovider", mFile);

            //content://com.xiaoyehai.takephoto.fileprovider/images/1533796434054.jpg
            Log.e("xyh", "onActivityResult: " + uri);

            mImageView.setImageBitmap(BitmapFactory.decodeFile(mFile.getAbsolutePath()));

            //在手机相册中显示刚拍摄的图片
            Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
            Uri contentUri = Uri.fromFile(mFile);
            mediaScanIntent.setData(contentUri);
            sendBroadcast(mediaScanIntent);
        }
    }
}

如果图片太大,会造成OOM,可以对图片进行压缩

  @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        if (requestCode == REQUEST_CAMERA && resultCode == RESULT_OK) {
            Uri uri = FileProvider.getUriForFile(this, "com.xiaoyehai.takephoto.fileprovider", mFile);

            //content://com.xiaoyehai.takephoto.fileprovider/images/1533796434054.jpg
            Log.e("xyh", "onActivityResult: " + uri);

            //如果图片太大,可以对图片进行压缩
            Bitmap bitmap = BitmapUtils.compressBitmap(mFile.getAbsolutePath(), mImageView.getMeasuredWidth(), mImageView.getMeasuredHeight());
            mImageView.setImageBitmap(bitmap);

            //在手机相册中显示刚拍摄的图片
            Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
            Uri contentUri = Uri.fromFile(mFile);
            mediaScanIntent.setData(contentUri);
            sendBroadcast(mediaScanIntent);
        }
    }

BitmapUtils

package com.xiaoyehai.takephoto;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.util.Base64;

import java.io.ByteArrayOutputStream;

/**
 * Created by xiaoyehai on 2018/3/2 0002.
 */

public class BitmapUtils {

    /**
     * Base64字符串转换成图片
     *
     * @param string
     * @return
     */
    public static Bitmap stringtoBitmap(String string) {
        Bitmap bitmap = null;
        try {
            byte[] bitmapArray;
            bitmapArray = Base64.decode(string, Base64.DEFAULT);
            bitmap = BitmapFactory.decodeByteArray(bitmapArray, 0, bitmapArray.length);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return bitmap;
    }

    /**
     * 图片转换成Base64字符串
     *
     * @param bitmap
     * @return
     */
    public static String bitmaptoString(Bitmap bitmap) {
        //将Bitmap转换成字符串
        String string = null;
        ByteArrayOutputStream bStream = new ByteArrayOutputStream();
        bitmap.compress(Bitmap.CompressFormat.PNG, 100, bStream);
        byte[] bytes = bStream.toByteArray();
        string = Base64.encodeToString(bytes, Base64.DEFAULT);
        return string;
    }

    /**
     * 对资源文件中的图片进行压缩
     *
     * @param context    上下文对象
     * @param imageId    压缩图片的id
     * @param destWidth  显示图片的控件宽度
     * @param destHeight 显示图片的控件高度
     * @return
     */
    public static Bitmap compressBitmap(Context context, int imageId, int destWidth, int destHeight) {
        //创建一个可选项对象,该对象用于配置图片的处理参数
        BitmapFactory.Options options = new BitmapFactory.Options();

        //第一次采样,该属性设置为true只会加载图片的边框进来,并不会加载图片具体的像素点,也就是说不会把图片加载到内存中
        options.inJustDecodeBounds = true;

        //加载图片,该方法只是从图片文件中读取图片的宽和高信息,而没有真正的加载到内存中
        BitmapFactory.decodeResource(context.getResources(), imageId, options);

        //获取图片的宽和高
        int imageWidth = options.outWidth;
        int imageHeight = options.outHeight;

        //定义缩放比例
        int sampleSize = 1;
        while (imageWidth / sampleSize > destHeight || imageHeight / sampleSize > destWidth) {
            //如果宽高的任意一方的缩放比例没有达到要求,都继续增大缩放比例
            //sampleSize应该为2的n次幂,如果给sampleSize设置的数字不是2的n次幂,那么系统会就近取值
            sampleSize *= 2;
        }

        //第二次采样,使用缩放比例进行缩放加载图,加载器就会返回图片了
        options.inJustDecodeBounds = false;

        //设置压缩比
        options.inSampleSize = sampleSize;

        /**
         * inPreferredConfig设置图片的质量:
         * ARGB_8888:默认的图片质量,也是最好的质量,32位,4个字节
         * ARGB_4444:是ARGB_8888占用内存的一半,但质量比较低,16位,不推荐使用
         * RGB_565:不带透明度,是ARGB_8888占用内存的一半,质量不错,16位,推荐使用
         * ALPHA_8:
         */
        //设置图片质量
        options.inPreferredConfig = Bitmap.Config.RGB_565;

        //返回压缩后的图片
        Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), imageId, options);

        //Log.i("info", "压缩后图片的大小:" + bitmap.getByteCount());
        return bitmap;
    }

    /**
     * 对内存卡中的图片进行压缩
     *
     * @param path       图片路径
     * @param destWidth  显示图片的控件宽度
     * @param destHeight 显示图片的控件高度
     * @return
     */
    public static Bitmap compressBitmap(String path, int destWidth, int destHeight) {
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(path, options);
        int imageWidth = options.outWidth;
        int imageHeight = options.outHeight;
        int sampleSize = 1;
        while (imageWidth / sampleSize > destHeight || imageHeight / sampleSize > destWidth) {
            sampleSize *= 2;
        }

        options.inJustDecodeBounds = false;
        options.inSampleSize = sampleSize;
        options.inPreferredConfig = Bitmap.Config.RGB_565;
        Bitmap bitmap = BitmapFactory.decodeFile(path, options);

        //Log.i("info", "压缩后图片的大小:" + bitmap.getByteCount());
        return bitmap;
    }

    /**
     * 通过网络请求返回的字节数据进行二次采样并返回bitmap
     *
     * @param bytes
     * @param destWidth  显示图片的控件宽度
     * @param destHeight 显示图片的控件高度
     * @return
     */
    public static Bitmap compressBitmap(byte[] bytes, int destWidth, int destHeight) {
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeByteArray(bytes, 0, bytes.length, options);
        int imageWidth = options.outWidth;
        int imageHeight = options.outHeight;
        int sampleSize = 1;
        while (imageWidth / sampleSize > destHeight || imageHeight / sampleSize > destWidth) {
            sampleSize *= 2;
        }

        options.inJustDecodeBounds = false;
        options.inSampleSize = sampleSize;
        options.inPreferredConfig = Bitmap.Config.RGB_565;
        Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length, options);

        // Log.i("info", "压缩后图片的大小:" + bitmap.getByteCount());
        return bitmap;
    }
}

猜你喜欢

转载自blog.csdn.net/qq_36699930/article/details/81536695