• 拍照、本地图片工具类(兼容至Android7.0)


     拍照、本地图片工具类:解决了4.4以上剪裁会提示“找不到文件”和6.0动态授予权限,及7.0报FileUriExposedException异常问题。

    package com.hb.weex.util;
    
    import android.Manifest;
    import android.app.Activity;
    import android.app.Dialog;
    import android.content.ClipData;
    import android.content.ContentUris;
    import android.content.ContentValues;
    import android.content.Context;
    import android.content.Intent;
    import android.content.pm.PackageManager;
    import android.content.pm.ResolveInfo;
    import android.database.Cursor;
    import android.graphics.Bitmap;
    import android.graphics.BitmapFactory;
    import android.net.Uri;
    import android.os.Build;
    import android.os.Environment;
    import android.provider.MediaStore;
    import android.support.v4.app.FragmentActivity;
    import android.support.v4.content.FileProvider;
    import android.view.View;
    import android.widget.Button;
    import com.hb.common.android.util.Log;
    import com.hb.weex.R;
    import com.hb.weex.util.ToastUtil;
    import com.hb.weex.util.UploadAvatarUtil;
    
    import java.io.ByteArrayInputStream;
    import java.io.ByteArrayOutputStream;
    import java.io.File;
    import java.io.FileNotFoundException;
    import java.io.IOException;
    import java.lang.reflect.Method;
    import java.util.HashMap;
    import java.util.Iterator;
    import java.util.List;
    
    import kr.co.namee.permissiongen.GrantPermissionActivity;
    import kr.co.namee.permissiongen.PermissionGen;
    import kr.co.namee.permissiongen.internal.Utils;
    
    /**
     * 拍照管理的类
     * Created by cjy on 2017/4/03.
     */
    public class TakePhotoManager implements View.OnClickListener,GrantPermissionActivity.OnGrantedListener {
        /**
         * 权限列表:写权限 读权限 调用摄像头权限
         */
        private static final String[] PERMISSIONS = new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE,
                Manifest.permission.READ_EXTERNAL_STORAGE,Manifest.permission.CAMERA};
    
        /* 上下文 */
        private Activity context;
    
        /* 对话框 */
        private Dialog mSelectPhotoDialog;
    
        /* 图片的存储地址-父路径 */
        private String mHeadImageFileParentPath = "";
    
        /* 照相机拍照后的照片 */
        private String mCameraImageFileName = "";
    
        /* 头像名称 */
        private String mHeadImageFileName = "";
    
        private Button mBtnTakePhoto;//拍照
        private Button mBtnPickPhoto;//选择本地图片
        private Button mBtnCancel;//取消
    
        private Uri imageUri;//原图保存地址
    
    
        public TakePhotoManager(Activity context) {
            this.context = context;
            mHeadImageFileParentPath = Environment.getExternalStorageDirectory() + File.separator+ context.getPackageName()+File.separator;
            mCameraImageFileName = "temp_camera_image.jpg";
            mHeadImageFileName = "tmp_head_image.jpg";
        }
    
        public void setmHeadImageFileParentPath(String mHeadImageFileParentPath) {
            this.mHeadImageFileParentPath = mHeadImageFileParentPath;
        }
    
        public void setmCameraImageFileName(String mCameraImageFileName) {
            this.mCameraImageFileName = mCameraImageFileName;
        }
    
        public void setmHeadImageFileName(String mHeadImageFileName) {
            this.mHeadImageFileName = mHeadImageFileName;
        }
    
        /**
         * 显示头像弹出窗
         */
        public void showSelectPhotoDialog() {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {//23
                //Android6.0及以上,需要动态授予权限
                // 验证所有权限是否都已经授权了
                List<String> deniedPermissions = Utils.findDeniedPermissions(this.context, PERMISSIONS);
                if (deniedPermissions.size() == 0) {
                    showDialog();
                } else {
                    Intent intent = new Intent(this.context, GrantPermissionActivity.class);
                    intent.putExtra(GrantPermissionActivity.PARAM_PERMISSION_NAME_LIST, PERMISSIONS);
                    GrantPermissionActivity.mGrantedListener = this;
                    this.context.startActivity(intent);
                }
            }else{
                showDialog();
            }
        }
    
        private void showDialog(){
            View view = context.getLayoutInflater().inflate(R.layout.dlg_select_photo,
                    null);
            mBtnTakePhoto = (Button) view.findViewById(R.id.btn_take_photo);
            mBtnPickPhoto = (Button) view.findViewById(R.id.btn_pick_photo);
            mBtnCancel = (Button) view.findViewById(R.id.btn_cancel);
            mBtnTakePhoto.setOnClickListener(this);
            mBtnPickPhoto.setOnClickListener(this);
            mBtnCancel.setOnClickListener(this);
            mSelectPhotoDialog = UploadAvatarUtil.createDialog(context, view,
                    R.style.transparentFrameWindowStyle, R.style.select_photo_dialog_animstyle);
        }
    
        /**
         * 关闭头像弹出窗
         */
        public void hideSelectPhotoDialog() {
            if (mSelectPhotoDialog != null && mSelectPhotoDialog.isShowing()) {
                mSelectPhotoDialog.dismiss();
            }
        }
    
        /**
         * 拍照
         */
        public void takePhoto(Activity context, String imgUrl, String imageFileNameTemp) {
            File file = UploadAvatarUtil.getFile(imgUrl, imageFileNameTemp);
            // 打开相机
            Intent intentFromCapture = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                //FileUriExposedException这个异常只会在Android 7.0 + 出现,当app使用file:// url 共享给其他app时, 会抛出这个异常。
                //因为在android 6.0 + 权限需要 在运行时候检查, 其他app 可能没有读写文件的权限, 所以google在7.0的时候加上了这个限制。官方推荐使用 FileProvider 解决这个问题。
                intentFromCapture.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION ); //添加这一句表示对目标应用临时授权该Uri所代表的文件
                imageUri = FileProvider.getUriForFile(context, "com.hb.weex.accountant.fileprovider", file);//通过FileProvider创建一个content类型的Uri
            } else {
                imageUri = Uri.fromFile(file);
            }
            intentFromCapture.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);//将拍取的照片保存到指定URI
            context.startActivityForResult(intentFromCapture, UploadAvatarUtil.CAMERA_REQUEST_CODE);
        }
    
        /**
         * 选择本地图片
         */
        public void pickPhoto(Activity context) {
            Intent intent = new Intent(Intent.ACTION_PICK);
            intent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*");
            context.startActivityForResult(intent, UploadAvatarUtil.IMAGE_REQUEST_CODE);
        }
    
        public Object onActivityResult(Context context,int requestCode, int resultCode, Intent data) {
            //关闭头像弹出窗
            hideSelectPhotoDialog();
            if (resultCode != Activity.RESULT_CANCELED) {
                switch (requestCode) {
                    case UploadAvatarUtil.IMAGE_REQUEST_CODE:// 选择本地图片返回
                        if (null != data) {//为了取消选取不报空指针用的
                            imageUri = data.getData();
                            startPhotoZoom(context, imageUri , 1);
                        }
                        break;
                    case UploadAvatarUtil.CAMERA_REQUEST_CODE:// 拍照返回
                        if (UploadAvatarUtil.hasSdcard()) {
                            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {//24
                                startPhotoZoom(context, imageUri, 0);
                            }else{
                                File tempFile = getFileTmp();
                                startPhotoZoom(context, Uri.fromFile(tempFile), 0);
                            }
                        } else {
                            ToastUtil.showToast(context, context.getResources().getString(R.string.find_sdcard_none));
                        }
                        break;
                    case UploadAvatarUtil.CLIP_REQUEST_CODE:// 裁剪完成,删除照相机缓存的图片
                        Bitmap imageBitmap = null;
                        //获取头像文件
                        File file = getTmpHeadImage();
                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N){//24
                            try {
                                imageBitmap = BitmapFactory.decodeStream(context.getContentResolver().openInputStream(imageUri));
                            } catch (FileNotFoundException e) {
                                e.printStackTrace();
                            }
                        }else {
                            if (!file.exists()) {
                                return null;
                            }
                            imageBitmap = BitmapFactory.decodeFile(file.getAbsolutePath());
                        }
                        if (imageBitmap == null) {
                            return null;
                        }
                        ByteArrayOutputStream baos = new ByteArrayOutputStream();
                        imageBitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);
                        byte[] userImageData = baos.toByteArray();
                        //修改个人头像
                        HashMap<String, Object> result = new HashMap<String, Object>();
                        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
                            result.put("path", file.getAbsolutePath());
                        }
                        result.put("data",userImageData);
                        return result;
                }
            }
            return null;
        }
    
            /**
             * 裁剪图片
             *
             * @param uri from 1代表本地照片的裁剪,0代表拍照后的裁剪
             */
        public void startPhotoZoom(Context context, Uri uri, int from) {
            Intent intent = new Intent("com.android.camera.action.CROP");
            String url = convertPath(context, uri);
            /**
             * 当满足:SDK>4.0、选择本地照片操作、裁剪框为圆形(或者说路径与之前版本有异)三个条件时
             * 进行转换操作
             */
            if (Build.VERSION.SDK_INT >= 19 && from == 1 && url != null) {
                intent.setDataAndType(Uri.fromFile(new File(url)), "image/*");
            } else {
                intent.setDataAndType(uri, "image/*");
            }
    
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION );
            }
    
            // 设置裁剪
            intent.putExtra("crop", "true");
            // aspectX aspectY 是宽高的比例
            intent.putExtra("aspectX", 1);
            intent.putExtra("aspectY", 1);
            // outputX outputY 是裁剪图片宽高
            intent.putExtra("outputX", 100);
            intent.putExtra("outputY", 100);
    
            Uri uriPath;
            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {//小于24
                uriPath = Uri.fromFile(UploadAvatarUtil.getFile(mHeadImageFileParentPath, mHeadImageFileName));
            }else{
                uriPath = imageUri;
            }
            intent.putExtra(MediaStore.EXTRA_OUTPUT, uriPath);
            intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
            intent.putExtra("return-data", false);
            //intent.putExtra("return-data", true);
            //return-data为true时,会直接返回bitmap数据,但是大图裁剪时会出现问题。
            //设置为false比较好,但是,需要指定MediaStore.EXTRA_OUTPUT,来保存裁剪之后的图片
            ((Activity)context).startActivityForResult(intent, UploadAvatarUtil.CLIP_REQUEST_CODE);
        }
    
    
        /**
         * 删除缓存的头像
         */
        public void deleteHeadCache() {
            UploadAvatarUtil.deleteLocalImage(mHeadImageFileParentPath, mHeadImageFileName);
        }
    
        /**
         * 获取文件对象---照相机拍照的
         *
         * @return
         */
        public File getFileTmp() {
            return UploadAvatarUtil.getFile(mHeadImageFileParentPath, mCameraImageFileName);
        }
    
    
        /**
         * 获取裁剪之后的图片文件
         */
        public File getTmpHeadImage(){
            return UploadAvatarUtil.getFile(mHeadImageFileParentPath,mHeadImageFileName);
        }
    
        /**
         * 删除照相机拍照的图片
         */
        public void deleteCameraImage() {
            UploadAvatarUtil.deleteLocalImage(mHeadImageFileParentPath, mCameraImageFileName);
        }
    
        @Override
        public void onClick(View view) {
            switch (view.getId()) {
                case R.id.btn_take_photo:
                    takePhoto(context, mHeadImageFileParentPath, mCameraImageFileName);
                    break;
                case R.id.btn_pick_photo:
                    pickPhoto(context);
                    break;
                case R.id.btn_cancel:
                    hideSelectPhotoDialog();
                    break;
            }
        }
    
    
        /**
         * 将uri转换成字符串
         * 解决4.4版本以上获取到的uri是图片名称而非图片路径,导致剪裁图片时提示无法加载图片的问题
         * 详细的解决方案,请参考这篇文章
         * 当安卓的版本比较高时(如4.4),选择本地相册可能会返回“无法加载此图片”
         * 原因:正常uri是file://...而高版本是content://...
         * 所以需要一个转换操作
         *
         * @param context
         * @param uri
         * @return
         */
        public String convertPath(final Context context, final Uri uri) {
            //代表SDK4.4需要反射的类
            Class getClass = null;
            //代表两个SDK4.4里面反射的方法
            Method isMethod;
            Method getMethod;
            String stringMethod = "";
    
    
            //判断当前版本是否大于4.0
            final boolean isKitKat = Build.VERSION.SDK_INT >= 19;
            try {
                /**
                 * 获取类和方法
                 * 方法传参方式
                 * 获取返回值
                 */
                getClass = Class.forName("android.provider.DocumentsContract");
                getMethod = getClass.getMethod("getDocumentId", new Class[]{Uri.class});
                isMethod = getClass.getMethod("isDocumentUri", new Class[]{Context.class, Uri.class});
                Object isResult = isMethod.invoke(getClass, new Object[]{context, uri});
                Object getResult = getMethod.invoke(getClass, new Object[]{uri});
                stringMethod = (String) getResult;
                if (!(Boolean) isResult)
                    return null;
                //当手机SDK大于4.4且路径类型与以往不同时(isShot为True时往往裁剪框是圆形,即是新类型的路径)
                if (isKitKat) {
                    if (isExternalStorageDocument(uri)) {
                        final String docId = stringMethod;
                        final String[] split = docId.split(":");
                        final String type = split[0];
    
                        if ("primary".equalsIgnoreCase(type)) {
                            return Environment.getExternalStorageDirectory() + "/" + split[1];
                        }
    
                    } else if (isDownloadsDocument(uri)) {
                        final String id = stringMethod;
                        final Uri contentUri = ContentUris.withAppendedId(
                                //高版本的路径不同于低版本,需要转换
                                Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
    
                        return getDataColumn(context, contentUri, null, null);
                    } else if (isMediaDocument(uri)) {
                        final String docId = stringMethod;
                        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);
                    }
                } else if ("content".equalsIgnoreCase(uri.getScheme())) {
                    if (isGooglePhotosUri(uri))
                        return uri.getLastPathSegment();
    
                    return getDataColumn(context, uri, null, null);
                } else if ("file".equalsIgnoreCase(uri.getScheme())) {
                    return uri.getPath();
                }
    
                return null;
            } catch (Exception e) {
                Log.e("error", e.toString());
            }
            return null;
        }
    
    
        //获取String类型的路径
        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;
        }
    
        public static boolean isExternalStorageDocument(Uri uri) {
            return "com.android.externalstorage.documents".equals(uri.getAuthority());
        }
    
        public static boolean isDownloadsDocument(Uri uri) {
            return "com.android.providers.downloads.documents".equals(uri.getAuthority());
        }
    
        public static boolean isMediaDocument(Uri uri) {
            return "com.android.providers.media.documents".equals(uri.getAuthority());
        }
    
        public static boolean isGooglePhotosUri(Uri uri) {
            return "com.google.android.apps.photos.content".equals(uri.getAuthority());
        }
    
        @Override
        public void onGrantSuccess() {
            showDialog();
        }
    }

    在7.0 上使用FileProvider来获取图片的路径,需要以下几步设置:

    (1)在Androidmainfest的Application根标签中设置provider,相机,读写文件权限

      <!-- Android7.0以上,拍照需要设置FileProvider -->
            <provider
                android:name="android.support.v4.content.FileProvider"
                android:authorities="com.hb.accountant.accountant.fileprovider"
                android:grantUriPermissions="true"
                android:exported="false">
                <meta-data
                    android:name="android.support.FILE_PROVIDER_PATHS"
                    android:resource="@xml/file_paths" />
            </provider>
    
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.CAMERA"/>

    (2)在res/xml目录中创建文件file_paths.xml:

    <?xml version="1.0" encoding="utf-8"?>
    <paths xmlns:android="http://schemas.android.com/apk/res/android">
    
        <!--external-path 就是用来指定URI共享的
        name属性的值可以随便写
        path属性的值表示共享的具体位置,设置空就表示将整个SD卡进行共享
        用该路径保存的好处是,文件会随着应用的卸载而删除,file/header/为自定义路径
    Android/data/com.bugull.cameratakedemo/files/header/
         -->
    
        <!--<external-path  name = "my-images" path = "demo"/>-->
    
        <paths>
            <external-path path="包名" name="camera_photos" />
        </paths>
    </paths>

    注:文件中涉及的其他文件如下:

      (1)动态权限授权使用第三方PermissionGen

    (2)UploadAvatarUtil.java

    package com.hb.weex.util;
    
    import android.app.Activity;
    import android.app.Dialog;
    import android.content.Context;
    import android.content.Intent;
    import android.graphics.*;
    import android.graphics.drawable.BitmapDrawable;
    import android.graphics.drawable.Drawable;
    import android.graphics.drawable.LayerDrawable;
    import android.net.Uri;
    import android.os.Environment;
    import android.provider.MediaStore;
    import android.view.View;
    import android.view.ViewGroup;
    import android.view.Window;
    import android.view.WindowManager;
    import com.hb.common.android.util.Log;
    
    import java.io.File;
    import java.io.FileOutputStream;
    import java.io.IOException;
    
    
    /**
     * 上传用户头像
     * 功能如下:
     * 1、保存图片到本地、删除本地图片
     * 2、拍照、从图库中选择照片、剪裁
     * 3、创建文件目录、获取文件对象
     * 4、检查Sdcard是否存在
     * 5、创建圆角矩形图片
     * 6、创建圆角图片
     * 7、自定义从下往上显示的Dialog(模仿QQ退出效果)
     * 8、图片上绘制文字
     * Created by cjy on 2015/4/9.
     */
    public class UploadAvatarUtil {
        public static final int IMAGE_REQUEST_CODE = 0;  //选择本地图片
        public static final int CAMERA_REQUEST_CODE = 1; //拍照
        public static final int CLIP_REQUEST_CODE = 2;   //裁剪
    
        private static final int DEFAULT_TEXT_SIZE = 32;//默认的字体大小
    
        /**
         * 检查是否存在sdcard
         *
         * @return
         */
        public static boolean hasSdcard() {
            String state = Environment.getExternalStorageState();
            if (state.equals(Environment.MEDIA_MOUNTED)) {
                return true;
            } else {
                return false;
            }
        }
    
        /**
         * 创建文件目录
         *
         * @param filePath 文件路径
         */
        public static File makeFileDir(String filePath) {
            File file = null;
            try {
                file = new File(filePath);
                if (!file.exists()) {
                    file.mkdirs();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            return file;
        }
    
        /**
         * 获取文件对象
         *
         * @param filePath 文件路径
         * @param fileName 文件名称
         * @return
         */
        public static File getFile(String filePath, String fileName) {
            File file = null;
            //创建文件目录
            makeFileDir(filePath);
            try {
                file = new File(filePath + fileName);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return file;
        }
    
        /**
         * 保存图片到本地
         *
         * @param imgUrl        图片路径
         * @param imageFileName 图片名称
         * @param bitmap
         */
        public static void saveLocalImage(String imgUrl, String imageFileName, Bitmap bitmap) {
            try {
                File f = getFile(imgUrl, imageFileName);
                FileOutputStream fOut = new FileOutputStream(f);
                bitmap.compress(Bitmap.CompressFormat.PNG, 100, fOut);
                fOut.flush();
                fOut.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        /**
         * 删除本地图片
         *
         * @param imgUrl        图片路径
         * @param imageFileName 图片名称
         */
        public static void deleteLocalImage(String imgUrl, String imageFileName) {
            File f = getFile(imgUrl, imageFileName);
            if (f.isFile() && f.exists()) {
                f.delete();
            }
        }
    
        /**
         * 绘制圆角矩形图片
         * 圆形 x=120,y=120,outerRadiusRat=60
         *
         * @param x
         * @param y
         * @param image
         * @param outerRadiusRat
         * @return
         */
        public static Bitmap createFramedPhoto(int x, int y, Bitmap image,
                                               float outerRadiusRat) {
            // 根据源文件新建一个darwable对象
            Drawable imageDrawable = new BitmapDrawable(image);
    
            // 新建一个新的输出图片
            Bitmap output = Bitmap.createBitmap(x, y, Bitmap.Config.ARGB_8888);
            Canvas canvas = new Canvas(output);
    
            // 新建一个矩形
            RectF outerRect = new RectF(0, 0, x, y);
    
            // 产生一个白色的圆角矩形
            Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
            paint.setColor(Color.RED);
            canvas.drawRoundRect(outerRect, outerRadiusRat, outerRadiusRat, paint);
    
            // 将源图片绘制到这个圆角矩形上
            paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
            imageDrawable.setBounds(0, 0, x, y);
            canvas.saveLayer(outerRect, paint, Canvas.ALL_SAVE_FLAG);
            imageDrawable.draw(canvas);
            canvas.restore();
    
            return output;
        }
    
        /**
         * 选择本地图片
         */
        public static void pickPhoto(Context context) {
            Intent intentFromGallery = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
            intentFromGallery.setType("image/*"); // 设置文件类型
            intentFromGallery.setAction(Intent.ACTION_GET_CONTENT);
            ((Activity) context).startActivityForResult(intentFromGallery, IMAGE_REQUEST_CODE);
        }
    
        /**
         * 拍照
         */
        public static void takePhoto(Context context, String imgUrl, String imageFileNameTemp) {
            // 打开相机
            Intent intentFromCapture = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
            // 判断存储卡是否可以用,存储缓存图片
            if (hasSdcard()) {
                intentFromCapture.putExtra(MediaStore.EXTRA_OUTPUT,
                        Uri.fromFile(getFile(imgUrl, imageFileNameTemp)));
            }
            ((Activity) context).startActivityForResult(intentFromCapture, CAMERA_REQUEST_CODE);
        }
    
        /**
         * 裁剪图片
         *
         * @param uri
         */
        public static void startPhotoZoom(Context context, Uri uri) {
            Intent intent = new Intent("com.android.camera.action.CROP");
            intent.setDataAndType(uri, "image/*");
            // 设置裁剪
            intent.putExtra("crop", "true");
            // aspectX aspectY 是宽高的比例
            intent.putExtra("aspectX", 1);
            intent.putExtra("aspectY", 1);
            // outputX outputY 是裁剪图片宽高
            intent.putExtra("outputX", 200);
            intent.putExtra("outputY", 200);
            intent.putExtra("return-data", true);
    //        intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
    //        intent.putExtra("return-data", false);//设置为不返回数据
            ((Activity) context).startActivityForResult(intent, CLIP_REQUEST_CODE);
        }
    
        /**
         * 创建指定样式、指定动画的Dialog
         *
         * @param context
         * @param view        Dialog的布局
         * @param styleId     Dialog的样式
         * @param animStyleId Dialog的动画样式
         * @return
         */
        public static Dialog createDialog(Context context, View view, int styleId, int animStyleId) {
            Dialog mSelectPhotoDialog = new Dialog(context, styleId);
            mSelectPhotoDialog.setContentView(view);
            Window window = mSelectPhotoDialog.getWindow();
            // 设置显示动画
            window.setWindowAnimations(animStyleId);
            WindowManager.LayoutParams wl = window.getAttributes();
            wl.x = 0;
            wl.y = ((Activity) context).getWindowManager().getDefaultDisplay().getHeight();
            // 以下这两句是为了保证按钮可以水平满屏
            wl.width = ViewGroup.LayoutParams.MATCH_PARENT;
            wl.height = ViewGroup.LayoutParams.WRAP_CONTENT;
            // 设置显示位置
            mSelectPhotoDialog.onWindowAttributesChanged(wl);
            // 设置点击外围解散
            mSelectPhotoDialog.setCanceledOnTouchOutside(true);
            mSelectPhotoDialog.show();
    
            return mSelectPhotoDialog;
        }
    
        /**
         * 第1种方法:图片上绘制文字
         *
         * @param context
         * @param drawableId
         * @param text
         * @param color
         * @return
         */
        public static Bitmap drawTextAtBitmap(Context context, int drawableId, String text, int color, float density) {
            Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), drawableId);
    
            int[] size = getBitmapSize(context, drawableId);
    //        Log.e("density", density + "");
            int x = size[0];
            int y = size[1];
    //        int x = (int) (size[0] * density);
    //        int y = (int) (size[1] * density);
    //        Log.e("x", x + "");
    //        Log.e("y", y + "");
    //        bitmap = getScaleBitmap(context,bitmap);
    
            // 创建一个和原图同样大小的位图
            Bitmap newbit = Bitmap.createBitmap(x, y, Bitmap.Config.ARGB_8888);
            Canvas canvas = new Canvas(newbit);
            Paint paint = new Paint();
            // 贴图 在原始位置0,0插入原图
            canvas.drawBitmap(bitmap, 0, 0, paint);
            paint.setColor(color);
            int textSize = DEFAULT_TEXT_SIZE;
            if (density >= 3) {
                textSize *= (density + 1);
            } else if (density >= 2) {
                textSize *= (density + 0.1);
            }
            paint.setTextSize(textSize);
            paint.setTextAlign(Paint.Align.CENTER);
            // 在原图指定位置写上字
    //        canvas.drawText(text, x / 2 - 10 * density, y / 2, paint);
            canvas.drawText(text, x / 2, y / 2 + 20 * (density-1) + 2, paint);
    
            canvas.save(Canvas.ALL_SAVE_FLAG);
    
            // 存储
            canvas.restore();
            return newbit;
        }
    
        /**
         * 图片叠加
         *
         * @param bitmap1
         * @param bitmap2
         * @return
         */
        public static Bitmap layerBitmap(Bitmap bitmap1, Bitmap bitmap2) {
    
            // copy 防止出现Immutable bitmap passed to Canvas constructor错误
            bitmap1 = bitmap1.copy(Bitmap.Config.ARGB_8888, true);
    
            Bitmap newBitmap = null;
    
            newBitmap = Bitmap.createBitmap(bitmap1);
            Canvas canvas = new Canvas(newBitmap);
            Paint paint = new Paint();
    
            int w = bitmap1.getWidth();
            int h = bitmap1.getHeight();
    
            int w_2 = bitmap2.getWidth();
            int h_2 = bitmap2.getHeight();
    
            paint.setColor(Color.GRAY);
            paint.setAlpha(125);
            canvas.drawRect(0, 0, bitmap1.getWidth(), bitmap1.getHeight(), paint);
    
            paint = new Paint();
            canvas.drawBitmap(bitmap2, Math.abs(w - w_2) / 2,
                    Math.abs(h - h_2) / 2, paint);
            canvas.save(Canvas.ALL_SAVE_FLAG);
            // 存储新合成的图片
            canvas.restore();
    
            return newBitmap;
    
    
        }
    
        /**
         * 图片叠加
         *
         * @param bitmap1
         * @param bitmap2
         * @return
         */
        public static LayerDrawable layerDrawable(Bitmap bitmap1, Bitmap bitmap2) {
            Drawable[] array = new Drawable[2];
            array[0] = new BitmapDrawable(bitmap1);
            array[1] = new BitmapDrawable(bitmap2);
            LayerDrawable la = new LayerDrawable(array);
            // 其中第一个参数为层的索引号,后面的四个参数分别为left、top、right和bottom
            la.setLayerInset(0, 0, 0, 0, 0);
            la.setLayerInset(1, 10, 10, 10, 10);
    
            return la;
        }
    
        /**
         * 获取Bitmap的宽高
         *
         * @param context
         * @param drawableId 图片id
         * @return
         */
        private static int[] getBitmapSize(Context context, int drawableId) {
            int[] size = new int[2];
            BitmapFactory.Options opts = new BitmapFactory.Options();
            opts.inJustDecodeBounds = true;
            BitmapFactory.decodeResource(context.getResources(), drawableId, opts);
            int width = opts.outWidth;
            int height = opts.outHeight;
            size[0] = width;
            size[1] = height;
            return size;
        }
    
    
        /**
         * 等比例缩放
         *
         * @param context
         * @param bitmap
         * @return
         */
        public static Bitmap getScaleBitmap(Context context, Bitmap bitmap) {
            int[] screen = ScreenPixelsUtil.getScreenPixels(context);
            Matrix matrix = new Matrix();
            int width = bitmap.getWidth();
            int height = bitmap.getHeight();
            Log.e("Width", width + "");
            Log.e("Height", height + "");
            //屏幕宽度/图片宽度
            float w = screen[0] / width;
            float h = screen[1] / height;
            matrix.postScale(w, h);// 获取缩放比例
            // 根据缩放比例获取新的位图
            Bitmap newbmp = Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true);
            return newbmp;
        }
    
    }
    

    (3)资源文件:

     dlg_select_photo.xml

    <?xml version="1.0" encoding="utf-8"?>
    
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
                  android:id="@+id/pop_layout"
                  android:orientation="vertical"
                  android:layout_width="match_parent"
                  android:layout_height="match_parent"
                  android:background="@color/transparent"
                  android:gravity="bottom"
                  android:layout_gravity="center_horizontal"
                  android:paddingLeft="10dp"
                  android:paddingRight="10dp"
                  android:paddingBottom="10dp"
            >
        <LinearLayout
                      android:orientation="vertical"
                      android:layout_width="match_parent"
                      android:layout_height="wrap_content"
                      android:background="@drawable/setting_dialog"
        >
        <Button
                android:id="@+id/btn_take_photo"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="@string/take_photo"
                android:paddingTop="14dp"
                android:paddingBottom="14dp"
                android:layout_marginTop="2dp"
                android:layout_marginLeft="4dp"
                android:layout_marginRight="4dp"
                android:textSize="17dp"
                android:textColor="#333333"
                android:background="@color/white"/>
    
        <View android:layout_width="match_parent"
              android:layout_height="0.5dp"
              android:background="@color/dropdownmenu_line"/>
        <Button
                android:id="@+id/btn_pick_photo"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="@string/pick_photo"
                android:paddingTop="14dp"
                android:paddingBottom="14dp"
                android:layout_marginLeft="4dp"
                android:layout_marginRight="4dp"
                android:textSize="17dp"
                android:textColor="#333333"
                android:background="@color/white"/>
            </LinearLayout>
        <Button
                android:id="@+id/btn_cancel"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="取消"
                android:paddingTop="14dp"
                android:paddingBottom="14dp"
                android:textSize="17dp"
                android:textColor="@color/gray"
                android:background="@drawable/setting_dialog"
                android:layout_marginTop="16dp"/>
    
    </LinearLayout>
    

    styles.xml

     <!-- 头像弹出窗的动画效果 -->
        <style name="select_photo_dialog_animstyle">
            <item name="android:windowEnterAnimation">@anim/photo_dialog_in_anim</item>
            <item name="android:windowExitAnimation">@anim/photo_dialog_out_anim</item>
        </style>
    

    drawable

    //photo_dialog_in_anim.xml
    <?xml version="1.0" encoding="utf-8"?>
    <set xmlns:android="http://schemas.android.com/apk/res/android" >
    
        <translate
            android:duration="500"
            android:fromXDelta="0"
            android:fromYDelta="1000"
            android:toXDelta="0"
            android:toYDelta="0" />
    
    </set>
    
    
    //photo_dialog_out_anim.xml
    <?xml version="1.0" encoding="utf-8"?>
    <set xmlns:android="http://schemas.android.com/apk/res/android" >
    
        <translate
            android:duration="500"
            android:fromXDelta="0"
            android:fromYDelta="0"
            android:toXDelta="0"
            android:toYDelta="1000" />
    
    </set>
    

      

      

      

      

  • 相关阅读:
    CSharpGL(26)在opengl中实现控件布局/渲染文字
    CSharpGL(25)一个用raycast实现体渲染VolumeRender的例子
    some OpenGL constants
    CSharpGL(24)用ComputeShader实现一个简单的图像边缘检测功能
    CSharpGL(23)用ComputeShader实现一个简单的ParticleSimulator
    CSharpGL(22)实现顺序无关的半透明渲染(Order-Independent-Transparency)
    CSharpGL(21)用鼠标拾取、拖拽VBO图元内的点、线或本身
    批量重命名文件
    [译]基于GPU的体渲染高级技术之raycasting算法
    CSharpGL(20)用unProject和Project实现鼠标拖拽图元
  • 原文地址:https://www.cnblogs.com/hacjy/p/6723611.html
Copyright © 2020-2023  润新知