Android拍照功能相信都不陌生。这篇文章总结下Android拍照功能的具体知识。


分两种场景:

  • 场景一,拍照然后显示照片在页面;
  • 场景二,拍照然后将照片以文件方式存储。

简单的拍照功能

原理:调用系统的Camera应用生成一张照片

1.要求系统支持拍照功能

... >    "android.hardware.camera"                  android:required="true" />    ...

在AndroidManifest.xml中注册相机权限,这样在支持拍照功能的手机上允许安装应用。如果手机系统不支持拍照功能,则不允许安装应用程序。

2.使用Camera App拍照

static final int REQUEST_IMAGE_CAPTURE = 1;private void dispatchTakePictureIntent() {    Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);    if (takePictureIntent.resolveActivity(getPackageManager()) != null) {        startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE);    }}

方法中用到一个resolveActivity(),该方法返回intent可以操作的第一个Activity。使用该方法可以防止Intent启动过程出现空指针异常

3.处理缩略图

Camera应用程序将照片作为小的位图发送到onActivityResult()的Intent中,key值为data。

 @Override    protected void onActivityResult(int requestCode, int resultCode, Intent data) {        if(requestCode == REQUEST_IMAGE_CAPTURE){            Bundle bundle = data.getExtras();            Bitmap bitmap = (Bitmap) bundle.get("data");            mImageView.setImageBitmap(bitmap);        }    }

上面介绍了使用Android系统的Camera应用生成一个缩略图,如果我们希望获取完整的拍照图片,我们需要以File的形式来存储拍摄照片。

保存完整的拍照图片

保存拍照图片为完整的文件,关键是得到图片的Uri,然后用Intent调起拍照的时候将文件的Uri放入MediaStore.EXTRA_OUTPUT参数中。

1.首先添加文件的写入权限

...>    "android.permission.WRITE_EXTERNAL_STORAGE" />    ...

2.创建文件目录

String mCurrentPhotoPath;private File createImageFile() throws IOException {    // Create an image file name    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());    String imageFileName = "JPEG_" + timeStamp + "_";    File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);    File image = File.createTempFile(        imageFileName,  /* prefix */        ".jpg",         /* suffix */        storageDir      /* directory */    );    // Save a file: path for use with ACTION_VIEW intents    mCurrentPhotoPath = image.getAbsolutePath();    return image;}

getExternalFilesDir(Environment.DIRECTORY_PICTURES)方法获取到的文件目录是在:

Android/data/包名/files/Pictures

当然,你可以将图片放到任何位置,比如SDCard中、Public目录中等等。该方法可以作为一个文件目录创建的参考。

3.拍照操作

static final int REQUEST_TAKE_PHOTO = 2;private void dispatchTakePictureFileIntent() {        Uri photoURI;        Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);        if (takePictureIntent.resolveActivity(getPackageManager()) != null) {            File photoFile = null;            try {                photoFile = createImageFile();                if (photoFile != null) {                    //根据不同的系统版本处理文件目录访问的方式                    if(Build.VERSION.SDK_INT >= 24){                        photoURI = FileProvider.getUriForFile(this,                                "com.camerademo.fileprovider",                                photoFile);                    }else {                        photoURI = Uri.fromFile(photoFile);                    }                    takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);                    startActivityForResult(takePictureIntent, REQUEST_TAKE_PHOTO);                }            } catch (IOException e) {                e.printStackTrace();            }        }    }

因为Android7.0以后改变了文件的Uri操作方式。Android7.0需要通过FileProvider来获取文件的Uri路径。

Android7.0及以上获取到的Uri:file:// URIAndroid7.0以前获取到的Uri:content:// URI

FileProvider配置

因此,我们需要在AndroidMainfest.xml里面指定我们的FileProvider:

   ...   "android.support.v4.content.FileProvider"        android:authorities="com.camerademo.fileprovider"        android:exported="false"        android:grantUriPermissions="true">        "android.support.FILE_PROVIDER_PATHS"            android:resource="@xml/file_paths">        ...

注意:这里的authorities就是上面代码FileProvider.getUriForFile()中的对应的名称。resource下面的file_paths是在values->xml目录下的file_paths文件

<?xml version="1.0" encoding="utf-8"?><paths xmlns:android="http://schemas.android.com/apk/res/android">    <external-path name="my_images" path="Android/data/com.camerademo/files/Pictures" />paths>

这里可以指定path的目录,也可以将path目录滞空。


图片压缩

使用相机拍照生成的照片往往好几兆,当我们显示在页面上的时候根本不需要显示像素这么高的图片,不仅会增大我们应用的内存消耗,有时候甚至会导致应用内存泄漏,因此在显示照片的时候我们都要做图片的压缩处理。

private void setPic() {    // Get the dimensions of the View    int targetW = mImageView.getWidth();    int targetH = mImageView.getHeight();    // Get the dimensions of the bitmap    BitmapFactory.Options bmOptions = new BitmapFactory.Options();    bmOptions.inJustDecodeBounds = true;    BitmapFactory.decodeFile(mCurrentPhotoPath, bmOptions);    int photoW = bmOptions.outWidth;    int photoH = bmOptions.outHeight;    Log.e("wj","压缩前的图片宽高:" + photoW + "*" + photoH);    // Determine how much to scale down the image    int scaleFactor = Math.min(photoW/targetW, photoH/targetH);    // Decode the image file into a Bitmap sized to fill the View    bmOptions.inJustDecodeBounds = false;    bmOptions.inSampleSize = scaleFactor;    bmOptions.inPurgeable = true;    Bitmap bitmap = BitmapFactory.decodeFile(mCurrentPhotoPath, bmOptions);    Log.e("wj","压缩后的图片宽高:" + bmOptions.outWidth + "*" + bmOptions.outHeight);    mImageView.setImageBitmap(bitmap);}

我们看下图片在处理前和处理后,大小区别

09-05 14:20:49.972 18911-18911/com.camerademo E/wj: 压缩前的图片宽高:1840*326409-05 14:20:50.192 18911-18911/com.camerademo E/wj: 压缩后的图片宽高:460*816

图片压缩也是我们常用方法之一。该方法可以当做图片压缩的一个处理的参考。


至此拍照功能介绍结束。

最后我们考虑这样一个问题,我们在上面存储拍照后的图片使用的文件路径是getExternalFilesDir(),该路径只能在我们应用内访问,系统不会将该图片添加到系统的Media Provider中,也就是说我们无法在其他应用中通过Media Scanner功能发现该照片。
要想让其他应用可以通过媒体搜索发现我们拍照生成照片,我们需要发送一个系统广播,通知系统将我们的照片路径下的照片文件添加到系统的Media Provider 的database中。

private void galleryAddPic() {    Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);    File f = new File(mCurrentPhotoPath);    Uri contentUri = Uri.fromFile(f);    mediaScanIntent.setData(contentUri);    this.sendBroadcast(mediaScanIntent);}

欢迎大家留言交流。

更多相关文章

  1. 一款常用的 Squid 日志分析工具
  2. GitHub 标星 8K+!一款开源替代 ls 的工具你值得拥有!
  3. RHEL 6 下 DHCP+TFTP+FTP+PXE+Kickstart 实现无人值守安装
  4. Linux 环境下实战 Rsync 备份工具及配置 rsync+inotify 实时同步
  5. Android(安卓)GPIO LED 驱动与HAL分析
  6. Android(安卓)动态加载布局
  7. Android通过AIDL接口实现跨进程通讯
  8. Android第三方log库——Logger
  9. Android(安卓)逐帧动画

随机推荐

  1. Android拓展系列(9)--Android视频录制scr
  2. android绘制几何图形
  3. EditText 光标不显示问题
  4. android拍照上传的效果是如何实现的
  5. Android开发问题 - Some projects cannot
  6. Android(安卓)生成不同服务器配置,不同APP
  7. Android 异常处理:java.lang.IllegalArgum
  8. JNI之------C调用java接口
  9. 查询遇到双引号
  10. Android(安卓)Studio进行APP图标更改的两