from:

在Android的开发过程中,我们可能会读取手机里面的照片或者通过相机拍摄获取照片,这是两种常用的获取图片的方式,在做项目过程中也会经常遇到,下面来介绍一下这两种获取方式..

1.从本地相册获取照片:

一般就是写出这个方法

public void openAlbum(OpenAlbumEvent event){
    	Intent intent = new Intent();
    	intent.setType("image/*");   
        intent.setAction(Intent.ACTION_PICK);   
    	this.startActivityForResult(intent,REQUEST_CODE_PICK_IMAGE);
    }

ACTION_GET_CONTENT返回的uri是类似于这样的:content://com.android.providers.media.documents/document/image%3A1666,与低版本不兼容!

KitKat in theory handles these URI's like this:
content://com.android.providers.media.documents/document/image:3951
KitKat in practice gives you permission to this URI:
content://com.android.providers.media.documents/document/image%A3951

So, if you were to decode the URI and try to access the actual image, you get a permissions error, because that's not what you were given permission to access. These permissions are per document and per intent, so just giving your app MANAGE_DOCUMENTS permission isn't going to fly either. This isn't going to be fixed any time soon, and I don't want broken Android behaviour to hold up our release.

from:https://issues.apache.org/jira/browse/CB-5398

参考:http://stackoverflow.com/questions/20067508/get-real-path-from-uri-android-kitkat-new-storage-access-framework/20559175

2.从照相机获取照片

一般就是写出这个方法


1. protected void getImageFromCamera() {  
2.        String state = Environment.getExternalStorageState();  
3. if (state.equals(Environment.MEDIA_MOUNTED)) {  
4. new Intent(MediaStore.ACTION_IMAGE_CAPTURE);     
5.            startActivityForResult(getImageByCamera, REQUEST_CODE_CAPTURE_CAMEIA);  
6.        }  
7. else {  
8. "请确认已经插入SD卡", Toast.LENGTH_LONG).show();  
9.        }  
10.    }


写完这个方法后,一般我们还需要通过响应这个方法去获取图片


1. @Override  
2. protected void onActivityResult(int requestCode, int resultCode, Intent data) {  
3. if (requestCode == REQUEST_CODE_PICK_IMAGE) {             
4.                 Uri uri = data.getData();  
5. //to do find the path of pic  
6.             
7. else if (requestCode == REQUEST_CODE_CAPTURE_CAMEIA ) {             
8.         Uri uri = data.getData();  
9. //to do find the path of pic  
10.  } }



但是,有时候我们会发现用相机拍摄获取照片的时候,得到的 uri 是 null 的,这是因为android把拍摄的图片封装到bundle中传递回来,但是根据不同的机器获得相片的方式不太一样,可能有的相机能够通过  

inten.getData()获取到uri, 然后再根据uri获取数据的路径,在封装成bitmap,但有时候有的相机获取到的是null的,这时候我们该怎么办呢? 其实这时候我们就应该从bundle中获取数据,通过 (Bitmap) bundle.get("data"); 获取到相机图片的bitmap数据。


为了能够同时适应上述两种情况,我们这时候就应该在获取图片时做判断了。我们可以在响应的时候做一个判断:

1. @Override  
2. protected void onActivityResult(int requestCode, int resultCode, Intent data) {  
3. if (requestCode == REQUEST_CODE_PICK_IMAGE) {             
4.                Uri uri = data.getData();  
5. //to do find the path of pic by uri  
6.            
7. else if (requestCode == REQUEST_CODE_CAPTURE_CAMEIA ) {             
8.        Uri uri = data.getData();  
9. if(uri == null){  
10. //use bundle to get data  
11.            Bundle bundle = data.getExtras();    
12. if (bundle != null) {                 
13. "data"); //get bitmap  
14. //spath :生成图片取个名字和路径包含类型                              
15.                saveImage(Bitmap photo, String spath);  
16. else {           
17. "err****", Toast.LENGTH_LONG).show();           
18. return;        
19.                 }    
20. else{  
21. //to do find the path of pic by uri  
22.        }   
23.    }  
24. }

后面的过程就需要通过bitmap转化成相应的图片文件了。不过得到最终 的图片是被压缩了的 。


    1. public static void saveImage(Bitmap photo, String spath) {  
    2. try {  
    3. new BufferedOutputStream(  
    4. new FileOutputStream(spath, false));  
    5. 100, bos);  
    6.             bos.flush();  
    7.             bos.close();  
    8. catch (Exception e) {  
    9.             e.printStackTrace();  
    10. return false;  
    11.         }  
    12. return true;  
    13.     }


    这样就能解决照相机取到的图片uri为空的状态了。但是在获取到uri为null情况下,如果想得到没有被压缩过的照片,也就是说得到的是直接从相机拍摄到的照片怎么做呢?


    上一篇文章中讲解了照相机获取照片的时候遇到了可能取得的uri为null的状态,并给出了相应的解决方案,但是那种解决方案得到的图片是压缩过的,如果我们想得到相机拍摄出来的原照片,我们又应该怎样做呢?
    其实方式很简单,在
    Intent getImageByCamera = new Intent("android.media.action.IMAGE_CAPTURE");之后我们直接讲文件先保存到指定的路径filepath,然后直接在
    onActivityResult(int requestCode, int resultCode, Intent data)中把filepath传递过去就行了。

    private String capturePath = null;




    //拍照
        public void takePicture(){
        	String state = Environment.getExternalStorageState();  
            if (state.equals(Environment.MEDIA_MOUNTED)) { 
                Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); 
                File outDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);  
                if (!outDir.exists()) {  
                	outDir.mkdirs();  
                }  
                File outFile =  new File(outDir, System.currentTimeMillis() + ".jpg");  
                capturePath = outFile.getAbsolutePath();
                intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(outFile));  
                intent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 1);  
                startActivityForResult(intent, REQUEST_CODE_CAPTURE_CAMEIA);  
            } else{
            	AToast.show(R.string.ordergoods_refund_no_sdcard_tip);
            }
        }


    在onActivityResult(int requestCode, int resultCode, Intent data)中我们只要把路径filepath定义为全局的变量传送过来就行了。

    这样得到的图片是直接从相机中拍摄得到的照片,不会被压缩了。

    from:


    在做照相机图片相关操作的时候,由于android手机的适配原因,不同手机上出发的相机操作可能在细节上有很多不同,例如摄像头拍照的角度旋转了,使得获取到的图片也是旋转后的,再比如某些相机的图片像素太高了,对图片数据进行操作的时候造成内存不足等。下面就对相机拍摄时的图像被旋转的问题进行一些实际的解决方案:

    问题:由于摄像头拍照 是竖屏,显示的时候需要旋转了 90 度。也就是说显示的是 旋转90度后的 预览 图片?怎么处理...

    有一种方法是在说在拍照的时候将内容显示设定为横屏显示,

    1. <activity android:name=".MainActivity" android:label="@string/app_name" android:screenOrientation="landscape">

    还有在onCreate函数加入

    1. setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);

    这样拍出来的图片就不能被旋转了。说实话,这种方式不具有通用型,而且很不灵活,不能适配所有手机。所以不建议,但是可以作为一个想法。

    其实真正能解决这种问题的方法是找到相机在拍照后得到的原图和实际显示的图片的旋转角度,然后我们再通过Matrix对图片进行旋转就Ok了。

    那么我们怎样获取相机拍摄的原图和实际显示图片的旋转角度呢?在网上找到了这种方法,经过验证,着实可行。


      1. /**
      2.          * 读取照片exif信息中的旋转角度<br>http:///thread-196978-1-1.html
      3.          * @param path 照片路径
      4.          * @return角度
      5.          */  
      6. public static int readPictureDegree(String path) {  
      7. int degree  = 0;  
      8. try {  
      9. new ExifInterface(path);  
      10. int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);  
      11. switch (orientation) {  
      12. case ExifInterface.ORIENTATION_ROTATE_90:  
      13. 90;  
      14. break;  
      15. case ExifInterface.ORIENTATION_ROTATE_180:  
      16. 180;  
      17. break;  
      18. case ExifInterface.ORIENTATION_ROTATE_270:  
      19. 270;  
      20. break;  
      21.                         }  
      22. catch (IOException e) {  
      23.                         e.printStackTrace();  
      24.                 }  
      25. return degree;  
      26.         }


      得到原图和实际显示的图片的旋转角度后,我们再通过对原图进行旋转degree就行了,这个旋转方法可以通过 Matrix实现。

      注意:打开本地相册的代码有bug,要按照本文开头说的改一下