zoukankan      html  css  js  c++  java
  • 拍照/选择相册,图片压缩旋转处理

    最近做项目需要用到拍照和选择相册照片,并显示出来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获取图片信息:

     @Override
        protected 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 to
            if (Build.VERSION.SDK_INT >= 19 && DocumentsContract.isDocumentUri(context.getApplicationContext(), uri)) {
                String authority = uri.getAuthority();
                if ("com.android.externalstorage.documents".equals(authority)) {
                    // isExternalStorageDocument
                    final String docId = DocumentsContract.getDocumentId(uri);
                    final String[] split = docId.split(":");
                    return Environment.getExternalStorageDirectory() + "/" + split[1];
                } else if ("com.android.providers.downloads.documents".equals(authority)) {
                    // isDownloadsDocument
                    final 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)) {
                    // isMediaDocument
                    final 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;
        }

    这些代码百分之七八十来自开源中国。感谢原作者。

    源码下载

  • 相关阅读:
    k8s的包管理
    k8s的paas平台
    zookeeper相关
    java之rpc/orm
    java之spring
    EK算法
    SAM学习笔记
    生日悖论不是“悖论”!
    分块--莫队学习粗略预习
    二项式反演学习笔记
  • 原文地址:https://www.cnblogs.com/forezp/p/9852209.html
Copyright © 2011-2022 走看看