Android开发基础 调用相机 系统相册(并对图片进行压缩处理)

前言:做了好久的安卓开发了,一直想写点东西分享下。但是又总觉得自己学的还不够好,说出来有可能会误导人,所以一直都没有发. 最近在项目中遇到了最多的问题就是关于图片的问题,应该算是比较简单的了,拿出来跟大家分享下。(第一次写博客,希望给位大神能够多提意见^_^)


最近做的项目需要上传手机相册的图片或者通过相机拍照上传,但是以前从网上找的方法需要在拍照或选择完图片后再进行截取,不太符合现在的需求,于是从网上找了一些方法,但是莫名其妙的出了各种问题,于是各种百度,从网上找了一些方法,拿出来分享下,并方便自己以后的使用。

开启相机

/**
 * 开启相机
 * @param actionCode 请求码
 * /
private void getImageFromCamera(int actionCode) {  
   //这种方法是我们最常见的方法,但是这种方法获取到的图片时是进行压缩后的图片,有可能不是我们想要的
   //可能压缩后的文件会非常模糊
    Intent getImageByCamera = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);  
    startActivityForResult(getImageByCamera , actionCode);  
}   

上面的那种方法可能获得的压缩图片不是我们想要,可能我们会想要高清大图,这时我们可以使用下面的方法,在
Intent getImageByCamera = new Intent(“android.media.action.IMAGE_CAPTURE”);
之后我们直接将文件先保存到指定的路径filepath,然后直接在
onActivityResult(int requestCode, int resultCode, Intent data)
中把filepath传递过去就行了。方法如下

//定义一个成员变量,用于保存相机拍照的图片
private String capturePath = null;
/**
 * 开启相机
 * @param actionCode 请求码
 */
protected void getImageFromCamera(int actionCode) {
        String state = Environment.getExternalStorageState();
        if (state.equals(Environment.MEDIA_MOUNTED)) {
            Intent getImageByCamera = new Intent("android.media.action.IMAGE_CAPTURE");
            //获取保存的路径
            String out_file_path = getSDPath();
            File dir = new File(out_file_path);
            //给成员变量赋值
            capturePath = getSDPath() + "/" + System.currentTimeMillis() + ".jpg";
            if (!dir.exists()) {
                dir.mkdirs();
            }

            getImageByCamera.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(new File(capturePath)));
            getImageByCamera.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 1);
            startActivityForResult(getImageByCamera, actionCode);
        } else {
            Toast.makeText(getApplicationContext(), "请确认已经插入SD卡", Toast.LENGTH_LONG).show();
        }
    }

/**
 * 获取存储路径,可以写在FileUtils中
 */
 public String getSDPath() {
        File sdDir = null;
        boolean sdCardExist = Environment.getExternalStorageState()
                .equals(android.os.Environment.MEDIA_MOUNTED);//判断sd卡是否存在
        if (sdCardExist) {
            sdDir = Environment.getExternalStorageDirectory();//获取跟目录
        }
        return sdDir.toString();
    }

开启相册

 /**
  * 获取相册的图片
  */
 protected void getImageFromAlbum(int actionCode) {
      //就是利用Intent调用系统的相册
      Intent intent = new Intent(Intent.ACTION_PICK);
      intent.setType("image/*");//相片类型
      startActivityForResult(intent, actionCode);
 }

好了做好以上的工作以后就可以选择图片或者拍摄图片了,当确认好了以后就会再次跳到当前的页面来,这时我们在onActivityResult()方法中进行数据的处理就行了。

接收从相册或相机中返回的数据

1.接收从相机中返回的数据
<1>当开启相机使用的方法为简单的Intent直接调用时,我们在onActivityResult()方法中需要对返回的Intent进行判断处理。原因是因为android把拍摄的图片封装到bundle中传递回来,但是根据不同的机器获得相片的方式不太一样,可能有的相机能够通过 inten.getData()获取到uri然后再根据uri获取数据的路径,在封装成bitmap,但有时候有的相机获取到的是null的,这时候我们该怎么办呢?其实这时候我们就应该从bundle中获取数据,通过(Bitmap) bundle.get(“data”)获取到相机图片的bitmap数据。

  为了能够同时适应上述两种情况,我们这时候就应该在获取图片时做判断了。我们可以在响应的时候做一个判断:
 protected void onActivityResult(int requestCode, int resultCode, Intent data) {  
       if (requestCode == REQUEST_CODE_PICK_IMAGE) {             
               Uri uri = data.getData();  
               //to do find the path of pic by uri  

       } else if (requestCode == REQUEST_CODE_CAPTURE_CAMEIA ) {             
       Uri uri = data.getData();  
       if(uri == null){  
           //use bundle to get data  
           Bundle bundle = data.getExtras();    
               if (bundle != null) { 
               //可以通过获取到的这个Bitmap对象设置到ImageView控件中,让他显示出来                
               Bitmap  photo = (Bitmap) bundle.get("data"); //get bitmap  
               //spath :生成图片取个名字和路径包含类型                              
               saveImage(photo, spath);  
               } else {           
                   Toast.makeText(getApplicationContext(), "err****", Toast.LENGTH_LONG).show();           
                return;        
                }    
       }else{  
                //to do find the path of pic by uri  
       }   
   }  
}

public static boolean saveImage(Bitmap photo, String spath) {  
        try {  
            BufferedOutputStream bos = new BufferedOutputStream(  
                    new FileOutputStream(spath, false));  
            photo.compress(Bitmap.CompressFormat.JPEG, 100, bos);  
            bos.flush();  
            bos.close();  
        } catch (Exception e) {  
            e.printStackTrace();  
            return false;  
        }  
        return true;  
    } 
//以上方法引用的是网上的一段代码  

<2>好了说完了直接简单的使用Intent方法调用相机,就该说说我们的重头戏了,那就是不要缩高清无码的大图了^_^。

这个时候在onActivityResult方法中就不需要进行对Intent进行判断处理了,只需将获取到的Bitmap对象进行处理,因为当前的地址肯定不会是空的。废话不多说,直接上代码。

     @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {


        Bitmap bm = null;
        if (requestCode == REQUEST_CODE_PICK_IMAGE) {


        } else if (requestCode == REQUEST_CODE_CAPTURE_CAMEIA) {

            //通过图片路径直接获取Bitmap对象(注意这个时候的Bitmap对象有可能会很大需要进行压缩处理)
            bm = getBitmap(capturePath);
            //对Bitmap对象进行压缩处理
            bm = BitmapCompressUtils.imageZoom(bm, 310.00);
            if (bm==null){
                //设置默认的图片
            }else{
                img.setImageBitmap(bm);
            }


            //将bitmap放至数组中,意在bitmap的大小(与实际读取的原文件要大)
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            bm.compress(Bitmap.CompressFormat.JPEG, 100, baos);
            byte[] b = baos.toByteArray();
            //将字节换成KB
            double mid = b.length / 1024;

            tv.setText("存储路径" + capturePath + "\n图片大小" + mid);

        }
    }

    /**
     * 通过路径获取Bitmap对象
     *
     * @param path
     * @return
     */
    public static Bitmap getBitmap(String path) {
        Bitmap bm = null;
        InputStream is = null;
        try {
            File outFilePath = new File(path);
            //判断如果当前的文件不存在时,创建该文件一般不会不存在
            if (!outFilePath.exists()) {
                boolean flag = false;
                try {
                    flag = outFilePath.createNewFile();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                System.out.println("---创建文件结果----" + flag);
            }
            is = new FileInputStream(outFilePath);
            bm = BitmapFactory.decodeStream(is);

        } catch (FileNotFoundException e) {
            e.printStackTrace();
            return null;
        } finally {
            try {
                is.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return bm;
    }

然后就是压缩图片的工具类
首先需要说明的是,对图片压缩处理的方法大体上分为三种,我现在用的是最耗时的一个不太建议使用。另外的几种先介绍下,日后再附上代码。

第一种是BitmapFactory和BitmapFactory.Options。
首先,BitmapFactory.Options有几个Fields很有用:
inJustDecodeBounds:If set to true, the decoder will return null (no bitmap), but the out…
也就是说,当inJustDecodeBounds设成true时,bitmap并不加载到内存,这样效率很高哦。而这时,你可以获得bitmap的高、宽等信息。
outHeight:The resulting height of the bitmap, set independent of the state of inJustDecodeBounds.
outWidth:The resulting width of the bitmap, set independent of the state of inJustDecodeBounds.
看到了吧,上面3个变量是相关联的哦。
inSampleSize : If set to a value > 1, requests the decoder to subsample the original image, returning a smaller image to save memory.
这就是用来做缩放比的。这里有个技巧:
inSampleSize=(outHeight/Height+outWidth/Width)/2
实践证明,这样缩放出来的图片还是很好的。
最后用BitmapFactory.decodeFile(path, options)生成。
由于只是对bitmap加载到内存一次,所以效率比较高。解析速度快。

第二种是使用Bitmap加Matrix来缩放。
首先要获得原bitmap,再从原bitmap的基础上生成新图片。这样效率很低。
第三种是用2.2新加的类ThumbnailUtils来做。
让我们新看看这个类,从API中来看,此类就三个静态方法:createVideoThumbnail、extractThumbnail(Bitmap source, int width, int height, int options)、extractThumbnail(Bitmap source, int width, int height)。
是上面我们用到的BitmapFactory.Options和Matrix等经过人家一阵加工而成。效率好像比第二种方法高一点点。

/**
 * Created by l_zp on 2016/1/20.
 * 这是一个将图片进行压缩的工具类
 */
public class BitmapCompressUtils {


  /**
     * 压缩图片
     *
     * @param bitMap  要压缩的bitmap对象
     * @param maxSize 压缩的大小(kb)不是很准确大约比输入值大于100k是因为比例决定的
     * @return
     */
    public static Bitmap imageZoom(Bitmap bitMap, double maxSize) {
        if (bitMap != null) {
            //将bitmap放至数组中,意在bitmap的大小(与实际读取的原文件要大)
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            bitMap.compress(Bitmap.CompressFormat.JPEG, 100, baos);
            byte[] b = baos.toByteArray();
            //将字节换成KB
            double mid = b.length / 1024;
            //判断bitmap占用空间是否大于允许最大空间  如果大于则压缩 小于则不压缩
            if (mid > maxSize) {
                //获取bitmap大小 是允许最大大小的多少倍
                double i = mid / maxSize;
                //开始压缩  此处用到平方根 将宽带和高度压缩掉对应的平方根倍 (1.保持刻度和高度和原bitmap比率一致,压缩后也达到了最大大小占用空间的大小)
                bitMap = zoomImage(bitMap, bitMap.getWidth() / Math.sqrt(i),
                        bitMap.getHeight() / Math.sqrt(i));
            }
        }
        return bitMap;
    }


    /***
     * 图片的缩放方法
     *
     * @param bgimage   :源图片资源
     * @param newWidth  :缩放后宽度
     * @param newHeight :缩放后高度
     * @return
     */
    public static Bitmap zoomImage(Bitmap bgimage, double newWidth,
                                   double newHeight) {
        // 获取这个图片的宽和高
        float width = bgimage.getWidth();
        float height = bgimage.getHeight();
        // 创建操作图片用的matrix对象
        Matrix matrix = new Matrix();
        // 计算宽高缩放率
        float scaleWidth = ((float) newWidth) / width;
        float scaleHeight = ((float) newHeight) / height;
        // 缩放图片动作
        matrix.postScale(scaleWidth, scaleHeight);
        Bitmap bitmap = Bitmap.createBitmap(bgimage, 0, 0, (int) width,
                (int) height, matrix, true);
        return bitmap;
    }

另外附上从Uri中获取绝对路径的工具类

/**
 * Created by l_zp on 2016/3/10.
 *
 * 文件工具类
 */
public class FileUtils {

    /**
     * 从Uri中获取绝对路径
     *
     * @param context
     * @param uri
     * @return the file path or null
     */
    public static String getRealFilePath( final Context context, final Uri uri ) {
        if ( null == uri ) return null;
        final String scheme = uri.getScheme();
        String data = null;
        if ( scheme == null )
            data = uri.getPath();
        else if ( ContentResolver.SCHEME_FILE.equals( scheme ) ) {
            data = uri.getPath();
        } else if ( ContentResolver.SCHEME_CONTENT.equals( scheme ) ) {
            Cursor cursor = context.getContentResolver().query( uri, new String[] { MediaStore.Images.ImageColumns.DATA }, null, null, null );
            if ( null != cursor ) {
                if ( cursor.moveToFirst() ) {
                    int index = cursor.getColumnIndex( MediaStore.Images.ImageColumns.DATA );
                    if ( index > -1 ) {
                        data = cursor.getString( index );
                    }
                }
                cursor.close();
            }
        }
        return data;
    }
}

2.获取从相册中返回的数据

 @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {


        Bitmap bm = null;
        if (requestCode == REQUEST_CODE_PICK_IMAGE) {
            //这里判断data是否为空是为了防止用户开启完相册后,没有选择就返回
            if (data != null) {
                //外界的程序访问ContentProvider所提供数据 可以通过ContentResolver接口
                Uri originalUri = data.getData();
                //to do find the path of pic by uri
                try {
                    //显得到bitmap图片这里开始的第二部分,获取图片的路径:
                    String path = FileUtils.getRealFilePath(MainActivity.this, originalUri);
                    bm = getBitmap(path);
                    System.out.println("----像素密度值---" + bm.getDensity());
                    bm = BitmapCompressUtils.imageZoom(bm, 210.00);
                    img.setImageBitmap(bm);
                    //将bitmap放至数组中,意在bitmap的大小(与实际读取的原文件要大)
                    ByteArrayOutputStream baos = new ByteArrayOutputStream();
                    bm.compress(Bitmap.CompressFormat.JPEG, 100, baos);
                    byte[] b = baos.toByteArray();
                    //将字节换成KB
                    double mid = b.length / 1024;
                    tv.setText("存储路径" + path + "\n图片大小" + mid);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        } else if (requestCode == REQUEST_CODE_CAPTURE_CAMEIA) {



        }
    }

参考http://blog.csdn.net/beyond0525/article/details/8939984感谢前辈

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值