【移动开发】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,  0 0 , 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,如需转载请自行联系原作者




相关文章
|
存储 数据可视化 Android开发
Android 实现拍照功能,并将图片保存到本地存储
Android 实现拍照功能,并将图片保存到本地存储
695 0
|
存储 XML API
Android 拍摄照片后返回缩略图的两种方法详解
Android 拍摄照片后返回缩略图的两种方法详解
88 0
|
存储 XML API
Android调用相机拍照录视频录音以及存储,7.0以上及以下都可使用。
Android调用相机拍照录视频录音以及存储,7.0以上及以下都可使用。
348 0
|
Android开发
保存图片到相册/图库___Android基础篇
保存图片到相册/图库___Android基础篇
667 1
保存图片到相册/图库___Android基础篇
|
Android开发
android 拍照,图库,相册,上传
android 拍照,图库,相册,上传
|
Android开发 数据格式 XML
基于Android TextureView与SurfaceTexture实现相机Camera拍照预览与保存照片
基于Android TextureView与SurfaceTexture实现相机Camera拍照预览与保存照片 写一个简单的例子,实现一个常见的开发功能:拍照功能。
2113 0
|
Android开发 Java Maven
android 图片选择,可选择图片,视频,音频,文件,方便扩展
AndroidFilePicker android file picker ,you can choose image,video,file,etc.. Image selector library for Android. Support single choice、multi-choice、cropping image and preview image. Qui
2334 0
下一篇
无影云桌面