最近做项目需要用到拍照和选择相册照片,并显示出来imageview 上,然后压缩上传到服务器中,这本是一个非常常见的功能,但对于图片的处理确实一个技术活,稍微不注意会出现oom,图片压缩也要处理的刚刚好,不能浪费用户的流量,也不能过分的压缩使图片失真,这真的不简单,好在开源中国的安卓端app以开源,本人特意从开源中国整理了这个demo,分享给大家。
进入相册选择照片:注意6.0之后要申请运行时权限,即api23。
Intent intent;if (Build.VERSION.SDK_INT < 19) {intent = new Intent();intent.setAction(Intent.ACTION_GET_CONTENT);intent.setType("image/*");startActivityForResult(Intent.createChooser(intent, "选择图片"), ImageUtils.REQUEST_CODE_GETIMAGE_BYSDCARD);} else {intent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);intent.setType("image/*");startActivityForResult(Intent.createChooser(intent, "选择图片"), ImageUtils.REQUEST_CODE_GETIMAGE_BYSDCARD);}
或者拍照:
private void toCamera() {// 判断是否挂载了SD卡String savePath = "";String storageState = Environment.getExternalStorageState();if (storageState.equals(Environment.MEDIA_MOUNTED)) {savePath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/oschina/Camera/";File savedir = new File(savePath);if (!savedir.exists()) {savedir.mkdirs();}}// 没有挂载SD卡,无法保存文件if (TextUtils.isEmpty(savePath)) {// AppContext.showToastShort("无法保存照片,请检查SD卡是否挂载");return;}String timeStamp = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());String fileName = timeStamp + ".jpg";// 照片命名File out = new File(savePath, fileName);Uri uri = Uri.fromFile(out);//tweet.setImageFilePath(savePath + fileName); // 该照片的绝对路径mPhotoPath=savePath + fileName;Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);startActivityForResult(intent, ImageUtils.REQUEST_CODE_GETIMAGE_BYCAMERA);}
在onActivity获取图片信息:
@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) {super.onActivityResult(requestCode, resultCode, data);if (resultCode != Activity.RESULT_OK)return;if (requestCode == ImageUtils.REQUEST_CODE_GETIMAGE_BYSDCARD) {if (data == null)return;Uri selectedImageUri = data.getData();if (selectedImageUri != null) {String path = ImageUtils.getImagePath(selectedImageUri, this);setImageFromPath(path);}} else if (requestCode == ImageUtils.REQUEST_CODE_GETIMAGE_BYCAMERA) {//setImageFromPath(tweet.getImageFilePath());setImageFromPath(mPhotoPath);}}
通过返回的uri获取图片路径
/*** 通过Uri获取文件路径* 支持图片媒体,文件等* <p/>* Author qiujuer@live.cn** @param uri Uri* @param context Context* @return 文件路径*/@SuppressLint({"NewApi", "Recycle"})public static String getImagePath(Uri uri, Context context) {String selection = null;String[] selectionArgs = null;// Uri is different in versions after KITKAT (Android 4.4), we need toif (Build.VERSION.SDK_INT >= 19 && DocumentsContract.isDocumentUri(context.getApplicationContext(), uri)) {String authority = uri.getAuthority();if ("com.android.externalstorage.documents".equals(authority)) {// isExternalStorageDocumentfinal String docId = DocumentsContract.getDocumentId(uri);final String[] split = docId.split(":");return Environment.getExternalStorageDirectory() + "/" + split[1];} else if ("com.android.providers.downloads.documents".equals(authority)) {// isDownloadsDocumentfinal String id = DocumentsContract.getDocumentId(uri);uri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));} else if ("com.android.providers.media.documents".equals(authority)) {// isMediaDocumentfinal String docId = DocumentsContract.getDocumentId(uri);final String[] split = docId.split(":");final String type = split[0];if ("image".equals(type)) {uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;} else if ("video".equals(type)) {uri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;} else if ("audio".equals(type)) {uri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;}selection = "_id=?";selectionArgs = new String[]{split[1]};}}if ("content".equalsIgnoreCase(uri.getScheme())) {String[] projection = {MediaStore.Images.Media.DATA};Cursor cursor = null;try {cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null);if (cursor != null) {int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);if (cursor.moveToFirst()) {return cursor.getString(column_index);}}} catch (Exception e) {e.fillInStackTrace();} finally {if (cursor != null)cursor.close();}} else if ("file".equalsIgnoreCase(uri.getScheme())) {return uri.getPath();}return null;}
根据图片地址去获取bitmap这时需要自己传入图片的大小即高度和宽度,根据自己的需求去传。
Bitmap bitmap = BitmapCreate.bitmapFromStream(new FileInputStream(path), 512, 512);
图片压缩
/*** 获取一个指定大小的bitmap<br>* 实际调用的方法是bitmapFromByteArray(data, 0, data.length, w, h);** @param is 从输入流中读取Bitmap* @param reqWidth 目标宽度* @param reqHeight 目标高度*/public static Bitmap bitmapFromStream(InputStream is, int reqWidth,int reqHeight) {if (reqHeight == 0 || reqWidth == 0) {try {return BitmapFactory.decodeStream(is);} catch (OutOfMemoryError e) {}}byte[] data = FileUtils.input2byte(is);return bitmapFromByteArray(data, 0, data.length, reqWidth, reqHeight);}/*** 获取一个指定大小的bitmap** @param data Bitmap的byte数组* @param offset image从byte数组创建的起始位置* @param length the number of bytes, 从offset处开始的长度* @param reqWidth 目标宽度* @param reqHeight 目标高度*/public static Bitmap bitmapFromByteArray(byte[] data, int offset,int length, int reqWidth, int reqHeight) {if (reqHeight == 0 || reqWidth == 0) {try {return BitmapFactory.decodeByteArray(data, offset, length);} catch (OutOfMemoryError e) {}}BitmapFactory.Options options = new BitmapFactory.Options();options.inJustDecodeBounds = true;options.inPurgeable = true;BitmapFactory.decodeByteArray(data, offset, length, options);options = calculateInSampleSize(options, reqWidth, reqHeight);return BitmapFactory.decodeByteArray(data, offset, length, options);}/*** 图片压缩处理(使用Options的方法)* <br>* <b>说明</b> 使用方法:* 首先你要将Options的inJustDecodeBounds属性设置为true,BitmapFactory.decode一次图片 。* 然后将Options连同期望的宽度和高度一起传递到到本方法中。* 之后再使用本方法的返回值做参数调用BitmapFactory.decode创建图片。* <br>* <b>说明</b> BitmapFactory创建bitmap会尝试为已经构建的bitmap分配内存* ,这时就会很容易导致OOM出现。为此每一种创建方法都提供了一个可选的Options参数* ,将这个参数的inJustDecodeBounds属性设置为true就可以让解析方法禁止为bitmap分配内存* ,返回值也不再是一个Bitmap对象, 而是null。虽然Bitmap是null了,但是Options的outWidth、* outHeight和outMimeType属性都会被赋值。** @param reqWidth 目标宽度,这里的宽高只是阀值,实际显示的图片将小于等于这个值* @param reqHeight 目标高度,这里的宽高只是阀值,实际显示的图片将小于等于这个值*/public static BitmapFactory.Options calculateInSampleSize(final BitmapFactory.Options options, final int reqWidth,final int reqHeight) {// 源图片的高度和宽度final int height = options.outHeight;final int width = options.outWidth;int inSampleSize = 1;if (height > reqHeight || width > reqWidth) {// 计算出实际宽高和目标宽高的比率final int heightRatio = Math.round((float) height/ (float) reqHeight);final int widthRatio = Math.round((float) width / (float) reqWidth);// 选择宽和高中最小的比率作为inSampleSize的值,这样可以保证最终图片的宽和高// 一定都会大于等于目标的宽和高。inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;}// 设置压缩比例options.inSampleSize = inSampleSize;options.inJustDecodeBounds = false;return options;}
将压缩后的bitmap存在sdcard中,待会儿要上传到服务器中。
/*** 图片写入文件** @param bitmap* 图片* @param filePath* 文件路径* @return 是否写入成功*/public static boolean bitmapToFile(Bitmap bitmap, String filePath) {boolean isSuccess = false;if (bitmap == null) {return isSuccess;}File file = new File(filePath.substring(0,filePath.lastIndexOf(File.separator)));if (!file.exists()) {file.mkdirs();}OutputStream out = null;try {out = new BufferedOutputStream(new FileOutputStream(filePath),8 * 1024);isSuccess = bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);} catch (FileNotFoundException e) {e.printStackTrace();} finally {closeIO(out);}return isSuccess;}
将压缩后的bitmap 根据需求进一步缩放,显示在imageview上。
/*** 放大缩小图片** @param bitmap* @param w* @param h* @return*/public static Bitmap zoomBitmap(Bitmap bitmap, int w, int h) {Bitmap newbmp = null;if (bitmap != null) {int width = bitmap.getWidth();int height = bitmap.getHeight();Matrix matrix = new Matrix();float scaleWidht = ((float) w / width);float scaleHeight = ((float) h / height);matrix.postScale(scaleWidht, scaleHeight);newbmp = Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix,true);}return newbmp;}
在拍照的过程中,有的机型照片会倒转,这是需要处理一下即可
/*** 读取图片属性:旋转的角度* @param path 图片绝对路径* @return degree旋转的角度*/public static int readPictureDegree(String path) {int degree = 0;try {ExifInterface exifInterface = new ExifInterface(path);int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);switch (orientation) {case ExifInterface.ORIENTATION_ROTATE_90:degree = 90;break;case ExifInterface.ORIENTATION_ROTATE_180:degree = 180;break;case ExifInterface.ORIENTATION_ROTATE_270:degree = 270;break;}} catch (IOException e) {e.printStackTrace();}return degree;}/*** 旋转图片* @param angle* @param bitmap* @return*/public static Bitmap rotaingImageView(int angle , Bitmap bitmap) {//旋转图片 动作Matrix matrix = new Matrix();matrix.postRotate(angle);System.out.println("angle2=" + angle);// 创建新的图片Bitmap resizedBitmap = Bitmap.createBitmap(bitmap, 0, 0,bitmap.getWidth(), bitmap.getHeight(), matrix, true);return resizedBitmap;}
这些代码百分之七八十来自开源中国。感谢原作者。
源码下载