拍照、相册及裁剪的终极实现(一)——拍照及裁剪功能实现

本文详细介绍如何在Android中实现拍照及裁剪功能,包括基础讲解、仅拍照、拍照及裁剪初步实现等内容。

这里有几篇写的比较好的文章,虽然不是终极方案,但也能我起到了启蒙作用,链接如下:

1、《 如何使用Android MediaStore裁剪大图片》

2、《Android大图片裁剪终极解决方案(上:原理分析)》 及其他文章底部链接中的上、中、下三篇

3、《Android 大图片裁切时遇到的问题》  这篇文章写的极好,分析问题非常出众

4、《Android大图片裁剪终极解决方案 原理分析》这个大哥分析的也极好,不过他的终极解决方案在一些手机上行不通


一、基础讲解

一般而言,使用拍照和裁剪功能基本上都是使用系统自带的Intent来实现,看起来直接调别人的写好的东东会比较容易,但真正用起来确发现根本不是那回事,找不到源码是个最大的问题,话说我至今都没找到源码的位置,有哪位同学知道源码位置的留言下哦。

言规正转,我们要将别人写好的Intent,那肯定要使用隐式Intent的方式来启用了,这里使用的是匹配Action:MediaStore.ACTION_IMAGE_CAPTURE,具体的值是:

(MediaStore.Java

拍照:(MediaStore.ACTION_IMAGE_CAPTURE)

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. public static final java.lang.String ACTION_IMAGE_CAPTURE = "android.media.action.IMAGE_CAPTURE";  

启用相册:(Intent.ACTION_GET_CONTENT)

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. public static final java.lang.String ACTION_GET_CONTENT = "android.intent.action.GET_CONTENT";  
启用裁剪:
[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. com.android.camera.action.CROP  

有关启用隐式Intent和显式Intent的方式参看这两篇文章: 《 intent详解(一)》 《intent详解(二)》
要使用相应的功能是通过Intent.PutExtra("key",value);来实现的,对应的KEY和Valude

Exta Options Table for image/* crop:

附加选项数据类型描述
cropString发送裁剪信号
aspectXintX方向上的比例
aspectYintY方向上的比例
outputXint裁剪区的宽
outputYint裁剪区的高
scaleboolean是否保留比例
return-databoolean是否将数据保留在Bitmap中返回
dataParcelable相应的Bitmap数据
circleCropString圆形裁剪区域?
MediaStore.EXTRA_OUTPUT ("output")URI将URI指向相应的file:///...,详见代码示例
outputFormatString输出格式,一般设为Bitmap格式:Bitmap.CompressFormat.JPEG.toString()
noFaceDetectionboolean是否取消人脸识别功能

这些参数是可以选择性使用的,想使用哪个功能就直接写上,不使用就不写,下面我们就一个个试试。这里我会始终将return_data设为false,因为如何设为TRUE,那对于有些手机而言,只会得到缩略图,所以这里一致用URI来输出。而URI在有些手机上也是存在问题的,这里先不谈,先用URI,因为这是网上一致认为的终极方案………………

写在前面:

由于我们会读写SD卡,所以先在AndroidManifest.xml中添加上SD卡的读写权限:

[html]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />  
  2. <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />  

二、仅拍照

(1)、核心代码:

我们仅仅使用拍照的功能,而且将其输出到URI中,代码如下:

启用拍照Activity

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. private static final int RESULT_CAMERA_ONLY = 100;  

先构造一个temp.jpg的URI

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. String path = getSDCardPath();  
  2. File file = new File(path + "/temp.jpg");  
  3. imageUri = Uri.fromFile(file);  

然后通过MediaStore.ACTION_IMAGE_CAPTURE来隐式调起拍照Intent;

然后将返回值设为false,并将MediaStore.EXTRA_OUTPU输出指定为 imageUri;

然后将URI的输出格式设为JPEG,这是因为我们在构造URI时,使用的JPG格式:temp.jpg

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. Intent intent = null;  
  2. intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);  
  3. intent.putExtra("return-data"false);  
  4. intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);  
  5. intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());  
  6. intent.putExtra("noFaceDetection"true);  
  7. startActivityForResult(intent, RESULT_CAMERA_ONLY);  

大家可能对return-data和MediaStore.EXTRA_OUTPUT的作用有些迷糊;

return-data:是将结果保存在data中返回,在onActivityResult中,直接调用intent.getdata()就可以获取值了,这里设为fase,就是不让它保存在data中

MediaStore.EXTRA_OUTPUT:由于我们不让它保存在Intent的data域中,但我们总要有地方来保存我们的图片啊,这个参数就是转移保存地址的,对应Value中保存的URI就是指定的保存地址。至于这两个参数能不能同时设为输出,这个我也不清楚……

在onActivityResult中接收:

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. protected void onActivityResult(int requestCode, int resultCode, Intent data) {  
  2.     super.onActivityResult(requestCode, resultCode, data);  
  3.     if (resultCode != Activity.RESULT_OK)  
  4.         return;  
  5.     switch (requestCode) {  
  6.         case RESULT_CAMERA_ONLY: {  
  7.             try {  
  8.                 Bitmap bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(imageUri));  
  9.                 mImage.setImageBitmap(bitmap);  
  10.             } catch (Exception e) {  
  11.                 e.printStackTrace();  
  12.             }  
  13.         }  
  14.         break;  
  15.     }  
  16. }  
将接收到的ImageUri解析为Bitmap,因为我们的URI本来就是个Bitmap,然后将其设置到一个ImageView中显示;

但在有的手机中ImageView并不会显示这个Bitmap,而查看根目录下的temp.jpg确实已经生成了。这是为什么?

查看日志,报了个错:

[html]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. Bitmap too large to be uploaded into a texture (3120x4160, max=4096x4096)  
这是因为Bitmap太大了,超出了ImageView的显示范围所致,这里有三种解决办法:

1、强制显示,关闭OpenGL加速(容易导致OOM)
在AndroidManifest.xml中,application标签下添加一个属性:

[html]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. android:hardwareAccelerated="false"  
即:

[html]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. <application  
  2. style="white-space:pre">  </span>……  
  3.     android:hardwareAccelerated="false">  
  4. </application>  
2、将图片缩小

将指定图片缩小SCALE倍的代码如下:

但如果图片足够大,缩小后也不定能显示……

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. private Bitmap setScaleBitmap(Bitmap photo,int SCALE) {  
  2.     if (photo != null) {  
  3.         //为防止原始图片过大导致内存溢出,这里先缩小原图显示,然后释放原始Bitmap占用的内存  
  4.         //这里缩小了1/2,但图片过大时仍然会出现加载不了,但系统中一个BITMAP最大是在10M左右,我们可以根据BITMAP的大小  
  5.         //根据当前的比例缩小,即如果当前是15M,那如果定缩小后是6M,那么SCALE= 15/6  
  6.         Bitmap smallBitmap = zoomBitmap(photo, photo.getWidth() / SCALE, photo.getHeight() / SCALE);  
  7.         //释放原始图片占用的内存,防止out of memory异常发生  
  8.         photo.recycle();  
  9.         return smallBitmap;  
  10.     }  
  11.     return null;  
  12. }  

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. public Bitmap zoomBitmap(Bitmap bitmap, int width, int height) {  
  2.     int w = bitmap.getWidth();  
  3.     int h = bitmap.getHeight();  
  4.     Matrix matrix = new Matrix();  
  5.     float scaleWidth = ((float) width / w);  
  6.     float scaleHeight = ((float) height / h);  
  7.     matrix.postScale(scaleWidth, scaleHeight);// 利用矩阵进行缩放不会造成内存溢出  
  8.     Bitmap newbmp = Bitmap.createBitmap(bitmap, 00, w, h, matrix, true);  
  9.     return newbmp;  
  10. }  

3、分块显示
看这里 《解决:Bitmap too large to be uploaded into a texture exception》

(2)、实例

效果图:
点击按钮调起系统相册拍照,然后显示在ImageView中

    

1、AndroidManifest.xml添加SD卡读写权限

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />  
  2. <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />  
2、主布局

[html]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  2.     xmlns:tools="http://schemas.android.com/tools"  
  3.     android:layout_width="match_parent"  
  4.     android:layout_height="match_parent"  
  5.     android:orientation="vertical"  
  6.     tools:context=".MainActivity">  
  7.   
  8.     <Button  
  9.         android:id="@+id/btn_camera_only"  
  10.         android:layout_width="fill_parent"  
  11.         android:layout_height="wrap_content"  
  12.         android:text="仅拍照"/>  
  13.   
  14.     <ImageView  
  15.         android:id="@+id/image_result"  
  16.         android:layout_width="200dip"  
  17.         android:layout_height="200dip"  
  18.         android:scaleType="centerInside"  
  19.         android:layout_gravity="center_horizontal"/>  
  20.   
  21. </LinearLayout>  
3、主程序(MainActivity.java)
三个变量:

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. private static final int RESULT_CAMERA_ONLY = 100;  
  2. private ImageView mImage;  
  3. private Uri imageUri;  
其中imageUri用来保存拍照后存储的数据;

OnCreate()函数:

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. protected void onCreate(Bundle savedInstanceState) {  
  2.     super.onCreate(savedInstanceState);  
  3.     setContentView(R.layout.activity_main);  
  4.   
  5.     String path = getSDCardPath();  
  6.     File file = new File(path + "/temp.jpg");  
  7.     imageUri = Uri.fromFile(file);  
  8.   
  9.     mImage = (ImageView)findViewById(R.id.image_result);  
  10.     Button btn_take_camera_only = (Button)findViewById(R.id.btn_camera_only);  
  11.     btn_take_camera_only.setOnClickListener(new View.OnClickListener() {  
  12.         @Override  
  13.         public void onClick(View view) {  
  14.             takeCameraOnly();  
  15.         }  
  16.     });  
  17. }  
做了两件事:

第一:初始化imageUri

其中的getSDCardPath()是自己写的函数,下面会给出源码;

第二:在点击按钮时调起相机:

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. private void takeCameraOnly(){  
  2.     Intent intent = null;  
  3.     intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);//action is capture  
  4.     intent.putExtra("return-data"false);  
  5.     intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);  
  6.     intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());  
  7.     intent.putExtra("noFaceDetection"true);  
  8.     startActivityForResult(intent, RESULT_CAMERA_ONLY);  
  9. }  
然后对返回的数据进行处理:

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. protected void onActivityResult(int requestCode, int resultCode, Intent data) {  
  2.     super.onActivityResult(requestCode, resultCode, data);  
  3.     if (resultCode != Activity.RESULT_OK)  
  4.         return;  
  5.     switch (requestCode){  
  6.         case RESULT_CAMERA_ONLY:{  
  7.             try {  
  8.             Bitmap bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(imageUri));  
  9.             mImage.setImageBitmap(bitmap);  
  10.         } catch (Exception e) {  
  11.             e.printStackTrace();  
  12.         }  
  13.     }  
  14.     break;  
  15.   
  16.     }  
  17. }  
其中的获取SD卡路径的代码为:

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. public static String getSDCardPath() {  
  2.     String cmd = "cat /proc/mounts";  
  3.     Runtime run = Runtime.getRuntime();// 返回与当前 Java 应用程序相关的运行时对象  
  4.     try {  
  5.         Process p = run.exec(cmd);// 启动另一个进程来执行命令  
  6.         BufferedInputStream in = new BufferedInputStream(p.getInputStream());  
  7.         BufferedReader inBr = new BufferedReader(new InputStreamReader(in));  
  8.   
  9.         String lineStr;  
  10.         while ((lineStr = inBr.readLine()) != null) {  
  11.             // 获得命令执行后在控制台的输出信息  
  12.             if (lineStr.contains("sdcard")  
  13.                     && lineStr.contains(".android_secure")) {  
  14.                 String[] strArray = lineStr.split(" ");  
  15.                 if (strArray != null && strArray.length >= 5) {  
  16.                     String result = strArray[1].replace("/.android_secure",  
  17.                             "");  
  18.                     return result;  
  19.                 }  
  20.             }  
  21.             // 检查命令是否执行失败。  
  22.             if (p.waitFor() != 0 && p.exitValue() == 1) {  
  23.                 // p.exitValue()==0表示正常结束,1:非正常结束  
  24.             }  
  25.         }  
  26.         inBr.close();  
  27.         in.close();  
  28.     } catch (Exception e) {  
  29.   
  30.         return Environment.getExternalStorageDirectory().getPath();  
  31.     }  
  32.   
  33.     return Environment.getExternalStorageDirectory().getPath();  
  34. }  
源码会在文章底部给出

三、拍照及裁剪初步实现

效果图:

点击按钮弹出拍照Intent,然后进入裁剪Intent,最后将裁剪后的图显示在ImageView中;

                 (一)                                (二)

    

                 (三)                                 (四)

  



在第一节说过,上面的几个参数是可以随意匹配使用的,那我们直接加上裁剪选项,并将结果存在imageUri中,看看会怎样。

那我们在上面的纯拍照的代码中加以修改,在点击按钮时,强制拍照Intent,然后结果自己加入裁剪Intent中,结果同样存在imageUri中;

OnCreate()中:

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. protected void onCreate(Bundle savedInstanceState) {  
  2.     super.onCreate(savedInstanceState);  
  3.     setContentView(R.layout.activity_main);  
  4.   
  5.     String path = getSDCardPath();  
  6.     File file = new File(path + "/temp.jpg");  
  7.     imageUri = Uri.fromFile(file);  
  8.   
  9.     mImage = (ImageView) findViewById(R.id.image_result);  
  10.     Button btn_take_camera_only = (Button) findViewById(R.id.btn_camera_only);  
  11.     btn_take_camera_only.setOnClickListener(new View.OnClickListener() {  
  12.         @Override  
  13.         public void onClick(View view) {  
  14.             takeCameraCropUri();  
  15.         }  
  16.     });  
  17. }  
开启拍照及裁剪功能:
[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. private void takeCameraCropUri() {  
  2.     Intent intent = null;  
  3.     intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);//action is capture  
  4.     intent.putExtra("crop""true");  
  5.     intent.putExtra("aspectX"1);  
  6.     intent.putExtra("aspectY"1);  
  7.     intent.putExtra("outputX"1000);  
  8.     intent.putExtra("outputY"1000);  
  9.     intent.putExtra("scale"true);  
  10.     intent.putExtra("return-data"false);  
  11.     intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);  
  12.     intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());  
  13.     intent.putExtra("noFaceDetection"true);  
  14.     startActivityForResult(intent, RESULT_CAMERA_CROP_URI);  
  15. }  
结果接收:

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. protected void onActivityResult(int requestCode, int resultCode, Intent data) {  
  2.     super.onActivityResult(requestCode, resultCode, data);  
  3.     if (resultCode != Activity.RESULT_OK)  
  4.         return;  
  5.     switch (requestCode) {  
  6.         case RESULT_CAMERA_CROP_URI: {  
  7.             try {  
  8.                 Bitmap bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(imageUri));  
  9.                 //出不来  
  10.                 mImage.setImageBitmap(bitmap);  
  11.             } catch (Exception e) {  
  12.                 e.printStackTrace();  
  13.             }  
  14.         }  
  15.         break;  
  16.     }  
  17. }  
一切看起来那么美好,但一运行会发现——拍照完成之后崩了!!!!!!

为什么会这样!!!!我也不知道怎么找源码,只能靠猜了……个人认为,我们把最终结果存在了imageUri中,但从拍照Intent到裁剪Intent之间结果是怎么传的呢?估计是通过Intent中的data来传的,当数据过大,即超过1M时就崩了!!!!

所以我们要想办法分离这个过程,将中间数据先暂存一下,然后再调裁剪Intent,最后把结果存在Uri中。

基于这个想法,下面看看具体实现过程:

四、拍照及裁剪终极方案

首先声明两个Uri,一个保存拍照的结果,一个保存裁剪的结果:

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. private static final int RESULT_CAMERA_ONLY = 100;  
  2. private static final int RESULT_CAMERA_CROP_PATH_RESULT = 301;  
  3. private ImageView mImage;  
  4. private Uri imageUri;  
  5. private Uri imageCropUri;  
然后在OnCreate()函数中初始化:
[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. protected void onCreate(Bundle savedInstanceState) {  
  2.     super.onCreate(savedInstanceState);  
  3.     setContentView(R.layout.activity_main);  
  4.   
  5.     String path = getSDCardPath();  
  6.     File file = new File(path + "/temp.jpg");  
  7.     imageUri = Uri.fromFile(file);  
  8.     File cropFile = new File(getSDCardPath() + "/temp_crop.jpg");  
  9.     imageCropUri = Uri.fromFile(cropFile);  
  10.   
  11.     mImage = (ImageView) findViewById(R.id.image_result);  
  12.     Button btn_take_camera_only = (Button) findViewById(R.id.btn_camera_only);  
  13.     btn_take_camera_only.setOnClickListener(new View.OnClickListener() {  
  14.         @Override  
  15.         public void onClick(View view) {  
  16.             takeCameraOnly();  
  17.         }  
  18.     });  
  19. }  
点击按钮时仅调起拍照Intent,将结果存在imageUri中

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. private void takeCameraOnly() {  
  2.     Intent intent = null;  
  3.     intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);//action is capture  
  4.     intent.putExtra("return-data"false);  
  5.     intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);  
  6.     intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());  
  7.     intent.putExtra("noFaceDetection"true);  
  8.     startActivityForResult(intent, RESULT_CAMERA_ONLY);  
  9. }  
在接收到返回的消息后,调起裁剪Intent:

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. protected void onActivityResult(int requestCode, int resultCode, Intent data) {  
  2.     super.onActivityResult(requestCode, resultCode, data);  
  3.     if (resultCode != Activity.RESULT_OK)  
  4.         return;  
  5.     switch (requestCode) {  
  6.         case RESULT_CAMERA_ONLY: {  
  7.             cropImg(imageUri);  
  8.         }  
  9.         break;  
  10.     }  
  11. }  
其中cropImg(Uri uri)是调起裁剪Intent,代码如下:

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. public void cropImg(Uri uri) {  
  2.     Intent intent = new Intent("com.android.camera.action.CROP");  
  3.     intent.setDataAndType(uri, "image/*");  
  4.     intent.putExtra("crop""true");  
  5.     intent.putExtra("aspectX"1);  
  6.     intent.putExtra("aspectY"1);  
  7.     intent.putExtra("outputX"700);  
  8.     intent.putExtra("outputY"700);  
  9.     intent.putExtra("return-data"false);  
  10.     intent.putExtra(MediaStore.EXTRA_OUTPUT, imageCropUri);  
  11.     intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());  
  12.     intent.putExtra("noFaceDetection"true);  
  13.     startActivityForResult(intent, RESULT_CAMERA_CROP_PATH_RESULT);  
  14. }  
将传进去的uri做为源数据,即被裁剪的数据,将结果存储在imageCropUri中;

然后接收返回的结果:

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. protected void onActivityResult(int requestCode, int resultCode, Intent data) {  
  2.     super.onActivityResult(requestCode, resultCode, data);  
  3.     if (resultCode != Activity.RESULT_OK)  
  4.         return;  
  5.     switch (requestCode) {  
  6.         case RESULT_CAMERA_ONLY: {  
  7.             cropImg(imageUri);  
  8.         }  
  9.         break;  
  10.         case RESULT_CAMERA_CROP_PATH_RESULT: {  
  11.             Bundle extras = data.getExtras();  
  12.             if (extras != null) {  
  13.                 try {  
  14.                     Bitmap bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(imageCropUri));  
  15.                     mImage.setImageBitmap(bitmap);  
  16.                 } catch (Exception e) {  
  17.                     e.printStackTrace();  
  18.                 }  
  19.             }  
  20.         }  
  21.         break;  
  22.     }  
  23. }  
将存储裁剪结果的imageCropUri,转换为Bitmap,然后在ImageView中显示;
完整的代码如下:

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. public class MainActivity extends Activity {  
  2.     private static final int RESULT_CAMERA_ONLY = 100;  
  3.     private static final int RESULT_CAMERA_CROP_PATH_RESULT = 301;  
  4.     private ImageView mImage;  
  5.     private Uri imageUri;  
  6.     private Uri imageCropUri;  
  7.   
  8.     @Override  
  9.     protected void onCreate(Bundle savedInstanceState) {  
  10.         super.onCreate(savedInstanceState);  
  11.         setContentView(R.layout.activity_main);  
  12.   
  13.         String path = getSDCardPath();  
  14.         File file = new File(path + "/temp.jpg");  
  15.         imageUri = Uri.fromFile(file);  
  16.         File cropFile = new File(getSDCardPath() + "/temp_crop.jpg");  
  17.         imageCropUri = Uri.fromFile(cropFile);  
  18.   
  19.         mImage = (ImageView) findViewById(R.id.image_result);  
  20.         Button btn_take_camera_only = (Button) findViewById(R.id.btn_camera_only);  
  21.         btn_take_camera_only.setOnClickListener(new View.OnClickListener() {  
  22.             @Override  
  23.             public void onClick(View view) {  
  24.                 takeCameraOnly();  
  25.             }  
  26.         });  
  27.     }  
  28.   
  29.   
  30.     private void takeCameraOnly() {  
  31.         Intent intent = null;  
  32.         intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);//action is capture  
  33.         intent.putExtra("return-data"false);  
  34.         intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);  
  35.         intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());  
  36.         intent.putExtra("noFaceDetection"true);  
  37.         startActivityForResult(intent, RESULT_CAMERA_ONLY);  
  38.     }  
  39.   
  40.     public void cropImg(Uri uri) {  
  41.         Intent intent = new Intent("com.android.camera.action.CROP");  
  42.         intent.setDataAndType(uri, "image/*");  
  43.         intent.putExtra("crop""true");  
  44.         intent.putExtra("aspectX"1);  
  45.         intent.putExtra("aspectY"1);  
  46.         intent.putExtra("outputX"700);  
  47.         intent.putExtra("outputY"700);  
  48.         intent.putExtra("return-data"false);  
  49.         intent.putExtra(MediaStore.EXTRA_OUTPUT, imageCropUri);  
  50.         intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());  
  51.         intent.putExtra("noFaceDetection"true);  
  52.         startActivityForResult(intent, RESULT_CAMERA_CROP_PATH_RESULT);  
  53.     }  
  54.   
  55.     @Override  
  56.     protected void onActivityResult(int requestCode, int resultCode, Intent data) {  
  57.         super.onActivityResult(requestCode, resultCode, data);  
  58.         if (resultCode != Activity.RESULT_OK)  
  59.             return;  
  60.         switch (requestCode) {  
  61.             case RESULT_CAMERA_ONLY: {  
  62.                 cropImg(imageUri);  
  63.             }  
  64.             break;  
  65.             case RESULT_CAMERA_CROP_PATH_RESULT: {  
  66.                 Bundle extras = data.getExtras();  
  67.                 if (extras != null) {  
  68.                     try {  
  69.                         Bitmap bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(imageCropUri));  
  70.                         mImage.setImageBitmap(bitmap);  
  71.                     } catch (Exception e) {  
  72.                         e.printStackTrace();  
  73.                     }  
  74.                 }  
  75.             }  
  76.             break;  
  77.         }  
  78.     }  
  79.   
  80.     public static String getSDCardPath() {  
  81.         String cmd = "cat /proc/mounts";  
  82.         Runtime run = Runtime.getRuntime();// 返回与当前 Java 应用程序相关的运行时对象  
  83.         try {  
  84.             Process p = run.exec(cmd);// 启动另一个进程来执行命令  
  85.             BufferedInputStream in = new BufferedInputStream(p.getInputStream());  
  86.             BufferedReader inBr = new BufferedReader(new InputStreamReader(in));  
  87.   
  88.             String lineStr;  
  89.             while ((lineStr = inBr.readLine()) != null) {  
  90.                 // 获得命令执行后在控制台的输出信息  
  91.                 if (lineStr.contains("sdcard")  
  92.                         && lineStr.contains(".android_secure")) {  
  93.                     String[] strArray = lineStr.split(" ");  
  94.                     if (strArray != null && strArray.length >= 5) {  
  95.                         String result = strArray[1].replace("/.android_secure",  
  96.                                 "");  
  97.                         return result;  
  98.                     }  
  99.                 }  
  100.                 // 检查命令是否执行失败。  
  101.                 if (p.waitFor() != 0 && p.exitValue() == 1) {  
  102.                     // p.exitValue()==0表示正常结束,1:非正常结束  
  103.                 }  
  104.             }  
  105.             inBr.close();  
  106.             in.close();  
  107.         } catch (Exception e) {  
  108.   
  109.             return Environment.getExternalStorageDirectory().getPath();  
  110.         }  
  111.   
  112.         return Environment.getExternalStorageDirectory().getPath();  
  113.     }  
  114. }  


到这里,这篇文章就讲完了,写的比较乱,原理应该是讲清楚了,有关从相册选择及裁剪的部分在下篇中讲解。

源码内容:

1、BlogCameraOnly:仅拍照功能

2、BlogCameraCropCrash:第三部分对应的源码,根本起不来裁剪Intent,造成Crash

3、BlogCameraCropFinally:拍照及裁剪的终极方案;

如果本文有帮到你,记得关注哦

源码下载地址:http://download.youkuaiyun.com/detail/harvic880925/8412983

请大家尊重原创者版权,转载请标明出处:http://blog.youkuaiyun.com/harvic880925/article/details/43163175  谢谢。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值