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

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.拍照时,将拍得的照片先保存在本地,通过修改之前的代码如下:

Uri p_w_picpathUri = Uri.fromFile(new File(Environment.getExternalStorageDirectory(),"p_w_picpath.jpg"));

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

openCameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, p_w_picpathUri);


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

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



   2.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()+"/p_w_picpath.jpg");  Bitmap newBitmap = zoomBitmap(bitmap, bitmap.getWidth() / SCALE, bitmap.getHeight() / SCALE);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     //由于Bitmap内存占用较大,这里需要回收内存,否则会报out of memory异常                bitmap.recycle();                //将处理过的图片显示在界面上,并保存到本地                iv_p_w_picpath.setImageBitmap(newBitmap);                savePhotoToSDCard(newBitmap, Environment.getExternalStorageDirectory().getAbsolutePath(), String.valueOf(System.currentTimeMillis()));                break;            default:                break;            }        }    }

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


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


1.打开相册选取图片:

Intent openAlbumIntent = new Intent(Intent.ACTION_GET_CONTENT);                    openAlbumIntent.setType("p_w_picpath/*");                    startActivityForResult(openAlbumIntent, CHOOSE_PICTURE);


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

@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_p_w_picpath.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("p_w_picpath/*");  // 开启Pictures画面Type设定为p_w_picpath        intent.setAction(Intent.ACTION_GET_CONTENT); //使用Intent.ACTION_GET_CONTENT这个Action                                                                                                                                                                                                                                                                                                                                                                                                                //实现对图片的裁剪,必须要设置图片的属性和大小        intent.setType("p_w_picpath/*");  //获取任意图片类型        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;}

保存图片到SD卡

/**Save p_w_picpath 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 p_w_picpathsList; //各个图片的路径                                                                                                         public ImagesListAdapter(Context context, List p_w_picpathsList) {        this.context = context;        this.p_w_picpathsList = p_w_picpathsList;    }                                                                                                         /**得到总的数量**/    @Override    public int getCount() {        // TODO Auto-generated method stub        return p_w_picpathsList.size();    }    /**根据ListView位置返回View**/    @Override    public Object getItem(int position) {        return p_w_picpathsList.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_p_w_picpath_item, null);        }                                                                                                                 ImageView img = (ImageView) convertView.findViewById(R.id.newwrite_et_content_p_w_picpath);  //图片列表项                                                                                                                 if(!p_w_picpathsList.get(position).equals("")) {//没有图片            Bitmap tempBitmap = BitmapFactory.decodeFile(p_w_picpathsList.get(position));//根据路径显示对应的图片            Bitmap newBitmap = new ImageManager(context).zoomBitmap(tempBitmap, tempBitmap.getWidth(), tempBitmap.getHeight() / 3);            img.setImageBitmap(newBitmap);//对应的行上显示对应的图片        }        return convertView;    }}

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



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










更多相关文章

  1. Android(安卓)fragment 获取id,findViewById为空
  2. NDK学习笔记(十四) 使用AVILib+window创建一个AVI视频播放器
  3. Android上关于view的事件问题
  4. Android(安卓)创建AlertDislog时要小心哦
  5. GitHub上受欢迎的Android(安卓)UI 库2
  6. Android之Looper、Handler、Message、MessageQueue应用篇
  7. Android(安卓)SurviceView的触控和轨迹球事件 .
  8. Android(安卓)图片的读取与写入
  9. Android(安卓)Studio获取SHA1(获取SHA1的通用方法)

随机推荐

  1. (Android(安卓)studio)关于drawable文件夹
  2. Android浏览器打开本地app前端同学的两种
  3. 在 Android(安卓)11 上使用第三方 SDK 向
  4. Pro Android(安卓)4 第一章 Android(安卓
  5. 搭建Android生产环境傻瓜教程(一)Ubuntu系
  6. 以人为本 | Android(安卓)11 的消息通知
  7. Android热修复之Tinker接入流程
  8. 隐私策略更新 | Android(安卓)11 应用兼
  9. 安卓阵营猛兽多,摩托Droid 3酷了一夏!
  10. 协程 Flow 最佳实践 | 基于 Android(安卓