记载图库照片和照相后进行压缩(7.0)

首先是权限

<!-- 拍照权限 -->
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />

<uses-permission android:name="android.permission.WRITE_CALL_LOG" />
<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.READ_CALL_LOG" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />


首先是布局,首页的布局,很简单,就是两个按钮和一个图片

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/llImage"
    >
   <Button
       android:id="@+id/button"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:text="选择图片"
       />
   <Button
       android:id="@+id/button2"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:text="拍照图片"
       />
   <ImageView
       android:id="@+id/image"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:layout_centerVertical="true"
       android:layout_centerHorizontal="true"
       android:scaleType="centerCrop"
       android:layout_margin="10dp"/>
</LinearLayout>

然后是封装的工具类,调用照相和相册,以及裁剪等

/**
 * 工具类,用来执行调用相机拍照和图库,裁剪等
 * Created by Administrator on 2018/3/21.
 */

public class PhotoUtils {
    private static final String TAG = "PhotoUtils";

    /**
     * @param activity    当前activity
     * @param imageUri    拍照后照片存储路径
     * @param requestCode 调用系统相机请求码
     */
    public static void takePicture(Activity activity, Uri imageUri, int requestCode) {
        //调用系统相机
        Intent intentCamera = new Intent();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            //添加这一句表示对目标应用临时授权该Uri所代表的文件
            intentCamera.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        }
        intentCamera.setAction(MediaStore.ACTION_IMAGE_CAPTURE);
        //将拍照结果保存至photo_file的Uri中,不保留在相册中
        intentCamera.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
        activity.startActivityForResult(intentCamera, requestCode);
    }

    /**
     * @param activity    当前activity
     * @param requestCode 打开相册的请求码
     */
    public static void openPic(Activity activity, int requestCode) {
        Intent photoPickerIntent = new Intent(Intent.ACTION_GET_CONTENT);
        photoPickerIntent.setType("image/*");
        activity.startActivityForResult(photoPickerIntent, requestCode);
    }

    /**
     * @param activity    当前activity
     * @param orgUri      剪裁原图的Uri
     * @param desUri      剪裁后的图片的Uri
     * @param aspectX     X方向的比例
     * @param aspectY     Y方向的比例
     * @param width       剪裁图片的宽度
     * @param height      剪裁图片高度
     * @param requestCode 剪裁图片的请求码
     */
    public static void cropImageUri(Activity activity, Uri orgUri, Uri desUri, int aspectX, int aspectY, int width, int height, int requestCode) {
        Intent intent = new Intent("com.android.camera.action.CROP");
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        }
        intent.setDataAndType(orgUri, "image/*");
        intent.putExtra("crop", "true");
        intent.putExtra("aspectX", aspectX);
        intent.putExtra("aspectY", aspectY);
        intent.putExtra("outputX", width);
        intent.putExtra("outputY", height);
        intent.putExtra("scale", true);
        intent.putExtra("scaleUpIfNeeded", true);
        //将剪切的图片保存到目标Uri中
        intent.putExtra(MediaStore.EXTRA_OUTPUT, desUri);
        intent.putExtra("return-data", false);
        intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
        intent.putExtra("noFaceDetection", true);
        activity.startActivityForResult(intent, requestCode);
    }




    /**
     * 读取uri所在的图片
     *
     * @param uri      图片对应的Uri
     * @param mContext 上下文对象
     * @return 获取图像的Bitmap
     */
    public static Bitmap getBitmapFromUri(Uri uri, Context mContext) {
        try {
            Bitmap bitmap = MediaStore.Images.Media.getBitmap(mContext.getContentResolver(), uri);
            return bitmap;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * @param context 上下文对象
     * @param uri     当前相册照片的Uri
     * @return 解析后的Uri对应的String
     */
    @SuppressLint("NewApi")
    public static String getPath(final Context context, final Uri uri) {

        final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
        String pathHead = "file:///";
        // 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 pathHead + 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 pathHead + 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 pathHead + getDataColumn(context, contentUri, selection, selectionArgs);
            }
        }
        // MediaStore (and general)
        else if ("content".equalsIgnoreCase(uri.getScheme())) {
            return pathHead + getDataColumn(context, uri, null, null);
        }
        // File
        else if ("file".equalsIgnoreCase(uri.getScheme())) {
            return pathHead + uri.getPath();
        }
        return null;
    }

    /**
     * Get the value of the data column for this Uri. This is useful for
     * 获取此Uri的数据列的值。这是有用的
     * MediaStore Uris, and other file-based ContentProviders.
     *mediastore URI,和基于内容提供商的其他文件
     *
     * @param context       The context.上下文
     * @param uri           The Uri to query. uri路径
     * @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. 该_data列的值,这是一个典型的文件路径。
     */
    private 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 column_index = cursor.getColumnIndexOrThrow(column);
                return cursor.getString(column_index);
            }
        } finally {
            if (cursor != null)
                cursor.close();
        }
        return null;
    }

    /**
     * @param uri The Uri to check.
     * @return Whether the Uri authority is ExternalStorageProvider.
     *   不管Uri我自己的存储路径(百度翻译自行理解)
     */
    private static boolean isExternalStorageDocument(Uri uri) {
        return "com.android.externalstorage.documents".equals(uri.getAuthority());
    }

    /**
     * @param uri The Uri to check.要检查的URI。
     * @return Whether the Uri authority is DownloadsProvider.
     */
    private 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.
     * Uri当局是否是媒体提供者?
     */
    private static boolean isMediaDocument(Uri uri) {
        return "com.android.providers.media.documents".equals(uri.getAuthority());
    }
}
 
 

随后,就是在主类中进行调用,而大部分7.0的权限需要自己申请,由用户同意,而不是向4.0以下那种,给了权限你就是大爷。

我直接将整个类贴出来,包括对图片的压缩与转码成base64,base64大部分都是用来将图片上传到后台的,所以可以根据个人需求来取消。

public class MainActivity extends AppCompatActivity implements View.OnClickListener{
    private static int STORAGE_PERMISSIONS_REQUEST_CODE = 0x04;
    private static final int CODE_RESULT_REQUEST = 0xa2;
    private static final int CODE_GALLERY_REQUEST = 0xa0;
    private static final int CODE_CAMERA_REQUEST = 0xa1;
    private static final int CAMERA_PERMISSIONS_REQUEST_CODE = 0x03;
    private ImageView imageVie;
    private Uri cropImageUri;
    private Button button;
    private Uri imageUri;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        imageVie = findViewById(R.id.image);
        button = findViewById(R.id.button);

        Button button2=findViewById(R.id.button2);
        imageVie.setOnClickListener(this);
        button.setOnClickListener(this);
        button2.setOnClickListener(this);
    }

    @Override
    public void onClick(View view) {
   switch (view.getId()){
       case R.id.image:


           break;
       case R.id.button:
           //调用相册授权
           autoObtainCameraPermission();
           break;
       case R.id.button2://拍照
           autoObtainStoragePermission();
           break;


   }


    }

    //自动获取相机权限
    private void autoObtainCameraPermission(){
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE)!= PackageManager.PERMISSION_GRANTED){
            ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},STORAGE_PERMISSIONS_REQUEST_CODE );
        }else {
            PhotoUtils.openPic(this,CODE_GALLERY_REQUEST);
        }


    }


    //返回值回掉
    private static final int OUTPUT_X = 480;
    private static final int OUTPUT_Y = 480;

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
     switch (requestCode){
         //拍照完成回调
         case CODE_CAMERA_REQUEST:
             cropImageUri = Uri.fromFile(new File(Environment.getExternalStorageDirectory().getPath() + "/crop_photo"+ UUID.randomUUID()+".jpg"));
             if (imageUri!=null&&cropImageUri!=null){
 //---------------------不裁剪图片,也就是调用系统,可以自定义大小的裁剪框,上传证书啊之类的-----------------------------------------------------------------------------------------------------------------
                 Intent intent = new Intent("com.android.camera.action.CROP");
                 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                     intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
                 }
                 intent.setDataAndType(imageUri, "image/*");
                 intent.putExtra("scale", true);
                 intent.putExtra("scaleUpIfNeeded", true);
                 //将剪切的图片保存到目标Uri中
                 intent.putExtra(MediaStore.EXTRA_OUTPUT, cropImageUri);
                 intent.putExtra("return-data", false);
                 intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
                 intent.putExtra("noFaceDetection", true);
                 startActivityForResult(intent, CODE_RESULT_REQUEST);

//---------------------------规定大小裁剪图片,只能选择放大或缩小图片,裁剪固定范围,图片无法完全展示,头像什么的没有问题---------------------------------------------------------------------------------------------------
//                    PhotoUtils.cropImageUri(this, imageUri, cropImageUri, 1, 1, OUTPUT_X, OUTPUT_Y, CODE_RESULT_REQUEST);
             }

             break;
          //调用系统裁剪等回调
         case CODE_RESULT_REQUEST:
             Bitmap bitmap = PhotoUtils.getBitmapFromUri(cropImageUri, this);

             if (bitmap != null) {
                 InputStream input=null;
                 try {
                     input = getContentResolver().openInputStream(cropImageUri);
                     int available = input.available();
                     Log.e("LOG",(available/1024/1024)+"m");
                     if (available/1024/1024<4){

                         String path = cropImageUri.getPath();
                         //二次采样,通过长宽对图片进行压缩,减小内存,图片尺寸越大,压缩的越模糊
                         Bitmap bitmap1 = getBitmap(path, 600, 600);
                         //转为base64,上传后台或自行处理
                         showImages(bitmap1);
                         //展示压缩后的图片,可以去掉
                         imageVie.setImageBitmap(bitmap1);
                     }else {
                         Toast.makeText(this, "图片不能超过4M", Toast.LENGTH_SHORT).show();
                     }
                     input.close();
                 } catch (FileNotFoundException e) {
                     e.printStackTrace();
                 } catch (IOException e) {
                     e.printStackTrace();
                 }
             }
             break;
         case CODE_GALLERY_REQUEST:
             if (hasSdcard()) {
                 if (data!=null){
                     cropImageUri = Uri.fromFile(new File(Environment.getExternalStorageDirectory().getPath() + "/crop_photo"+UUID.randomUUID()+".jpg"));
                     Uri newUri = Uri.parse(PhotoUtils.getPath(this, data.getData()));
                     if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                         newUri = FileProvider.getUriForFile(this, "text.jdyx.com.jdyx.fileprovider", new File(newUri.getPath()));
                     }
//------------------------不裁剪图片,也就是调用系统,可以自定义大小的裁剪框,上传证书啊之类的-----------------------------------------------------------------------------------------------------------------
                     Intent intent = new Intent("com.android.camera.action.CROP");
                     if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                         intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
                     }
                     intent.setDataAndType(newUri, "image/*");
                     intent.putExtra("scale", true);
                     intent.putExtra("scaleUpIfNeeded", true);
                     //将剪切的图片保存到目标Uri中
                     intent.putExtra(MediaStore.EXTRA_OUTPUT, cropImageUri);
                     intent.putExtra("return-data", false);
                     intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
                     intent.putExtra("noFaceDetection", true);
                     startActivityForResult(intent, CODE_RESULT_REQUEST);

//------------------------------规定大小裁剪图片,只能选择放大或缩小图片,裁剪固定范围,图片无法完全展示,头像什么的没有问题-------------------------------------------------------------------------------------------------------------
//                        PhotoUtils.cropImageUri(this, newUri, cropImageUri, 1, 1, OUTPUT_X, OUTPUT_Y, CODE_RESULT_REQUEST);//跳转裁剪图片
                 }

             } else {
                 Toast.makeText(this, "设备没有SD卡!", Toast.LENGTH_SHORT).show();
             }
             break;

     }

    }
    /**
     * 检查设备是否存在SDCard的工具方法
     */
    public static boolean hasSdcard() {
        String state = Environment.getExternalStorageState();
        return state.equals(Environment.MEDIA_MOUNTED);
    }
    /**
     * @param filePath   要加载的图片路径
     * @param destWidth  显示图片的控件宽度
     * @param destHeight 显示图片的控件的高度
     * @return
     */
    public  Bitmap getBitmap(String filePath, int destWidth, int destHeight) {
        //第一次采样
        BitmapFactory.Options options = new BitmapFactory.Options();
        //该属性设置为true只会加载图片的边框进来,并不会加载图片具体的像素点
        options.inJustDecodeBounds = true;
        //第一次加载图片,这时只会加载图片的边框进来,并不会加载图片中的像素点
        BitmapFactory.decodeFile(filePath, options);
        //获得原图的宽和高
        int outWidth = options.outWidth;
        int outHeight = options.outHeight;
        //定义缩放比例
        int sampleSize = 1;
        while (outHeight / sampleSize > destHeight || outWidth / sampleSize > destWidth) {
            //如果宽高的任意一方的缩放比例没有达到要求,都继续增大缩放比例
//            /mpleSize应该为2的n次幂,如果给sampleSize设置的数字不是2的n次幂,那么系统会就近取值
            sampleSize *= 2;
        }
        /********************************************************************************************/
        //至此,第一次采样已经结束,我们已经成功的计算出了sampleSize的大小
        /********************************************************************************************/
        //二次采样开始
        //二次采样时我需要将图片加载出来显示,不能只加载图片的框架,因此inJustDecodeBounds属性要设置为false
        options.inJustDecodeBounds = false;
        //设置缩放比例
        options.inSampleSize = sampleSize;
        options.inPreferredConfig = Bitmap.Config.ARGB_8888;
        //加载图片并返回
        return BitmapFactory.decodeFile(filePath, options);

    }
    //可以在这里执行向后台上传图片base64
    private void showImages(Bitmap bitmap) {

//      压缩图片,此为质量压缩,但是为了保证上传的清晰度,不进行压缩,同时转为base64上传到后台
        ByteArrayOutputStream onputStream = new ByteArrayOutputStream();
        bitmap.compress(Bitmap.CompressFormat.JPEG, 100, onputStream);
        byte[] bytes = onputStream.toByteArray();

         //转为base64
        String base64 = Base64.encodeToString(bytes, Base64.DEFAULT);

        Log.e("TAG","Base64:"+base64);
        JSONObject jsonObjectUpImage = new JSONObject();
        try {
            String newUriStr = cropImageUri.toString();
            //判断图片格式,选择保存
            String imageType = newUriStr.substring(newUriStr.length() - 3, newUriStr.length()).trim();
            if (imageType.equals("jpg")){
                jsonObjectUpImage.put("contentType","JPG");
            }
            if (imageType.equals("png")){
                jsonObjectUpImage.put("contentType","PNG");
            }
            if (imageType.equals("jpeg")){
                jsonObjectUpImage.put("contentType","JPEG");
            }
            if (imageType.equals("gif")){
                jsonObjectUpImage.put("contentType","GIF");
            }

        } catch (JSONException e) {
            e.printStackTrace();
        }
    }
    //拍照,自动获取存储权限
    private void autoObtainStoragePermission() {
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED
                || ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {

            if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA)) {
                Toast.makeText(this, "您已经拒绝过一次", Toast.LENGTH_SHORT).show();
            }
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA, Manifest.permission.READ_EXTERNAL_STORAGE}, CAMERA_PERMISSIONS_REQUEST_CODE);
        } else {//有权限直接调用系统相机拍照
            if (hasSdcard()) {
                imageUri = Uri.fromFile(new File(Environment.getExternalStorageDirectory().getPath() + "/photo"+ UUID.randomUUID()+".jpg"));
                //通过FileProvider创建一个content类型的Uri
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                    imageUri = FileProvider.getUriForFile(MainActivity.this, "text.jdyx.com.jdyx.fileprovider", new File(Environment.getExternalStorageDirectory().getPath() + "/photo"+UUID.randomUUID()+".jpg"));
                }
                PhotoUtils.takePicture(this, imageUri, CODE_CAMERA_REQUEST);
            } else {
                Toast.makeText(this, "设备没有SD卡", Toast.LENGTH_SHORT).show();
            }
        }
    }

}


































猜你喜欢

转载自blog.csdn.net/liu_ser/article/details/79644233