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;
    }
}
时间: 2024-11-06 13:30:56

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

ios中摄像头/相册获取图片,压缩图片,上传服务器方法总结

相册 iphone的相册包含摄像头胶卷+用户计算机同步的部分照片.用户可以通过UIImagePickerController类提供的交互对话框来从相册中选择图像.但是,注意:相册中的图片机器路径无法直接从应用程序访问,只能通过终端用户去选择和使用相册图片 应用程序包 应用程序包可能会将图像与可执行程序.Info.plist文件和其他资源一同存储.我们可以通过本地文件路径来读取这些基于包的图像并在应用程序中显示它们. 沙盒 借助沙盒,我们可以把图片存储到Documents.Library.tmp文

Android—将Bitmap图片保存到SD卡目录下或者指定目录

直接上代码就不废话啦 一:保存到SD卡下 [java] view plain copy File file = new File(Environment.getExternalStorageDirectory(), System.currentTimeMillis()+".jpg"); try { out = new FileOutputStream(file); btImage.compress(Bitmap.CompressFormat.JPEG, 90, out); System

Android开发调试日志工具类[支持保存到SD卡]

直接上代码: package com.example.callstatus; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; import java.io.StringWriter; import java.net.UnknownHostException; import java.text.SimpleDateFormat; impor

Android开发 将数据保存到SD卡

前言: 使用Activity的openFileOutput()方法保存文件,文件是存放在手机空间上,一般手机的存储空间不是很大,存放些小文件还行,如果要存放像视频这样的大文件,是不可行的.对于像视频这样的大文件,我们可以把它存放在SDCard. SDCard是干什么的?你可以把它看作是移动硬盘或U盘. 在模拟器中使用SDCard,你需要先创建一张SDCard卡(当然不是真的SDCard,只是镜像文件).创建SDCard可以在Eclipse创建模拟器时随同创建,也可以使用DOS命令进行创建,如下:

android文件保存到sd卡和内存

1.保存到SD卡中: 获取SDCard的状态: Environment.getExtemalStorageState() Environment.MEDIA_MOUNTED手机装有SDCard,并且可以进行读写 获取SDCard的目录:Environment.getExtemalStorageDirectory() //============================================= File saveFile=new File("/sdcard/zhzhg.txt&q

从相机相册获取图片裁剪后用于评论晒图或更换背景图

这是我人生中写的第一篇博客,是否要纪念一下这一刻(2016.09.01 16:52).其实关于写博客,老早就有这种写法,首先觉得他能够帮我总结我学到的和用过的技术,其次还能帮助那些和我有一样需求的人,我也是很开心啊,但是至于为什么现在才写第一篇,首先没有想好写什么,然后前段时间也确实比较忙.是不是那些来观技术的人已经想骂人了啊...啊哦!原谅我第一次写博客的激动心情吧! 废话不多说,开始我们的问题吧,首先因为我做了两次关于调用相机和相册获取图片的功能,觉得很有必要总结一下,下面我将从这两个功能出

Android从相册获取图片

应用中经常会有去相册获取图片的需求,每次总是会忘,现在这做个记录,以便以后查阅. 从应用去相册获取图片主要有以下几个步骤: 1.设置intent调用系统相册 2.进入相册选取图片,如果相册没有满意的图片,可以使用相机照相获取,最后返回数据到应用 3.应用获取图片后,调用裁剪程序对图片进行裁剪 4.返回裁剪的图片并显示出来 一.设置intent调用系统相册,并进入相册选取图片 /** * 调用相册 */ private void goAlbums() { Intent intent = new I

android 从相册获取图片

从相册获取图片 在android应用中是运用得很多的一项技术了 其实很简单 使用intent就可以了 刚敲了一个dome  睡觉之前还是分享一下把 1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 2 xmlns:tools="http://schemas.android.com/tools" 3 android:layout_width="match

iOS 使用AFN 进行单图和多图上传 摄像头/相册获取图片,压缩图片

图片上传时必要将图片进行压缩,不然会上传失败 首先是同系统相册选择图片和视频.iOS系统自带有UIImagePickerController,可以选择或拍摄图片视频,但是最大的问题是只支持单选,由于项目要求需要支持多选,只能自己自定义.获取系统图库的框架有两个,一个是ALAssetsLibrary,兼容iOS低版本,但是在iOS9中是不建议使用的:另一个是PHAsset,但最低要求iOS8以上.兼容到iOS7,可以选择了ALAssetsLibrary 现在我们先说选择一张图的情况 一.单图多图上