【移动开发】Android相机、相册获取图片显示并保存到SD卡-阿里云开发者社区

开发者社区> 技术小胖子> 正文

【移动开发】Android相机、相册获取图片显示并保存到SD卡

简介:
+关注继续查看

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

1
2
Intent openCameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(openCameraIntent, TAKE_PICTURE);

    在onActivityResult方法里通过IntentgetData方法获取的数据转换成bitmap并显示在界面上,有时候会有取不到数据,或者显示的bitmap会非常小,如果将bitmap保存到sd卡后会发现,图片的分辨率很低,并且图片大小也是经过压缩的,不管将相机的像素设置多高,最后通过这种方式返回的bitmap总是经过压缩了的。如果想获得理想的照片大小和分辨率改如何处理呢?

    大家都知道,现在手机像素少则500W800W,多则4KW(某亚),就拿常见的800W像素的相机拍出来的照片来说,分辨率大概在3200*2400左右,照片大小在2M左右。试想一下,在Android系统中bitmap占用4个字节,3200*2400*4=?,结果大家自己算算,如果为了一张图片,耗用这么大的内存,肯定是不合理的,并且,官方文档中有说明,Android系统分配给每个应用的最大内存是16M,所以,系统为了防止应用内存占用过大,对于在应用内通过相机拍摄的图片最终返回来的结果进行了压缩,压缩后的图片变得很小,通过之前说的getData的方式只能满足比如显示个头像这样的需求。

    如果要显示大图,就会出现模糊的情况。那如何获取清晰的大图呢?我的解决思路如下:

   1.拍照时,将拍得的照片先保存在本地,通过修改之前的代码如下:

1
Uri imageUri = Uri.fromFile(new File(Environment.getExternalStorageDirectory(),"image.jpg"));

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

1
openCameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);


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

1
2
3
4
5
6
7
8
9
10
11
/**拍照获取相片**/
    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);  //用户点击了从相机获取
    }



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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@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;
            }
        }
    }

由于Androidbitmap分配的内存最大不超过8M,所以对使用完的较大的Bitmap要释放内存,调用其recycle()方法即可。然后将缩小后的bitmap显示在界面上或保存到SD卡,至于之前保存的原图,可以删掉,也可以放在那,下次拍照时,这张原图就会被下一张照片覆盖,所以SD卡上使用只有一张临时图片,占用也不是很大。


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


1.打开相册选取图片:

1
2
3
Intent openAlbumIntent = new Intent(Intent.ACTION_GET_CONTENT);
                    openAlbumIntent.setType("image/*");
                    startActivityForResult(openAlbumIntent, CHOOSE_PICTURE);


2.在onActivity方法中处理获取到的图片,思路和之前类似

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
@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(),代码如下:

1
2
3
4
5
6
7
8
9
10
11
/** 缩放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, 00, w, h, matrix, true);
        return newbmp;
    }


至此,功能已实现。


   下面是本人项目中所实现的功能在这里总结一下:


   1.要想对从图库选择的照片进行裁剪:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**从相册获取图片**/
    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;
    }

   调用此方法处:

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

ActivityForResult中和上面一样


   2.项目中要拍多少张 就保存多少张,显示图片列表:

   A.将拍照的照片或者图库选择的图片,保存到本地

创建图片名,不能重复哦!

1
2
3
4
5
6
7
8
9
/** 为图片创建不同的名称用于保存,避免覆盖 **/
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;
}

保存图片到SD卡

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
/**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卡上的图片名获取到集合中,在自定义的适配器中根据名字加载图片喽!

   自定义图片列表适配器代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
/**
 * 插入图片列表适配器
 * @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;
    }
}

   ok!完了,在显示图片的时候大家可能会碰到OOM(OutOfMemory)异常,在下一篇博客中我会具体解决了一下~



Demo已上传!下载附件即可!


     本文转自zhf651555765 51CTO博客,原文链接:http://blog.51cto.com/smallwoniu/1248695,如需转载请自行联系原作者






版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
用599块钱小米手机开发一款Tiktok是怎样一种体验?
1.准备工作 我们将用到以下全栈技术搭建tiktok 2.浏览器远程登陆VScode创建reactjs项目 3.创建firebase项目 4.在tiktok>src>App位置输入以下代码 5.firebase实时数据库实时更新tiktok数
16 0
微服务架构谈系列(1):切忌匆忙服务化(下)
微服务架构谈系列(1):切忌匆忙服务化(下)
3 0
谷歌云双飞微软VSCode和谷歌Android Studio云端远程开发环境云开发自己的爱啪啪APP
1.创建vscode和Android studio谷歌云远程开发环境准备工作 2.创建vscode和Android studio谷歌云远程开发环境的系统配置必要条件 3.开始安装 4.进入>创建vscode和Android studio谷歌云远程开发环境
7 0
编码 5 分钟,命名 2 小时?Java 开发都需要参考的一份命名规范!
简洁清爽的代码风格应该是大多数工程师所期待的。在工作中笔者常常因为起名字而纠结,命名已经成为我工作中的拦路虎,夸张点可以说是编程5分钟,命名两小时!
17 0
万字长文总结,带你重温 Java 基础
万字长文总结,带你重温 Java 基础
9 0
H5 data-*容易忽略的问题
H5 data-*容易忽略的问题
6 0
【Python 入门指北】No 2. 玩转 Pycharm
【Python 入门指北】No 2. 玩转 Pycharm
7 0
深入死磕 Java IO 流
深入死磕 Java IO 流
6 0
分辨率和刷新率达到峰值 手机屏幕参数PK还能玩什么?
分辨率和刷新率达到峰值 手机屏幕参数PK还能玩什么?
8 0
21119
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
《2021云上架构与运维峰会演讲合集》
立即下载
《零基础CSS入门教程》
立即下载
《零基础HTML入门教程》
立即下载