裁剪图像 Android Kotlin

Posted

技术标签:

【中文标题】裁剪图像 Android Kotlin【英文标题】:Crop Image Android Kotlin 【发布时间】:2018-09-20 23:46:40 【问题描述】:

我想制作一个图像选择器以允许我将图像返回到数据库,但它不起作用。 如果activityResult我是第一个,但是之后没有人可以帮助我吗?

imagePicker 的 Intent :

imageAccount.setOnClickListener 
        val intent = Intent(Intent.ACTION_PICK,MediaStore.Images.Media.EXTERNAL_CONTENT_URI)
        startActivityForResult(intent, CropImage.PICK_IMAGE_CHOOSER_REQUEST_CODE)
    

我的 onActivityResult :

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) 
    super.onActivityResult(requestCode, resultCode, data)
    if(requestCode == CropImage.PICK_IMAGE_CHOOSER_REQUEST_CODE && resultCode == android.app.Activity.RESULT_OK) 
        val imageUri = CropImage.getPickImageResultUri(context!!, data)
        CropImage.activity(imageUri)
                .setRequestedSize(1000, 1000)
                .start(this@Account.activity!!)
        Log.i("PICTURE","FIRST-IF")
    
    else if (requestCode == CropImage.CROP_IMAGE_ACTIVITY_REQUEST_CODE) 
        Log.i("PICTURE","ELSE-IF")
        val result = CropImage.getActivityResult(data)
        if (resultCode == android.app.Activity.RESULT_OK) 
            Log.i("PICTURE","SECOND-IF")
            picture = File(result.uri.path)
            Log.i("PICTURE","OK")


            val bitmap = BitmapFactory.decodeFile(result.uri.path)
            imageAccount.setImageBitmap(bitmap)
        
        else if (resultCode == CropImage.CROP_IMAGE_ACTIVITY_RESULT_ERROR_CODE) 
            Log.i("PICTURE","SECOND-ELSE-IF")
            //showError(result.error)
        
    
    Log.i("PICTURE","XX")



感谢您的帮助!

【问题讨论】:

【参考方案1】:

我用这段代码解决了我的问题:

imageAccount.setOnClickListener 
        if(CropImage.isExplicitCameraPermissionRequired(this@Account.activity!!)) 
            ActivityCompat.requestPermissions(this@Account.activity!!, arrayOf(android.Manifest.permission.CAMERA), REQUEST_PERMISSION_CAMERA)
        
        else 
            startActivityForResult(CropImage.getPickImageChooserIntent(this@Account.activity!!), CropImage.PICK_IMAGE_CHOOSER_REQUEST_CODE)
        
    

onActivityResult :

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) 
    super.onActivityResult(requestCode, resultCode, data)
    if(requestCode == CropImage.PICK_IMAGE_CHOOSER_REQUEST_CODE && resultCode == android.app.Activity.RESULT_OK) 
        val imageUri = CropImage.getPickImageResultUri(context!!, data)
        CropImage.activity(imageUri)
                .setRequestedSize(1000, 1000)
                .start(context!!,this)
    
    else if (requestCode == CropImage.CROP_IMAGE_ACTIVITY_REQUEST_CODE) 
        val result = CropImage.getActivityResult(data)
        if (resultCode == android.app.Activity.RESULT_OK) 
            picture = File(result.uri.path)


            val bitmap = BitmapFactory.decodeFile(result.uri.path)
            imageAccount.setImageBitmap(bitmap)
            updateProfile()
        
        else if (resultCode == CropImage.CROP_IMAGE_ACTIVITY_RESULT_ERROR_CODE) 
            //showError(result.error)
        
    

【讨论】:

【参考方案2】:

完整的图片选择和裁剪代码

第 1 步:- 添加此 gradle

implementation 'com.theartofdev.edmodo:android-image-cropper:1.2.1'

第 2 步:- 在您的包和清单中添加两个活动

<activity android:name=".ui.activities.CropImageActivity"
           android:label="Crop Image"></activity>

           <activity android:name=".ui.activities.ImagePickerActivity"
            android:label="Pick Image"></activity>

CropImageActivity

public class CropImageActivity extends AppCompatActivity implements CropImageView.OnSetImageUriCompleteListener, CropImageView.OnGetCroppedImageCompleteListener 

    private static final int DEFAULT_ASPECT_RATIO_VALUES = 100;

    public static final String CROPPED_IMAGE_PATH = "cropped_image_path";
    public static final String EXTRA_IMAGE_URI = "cropped_image_path";

    public static final String FIXED_ASPECT_RATIO = "extra_fixed_aspect_ratio";
    public static final String EXTRA_ASPECT_RATIO_X = "extra_aspect_ratio_x";
    public static final String EXTRA_ASPECT_RATIO_Y = "extra_aspect_ratio_y";

    private static final String ASPECT_RATIO_X = "ASPECT_RATIO_X";

    private static final String ASPECT_RATIO_Y = "ASPECT_RATIO_Y";

    private CropImageView mCropImageView;

    private int mAspectRatioX = DEFAULT_ASPECT_RATIO_VALUES;

    private int mAspectRatioY = DEFAULT_ASPECT_RATIO_VALUES;

    private boolean isFixedAspectRatio = false;

    Bitmap croppedImage;
    //endregion
    private TextView tv_cancel,tv_crop;

    // Saves the state upon rotating the screen/restarting the activity
    @Override
    protected void onSaveInstanceState(@SuppressWarnings("NullableProblems") Bundle bundle) 
        super.onSaveInstanceState(bundle);
        bundle.putInt(ASPECT_RATIO_X, mAspectRatioX);
        bundle.putInt(ASPECT_RATIO_Y, mAspectRatioY);
    

    // Restores the state upon rotating the screen/restarting the activity
    @Override
    protected void onRestoreInstanceState(@SuppressWarnings("NullableProblems") Bundle bundle) 
        super.onRestoreInstanceState(bundle);
        mAspectRatioX = bundle.getInt(ASPECT_RATIO_X);
        mAspectRatioY = bundle.getInt(ASPECT_RATIO_Y);
    

    public void onCreate(Bundle savedInstanceState) 

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_crop_image);
        tv_cancel=(TextView)findViewById(R.id.tv_cancel);
        tv_crop=(TextView)findViewById(R.id.tv_crop);
        if (!getIntent().hasExtra(EXTRA_IMAGE_URI)) 
            cropFailed();
            return;
        

        isFixedAspectRatio = getIntent().getBooleanExtra(FIXED_ASPECT_RATIO, false);
        mAspectRatioX = getIntent().getIntExtra(EXTRA_ASPECT_RATIO_X, DEFAULT_ASPECT_RATIO_VALUES);
        mAspectRatioY = getIntent().getIntExtra(EXTRA_ASPECT_RATIO_Y, DEFAULT_ASPECT_RATIO_VALUES);

        Uri imageUri = Uri.parse(getIntent().getStringExtra(EXTRA_IMAGE_URI));
        // Initialize components of the app
        mCropImageView = (CropImageView) findViewById(R.id.CropImageView);
        // If you want to fix the aspect ratio, set it to 'true'
        mCropImageView.setFixedAspectRatio(isFixedAspectRatio);

        if (savedInstanceState == null) 
            mCropImageView.setImageUriAsync(imageUri);
        
        tv_cancel.setOnClickListener(new View.OnClickListener() 
            @Override
            public void onClick(View v) 
                cropFailed();
            
        );
        tv_crop.setOnClickListener(new View.OnClickListener() 
            @Override
            public void onClick(View v) 
                mCropImageView.getCroppedImageAsync(mCropImageView.getCropShape(), 0, 0);
            
        );
    

    private void cropFailed() 
        Toast.makeText(mCropImageView.getContext(), "Image crop failed", Toast.LENGTH_LONG).show();
        setResult(RESULT_CANCELED);
        finish();
    

    @Override
    protected void onStart() 
        super.onStart();
        mCropImageView.setOnSetImageUriCompleteListener(this);
        mCropImageView.setOnGetCroppedImageCompleteListener(this);
    

    @Override
    protected void onStop() 
        super.onStop();
        mCropImageView.setOnSetImageUriCompleteListener(null);
        mCropImageView.setOnGetCroppedImageCompleteListener(null);
    

    @Override
    public void onSetImageUriComplete(CropImageView view, Uri uri, Exception error) 
        if (error == null) 
            //Toast.makeText(mCropImageView.getContext(), "Image load successful", Toast.LENGTH_SHORT).show();
         else 
            //Toast.makeText(mCropImageView.getContext(), "Image load failed: " + error.getMessage(), Toast.LENGTH_LONG).show();
            Toast.makeText(mCropImageView.getContext(), "Unable to load image", Toast.LENGTH_LONG).show();
        
    

    @Override
    public void onGetCroppedImageComplete(CropImageView view, Bitmap bitmap, Exception error) 
        if (error == null) 
            croppedImage = bitmap;
            try 
                String path = saveToInternalStorage(this, bitmap);
                Intent resultIntent = new Intent();
                resultIntent.putExtra(CROPPED_IMAGE_PATH, path);
                setResult(Activity.RESULT_OK, resultIntent);
                finish();
             catch (IOException e) 
                e.printStackTrace();
                cropFailed();
            
         else 
            cropFailed();
        
    

    private String saveToInternalStorage(Context context, Bitmap bitmapImage) throws IOException 
        ContextWrapper cw = new ContextWrapper(context);
        // path to /data/data/yourapp/app_data/imageDir
        File directory = cw.getDir("imageDir", Context.MODE_PRIVATE);
        // Create imageDir
        File mypath = new File(directory, "image.jpg");

        FileOutputStream fos = null;
        try 
            fos = new FileOutputStream(mypath);
            // Use the compress method on the BitMap object to write image to the OutputStream
            //Bitmap scaledBitmap = getCompressedBitmap(bitmapImage);
            bitmapImage.compress(Bitmap.CompressFormat.PNG, 70, fos);
         catch (Exception e) 
            e.printStackTrace();
         finally 
            fos.close();
        
        return directory.getAbsolutePath();
    

ImagePickerActivity

public class ImagePickerActivity extends AppCompatActivity 
    private static final int REQUEST_PICK_IMAGE = 2365;
    private static final int REQUEST_CROP_IMAGE = 2342;

    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);

        startActivityForResult(getPickImageChooserIntent(), REQUEST_PICK_IMAGE);
    

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) 
        if (resultCode == Activity.RESULT_OK) 
            if(requestCode == REQUEST_PICK_IMAGE) 
                Intent intent = new Intent(this, CropImageActivity.class);
                Uri imageUri = getPickImageResultUri(data);
                intent.putExtra(CropImageActivity.EXTRA_IMAGE_URI, imageUri.toString());
                startActivityForResult(intent, REQUEST_CROP_IMAGE);
            
            else if(requestCode == REQUEST_CROP_IMAGE) 
                System.out.println("Image crop success :"+data.getStringExtra(CropImageActivity.CROPPED_IMAGE_PATH));
                String imagePath = new File(data.getStringExtra(CropImageActivity.CROPPED_IMAGE_PATH), "image.jpg").getAbsolutePath();
                Intent result = new Intent();
                result.putExtra("image_path", imagePath);
                setResult(Activity.RESULT_OK, result);
                finish();
            
        
        else 
            System.out.println("Image crop failed");
            setResult(Activity.RESULT_CANCELED);
            finish();
        
    

    /**
     * Create a chooser intent to select the source to get image from.<br/>
     * The source can be camera's (ACTION_IMAGE_CAPTURE) or gallery's (ACTION_GET_CONTENT).<br/>
     * All possible sources are added to the intent chooser.
     */
    public Intent getPickImageChooserIntent() 

        // Determine Uri of camera image to save.
        Uri outputFileUri = getCaptureImageOutputUri();

        List<Intent> allIntents = new ArrayList<>();
        PackageManager packageManager = getPackageManager();

        // collect all camera intents
        Intent captureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        List<ResolveInfo> listCam = packageManager.queryIntentActivities(captureIntent, 0);
        for (ResolveInfo res : listCam) 
            Intent intent = new Intent(captureIntent);
            intent.setComponent(new ComponentName(res.activityInfo.packageName, res.activityInfo.name));
            intent.setPackage(res.activityInfo.packageName);
            if (outputFileUri != null) 
                intent.putExtra(MediaStore.EXTRA_OUTPUT, outputFileUri);
            
            allIntents.add(intent);
        

        // collect all gallery intents
        Intent galleryIntent = new Intent(Intent.ACTION_GET_CONTENT);
        galleryIntent.setType("image/*");
        List<ResolveInfo> listGallery = packageManager.queryIntentActivities(galleryIntent, 0);
        for (ResolveInfo res : listGallery) 
            Intent intent = new Intent(galleryIntent);
            intent.setComponent(new ComponentName(res.activityInfo.packageName, res.activityInfo.name));
            intent.setPackage(res.activityInfo.packageName);
            allIntents.add(intent);
        

        // the main intent is the last in the list, so pickup the useless one
        Intent mainIntent = allIntents.get(allIntents.size() - 1);
        for (Intent intent : allIntents) 
            if (intent.getComponent().getClassName().equals("com.android.documentsui.DocumentsActivity")) 
                mainIntent = intent;
                break;
            
        
        allIntents.remove(mainIntent);

        // Create a chooser from the main intent
        Intent chooserIntent = Intent.createChooser(mainIntent, "Select source");

        // Add all other intents
        chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, allIntents.toArray(new Parcelable[allIntents.size()]));

        return chooserIntent;
    

    /**
     * Get URI to image received from capture by camera.
     */
    private Uri getCaptureImageOutputUri() 
        Uri outputFileUri = null;
        File getImage = getExternalCacheDir();
        if (getImage != null) 
            outputFileUri = Uri.fromFile(new File(getImage.getPath(), "pickImageResult.jpeg"));
        
        return outputFileUri;
    

    /**
     * Get the URI of the selected image from @link #getPickImageChooserIntent().<br/>
     * Will return the correct URI for camera and gallery image.
     *
     * @param data the returned data of the activity result
     */
    public Uri getPickImageResultUri(Intent data) 
        boolean isCamera = true;
        if (data != null) 
            String action = data.getAction();
            isCamera = action != null && action.equals(MediaStore.ACTION_IMAGE_CAPTURE);
        
        return isCamera ? getCaptureImageOutputUri() : data.getData();
    

activity_crop_image.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_
    android:layout_>

    <RelativeLayout
        android:id="@+id/header"
        android:layout_
        android:layout_
        android:layout_alignParentTop="true"
        android:background="@color/colorblue"
        android:padding="15dp">


        <TextView
            android:id="@+id/tv_cancel"
            android:layout_
            android:layout_
            android:layout_alignParentLeft="true"
            android:layout_centerVertical="true"
            android:layout_marginLeft="10dp"
            android:text="Cancel"
            android:textColor="@color/colorwhite"
            android:textSize="18sp"
            android:textStyle="bold" />

        <TextView
            android:id="@+id/tv_crop"
            android:layout_
            android:layout_
            android:layout_alignParentRight="true"
            android:layout_below="@+id/tv_title"
            android:layout_centerVertical="true"
            android:layout_marginRight="10dp"
            android:text="Crop"
            android:textColor="@color/colorwhite"
            android:textSize="18sp"
            android:textStyle="bold" />


    </RelativeLayout>

    <com.theartofdev.edmodo.cropper.CropImageView
        android:id="@+id/CropImageView"
        android:layout_
        android:layout_
        android:layout_below="@+id/header"
        android:layout_gravity="center"
        app:cropFixAspectRatio="true" />
</RelativeLayout>

第 3 步:- 在片段或活动类中使用

 private val REQUEST_PICK_IMAGE = 1002
profile_pic1.setOnClickListener 
            startActivityForResult(Intent(activity, ImagePickerActivity::class.java), REQUEST_PICK_IMAGE)
        


fun setImage(imagePath: String) 
        profile_pic1.setImageBitmap(getImageFromStorage(imagePath));
    

    fun getImageFromStorage(path: String): Bitmap 
        var f = File(path);
        var options = BitmapFactory.Options();
        options.inJustDecodeBounds = false;
        // Calculate inSampleSize
        options.inSampleSize = calculateInSampleSize(options, 512, 512);
        return BitmapFactory.decodeStream(FileInputStream(f), null, options)
    

    private fun calculateInSampleSize(
            options: BitmapFactory.Options, reqWidth: Int, reqHeight: Int): Int 
        // Raw height and width of image
        val height = options.outHeight
        val width = options.outWidth
        var inSampleSize = 1

        if (height > reqHeight || width > reqWidth) 

            val halfHeight = height / 2
            val halfWidth = width / 2

            // Calculate the largest inSampleSize value that is a power of 2 and keeps both
            // height and width larger than the requested height and width.
            while (halfHeight / inSampleSize > reqHeight && halfWidth / inSampleSize > reqWidth) 
                inSampleSize *= 2
            
        

        return inSampleSize
    

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) 
        super.onActivityResult(requestCode, resultCode, data)
        if (resultCode == RESULT_OK && requestCode == requestCode) 
            var imagePath = data!!.getStringExtra("image_path");
            setImage(imagePath);
         else 
            System.out.println("Failed to load image");
        
    

注意:- 声明清单中的写入/读取和相机权限以及运行时权限

【讨论】:

以上是关于裁剪图像 Android Kotlin的主要内容,如果未能解决你的问题,请参考以下文章

无法在android中裁剪图像

裁剪后的Android图像视图仅显示小图像

Android中自定义图像裁剪的实现

在android中使用人脸检测裁剪图像

在android中裁剪后保存图像

Android 从 Intent 获取裁剪图像的 URI