美文网首页Android 图片处理第一行代码学习
Android拍照或从相册选择图片并裁剪

Android拍照或从相册选择图片并裁剪

作者: 冰鉴IT | 来源:发表于2016-10-29 14:04 被阅读4414次

    今天看《第一行代码》上面关于拍照和从相册选取图片那一部分,发现始终出不来效果,所以搜索其他资料学习一下相关知识,写一个简单的Demo。

    一、 拍照选择图片

    1、使用隐式Intent启动相机

    //构建隐式Intent
    Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    //调用系统相机
    startActivityForResult(intent, 1);
    

    2、处理相机拍照返回的结果

    //用户点击了取消
    if(data == null){
        return;
    }else{
        Bundle extras = data.getExtras();
        if (extras != null){
            //获得拍的照片
            Bitmap bm = extras.getParcelable("data");
        }
    }
    

    二、 从图库选择图片

    1、构建内容选择隐式Intent

    Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
    

    2、设置内容类型为图片

    intent.setType("image/*");
    

    3、启动图片选择

    startActivityForResult(intent, 2);
    

    4、处理图片选择结果

    if (data == null){
        return;
    }else{
        //用户从图库选择图片后会返回所选图片的Uri
        Uri uri;
        //获取到用户所选图片的Uri
        uri = data.getData();
    }
    

    三、 裁剪选择的图片

    从相机拍照得到的是Bitmap类型,所以我们需要先将其转化为文件Uri以供裁剪。同时我们还要顺便将相机拍的照片保存到本地。

    /**
     * 将Bitmap写入SD卡中的一个文件中,并返回写入文件的Uri
     * @param bm
     * @param dirPath
     * @return
     */
    private Uri saveBitmap(Bitmap bm, String dirPath) {
        //新建文件夹用于存放裁剪后的图片
        File tmpDir = new File(Environment.getExternalStorageDirectory() + "/" + dirPath);
        if (!tmpDir.exists()){
            tmpDir.mkdir();
        }
    
        //新建文件存储裁剪后的图片
        File img = new File(tmpDir.getAbsolutePath() + "/avator.png");
        try {
            //打开文件输出流
            FileOutputStream fos = new FileOutputStream(img);
            //将bitmap压缩后写入输出流(参数依次为图片格式、图片质量和输出流)
            bm.compress(Bitmap.CompressFormat.PNG, 85, fos);
            //刷新输出流
            fos.flush();
            //关闭输出流
            fos.close();
            //返回File类型的Uri
            return Uri.fromFile(img);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            return null;
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }
    

    从图库选择的图片返回的是content类型的Uri,我们需要转化为文件类型的Uri才能进行裁剪。

    /**
    * 将content类型的Uri转化为文件类型的Uri
    * @param uri
    * @return
    */
    private Uri convertUri(Uri uri){
       InputStream is;
       try {
           //Uri ----> InputStream
           is = getContentResolver().openInputStream(uri);
           //InputStream ----> Bitmap
           Bitmap bm = BitmapFactory.decodeStream(is);
           //关闭流
           is.close();
           return saveBitmap(bm, "temp");
       } catch (FileNotFoundException e) {
           e.printStackTrace();
           return null;
       } catch (IOException e) {
           e.printStackTrace();
           return null;
       }
    
    }
    

    下面便是设置裁剪的参数,用隐式Intent方式启动裁剪程序

    /**
     * 通过Uri传递图像信息以供裁剪
     * @param uri
     */
    private void startImageZoom(Uri uri){
        //构建隐式Intent来启动裁剪程序
        Intent intent = new Intent("com.android.camera.action.CROP");
        //设置数据uri和类型为图片类型
        intent.setDataAndType(uri, "image/*");
        //显示View为可裁剪的
        intent.putExtra("crop", true);
        //裁剪的宽高的比例为1:1
        intent.putExtra("aspectX", 1);
        intent.putExtra("aspectY", 1);
        //输出图片的宽高均为150
        intent.putExtra("outputX", 150);
        intent.putExtra("outputY", 150);
        //裁剪之后的数据是通过Intent返回
        intent.putExtra("return-data", true);
        startActivityForResult(intent, CROP_CODE);
    }
    

    下面是完整的布局文件和java文件


    activity_main.xml文件

    <?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">
    
        <ImageView
            android:id="@+id/show_image"
            android:layout_width="match_parent"
            android:layout_height="300dp"/>
        <Button
            android:id="@+id/choose_camera"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="摄像头"/>
        <Button
            android:id="@+id/choose_gallery"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="相册"/>
    </LinearLayout>
    

    MainActivity.java文件

    public class MainActivity extends AppCompatActivity implements View.OnClickListener {
        //用于展示选择的图片
        private ImageView mImageView;
    
        private static final int CAMERA_CODE = 1;
        private static final int GALLERY_CODE = 2;
        private static final int CROP_CODE = 3;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            initView();
        }
    
        private void initView() {
            mImageView = (ImageView) findViewById(R.id.show_image);
            Button chooseCamera = (Button) findViewById(R.id.choose_camera);
            chooseCamera.setOnClickListener(this);
            Button chooseGallery = (Button) findViewById(R.id.choose_gallery);
            chooseGallery.setOnClickListener(this);
        }
    
        @Override
        public void onClick(View view) {
            switch (view.getId()){
                case R.id.choose_camera:
                    //拍照选择
                    chooseFromCamera();
                    break;
                case R.id.choose_gallery:
                    //从相册选取
                    chooseFromGallery();
                    break;
                default:
                    break;
            }
        }
    
        /**
         * 拍照选择图片
         */
        private void chooseFromCamera() {
            //构建隐式Intent
            Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
            //调用系统相机
            startActivityForResult(intent, CAMERA_CODE);
        }
    
        /**
         * 从相册选择图片
         */
        private void chooseFromGallery() {
            //构建一个内容选择的Intent
            Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
            //设置选择类型为图片类型
            intent.setType("image/*");
            //打开图片选择
            startActivityForResult(intent, GALLERY_CODE);
        }
    
        @Override
        protected void onActivityResult(int requestCode, int resultCode, Intent data) {
            switch (requestCode){
                case CAMERA_CODE:
                    //用户点击了取消
                    if(data == null){
                        return;
                    }else{
                        Bundle extras = data.getExtras();
                        if (extras != null){
                            //获得拍的照片
                            Bitmap bm = extras.getParcelable("data");
                            //将Bitmap转化为uri
                            Uri uri = saveBitmap(bm, "temp");
                            //启动图像裁剪
                            startImageZoom(uri);
                        }
                    }
                    break;
                case GALLERY_CODE:
                    if (data == null){
                        return;
                    }else{
                        //用户从图库选择图片后会返回所选图片的Uri
                        Uri uri;
                        //获取到用户所选图片的Uri
                        uri = data.getData();
                        //返回的Uri为content类型的Uri,不能进行复制等操作,需要转换为文件Uri
                        uri = convertUri(uri);
                        startImageZoom(uri);
                    }
                    break;
                case CROP_CODE:
                    if (data == null){
                        return;
                    }else{
                        Bundle extras = data.getExtras();
                        if (extras != null){
                            //获取到裁剪后的图像
                            Bitmap bm = extras.getParcelable("data");
                            mImageView.setImageBitmap(bm);
                        }
                    }
                    break;
                default:
                    break;
            }
        }
    
        /**
         * 将content类型的Uri转化为文件类型的Uri
         * @param uri
         * @return
         */
        private Uri convertUri(Uri uri){
            InputStream is;
            try {
                //Uri ----> InputStream
                is = getContentResolver().openInputStream(uri);
                //InputStream ----> Bitmap
                Bitmap bm = BitmapFactory.decodeStream(is);
                //关闭流
                is.close();
                return saveBitmap(bm, "temp");
            } catch (FileNotFoundException e) {
                e.printStackTrace();
                return null;
            } catch (IOException e) {
                e.printStackTrace();
                return null;
            }
        }
    
        /**
         * 将Bitmap写入SD卡中的一个文件中,并返回写入文件的Uri
         * @param bm
         * @param dirPath
         * @return
         */
        private Uri saveBitmap(Bitmap bm, String dirPath) {
            //新建文件夹用于存放裁剪后的图片
            File tmpDir = new File(Environment.getExternalStorageDirectory() + "/" + dirPath);
            if (!tmpDir.exists()){
                tmpDir.mkdir();
            }
    
            //新建文件存储裁剪后的图片
            File img = new File(tmpDir.getAbsolutePath() + "/avator.png");
            try {
                //打开文件输出流
                FileOutputStream fos = new FileOutputStream(img);
                //将bitmap压缩后写入输出流(参数依次为图片格式、图片质量和输出流)
                bm.compress(Bitmap.CompressFormat.PNG, 85, fos);
                //刷新输出流
                fos.flush();
                //关闭输出流
                fos.close();
                //返回File类型的Uri
                return Uri.fromFile(img);
            } catch (FileNotFoundException e) {
                e.printStackTrace();
                return null;
            } catch (IOException e) {
                e.printStackTrace();
                return null;
            }
    
        }
    
        /**
         * 通过Uri传递图像信息以供裁剪
         * @param uri
         */
        private void startImageZoom(Uri uri){
            //构建隐式Intent来启动裁剪程序
            Intent intent = new Intent("com.android.camera.action.CROP");
            //设置数据uri和类型为图片类型
            intent.setDataAndType(uri, "image/*");
            //显示View为可裁剪的
            intent.putExtra("crop", true);
            //裁剪的宽高的比例为1:1
            intent.putExtra("aspectX", 1);
            intent.putExtra("aspectY", 1);
            //输出图片的宽高均为150
            intent.putExtra("outputX", 150);
            intent.putExtra("outputY", 150);
            //裁剪之后的数据是通过Intent返回
            intent.putExtra("return-data", true);
            startActivityForResult(intent, CROP_CODE);
        }
    }
    

    注:最后还需要在AndroidManifest文件中加入存储卡读写权限

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

    相关文章

      网友评论

      • 长大要当科学家_:6.0之后一定要做版本判断和运行时权限处理,否则直接崩溃,针对权限处理请求我准备尝试封装一个工具类和大家交流学习一下😁
      • 当个海贼多好:跳转不到剪辑功能 怎么办
      • 盼盼_d7c2:您好,我想问一下为什么照片这么模糊?
        bahelan0525:@盼盼_d7c2 已经完美解决
      • Endeav0r:666
        冰鉴IT: @Endeav0r 谢谢认同
      • dc36981ec4e1:权限都不做判断
        冰鉴IT: @7c66af8d1a56 如果系统是在Android6.0以下,只需要在AndroidManifest.xml文件中添加存储卡读写权限,如果要适配6.0,需要用到运行时权限申请,可以看看我的其他博客有介绍😁
        7c66af8d1a56:@冰鉴IT 那怎么设置权限呢
        冰鉴IT: @双开门 当时还没有做Android6.0权限适配😁
      • Leo724651142:怎么将最后显示的图片裁剪成圆形?能贴一下代码吗?
        Leo724651142:@冰鉴IT 恩恩,谢谢
        冰鉴IT: @e8943869101b 你看一下这篇文章http://www.jianshu.com/p/6b5eef0f6f3d
        冰鉴IT: @e8943869101b 这个要用到自定义view来处理吧,目前我还没做
      • eiun:不支持多选的的吧,每次只能选一张
        冰鉴IT:@eiun 嗯嗯,因为是选择作为头像,只是单选

      本文标题:Android拍照或从相册选择图片并裁剪

      本文链接:https://www.haomeiwen.com/subject/ijkyuttx.html