Android 拍照、从相册选取照片以及裁剪

4,023 阅读3分钟
原文链接: www.jianshu.com

经常需要用到这些功能,但是每次都去网上找源码,发现都存在各种各样的问题,于是花了一些时间写了一个,记下来,避免每次用的时候去网上一顿搜索,浪费时间。

拍照

    /**
     * 拍照
     */
    private void takePhoto() {
        //创建File对象,用于存储拍照后的图片
        //将此图片存储于SD卡的根目录下
        File outputImage = new File(Environment.getExternalStorageDirectory(),
                "tem.jpg");
        try {
            if (outputImage.exists()) {
                outputImage.delete();
            }
            outputImage.createNewFile();
        } catch (IOException e) {
            e.printStackTrace();
        }
        //将File对象转换成Uri对象
        //Uri表标识着图片的地址
        imageUri = Uri.fromFile(outputImage);
/**
 * 解决三星手机拍照通过imguri获取图片为空的bug
 */  
 PreferenceUtil.write(getApplicationContext(),"filepath",outputImage.getAbsolutePath());

        if (state.equals(Environment.MEDIA_MOUNTED)) {
            Intent getImageByCamera = new Intent("android.media.action.IMAGE_CAPTURE");
            getImageByCamera.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
            startActivityForResult(getImageByCamera, TAKE_PHOTO);
        } else {
            Toast.makeText(getApplicationContext(), "请确认已经插入SD卡", Toast.LENGTH_LONG).show();
        }
    }

从相册选取照片

        /**
         * 选择图片
         */
        private void selectPhoto() {
            Intent intent = new Intent(Intent.ACTION_PICK);
            intent.setType("image/*");//相片类型
            startActivityForResult(intent, PICTURE_CAPTURE);
        }

裁剪图片

        /*
         * 图片裁剪
         */
        private void startPhotoZoom(Uri uri, int i) {
            if (uri == null) {
                Toast.makeText(getApplicationContext(), "选择图片出错!", Toast.LENGTH_SHORT).show();
            }
            Intent intent = new Intent("com.android.camera.action.CROP");
            intent.setDataAndType(uri, "image/*");
            // 设置裁剪
            intent.putExtra("crop", "true");
            // aspectX aspectY 是宽高的比例
            intent.putExtra("aspectX", 1);
            intent.putExtra("aspectY", 1);
            // outputX outputY 是裁剪图片宽高
            intent.putExtra("outputX", 600);
            intent.putExtra("outputY", 600);
            //如果为true,则通过 Bitmap bmap = data.getParcelableExtra("data")取出数据
            intent.putExtra("return-data", false);
            intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
            startActivityForResult(intent, i);
        }
    }

通过Uri获取Bitmap

        /**
         * 通过uri获取bitmap
         */
        private Bitmap getBitmapFromUri(Uri uri) {
            try {
                // 读取uri所在的图片
                Bitmap bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), uri);
                return bitmap;
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
        }

完整代码


imageUri的作用是传递图片地址。

PreferenceUtil.write(getApplicationContext(),"filepath",outputImage.getAbsolutePath());用来把拍照获得图片路径保存到shareprefrence中,解决三星手机拍照完,通过imguri获取图片为空的bug。
PreferenceUtil是自己封装的shareprefrence,使用的时候换成自己的。

package org.raphets.takephoto;
import android.content.Intent;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.media.ExifInterface;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.os.PersistableBundle;
import android.provider.MediaStore;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.Toast;
import java.io.File;
import java.io.IOException;
public class MainActivity extends AppCompatActivity {
    private static final String TAG = MainActivity.class.getSimpleName();
    private Button btnTake;
    private Button btnSelect;
    private ImageView imageView;
    private String state;
    private Uri imageUri;
    private static final int TAKE_PHOTO = 1;//从相机选择
    private static final int PICTURE_CAPTURE = 2;//从相册选择
    private static final int ZOOM_AFTER_TAKE_PHOTO = 3;//从相机选择后截图
    private static final int ZOOM_AFTER_PICTURE_CAPTURE = 4;//从照片选择后截图
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        imageView = (ImageView) findViewById(R.id.imageView);
        btnTake = (Button) findViewById(R.id.btn_takephoto);
        btnSelect = (Button) findViewById(R.id.btn_xiangce);
        //存储介质
        state = Environment.getExternalStorageState();
        addListener();
    }
    /**
     * 添加监听器
     */
    private void addListener() {
        btnTake.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                takePhoto();
            }
        });
        btnSelect.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                selectPhoto();
            }
        });
    }
    /**
     * 选择图片
     */
    private void selectPhoto() {
        Intent intent = new Intent(Intent.ACTION_PICK);
        intent.setType("image/*");//相片类型
        startActivityForResult(intent, PICTURE_CAPTURE);
    }
    /**
     * 拍照
     */
    private void takePhoto() {
        //创建File对象,用于存储拍照后的图片
        //将此图片存储于SD卡的根目录下
        File outputImage = new File(Environment.getExternalStorageDirectory(),
                "tem.jpg");
        try {
            if (outputImage.exists()) {
                outputImage.delete();
            }
            outputImage.createNewFile();
        } catch (IOException e) {
            e.printStackTrace();
        }
        //将File对象转换成Uri对象
        //Uri表标识着图片的地址
        imageUri = Uri.fromFile(outputImage);
        PreferenceUtil.write(getApplicationContext(),"filepath",outputImage.getAbsolutePath());
        if (state.equals(Environment.MEDIA_MOUNTED)) {
            Intent getImageByCamera = new Intent("android.media.action.IMAGE_CAPTURE");
            getImageByCamera.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
            startActivityForResult(getImageByCamera, TAKE_PHOTO);
        } else {
            Toast.makeText(getApplicationContext(), "请确认已经插入SD卡", Toast.LENGTH_LONG).show();
        }
    }
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        Log.d(TAG,"onActivityResult requestCode:"+requestCode+" resultCode:"+resultCode+" data:"+data);
        String filepath;
        if (resultCode == RESULT_OK) {
            switch (requestCode) {
                case TAKE_PHOTO:
                    filepath = PreferenceUtil.readString(getApplicationContext(), "filepath");
                    imageUri = Uri.fromFile(new File(filepath));
                    startPhotoZoom(imageUri, ZOOM_AFTER_TAKE_PHOTO);
                    break;
                case PICTURE_CAPTURE:
                    imageUri = data.getData();
                    if (imageUri != null) {
                        startPhotoZoom(imageUri, ZOOM_AFTER_PICTURE_CAPTURE);
                    }
                    break;
                case ZOOM_AFTER_TAKE_PHOTO:
                    // 拿到照相截取后的剪切数据
                    //Bitmap bmap = data.getParcelableExtra("data");
                    filepath = PreferenceUtil.readString(getApplicationContext(), "filepath");
                    imageUri = Uri.fromFile(new File(filepath));
                    if (imageUri != null) {
                        Bitmap bitmap = getBitmapFromUri(imageUri);
                        imageView.setImageBitmap(bitmap);
                    }
                    break;
                case ZOOM_AFTER_PICTURE_CAPTURE:
                    // 拿到从相册选择截取后的剪切数据
                    if (imageUri != null) {
                        Bitmap bitmap = getBitmapFromUri(imageUri);
                        imageView.setImageBitmap(bitmap);
                    }
                    break;
                default:
                    break;
            }
        }
    }
    /**
     * 通过uri获取bitmap
     */
    private Bitmap getBitmapFromUri(Uri uri) {
        try {
            // 读取uri所在的图片
            Bitmap bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), uri);
            return bitmap;
        } catch (Exception e) {
            Log.e(TAG, e.getMessage());
            Log.e(TAG, "目录为:" + uri);
            e.printStackTrace();
            return null;
        }
    }
    /*
     * 图片裁剪
     */
    private void startPhotoZoom(Uri uri, int i) {
        Log.d(TAG,"startPhotoZoom uri:"+uri);
        if (uri == null) {
            Toast.makeText(getApplicationContext(), "选择图片出错!", Toast.LENGTH_SHORT).show();
        }
        Intent intent = new Intent("com.android.camera.action.CROP");
        intent.setDataAndType(uri, "image/*");
        // 设置裁剪
        intent.putExtra("crop", "true");
        // aspectX aspectY 是宽高的比例
        intent.putExtra("aspectX", 1);
        intent.putExtra("aspectY", 1);
        // outputX outputY 是裁剪图片宽高
        intent.putExtra("outputX", 600);
        intent.putExtra("outputY", 600);
        //如果为true,则通过 Bitmap bmap = data.getParcelableExtra("data")取出数据
        intent.putExtra("return-data", false);
        intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
        startActivityForResult(intent, i);
    }
}
1.注意在mianfest文件中添加读写文件权限
2.裁剪方法中intent.putExtra("return-data", false)最好为false,如果为true,大多数没问题,但是有的时候数据太大,会报错。如果为true,在activityResult中可以通过Bitmap bmap = intent.getParcelableExtra("data")获取数据
3.有的三星手机存在问题,在onActivityResult()中获得imguri为空,主要是三星手机拍完照屏幕会旋转几次,屏幕旋转导致imguri为空。解决办法:可以将imguri存入到shareprefrence中,然后在onActivityResult中获取一下。