zoukankan      html  css  js  c++  java
  • Android实现图片裁切

    介绍

    在应用开发中,如果涉及到个人信息,头像一般是不可避免的,类似这种情况,我们就需要用到图片裁切的功能,实现头像裁切,然后上传给服务器。

    一般裁切的做法就是图层叠加选取框,然后根据坐标,计算裁切区域,通过图形函数裁切,既然了解大概原理,造轮子的事情就不做了,上github找开源库,发现了一个叫做edmodo/cropper的库,是原生实现的裁切。

    地址:https://github.com/edmodo/cropper

    但是使用后发现这个库还存以下两个主要问题,体验就很不好了。

    1、图片太大会出现无法显示

    2、图片过小又无法自适应

    难道就没有更好的办法了?

    又百度了一下,发现原来android的Intent已经自带有裁切的action了,而且体验非常好,只需要在Intent附上参数就可以实现相册/相机裁切图片。

    地址:https://github.com/ryanhoo/PhotoCropper

    原理

    1、请看参数

    2、拍照裁切需要先将结果保存在本地,然后再读取保存的结果裁切,否则默认情况下拍照直接返回的结果是缩略图。

    3、通过onActivityResult来处理结果。

    实现

    参考的项目是经过重构的,但我总觉得看的晕,所以demo就全部放在一个页面,加上了个人理解注释,方便学习。

    CropParams类

    package com.example.cropimage;
    
    import android.graphics.Bitmap;
    import android.net.Uri;
    import android.os.Environment;
    
    public class CropParams {
    
        public static final String CROP_TYPE = "image/*";
        public static final String OUTPUT_FORMAT = Bitmap.CompressFormat.JPEG
                .toString();
    
        public static final int DEFAULT_ASPECT = 1;
        public static final int DEFAULT_OUTPUT = 300;
    
        public Uri uri;
    
        public String type;
        public String outputFormat;
        public String crop;
    
        public boolean scale;
        public boolean returnData;
        public boolean noFaceDetection;
        public boolean scaleUpIfNeeded;
    
        public int aspectX;
        public int aspectY;
    
        public int outputX;
        public int outputY;
    
        public CropParams() {
            uri = Uri.fromFile(Environment.getExternalStorageDirectory())
                    .buildUpon().appendPath("crop_cache_file.jpg").build();
            type = CROP_TYPE;
            outputFormat = OUTPUT_FORMAT;
            crop = "true";
            scale = true;
            returnData = false;
            noFaceDetection = true;
            scaleUpIfNeeded = true;
            aspectX = DEFAULT_ASPECT;
            aspectY = DEFAULT_ASPECT;
            outputX = DEFAULT_OUTPUT;
            outputY = DEFAULT_OUTPUT;
        }
    }

    核心代码

    package com.example.cropimage;
    
    import java.io.File;
    import java.io.FileNotFoundException;
    
    import android.support.v7.app.ActionBarActivity;
    import android.app.Activity;
    import android.app.AlertDialog;
    import android.app.Dialog;
    import android.content.Context;
    import android.content.DialogInterface;
    import android.content.Intent;
    import android.graphics.Bitmap;
    import android.graphics.BitmapFactory;
    import android.net.Uri;
    import android.os.Bundle;
    import android.provider.MediaStore;
    import android.util.Log;
    import android.view.Menu;
    import android.view.MenuItem;
    import android.widget.ImageView;
    import android.widget.Toast;
    
    public class MainActivity extends ActionBarActivity {
        ImageView imageView1;
        CropParams mCropParams = new CropParams();
        public static final int REQUEST_CROP = 127;
        public static final int REQUEST_CAMERA = 128;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            imageView1 = (ImageView) findViewById(R.id.imageView1);
    
            // 弹出提示框选择照片
            final String[] arrayFruit = new String[] { "拍照", "从相册选择照片" };
            Dialog alertDialog = new AlertDialog.Builder(MainActivity.this)
                    .setIcon(R.drawable.ic_launcher)
                    .setItems(arrayFruit, new DialogInterface.OnClickListener() {
    
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            switch (which) {
                            case 0:
                                // 进入相机
                                startActivityForResult(
                                        buildCaptureIntent(mCropParams.uri),
                                        REQUEST_CAMERA);
                                break;
                            case 1:
                                // 进入相册
                                startActivityForResult(
                                        buildCropFromGalleryIntent(mCropParams),
                                        REQUEST_CROP);
                                break;
                            default:
                                break;
                            }
                        }
                    })
                    .setNegativeButton("取消", new DialogInterface.OnClickListener() {
    
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            // TODO Auto-generated method stub
                        }
                    }).create();
            alertDialog.show();
        }
    
        @Override
        public boolean onCreateOptionsMenu(Menu menu) {
            // Inflate the menu; this adds items to the action bar if it is present.
            getMenuInflater().inflate(R.menu.main, menu);
            return true;
        }
    
        @Override
        protected void onActivityResult(int requestCode, int resultCode, Intent data) {
            if (resultCode == Activity.RESULT_CANCELED) {
                Toast.makeText(this, "Crop canceled!", Toast.LENGTH_LONG).show();
            } else if (resultCode == Activity.RESULT_OK) {
                switch (requestCode) {
                case REQUEST_CROP:
                    Log.d("cropImage", "Photo cropped!");
                    Toast.makeText(this, "Photo cropped!", Toast.LENGTH_LONG)
                            .show();
                    imageView1.setImageURI(mCropParams.uri);
                    break;
                case REQUEST_CAMERA:
                    Intent intent = buildCropFromUriIntent(mCropParams);
                    startActivityForResult(intent, REQUEST_CROP);
                    break;
                }
            }
            super.onActivityResult(requestCode, resultCode, data);
        }
    
        @Override
        public boolean onOptionsItemSelected(MenuItem item) {
            // Handle action bar item clicks here. The action bar will
            // automatically handle clicks on the Home/Up button, so long
            // as you specify a parent activity in AndroidManifest.xml.
            int id = item.getItemId();
            if (id == R.id.action_settings) {
                return true;
            }
            return super.onOptionsItemSelected(item);
        }
    
        /**
         * 结束后删除临时裁切图片,或者不删除,用来干别的。
         */
        @Override
        protected void onDestroy() {
            File file = new File(mCropParams.uri.getPath());
            if (file.exists()) {
                boolean result = file.delete();
                if (result)
                    Log.i("cropImage", "Cached crop file cleared.");
                else
                    Log.e("cropImage", "Failed to clear cached crop file.");
    
            } else {
                Log.w("cropImage",
                        "Trying to clear cached crop file but it does not exist.");
            }
            super.onDestroy();
        }
    
        /**
         * 创建裁切Intent
         * 
         * @param action
         *            操作
         * @param params
         *            参数
         * @return
         */
        public static Intent buildCropIntent(String action, CropParams params) {
            return new Intent(action, null)
                    .setDataAndType(params.uri, params.type)
                    // .setType(params.type)
                    .putExtra("crop", params.crop).putExtra("scale", params.scale)
                    .putExtra("aspectX", params.aspectX)
                    .putExtra("aspectY", params.aspectY)
                    .putExtra("outputX", params.outputX)
                    .putExtra("outputY", params.outputY)
                    .putExtra("return-data", params.returnData)
                    .putExtra("outputFormat", params.outputFormat)
                    .putExtra("noFaceDetection", params.noFaceDetection)
                    .putExtra("scaleUpIfNeeded", params.scaleUpIfNeeded)
                    .putExtra(MediaStore.EXTRA_OUTPUT, params.uri);
        }
    
        /**
         * 这一步是在相机拍照完成之后调用,注意action。
         * 
         * @param params
         * @return
         */
        public static Intent buildCropFromUriIntent(CropParams params) {
            return buildCropIntent("com.android.camera.action.CROP", params);
        }
    
        /**
         * 创建相册裁切Intent
         * 
         * @param params
         *            奥秘全在params里
         * @return
         */
        public static Intent buildCropFromGalleryIntent(CropParams params) {
            return buildCropIntent(Intent.ACTION_GET_CONTENT, params);
        }
    
        /**
         * 创建相机拍照Intent,由于相机拍照直接返回的是缩略图,所以一般的做法是拍照保存在本地之后,通过uri再读取一次
         * 
         * @param uri
         *            保存路径
         * @return
         */
        public static Intent buildCaptureIntent(Uri uri) {
            return new Intent(MediaStore.ACTION_IMAGE_CAPTURE).putExtra(
                    MediaStore.EXTRA_OUTPUT, uri);
        }
    
        /**
         * 解析uri成bitmap
         * 
         * @param context
         * @param uri
         * @return
         */
        public static Bitmap decodeUriAsBitmap(Context context, Uri uri) {
            if (context == null || uri == null)
                return null;
    
            Bitmap bitmap;
            try {
                bitmap = BitmapFactory.decodeStream(context.getContentResolver()
                        .openInputStream(uri));
            } catch (FileNotFoundException e) {
                e.printStackTrace();
                return null;
            }
            return bitmap;
        }
    }

    完成之后看起来是这样的

       

     demo地址:

    链接:http://pan.baidu.com/s/1c0xqxEw 密码:u2ot

    参考:

    http://ryanhoo.github.io/blog/2014/05/26/the-ultimate-approach-to-crop-photos-on-android-1/

  • 相关阅读:
    Core3.0部署后访问接口提示500.30
    Core3.0返回的Json数据大小写格式问题
    linux内核分析之fork()
    【转】【机器人学:运动规划】OMPL开源运动规划库的安装和demo
    【转】毫米波雷达和激光雷达的对比
    [转]开发者需要的 9 款代码比较工具
    [转]关于特征点法、直接法、光流法slam的对比
    [转]【视觉 SLAM-2】 视觉SLAM- ORB 源码详解 2
    [转]ORB特征提取-----FAST角点检测
    [转]图像金字塔
  • 原文地址:https://www.cnblogs.com/leestar54/p/4251706.html
Copyright © 2011-2022 走看看