android调用照相机拿到原图

时间:2021-08-24 20:27:50

转自:原地址
本文主要讲解的是保存拍照后的图片到系统默认文件夹下,并在日后使用系统自带 图库 应用时可以方便的看到。
本文主要内容:
1、调用系统相机拍照并存储;
2、处理大图片防止内存溢出(OOM);
3、获取系统默认照片路径并保存;
4、刷新系统相册,解决图库不能立刻显示最新照片的问题;
5、图片裁剪;
6、图片大小及尺寸调整。

随着《证件照片助手》http://www.eoemarket.com/soft/165173.html 这一工具类应用的开发和上线,个人的代码能力又得到了一些提高,积累了一些经验。现将用到的难点和一些小技巧分享给大家,望各位前辈批评指正!
调用系统相机,不用多说,网上已经有很多的例子了。当然,为了完整性,做再次说明:
首先,在要调用相机的代码位置,写上以下内容:

Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT,Uri.fromFile(new File(AppConf.BUFFER_FILE)));
startActivityForResult(intent, requestCode_camera);

这里有几点需要注意:
1、MediaStore.ACTION_IMAGE_CAPTURE和MediaStore.EXTRA_OUTPUT是MediaStore类的常量,这个类是安卓系统提供的多媒体相关的类;
2、AppConf.BUFFER_FILE是调用系统相机拍照成功并经过用户确认后生成的照片的存储路径。当然,你也可以直接把这个路径定义到系统默认相册路径上。这里是为了应用需要,使用了临时的目录来存放照片。有关系统默认相册路径和后续处理,请直接往后看;
3、requestCode_camera是为了标识从系统相册返回的。
然后,在回调方法onActivityResult()中,处理系统相机返回的数据。

    if (requestCode == requestCode_camera) {
        try {
           BitmapFactory.Options options = new BitmapFactory.Options();
            options.inTempStorage = new byte[1024 * 1024 * 2];
            options.inSampleSize = 2;
            Bitmap bitmap = BitmapFactory.decodeFile(AppConf.BUFFER_FILE,
                    options);
            if (bitmap != null) {
                ResizeActivity.bitmap = bitmap;
                startActivity(new Intent(MenuActivity.this,
                        ResizeActivity.class));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

这里,紫色文字部分是防止图片过大溢出的处理,使用了2MB的大小操作,这样避免了因图片过大造成OOM。灰色文字部分是本应用需要,可以忽略。
至此,我们就可以拿到用户刚刚拍照的照片的Bitmap对象了。
说到系统相册的默认路径,估计大家想到的应该是那个叫做“DCIM”的文件夹。这个一点都没错,我们可以直接用”/mnt/sdcard/DCIM”。可是,还有很多手机的路径是“/storage/sdcard0/DCIM”,特别是在4.1及以上的系统中。为了统一,可以用下面的方法来获取路径:

Environment.getExternalStorageDirectory() + File.separator + Environment.DIRECTORY_DCIM

这样就能获取系统的照片文件夹了。
下面我们就将刚刚生成好的Bitmap对象保存到这个目录下:

public static void save(Bitmap bitmap, Context context, Activity activity) {
     // 调整到100*130
    Matrix matrix = new Matrix();
    matrix.postScale(100f / bitmap.getWidth(), 130f / bitmap.getHeight());
    bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(),
            bitmap.getHeight(), matrix, true);
   int option = 100;
    FileOutputStream photo = null;
    File file = new File(AppConf.PHOTO_WRITE_PATH);
    file.mkdir();
    String str = null;
    Date date = null;
    SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss");
    date = new Date(System.currentTimeMillis());
    str = format.format(date);
    fileName = AppConf.PHOTO_WRITE_PATH + File.separator
            + "ht_choosephoto_" + str + ".jpg";
    try {
        photo = new FileOutputStream(fileName);
        bitmap.compress(Bitmap.CompressFormat.JPEG, option, photo);
        photo.flush();
        MediaStore.Images.Media.insertImage(context.getContentResolver(),
                fileName, new File(fileName).getName(),
                new File(fileName).getName());
        Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
        Uri uri = Uri.fromFile(new File(fileName));
        intent.setData(uri);
        activity.sendBroadcast(intent);
        while (new File(fileName).length() / 1024 >= 19) {
            option -= 10;
            photo = new FileOutputStream(fileName);
            bitmap.compress(Bitmap.CompressFormat.JPEG, option, photo);
            photo.flush();
        }
        ResizeActivity.mhandler.sendEmptyMessage(0);
        bitmap.recycle();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

这个方法的功能有三个:
1、调整照片尺寸以符合2寸电子照片标准;
2、限制图片大小20KB以内;
3、保存图片;
4、刷新系统相册。
如果在程序中不去刷新系统相册的话,刚刚保存的图片是无法及时在图库应用中显示的。可使用快图这样的软件却能看得到,可是,我们不能指望每个用户都去安装第三方的图片浏览器。为了使程序更加好用,添加刷新的操作还是很有必要的。
这里我们做一个延伸思考:可以发现,刷新系统相册的操作实际上就是发送了系统内置的广播。也就是说,我们可以虚假发送系统的广播(尚未验证可用性)。所以在我们以后每次要发送这样的广播的时候,务必不要发错了,以免造成一些很奇怪的状况。
关于图片裁剪,首先看一下效果图:

Android开发 拍照、图片及保存照片技巧

效果是这样的:中间的调整部分实际上是一个ImageView,这个ImageView上面放置了一个只有白色边框的透明度图片,ImageView四周是由4个带有灰色背景的ImageView包裹的。这样一来,用户就可以清楚的分辨出白框内的图像就是裁剪后要保存的图片了。
思路是这样的:首先对整个屏幕进行截图,然后获取中间ImageView的坐标及控件大小,最后只要保存这个ImageView的截图就OK了。
具体实现是这样的:

int width = cutWindow.getRight() - cutWindow.getLeft();
int height = cutWindow.getBottom() - cutWindow.getTop();
// 截屏
View view = getWindow().getDecorView();
Display display = ResizeActivity.this.getWindowManager().getDefaultDisplay();
view.layout(0, 0, display.getWidth(), display.getHeight());
view.setDrawingCacheEnabled(true);
Bitmap tempbmp = Bitmap.createBitmap(view.getDrawingCache());
// 裁剪
Bitmap bmp = Bitmap.createBitmap(tempbmp, display.getWidth()/ 2 - width / 2 + 2,display.getHeight() / 2 - height/ 2 + 2, width - 4, height - 4);

对于Bitmap对象bmp的处理还需注意:由于裁剪后得到的是ImageView的截图,因此四周的白框仍然是有的。我们需要减去1-2个像素来去掉四周的白框。