• Android相机、相册获取图片显示(压缩)并保存到SD卡


    做过类似需求的同学都知道,Activity中通过如下代码可以启动相机,然后在重写的onActivityResult方法中可以获取到返回的照片数据:

    Intent openCameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    
    startActivityForResult(openCameraIntent, TAKE_PICTURE);
    在onActivityResult方法里通过Intent的getData方法获取的数据转换成bitmap并显示在界面上,有时候会有取不到数据,或者显示的bitmap会非常小,如果将bitmap保存到sd卡后会发现,图片的分辨率很低,并且图片大小也是经过压缩的,不管将相机的像素设置多高,最后通过这种方式返回的bitmap总是经过压缩了的。如果想获得理想的照片大小和分辨率改如何处理呢?
          大家都知道,现在手机像素少则500W或800W,多则4KW(某亚),就拿常见的800W像素的相机拍出来的照片来说,分辨率大概在3200*2400左右,照片大小在2M左右。试想一下,在Android系统中bitmap占用4个字节,3200*2400*4=?,结果大家自己算算,如果为了一张图片,耗用这么大的内存,肯定是不合理的,并且,官方文档中有说明,Android系统分配给每个应用的最大内存是16M,所以,系统为了防止应用内存占用过大,对于在应用内通过相机拍摄的图片最终返回来的结果进行了压缩,压缩后的图片变得很小,通过之前说的getData的方式只能满足比如显示个头像这样的需求。
         如果要显示大图,就会出现模糊的情况。那如何获取清晰的大图呢?我的解决思路如下:
    1.拍照时,将拍得的照片先保存在本地,通过修改之前的代码如下:
    Uri imageUri = Uri.fromFile(new File(Environment.getExternalStorageDirectory(),"image.jpg"));

    指定照片保存路径(SD卡),image.jpg为一个临时文件,每次拍照后这个图片都会被替换

    openCameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);

    如何调取相机拍照,代码如下:

    /**拍照获取相片**/
    
        private void doTakePhoto() {
    
            Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); //调用系统相机
    
                                        
    
            Uri imageUri = Uri.fromFile(new File(Environment.getExternalStorageDirectory(),"image.jpg"));
    
            //指定照片保存路径(SD卡),image.jpg为一个临时文件,每次拍照后这个图片都会被替换
    
            intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
    
                                        
    
            //直接使用,没有缩小
    
            startActivityForResult(intent, PHOTO_WITH_CAMERA);  //用户点击了从相机获取
    
        }

    在onActivityResult方法中再将图片取出,并经过缩小处理再显示在界面上或上传给服务器(压缩比例自定义)

    @Override
    
        protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    
            super.onActivityResult(requestCode, resultCode, data);
    
            if (resultCode == RESULT_OK) {
    
                switch (requestCode) {
    
                case TAKE_PICTURE:
    
                    //将保存在本地的图片取出并缩小后显示在界面上
    
        Bitmap bitmap = BitmapFactory.decodeFile(Environment.getExternalStorageDirectory()+"/image.jpg");
    
      Bitmap newBitmap = zoomBitmap(bitmap, bitmap.getWidth() / SCALE, bitmap.getHeight() / SCALE);
    
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   
    
           //由于Bitmap内存占用较大,这里需要回收内存,否则会报out of memory异常
    
                    bitmap.recycle();
    
                    //将处理过的图片显示在界面上,并保存到本地
    
                    iv_image.setImageBitmap(newBitmap);
    
                    savePhotoToSDCard(newBitmap, Environment.getExternalStorageDirectory().getAbsolutePath(), String.valueOf(System.currentTimeMillis()));
    
                    break;
    
                default:
    
                    break;
    
                }
    
            }
    
        }
    由于Android给bitmap分配的内存最大不超过8M,所以对使用完的较大的Bitmap要释放内存,调用其recycle()方法即可。然后将缩小后的bitmap显示在界面上或保存到SD卡,至于之前保存的原图,可以删掉,也可以放在那,下次拍照时,这张原图就会被下一张照片覆盖,所以SD卡上使用只有一张临时图片,占用也不是很大。

        以上讲的是拍照获取图片,如果是从相册中获取图片又如何处理呢,我的方法如下:
    1.打开相册选取图片:

    Intent openAlbumIntent = new Intent(Intent.ACTION_GET_CONTENT);
    
                        openAlbumIntent.setType("image/*");
    
                        startActivityForResult(openAlbumIntent, CHOOSE_PICTURE); 
    @Override
    
        protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    
            super.onActivityResult(requestCode, resultCode, data);
    
            if (resultCode == RESULT_OK) {
    
                switch (requestCode) {
    
                case CHOOSE_PICTURE:
    
                    ContentResolver resolver = getContentResolver();
    
                    //照片的原始资源地址
    
                    Uri originalUri = data.getData();
    
                    try {
    
                        //使用ContentProvider通过URI获取原始图片
    
                        Bitmap photo = MediaStore.Images.Media.getBitmap(resolver, originalUri);
    
                        if (photo != null) {
    
                            //为防止原始图片过大导致内存溢出,这里先缩小原图显示,然后释放原始Bitmap占用的内存
    
                            Bitmap smallBitmap = zoomBitmap(photo, photo.getWidth() / SCALE, photo.getHeight() / SCALE);
    
                            //释放原始图片占用的内存,防止out of memory异常发生
    
                            photo.recycle();
    
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   
    
                            iv_image.setImageBitmap(smallBitmap);
    
                        }
    
                    } catch (FileNotFoundException e) {
    
                        e.printStackTrace();
    
                    } catch (IOException e) {
    
                        e.printStackTrace();
    
                    }
    
                    break;
    
                default:
    
                    break;
    
                }
    
            }
    
        }

    还有一个方法 zoomBitmap(),代码如下:

    /** 缩放Bitmap图片 **/
    
        public Bitmap zoomBitmap(Bitmap bitmap, int width, int height) {
    
            int w = bitmap.getWidth();
    
            int h = bitmap.getHeight();
    
            Matrix matrix = new Matrix();
    
            float scaleWidth = ((float) width / w);
    
            float scaleHeight = ((float) height / h);
    
            matrix.postScale(scaleWidth, scaleHeight);// 利用矩阵进行缩放不会造成内存溢出
    
            Bitmap newbmp = Bitmap.createBitmap(bitmap, 0, 0, w, h, matrix, true);
    
            return newbmp;
    
        }

    至此,功能已实现。
        下面是本人项目中所实现的功能在这里总结一下:
        1.要想对从图库选择的照片进行裁剪:

    /**从相册获取图片**/
    
        private Intent doPickPhotoFromGallery() {
    
            Intent intent = new Intent();
    
            intent.setType("image/*");  // 开启Pictures画面Type设定为image
    
            intent.setAction(Intent.ACTION_GET_CONTENT); //使用Intent.ACTION_GET_CONTENT这个Action
    
                                                                                                                                                                                                                                                                                                                                                                                                             
    
            //实现对图片的裁剪,必须要设置图片的属性和大小
    
            intent.setType("image/*");  //获取任意图片类型
    
            intent.putExtra("crop", "true");  //滑动选中图片区域
    
            intent.putExtra("aspectX", 1);  //裁剪框比例1:1
    
            intent.putExtra("aspectY", 1);
    
            intent.putExtra("outputX", 300);  //输出图片大小
    
            intent.putExtra("outputY", 300);
    
            intent.putExtra("return-data", true);  //有返回值
            return intent;
    
        }

    调用此方法处:

    Intent intent2 = doPickPhotoFromGallery();
    
    startActivityForResult(intent2, PHOTO_WITH_DATA);

    ActivityForResult中和上面一样
        2.项目中要拍多少张 就保存多少张,显示图片列表:
        A.将拍照的照片或者图库选择的图片,保存到本地
    创建图片名,不能重复哦!

    /** 为图片创建不同的名称用于保存,避免覆盖 **/
    
    public static String createFileName() {
    
        String fileName = "";
    
        Date date = new Date(System.currentTimeMillis()); // 系统当前时间
    
        SimpleDateFormat dateFormat = new SimpleDateFormat(
    
                "'IMG'_yyyyMMdd_HHmmss");
    
        fileName = dateFormat.format(date) + ".jpg";
    
        return fileName;
    
    }
    /**Save image to the SD card**/
    
        public static void savePhotoToSDCard(String path, String photoName,
    
                Bitmap photoBitmap) {
    
            if (android.os.Environment.getExternalStorageState().equals(
    
                    android.os.Environment.MEDIA_MOUNTED)) {
    
                File dir = new File(path);
    
                if (!dir.exists()) {
    
                    dir.mkdirs();
    
                }
    
                File photoFile = new File(path, photoName); //在指定路径下创建文件
    
                FileOutputStream fileOutputStream = null;
    
                try {
    
                    fileOutputStream = new FileOutputStream(photoFile);
    
                    if (photoBitmap != null) {
    
                        if (photoBitmap.compress(Bitmap.CompressFormat.PNG, 100,
    
                                fileOutputStream)) {
    
                            fileOutputStream.flush();
    
                        }
    
                    }
    
                } catch (FileNotFoundException e) {
    
                    photoFile.delete();
    
                    e.printStackTrace();
    
                } catch (IOException e) {
    
                    photoFile.delete();
    
                    e.printStackTrace();
    
                } finally {
    
                    try {
    
                        fileOutputStream.close();
    
                    } catch (IOException e) {
    
                        e.printStackTrace();
    
                    }
    
                }
    
            }
    
        }

    B.最后就是显示图片列表,因为我们要用到listView,自然少不了Adapter了,我们将保存到SD卡上的图片名获取到集合中,在自定义的适配器中根据名字加载图片喽!
        自定义图片列表适配器代码:

    /**
    
     * 插入图片列表适配器
    
     * @author ZHF
    
     *
    
     */
    
    public class ImagesListAdapter extends BaseAdapter {
    
                                                                                                          
    
        private Context context;
    
        private List<String> imagesList; //各个图片的路径
    
                                                                                                          
    
        public ImagesListAdapter(Context context, List<String> imagesList) {
    
            this.context = context;
    
            this.imagesList = imagesList;
    
        }
    
                                                                                                          
    
        /**得到总的数量**/
    
        @Override
    
        public int getCount() {
    
            // TODO Auto-generated method stub
    
            return imagesList.size();
    
        }
    
        /**根据ListView位置返回View**/
    
        @Override
    
        public Object getItem(int position) {
    
            return imagesList.get(position);  //返回当前选中的item图片的路径
    
        }
    
        /**根据ListView位置得到List中的ID**/
    
        @Override
    
        public long getItemId(int position) {
    
            // TODO Auto-generated method stub
    
            return position;  //返回当前选中项的Id
    
        }
    
        /**根据位置得到View对象**/
    
        @Override
    
        public View getView(int position, View convertView, ViewGroup parent) {
                                                                                   
            if(convertView == null) {
                convertView = LayoutInflater.from(context).inflate(R.layout.newwrite_image_item, null);
            }
            ImageView img = (ImageView) convertView.findViewById(R.id.newwrite_et_content_image);  //图片列表项
            if(!imagesList.get(position).equals("")) {//没有图片
                Bitmap tempBitmap = BitmapFactory.decodeFile(imagesList.get(position));//根据路径显示对应的图片
                Bitmap newBitmap = new ImageManager(context).zoomBitmap(tempBitmap, tempBitmap.getWidth(), tempBitmap.getHeight() / 3);
                img.setImageBitmap(newBitmap);//对应的行上显示对应的图片
    
            }
            return convertView;
        }
    }
  • 相关阅读:
    SDUST OJ 时间类的加、减法赋值运算
    POJ 2823 (滑动窗口)
    POJ 2229 计数DP
    POJ 1995 (快速幂)
    poj 3009 (深搜求最短路)
    C++ 学习笔记之 STL 队列
    C++ 学习笔记之 引用
    Anaconda3使用
    Ubuntu 18.04安装Conda、Jupyter Notebook、Anaconda
    Ubuntu 18.04安装 pyenv、pyenv-virtualenv、virtualenv、Numpy、SciPy、Pillow、Matplotlib
  • 原文地址:https://www.cnblogs.com/a354823200/p/3992992.html
Copyright © 2020-2023  润新知