Crop image in android

162.7k Views Asked by At

I want to do cropping of image i found some pretty useful ones but somehow is like lacking of the darken the unselected areas so I wondering do anyone know how? or lead me to the right direction? The online tutorial i found shows that is will darken the selected area but when I use it, it won't. Please help me thanks alot and sorry for my bad command of english.

Links to the tutorial I use.

Crop image tutorial 1

Crop Image tutorial 2

I want it to be something like this.

I want it be something like this

editButton.setOnClickListener(new Button.OnClickListener(){

        @Override
        public void onClick(View v) {
            // TODO Auto-generated method stub
            Intent goEdit;
            goEdit = new Intent(PreviewActivity.this, CropImage.class);
            goEdit.putExtra("image-path", path);
            goEdit.putExtra("scale", true);
            goEdit.putExtra("fileName", nameFromPath);
            //finish();
            checkEdit = true;
            startActivityForResult(goEdit,0);

        }
});

EDIT I use this button listener to call into the cropImage file by calling to the class CropImage activity. This is a custom intent not the crop feature inside android but I think is the copy of it so that make it support for all versions but when I call into it the selected area isnt brighten and I donno where is the problem can anyone guide me? Thanks This is the library I'm using drioid4you crop image

5

There are 5 best solutions below

29
On BEST ANSWER

Can you use default android Crop functionality?

Here is my code

private void performCrop(Uri picUri) {
    try {
        Intent cropIntent = new Intent("com.android.camera.action.CROP");
        // indicate image type and Uri
        cropIntent.setDataAndType(picUri, "image/*");
        // set crop properties here
        cropIntent.putExtra("crop", true);
        // indicate aspect of desired crop
        cropIntent.putExtra("aspectX", 1);
        cropIntent.putExtra("aspectY", 1);
        // indicate output X and Y
        cropIntent.putExtra("outputX", 128);
        cropIntent.putExtra("outputY", 128);
        // retrieve data on return
        cropIntent.putExtra("return-data", true);
        // start the activity - we handle returning in onActivityResult
        startActivityForResult(cropIntent, PIC_CROP);
    }
    // respond to users whose devices do not support the crop action
    catch (ActivityNotFoundException anfe) {
        // display an error message
        String errorMessage = "Whoops - your device doesn't support the crop action!";
        Toast toast = Toast.makeText(this, errorMessage, Toast.LENGTH_SHORT);
        toast.show();
    }
}

declare:

final int PIC_CROP = 1;

at top.

In onActivity result method, writ following code:

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);

    if (requestCode == PIC_CROP) {
        if (data != null) {
            // get the returned data
            Bundle extras = data.getExtras();
            // get the cropped bitmap
            Bitmap selectedBitmap = extras.getParcelable("data");

            imgView.setImageBitmap(selectedBitmap);
        }
    }
}

It is pretty easy for me to implement and also shows darken areas.

3
On

I made a really cool library, try this out. this is really smooth and easy to use.

https://github.com/TakuSemba/CropMe

1
On

hope you are doing well. you can use my code to crop image.you just have to make a class and use this class into your XMl and java classes. Crop image. you can crop your selected image into circle and square into many of option. hope fully it will works for you.because this is totally manageable for you and you can change it according to you.

enjoy your work :)

6
On

This library: Android-Image-Cropper is very powerful to CropImages. It has 3,731 stars on github at this time.

You will crop your images with a few lines of code.

1 - Add the dependecies into buid.gradle (Module: app)

compile 'com.theartofdev.edmodo:android-image-cropper:2.7.+'

2 - Add the permissions into AndroidManifest.xml

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

3 - Add CropImageActivity into AndroidManifest.xml

<activity android:name="com.theartofdev.edmodo.cropper.CropImageActivity"
 android:theme="@style/Base.Theme.AppCompat"/>

4 - Start the activity with one of the cases below, depending on your requirements.

// start picker to get image for cropping and then use the image in cropping activity
CropImage.activity()
.setGuidelines(CropImageView.Guidelines.ON)
.start(this);

// start cropping activity for pre-acquired image saved on the device
CropImage.activity(imageUri)
.start(this);

// for fragment (DO NOT use `getActivity()`)
CropImage.activity()
.start(getContext(), this);

5 - Get the result in onActivityResult

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
  if (requestCode == CropImage.CROP_IMAGE_ACTIVITY_REQUEST_CODE) {
    CropImage.ActivityResult result = CropImage.getActivityResult(data);
    if (resultCode == RESULT_OK) {
      Uri resultUri = result.getUri();
    } else if (resultCode == CropImage.CROP_IMAGE_ACTIVITY_RESULT_ERROR_CODE) {
      Exception error = result.getError();
    }
  }
}

You can do several customizations, as set the Aspect Ratio or the shape to RECTANGLE, OVAL and a lot more.

0
On

I just recently finished this one for my own project. Please customize it to your needs. You can also resize with 4 edges and 4 corners also! I'm not good at English but I did my best to add comments to the code. Please read them, they might be helpful.

...

enter image description here

XML

     <your_package_name.CV4
            android:id="@+id/cv4"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            />

        <Button
            android:id="@+id/cropBtn"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Crop"/>

        <ImageView
            android:id="@+id/croppedImage"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"/>

code in activity or fragment

cropBtn.setOnClickListener {
            val x = cv4.test()
            croppedImage.setImageBitmap(x)
        }

Mani Custom View Code

package your.package.name  

import android.annotation.SuppressLint
import android.content.Context
import android.graphics.*
import android.util.AttributeSet
import android.view.MotionEvent
import android.view.View
import com.voice.translator.app.speak.to.world.camerax.R
import kotlin.math.max
import kotlin.math.min


class CV4 @JvmOverloads constructor(
    context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {

//    onMeasure will be called before onSizeChanged and onDraw
//    please see the View lifecycle for more details
    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        screenWidth = MeasureSpec.getSize(widthMeasureSpec)
        imageWidth = screenWidth
        imageHeight = ((screenWidth.toFloat() / src.width) * src.height).toInt()
        setMeasuredDimension(screenWidth, imageHeight)
    }

    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
        super.onSizeChanged(w, h, oldw, oldh)

        val desiredWidthInPx = imageWidth
        val derivedHeightInPx = (desiredWidthInPx / aspectRatio).toInt()

        output = Bitmap.createScaledBitmap(src, desiredWidthInPx, derivedHeightInPx, true)
        rectF2 = RectF(0f, 0f, imageWidth.toFloat(), derivedHeightInPx.toFloat())
    }

    override fun onDraw(canvas: Canvas?) {
        super.onDraw(canvas)

        parent.requestDisallowInterceptTouchEvent(true)
        canvas?.apply {

            // background image under overlay
            drawBitmap(output, 0f, 0f, null)

            // dark overlay
            drawRect(rectF2, rectPaint2)

            // clip rect same as movable rect. This will hide everything outside
            clipRect(rectF)

            // visible clear image covered by clip rect
            drawBitmap(output, 0f, 0f, null)

            // movable rect
            drawRoundRect(rectF, 10f, 10f, rectPaint)
        }
    }


    @SuppressLint("ClickableViewAccessibility")
    override fun onTouchEvent(event: MotionEvent?): Boolean {

        if (event != null) {
            motionX = event.x
            motionY = event.y
            when (event.action) {
                MotionEvent.ACTION_MOVE -> moveMove()
                MotionEvent.ACTION_DOWN -> moveDown()
                MotionEvent.ACTION_UP -> moveUp()
            }
        }

        return true

    }

    private fun moveMove() {

        //moving the whole rect
        if (c5) {

            if (pr < screenWidth && motionX > plx) {
                pr = min(r + (motionX - plx), screenWidth.toFloat())
                pl = min(l + (motionX - plx), screenWidth.toFloat() - (r - l))
            }
            if (pl > 0 && motionX < plx) {
                pr = max(r - (plx - motionX), 0f + (r - l))
                pl = max(l - (plx - motionX), 0f)
            }
            if (pb < imageHeight && motionY > pty) {
                pb = min(b + (motionY - pty), imageHeight.toFloat())
                pt = min(t + (motionY - pty), imageHeight.toFloat() - (b - t))
            }
            if (pt > 0 && motionY < pty) {
                pb = max(b - (pty - motionY), 0f + (b - t))
                pt = max(t - (pty - motionY), 0f)
            }
            rectF.set(pl + 5, pt + 5, pr - 5, pb - 5)
            invalidate()
        }

        // moving while holding corners
        if (c6) {
            if (motionX > 0 && motionX < (pr - 100)) pl = motionX
            if (motionY > 0 && motionY < (pb - 100)) pt = motionY
        }
        if (c7) {
            if (motionY > 0 && motionY < (pb - 100)) pt = motionY
            if (motionX > (pl + 100) && motionX < screenWidth) pr = motionX
        }
        if (c8) {
            if (motionX > (pl + 100) && motionX < screenWidth) pr = motionX
            if (motionY > (pt + 100) && motionY < imageHeight) pb = motionY
        }
        if (c9) {
            if (motionX > 0 && motionX < (pr - 100)) pl = motionX
            if (motionY > (pt + 100) && motionY < imageHeight) pb = motionY
        }

        // For moving the edge
        if (c1) if (motionX > 0 && motionX < (pr - 100)) pl = motionX
        if (c2) if (motionY > 0 && motionY < (pb - 100)) pt = motionY
        if (c3) if (motionX > (pl + 100) && motionX < screenWidth) pr = motionX
        if (c4) if (motionY > (pt + 100) && motionY < imageHeight) pb = motionY


        rectF.set(pl + 5, pt + 5, pr - 5, pb - 5)
        invalidate()

    }

    private fun moveDown() {

        if (motionX > (pl + rng) && motionX < (pr - rng) && motionY > (pt + rng) && motionY < (pb - rng)) {

            c5 = true
            l = pl
            t = pt
            r = pr
            b = pb

            if (motionY >= 0 && motionY <= imageHeight) pty = motionY
            if (motionX >= 0 && motionX <= screenWidth) plx = motionX

            invalidate()
            return
        }

        if (motionX in pl - rng..pl + rng && motionY in pt - rng..pt + rng) {
            c6 = true
            invalidate()
            return
        }
        if (motionY in pt - rng..pt + rng && motionX in pr - rng..pr + rng) {
            c7 = true
            invalidate()
            return
        }
        if (motionX in pr - rng..pr + rng && motionY in pb - rng..pb + rng) {
            c8 = true
            invalidate()
            return
        }
        if (motionY in pb - rng..pb + rng && motionX in pl - rng..pl + rng) {
            c9 = true
            invalidate()
            return
        }




        if (motionX > (pl - rng) && motionX < (pl + rng) && motionY > pt && motionY < pb) {
            c1 = true
            invalidate()
            return
        }
        if (motionY > (pt - rng) && motionY < (pt + rng) && motionX > pl && motionX < pr) {
            c2 = true
            invalidate()
            return
        }
        if (motionX > (pr - rng) && motionX < (pr + rng) && motionY > pt && motionY < pb) {
            c3 = true
            invalidate()
            return
        }
        if (motionY > (pb - rng) && motionY < (pb + rng) && motionX > pl && motionX < pr) {
            c4 = true
            invalidate()
            return
        }


        invalidate()

    }

    private fun moveUp() {
        c1 = false
        c2 = false
        c3 = false
        c4 = false
        c5 = false

        c6 = false
        c7 = false
        c8 = false
        c9 = false

        invalidate()
    }


    // pass bitmap image
    private val src: Bitmap = BitmapFactory.decodeResource(resources, R.drawable.mountain)

    private var screenWidth = 0
    private var imageWidth = 0
    private var imageHeight = 0
    private val aspectRatio: Float = src.width / src.height.toFloat()

    //get the bitmap from test():Bitmap? function
    private lateinit var output: Bitmap

    fun test(): Bitmap? {

        val cropWidth: Float = (pr - pl)
        val cropHeight: Float = (pb - pt)

        invalidate()
        //returning the bitmap
        return Bitmap.createBitmap(
            output,
            pl.toInt(),
            pt.toInt(),
            cropWidth.toInt(),
            cropHeight.toInt()
        )
    }


    private var motionX = 0f
    private var motionY = 0f
    private var rng = 40f // Touch range for the 4 side and 4 corners of the rect

    // p for point and l=left t=top r=right b=bottom
    private var pl = 100f
    private var plx = 100f //hold motionX value from moveDown() function

    private var pt = 100f
    private var pty = 100f //hold motionY value from moveDown() function

    private var pr = 300f
    private var pb = 400f

    //hold left,top,right,bottom value from moveDown() function
    private var l = 0f
    private var t = 0f
    private var r = 0f
    private var b = 0f

    // check user touch Down on rect edges, corners or inside

    //edges point
    private var c1 = false
    private var c2 = false
    private var c3 = false
    private var c4 = false

    private var c5 = false  // for inside selection to move the whole rect

    //corners point
    private var c6 = false
    private var c7 = false
    private var c8 = false
    private var c9 = false


    // resizable rect
    private var rectF = RectF(pl + 5, pt + 5, pr - 5, pb - 5)
    private val rectPaint = Paint().apply {
        style = Paint.Style.STROKE
        strokeWidth = 10f
        color = Color.YELLOW

    }

    // dark overlay rect
    private val foregroundArcColor =
        context.resources?.getColor(R.color.custom3, null) ?: Color.GRAY
    private var rectF2 = RectF(0f, 0f, screenWidth.toFloat(), imageHeight.toFloat())
    private val rectPaint2 = Paint().apply {
        style = Paint.Style.FILL
        color = foregroundArcColor
    }

}