content: package com.rsen.util;
  
  import android.annotation.SuppressLint;
  import android.app.Activity;
  import android.content.ContentUris;
  import android.content.Context;
  import android.content.Intent;
  import android.content.res.Resources;
  import android.database.Cursor;
  import android.graphics.Bitmap;
  import android.graphics.BitmapFactory;
  import android.graphics.Matrix;
  import android.media.ExifInterface;
  import android.net.Uri;
  import android.os.Build;
  import android.os.Environment;
  import android.provider.DocumentsContract;
  import android.provider.MediaStore;
  
  import java.io.ByteArrayOutputStream;
  import java.io.IOException;
  import java.io.InputStream;
  import java.math.BigDecimal;
  import java.math.RoundingMode;
  import java.nio.ByteBuffer;
  import java.nio.channels.Channels;
  import java.nio.channels.ReadableByteChannel;
  
  /**
   * Created by angcyo on 15-11-02-002.
   */
  public class BitmapHelper {
  
      /**
       * get the orientation of the bitmap {@link android.media.ExifInterface}
       *
       * @param path
       * @return
       */
      public final static int getDegrees(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;
      }
  
      /**
       * rotate the bitmap
       *
       * @param bitmap
       * @param degress
       * @return
       */
      public static Bitmap rotateBitmap(Bitmap bitmap, int degress) {
          if (bitmap != null) {
              Matrix m = new Matrix();
              m.postRotate(degress);
              bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), m, true);
              return bitmap;
          }
          return bitmap;
      }
  
      /**
       * caculate the bitmap sampleSize
       *
       * @return
       */
      public final static int caculateInSampleSize(BitmapFactory.Options options, int rqsW, int rqsH) {
          final int height = options.outHeight;
          final int width = options.outWidth;
          int inSampleSize = 1;
          if (rqsW == 0 || rqsH == 0) return 1;
          if (height > rqsH || width > rqsW) {
              final int heightRatio = Math.round((float) height / (float) rqsH);
              final int widthRatio = Math.round((float) width / (float) rqsW);
              inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
          }
          return inSampleSize;
      }
  
      /**
       * 压缩指定路径的图片，并得到图片对象
       *
       * @param path bitmap source path
       * @return Bitmap {@link android.graphics.Bitmap}
       */
      public final static Bitmap compressBitmap(String path, int rqsW, int rqsH) {
          final BitmapFactory.Options options = new BitmapFactory.Options();
          options.inJustDecodeBounds = true;
          BitmapFactory.decodeFile(path, options);
          options.inSampleSize = caculateInSampleSize(options, rqsW, rqsH);
          options.inJustDecodeBounds = false;
          return BitmapFactory.decodeFile(path, options);
      }
  
      /**
       * 此方法过期，该方法可能造成OutOfMemoryError，使用不含isAdjust参数的方法
       *
       * @param is
       * @param reqsW
       * @param reqsH
       * @param isAdjust
       * @return
       */
      @Deprecated
      public final static Bitmap compressBitmap(InputStream is, int reqsW, int reqsH, boolean isAdjust) {
          Bitmap bitmap = BitmapFactory.decodeStream(is);
          return compressBitmap(bitmap, reqsW, reqsH, isAdjust);
      }
  
      /**
       * 压缩某个输入流中的图片，可以解决网络输入流压缩问题，并得到图片对象
       *
       * @return Bitmap {@link android.graphics.Bitmap}
       */
      public final static Bitmap compressBitmap(InputStream is, int reqsW, int reqsH) {
          try {
              ByteArrayOutputStream baos = new ByteArrayOutputStream();
              ReadableByteChannel channel = Channels.newChannel(is);
              ByteBuffer buffer = ByteBuffer.allocate(1024);
              while (channel.read(buffer) != -1) {
                  buffer.flip();
                  while (buffer.hasRemaining()) baos.write(buffer.get());
                  buffer.clear();
              }
              byte[] bts = baos.toByteArray();
              Bitmap bitmap = compressBitmap(bts, reqsW, reqsH);
              is.close();
              channel.close();
              baos.close();
              return bitmap;
          } catch (Exception e) {
              // TODO: handle exception
              e.printStackTrace();
              return null;
          }
      }
  
      /**
       * 压缩指定byte[]图片，并得到压缩后的图像
       *
       * @param bts
       * @param reqsW
       * @param reqsH
       * @return
       */
      public final static Bitmap compressBitmap(byte[] bts, int reqsW, int reqsH) {
          final BitmapFactory.Options options = new BitmapFactory.Options();
          options.inJustDecodeBounds = true;
          BitmapFactory.decodeByteArray(bts, 0, bts.length, options);
          options.inSampleSize = caculateInSampleSize(options, reqsW, reqsH);
          options.inJustDecodeBounds = false;
          return BitmapFactory.decodeByteArray(bts, 0, bts.length, options);
      }
  
      /**
       * 此方法已过期，该方法可能造成OutOfMemoryError，使用不含isAdjust参数的方法
       *
       * @param bitmap
       * @param reqsW
       * @param reqsH
       * @return
       */
      @Deprecated
      public final static Bitmap compressBitmap(Bitmap bitmap, int reqsW, int reqsH, boolean isAdjust) {
          if (bitmap == null || reqsW == 0 || reqsH == 0) return bitmap;
          if (bitmap.getWidth() > reqsW || bitmap.getHeight() > reqsH) {
              float scaleX = new BigDecimal(reqsW).divide(new BigDecimal(bitmap.getWidth()), 4, RoundingMode.DOWN).floatValue();
              float scaleY = new BigDecimal(reqsH).divide(new BigDecimal(bitmap.getHeight()), 4, RoundingMode.DOWN).floatValue();
              if (isAdjust) {
                  scaleX = scaleX < scaleY ? scaleX : scaleY;
                  scaleY = scaleX;
              }
              Matrix matrix = new Matrix();
              matrix.postScale(scaleX, scaleY);
              bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
          }
          return bitmap;
      }
  
      /**
       * 压缩已存在的图片对象，并返回压缩后的图片
       *
       * @param bitmap
       * @param reqsW
       * @param reqsH
       * @return
       */
      public final static Bitmap compressBitmap(Bitmap bitmap, int reqsW, int reqsH) {
          try {
              ByteArrayOutputStream baos = new ByteArrayOutputStream();
              bitmap.compress(Bitmap.CompressFormat.PNG, 100, baos);
              byte[] bts = baos.toByteArray();
              Bitmap res = compressBitmap(bts, reqsW, reqsH);
              baos.close();
              return res;
          } catch (IOException e) {
              // TODO Auto-generated catch block
              e.printStackTrace();
              return bitmap;
          }
      }
  
      /**
       * 此方法过期，该方法可能造成OutOfMemoryError，使用不含isAdjust参数的方法
       * get bitmap form resource dictory, and then compress bitmap according to reqsW and reqsH
       *
       * @param res   {@link android.content.res.Resources}
       * @param resID
       * @param reqsW
       * @param reqsH
       * @return
       */
      @Deprecated
      public final static Bitmap compressBitmap(Resources res, int resID, int reqsW, int reqsH, boolean isAdjust) {
          Bitmap bitmap = BitmapFactory.decodeResource(res, resID);
          return compressBitmap(bitmap, reqsW, reqsH, isAdjust);
      }
  
      /**
       * 压缩资源图片，并返回图片对象
       *
       * @param res   {@link android.content.res.Resources}
       * @param resID
       * @param reqsW
       * @param reqsH
       * @return
       */
      public final static Bitmap compressBitmap(Resources res, int resID, int reqsW, int reqsH) {
          final BitmapFactory.Options options = new BitmapFactory.Options();
          options.inJustDecodeBounds = true;
          BitmapFactory.decodeResource(res, resID, options);
          options.inSampleSize = caculateInSampleSize(options, reqsW, reqsH);
          options.inJustDecodeBounds = false;
          return BitmapFactory.decodeResource(res, resID, options);
      }
  
  
      /**
       * 基于质量的压缩算法， 此方法未 解决压缩后图像失真问题
       * <br> 可先调用比例压缩适当压缩图片后，再调用此方法可解决上述问题
       *
       * @param maxBytes 压缩后的图像最大大小 单位为byte
       * @return
       */
      public final static Bitmap compressBitmap(Bitmap bitmap, long maxBytes) {
          try {
              ByteArrayOutputStream baos = new ByteArrayOutputStream();
              bitmap.compress(Bitmap.CompressFormat.PNG, 100, baos);
              int options = 90;
              while (baos.toByteArray().length > maxBytes) {
                  baos.reset();
                  bitmap.compress(Bitmap.CompressFormat.PNG, options, baos);
                  options -= 10;
              }
              byte[] bts = baos.toByteArray();
              Bitmap bmp = BitmapFactory.decodeByteArray(bts, 0, bts.length);
              baos.close();
              return bmp;
          } catch (IOException e) {
              // TODO Auto-generated catch block
              e.printStackTrace();
              return null;
          }
      }
  
  //  public final static Bitmap compressBitmap(InputStream is, long maxBytes) {
  //      try {
  //          ByteArrayOutputStream baos = new ByteArrayOutputStream();
  //          byte[] bts = new byte[1024];
  //          while (is.read(bts) != -1) baos.write(bts, 0, bts.length);
  //          is.close();
  //          int options = 100;
  //          while (baos.toByteArray().length > maxBytes) {
  //
  //          }
  //      } catch (Exception e) {
  //          // TODO: handle exception
  //      }
  //  }
  
      /**
       * 得到指定路径图片的options
       *
       * @param srcPath
       * @return Options {@link android.graphics.BitmapFactory.Options}
       */
      public final static BitmapFactory.Options getBitmapOptions(String srcPath) {
          BitmapFactory.Options options = new BitmapFactory.Options();
          options.inJustDecodeBounds = true;
          BitmapFactory.decodeFile(srcPath, options);
          return options;
      }
  
      //--------------------------------------------------------
  
      /**
       * scale image
       *
       * @param org
       * @param newWidth
       * @param newHeight
       * @return
       */
      public static Bitmap scaleImageTo(Bitmap org, int newWidth, int newHeight) {
          float scaleWidth = (float) newWidth / org.getWidth();
          float scaleHeight = (float) newHeight / org.getHeight();
          float scale = Math.max(scaleWidth, scaleHeight);
          return scaleImage(org, scale, scale);
      }
  
      /**
       * scale image
       *
       * @param org
       * @param scaleWidth  sacle of width
       * @param scaleHeight scale of height
       * @return
       */
      public static Bitmap scaleImage(Bitmap org, float scaleWidth, float scaleHeight) {
          if (org == null) {
              return null;
          }
          Matrix matrix = new Matrix();
          matrix.postScale(scaleWidth, scaleHeight);
          return Bitmap.createBitmap(org, 0, 0, org.getWidth(), org.getHeight(), matrix, true);
      }
  
      /**
       * 计算压缩率
       */
      public static int calculateInSampleSize(BitmapFactory.Options options,
                                              int reqWidth, 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;
          }
          return inSampleSize;
      }
  
      /**
       * 压缩图片
       */
      public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
                                                           int reqWidth, int reqHeight) {
          // 第一次解析将inJustDecodeBounds设置为true，来获取图片大小
          final BitmapFactory.Options options = new BitmapFactory.Options();
          options.inJustDecodeBounds = true;
          // 调用上面定义的方法计算inSampleSize值
          options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
          // 使用获取到的inSampleSize值再次解析图片
          options.inJustDecodeBounds = false;
          return BitmapFactory.decodeResource(res, resId, options);
      }
  
      /**
       * 压缩图片
       */
      public static Bitmap decodeSampledBitmapFromResource(String bitmapPath,
                                                           int reqWidth, int reqHeight) {
          // 第一次解析将inJustDecodeBounds设置为true，来获取图片大小
          final BitmapFactory.Options options = new BitmapFactory.Options();
          options.inJustDecodeBounds = true;
          // 调用上面定义的方法计算inSampleSize值
          options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
          // 使用获取到的inSampleSize值再次解析图片
          options.inJustDecodeBounds = false;
          return BitmapFactory.decodeFile(bitmapPath, options);
      }
  
      /**
       * 拍照获取图片, imageUri.getPath() 图片路径
       */
      public static void getPhotoFromCamera(Activity context, int requestCode, Uri imageUri) {
          Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
          intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);
          intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri); // set the image file name
          context.startActivityForResult(intent, requestCode);
      }
  
      /**
       * 相册选择照片
       */
      public static void getPhotoFromPhotos(Activity context, int requestCode) {
          Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
          intent.addCategory(Intent.CATEGORY_OPENABLE);
          intent.setType("image/*");
          intent.setAction(Intent.ACTION_GET_CONTENT);
          context.startActivityForResult(Intent.createChooser(intent, "选择图片"), requestCode);
      }
  
      /**
       * 获取图片, 数据 extras.get("data") 或者 extras.getParcelable("data")
       */
      public static void getPhoto(Activity context, boolean camera, int requestCode) {
          if (camera) {
              String state = Environment.getExternalStorageState();
              if (state.equals(Environment.MEDIA_MOUNTED)) {
                  Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
                  context.startActivityForResult(intent, requestCode);
              } else {
                  T.show(context, "请确认已经插入SD卡");
              }
          } else {
              Intent intent = new Intent(Intent.ACTION_PICK);
              intent.setType("image/*");//相片类型
              context.startActivityForResult(intent, requestCode);
          }
      }
  
      /**
       * Get a file path from a Uri. This will get the the path for Storage Access
       * Framework Documents, as well as the _data field for the MediaStore and
       * other file-based ContentProviders.
       *
       * @param context The context.
       * @param uri     The Uri to query.
       */
      @SuppressLint("NewApi")
      public static String getPath(final Context context, final Uri uri) {
  
          final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
          // DocumentProvider
          if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
              // ExternalStorageProvider
              if (isExternalStorageDocument(uri)) {
                  final String docId = DocumentsContract.getDocumentId(uri);
                  final String[] split = docId.split(":");
                  final String type = split[0];
  
                  if ("primary".equalsIgnoreCase(type)) {
                      return Environment.getExternalStorageDirectory() + "/" + split[1];
                  }
  
              }
              // DownloadsProvider
              else if (isDownloadsDocument(uri)) {
  
                  final String id = DocumentsContract.getDocumentId(uri);
                  final Uri contentUri = ContentUris.withAppendedId(
                          Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
  
                  return getDataColumn(context, contentUri, null, null);
              }
              // MediaProvider
              else if (isMediaDocument(uri)) {
                  final String docId = DocumentsContract.getDocumentId(uri);
                  final String[] split = docId.split(":");
                  final String type = split[0];
  
                  Uri contentUri = null;
                  if ("image".equals(type)) {
                      contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
                  } else if ("video".equals(type)) {
                      contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
                  } else if ("audio".equals(type)) {
                      contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
                  }
  
                  final String selection = "_id=?";
                  final String[] selectionArgs = new String[]{
                          split[1]
                  };
  
                  return getDataColumn(context, contentUri, selection, selectionArgs);
              }
          }
          // MediaStore (and general)
          else if ("content".equalsIgnoreCase(uri.getScheme())) {
  
              // Return the remote address
              if (isGooglePhotosUri(uri))
                  return uri.getLastPathSegment();
  
              return getDataColumn(context, uri, null, null);
          }
          // File
          else if ("file".equalsIgnoreCase(uri.getScheme())) {
              return uri.getPath();
          }
  
          return null;
      }
  
      /**
       * 获取图片ID
       *
       * @param context 上下文
       * @param uri     图片url
       * @return id
       */
      @SuppressLint("NewApi")
      public static long getId(Context context, Uri uri) {
          final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
          if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
              if (isMediaDocument(uri)) {
                  final String docId = DocumentsContract.getDocumentId(uri);
                  final String[] split = docId.split(":");
                  final String type = split[0];
  
                  Uri contentUri = null;
                  if ("image".equals(type)) {
                      contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
                  } else if ("video".equals(type)) {
                      contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
                  } else if ("audio".equals(type)) {
                      contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
                  }
  
                  final String selection = "_id=?";
                  final String[] selectionArgs = new String[]{
                          split[1]
                  };
  
                  return getIdColumn(context, contentUri, selection, selectionArgs);
              }
          } else {
              return getIdColumn(context, uri, null, null);
          }
          return 0;
      }
  
      /**
       * Get the value of the data column for this Uri. This is useful for
       * MediaStore Uris, and other file-based ContentProviders.
       *
       * @param context       The context.
       * @param uri           The Uri to query.
       * @param selection     (Optional) Filter used in the query.
       * @param selectionArgs (Optional) Selection arguments used in the query.
       * @return The value of the _data column, which is typically a file path.
       */
      public static String getDataColumn(Context context, Uri uri, String selection,
                                         String[] selectionArgs) {
  
          Cursor cursor = null;
          final String column = "_data";
          final String[] projection = {
                  column
          };
  
          try {
              cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs,
                      null);
              if (cursor != null && cursor.moveToFirst()) {
                  final int index = cursor.getColumnIndexOrThrow(column);
                  return cursor.getString(index);
              }
          } finally {
              if (cursor != null)
                  cursor.close();
          }
          return null;
      }
  
      /**
       * 根据图片的uri 获取图片id
       *
       * @param context       上下文
       * @param uri           图片uri
       * @param selection     查询条件
       * @param selectionArgs 查询参数
       * @return id
       */
      public static long getIdColumn(Context context, Uri uri, String selection, String[] selectionArgs) {
          Cursor cursor = null;
          final String column = "_id";
          final String[] projection = {column};
  
          try {
              cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null);
              if (cursor != null && cursor.moveToFirst()) {
                  final int index = cursor.getColumnIndexOrThrow(column);
                  return cursor.getLong(index);
              }
          } finally {
              if (cursor != null) {
                  cursor.close();
              }
          }
          return 0;
      }
  
      /**
       * @param uri The Uri to check.
       * @return Whether the Uri authority is ExternalStorageProvider.
       */
      public static boolean isExternalStorageDocument(Uri uri) {
          return "com.android.externalstorage.documents".equals(uri.getAuthority());
      }
  
      /**
       * @param uri The Uri to check.
       * @return Whether the Uri authority is DownloadsProvider.
       */
      public static boolean isDownloadsDocument(Uri uri) {
          return "com.android.providers.downloads.documents".equals(uri.getAuthority());
      }
  
      /**
       * @param uri The Uri to check.
       * @return Whether the Uri authority is MediaProvider.
       */
      public static boolean isMediaDocument(Uri uri) {
          return "com.android.providers.media.documents".equals(uri.getAuthority());
      }
  
      /**
       * @param uri The Uri to check.
       * @return Whether the Uri authority is Google Photos.
       */
      public static boolean isGooglePhotosUri(Uri uri) {
          return "com.google.android.apps.photos.content".equals(uri.getAuthority());
      }
  
      /**
       * 用给定的uri,调用 裁剪程序
       */
      public static void cropImageByUri(Activity context, int requestCode, Uri from, Uri to, int outputX, int outputY) {
          Intent intent = new Intent("com.android.camera.action.CROP");
          intent.setDataAndType(from, "image/*");
          intent.putExtra("crop", "true");
          intent.putExtra("scale", true);
          intent.putExtra("scaleUpIfNeeded", true);
          intent.putExtra("aspectX", 1);
          intent.putExtra("aspectY", 2);
          intent.putExtra("outputX", outputX);
          intent.putExtra("outputY", outputY);
          intent.putExtra(MediaStore.EXTRA_OUTPUT, to);
          intent.putExtra("return-data", false);
          intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
          intent.putExtra("noFaceDetection", true); // no face detection
          context.startActivityForResult(intent, requestCode);
      }
  }