39

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

Alex Cohn
  • 56,089
  • 9
  • 113
  • 307
I Yeu C
  • 636
  • 2
  • 7
  • 13
  • 1
    Please can you post the code you tried? And also, describe what happens when you try it? Do you get an error message of any kind? – Jodes Mar 05 '13 at 16:43
  • i mean i didnt get any error message I just have no idea how to make the selected area brighten up and unselected area darken to show the differents – I Yeu C Mar 06 '13 at 00:59
  • Check [this question][1] for an alternative library I suggested there. [1]: http://stackoverflow.com/questions/12758425/how-to-set-the-output-image-use-com-android-camera-action-crop/ – hcpl May 22 '13 at 23:44
  • please proper declare how to use manual crop view .... – Ramani Hitesh Oct 26 '17 at 07:31
  • Check this stack overflow answer : https://stackoverflow.com/questions/38367876/android-cropped-image-quality-issue/50528138#50528138 – Hitesh Kanjani May 25 '18 at 11:29

5 Answers5

53

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.

Chetan Ashtivkar
  • 194
  • 2
  • 15
Akbari Dipali
  • 2,173
  • 1
  • 20
  • 26
  • Hi, I try ur code but it doesnt still nv show the darken region on my phone :( i wonder if it is because of my manifest? or phone version? – I Yeu C Mar 06 '13 at 07:10
  • which version are you using? – Akbari Dipali Mar 06 '13 at 07:33
  • the weird thing is that when I just use the normal app it will show but once I use it inside my app that I'm developing it wont show up. I wonder why – I Yeu C Mar 06 '13 at 09:07
  • try to set and and I am not sure if it will help but give it a try – Akbari Dipali Mar 06 '13 at 10:09
  • yup it works hahaha thanks alot i change the minsdkversion it work hahaha thanks alot :) – I Yeu C Mar 06 '13 at 10:30
  • I keep getting an ActivityNotFoundException when trying the above code. I've tried on 2.2, 2.3.3, 4.1 & 4.2. Any ideas? It's like the "com.android.camera.action.CROP" intent filter cannot be found on any of the devices I have?? – speedynomads Apr 25 '13 at 11:17
  • 1
    @domji84 have you set and in your manifest file? – Akbari Dipali Apr 25 '13 at 11:19
  • I found the problem. I was only setting the data uri and not the data type. using intent.setDataAndType(myImageURI, "image/*") fixed it. thanks – speedynomads Apr 25 '13 at 11:26
  • thanks. actually, i still have a problem. the selectedBitmap in onActivityResult is always null. any ideas? – speedynomads Apr 25 '13 at 11:36
  • Can you please debug the code and check the extra param of `Intent data`? whether it contains data or not? – Akbari Dipali Apr 25 '13 at 11:40
  • that data param is null. why would this be happening? – speedynomads Apr 25 '13 at 11:45
  • @AkbariDipali Hey your codes work fine but the selectedBitmap i got always takes a width and height of 160 even if i set cropIntent.putExtra("outputX", 300); cropIntent.putExtra("outputY", 300); – AndroidDev Jun 28 '13 at 07:12
  • @AndroidCoder please take a look at http://stackoverflow.com/questions/12758425/how-to-set-the-output-image-use-com-android-camera-action-crop/ this may help you – Akbari Dipali Jun 28 '13 at 08:37
  • @AkbariDipali Yeh i go through the code and after doing the step as mention in the answer..i tried to scaled my bitmap using following code...but it decreases the quality of image...http://pastebin.com/Y0R52gAp – AndroidDev Jun 28 '13 at 09:32
  • yes, scaling the bitmap will decrease the quality of the image.. But in my case, I was getting 128X128 image. – Akbari Dipali Jun 28 '13 at 09:41
  • may be it is device specific issue a it is written in http://stackoverflow.com/questions/12758425/how-to-set-the-output-image-use-com-android-camera-action-crop?answertab=active#tab-top – Akbari Dipali Jun 28 '13 at 09:42
  • @AkbariDipali Yep i know that in your case u r using 128 x 128 image. But in my case i allow user to select its own image from the gallery and then crop that image in circular shape and show to them. But thing is that how to scale the image in circular shape with losing its quality. – AndroidDev Jun 28 '13 at 09:59
  • oh, ok. I get it.I haven't tried the scaling one but there are many threads available on stack when I googled for `scale image without losing quality in android`. can you please check one? I will also try at my end and if will find any solution then, will give you – Akbari Dipali Jun 28 '13 at 10:11
  • @AkbariDipali Thanks a lot..i will search too – AndroidDev Jun 28 '13 at 11:07
  • Hi , thanks for answer, one question I have , How can I find the file path of the image in the activity result method? (I do not want to bitmapimage or data I want to image path because I want to upload it to my server?) – CompEng May 13 '14 at 13:11
  • you can use picUri.getPath() to get the path. Or If you want to upload bitmap to the server, Bitmap selectedBitmap = extras.getParcelable("data"); declare this bitmap variable at your activity level and use that bitmap to convert into outpuststream. just give it a try! – Akbari Dipali May 13 '14 at 13:33
  • Hi @AkbariDipali.. I am using your solution. Working fine. But my image size is getting too small after croping. How to fix the image size? For example I want image size 100X100. And I don't want to reduce the pixel(Picture Quality.) – Vijay Mar 20 '15 at 11:20
  • @Vijay you can change values here: cropIntent.putExtra("outputX", your_desired_size); cropIntent.putExtra("outputY", your_desired_size); . I have used 128 here as I needed thumbnail size image. – Akbari Dipali Mar 20 '15 at 14:02
  • 3
    In my case, `data.getExtras()` returns `null`, then how could i get the `Bitmap`? – SilentKnight Jun 12 '15 at 06:54
  • 28
    [Android does not have a `CROP` `Intent`](https://commonsware.com/blog/2013/01/23/no-android-does-not-have-crop-intent.html). – CommonsWare Aug 08 '15 at 18:47
  • Not working on Lolipop(5.1.1). Devices like moto g and Nexus 5 throws ActivityNotFoundException.... Working fine on Kitkat and Jelly Bean... – NikW Oct 27 '15 at 13:57
  • declare how to crop manual crop image and green hand crop image android – Ramani Hitesh Oct 26 '17 at 09:58
  • in code not perfect manual crop view display and crop image android – Ramani Hitesh Oct 26 '17 at 11:27
  • For a device like Samsung S6, it doesn't initiate the crop function also.Means not calling the intent. – blackjack Jan 05 '18 at 05:26
10

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.

Soon Santos
  • 2,107
  • 22
  • 43
  • i'm facing a problem that after crop my uri starts from 'file:///' but i want 'content://' its getting crash while getting path to string. – Kishan Jan 09 '19 at 06:41
  • how can i save image after crop – Vinit Poojary Feb 07 '19 at 14:35
  • Using the command: `mImageProfile.setImageBitmap(result.getBitmap());` returns a blank image, I mean the image is not visible. But using the command: `mImageProfile.setImageURI(result.getUri());` works normally. – Aliton Oliveira May 22 '19 at 21:07
  • You can also start it from `CustomAdapter`, by using this command: `CropImage.activity().setGuidelines(CropImageView.Guidelines.ON).start((AppCompatActivity) context);` – Aliton Oliveira May 23 '19 at 21:15
  • I'm using this library in my realme 3 pro which has android 10 and it is not showing option for the gallery it is only showing option for the camera however this gallery option is visible for the nexus 5x and realme U1 which have android 9. Any suggestions. – Akshay Rajput Jul 04 '20 at 16:38
  • 1
    This library is not maintained now. instead use this one -> [link](https://github.com/CanHub/Android-Image-Cropper) – Asif Ullah Oct 30 '21 at 07:40
3

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

https://github.com/TakuSemba/CropMe

EpicPandaForce
  • 79,669
  • 27
  • 256
  • 428
Taku Semba
  • 79
  • 5
  • 19
    you literally made that library. nothing wrong with that, but at least don't try to mislead people into thinking you found it, or consider posting it with a disclaimer – darkrider1287 Aug 28 '19 at 14:29
  • 2
    this library does not have proper usage directions with ``Fragments``. Also, the author does not reply well to issues. – Chayan C May 10 '20 at 11:07
  • This is a nice library, thank you for sharing. It has the exact behavioral spec I needed, which is really lucky as the other one (Android-Image-Cropper) did not. – EpicPandaForce Jun 17 '22 at 09:29
2

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 :)

John smith
  • 1,781
  • 17
  • 27
  • Your gist does not include `R.styleable.` so hard to get it to work especially for string attributes. – Xenolion Mar 25 '20 at 06:10
0

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
    }

}
Md Adilur Rashid
  • 700
  • 7
  • 13