Android开发基础 调用相机 系统相册(并对图片进行压缩处理)
2016-03-10 15:05
721 查看
前言:做了好久的安卓开发了,一直想写点东西分享下。但是又总觉得自己学的还不够好,说出来有可能会误导人,所以一直都没有发. 最近在项目中遇到了最多的问题就是关于图片的问题,应该算是比较简单的了,拿出来跟大家分享下。(第一次写博客,希望给位大神能够多提意见^_^)
最近做的项目需要上传手机相册的图片或者通过相机拍照上传,但是以前从网上找的方法需要在拍照或选择完图片后再进行截取,不太符合现在的需求,于是从网上找了一些方法,但是莫名其妙的出了各种问题,于是各种百度,从网上找了一些方法,拿出来分享下,并方便自己以后的使用。
上面的那种方法可能获得的压缩图片不是我们想要,可能我们会想要高清大图,这时我们可以使用下面的方法,在
Intent getImageByCamera = new Intent(“android.media.action.IMAGE_CAPTURE”);
之后我们直接将文件先保存到指定的路径filepath,然后直接在
onActivityResult(int requestCode, int resultCode, Intent data)
中把filepath传递过去就行了。方法如下
好了做好以上的工作以后就可以选择图片或者拍摄图片了,当确认好了以后就会再次跳到当前的页面来,这时我们在onActivityResult()方法中进行数据的处理就行了。
<1>当开启相机使用的方法为简单的Intent直接调用时,我们在onActivityResult()方法中需要对返回的Intent进行判断处理。原因是因为android把拍摄的图片封装到bundle中传递回来,但是根据不同的机器获得相片的方式不太一样,可能有的相机能够通过 inten.getData()获取到uri然后再根据uri获取数据的路径,在封装成bitmap,但有时候有的相机获取到的是null的,这时候我们该怎么办呢?其实这时候我们就应该从bundle中获取数据,通过(Bitmap) bundle.get(“data”)获取到相机图片的bitmap数据。
<2>好了说完了直接简单的使用Intent方法调用相机,就该说说我们的重头戏了,那就是不要缩高清无码的大图了^_^。
这个时候在onActivityResult方法中就不需要进行对Intent进行判断处理了,只需将获取到的Bitmap对象进行处理,因为当前的地址肯定不会是空的。废话不多说,直接上代码。
然后就是压缩图片的工具类
首先需要说明的是,对图片压缩处理的方法大体上分为三种,我现在用的是最耗时的一个不太建议使用。另外的几种先介绍下,日后再附上代码。
第一种是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等经过人家一阵加工而成。效率好像比第二种方法高一点点。
另外附上从Uri中获取绝对路径的工具类
2.获取从相册中返回的数据
参考/article/7664085.html感谢前辈
最近做的项目需要上传手机相册的图片或者通过相机拍照上传,但是以前从网上找的方法需要在拍照或选择完图片后再进行截取,不太符合现在的需求,于是从网上找了一些方法,但是莫名其妙的出了各种问题,于是各种百度,从网上找了一些方法,拿出来分享下,并方便自己以后的使用。
开启相机
/** * 开启相机 * @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) { } }
参考/article/7664085.html感谢前辈
相关文章推荐
- xxx is not translated in yyy, zzz 的解决方法
- s7500刷Android442
- android theme
- android中xmlns:tools属性详解
- android 获取当前fragment单个对象(解决fragment返回键问题)
- 关于com.android.support:design:23.2.0中的坑
- Android编程之LayoutInflater的inflate方法详解
- Android的Manifest配置文件介绍
- Android提取短信验证码并自动填写
- Android LayoutInflater深度解析 给你带来全新的认识
- 可能是最早的学习Android N新特性的文章
- 【Android】如何分享本地图片
- Android 开发系列(6) - 使用 winrar 和 dex2jar 对 apk 反编译成 jar
- 分享Android 蓝牙4.0(ble)开发的解决方案
- Android常见inputType
- Android中BroadCast与Activity之间的通信
- Android "再按一次返回键退出程序“实现
- Android中对Log日志文件的分析(解决ANR)
- 动态的修改xml中的drawable文件的solid颜色
- Android实现EditText输入金额