Capture and Crop an Image with the Device Camera

Capture and Crop an Image with the Device Camera

Tutorial Details
  • Technology: Android SDK
  • Difficulty: Intermediate
  • Completion Time: 30 - 60 Minutes

Many Android devices are equipped with built-in cameras. In this tutorial, we will work through the basic technique for capturing an image using the Android camera and then cropping it using apps the user already has installed on their device. Along the way, I’ll also show how to account for users whose devices do not support either the image capture or cropping actions.


Step 1: Start a New Android Project

Create a new Android project in Eclipse, or your chosen IDE. In your main Activity class, add the following import statements after the package declaration:

import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.Intent;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.Toast;

These will allow us to carry out image capture, crop and display within the app. Open your application’s strings XML file, which you should find in the “res/values” folder. Add the following strings:

<string name="intro">Capture a picture to crop!</string>
<string name="picture">Picture</string>
<string name="capture">Launch Camera</string>

We will use these strings within the user interface.


Step 2: Implement the App Layout

Let’s design the app layout. Open your main XML file, which should be in the “res/layout” folder. Use a Linear Layout as follows, which Eclipse may have already provided:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >
</LinearLayout>

Inside the Linear Layout, add the following text display:

<TextView
	android:layout_width="fill_parent"
	android:layout_height="wrap_content"
	android:text="@string/intro"
	android:layout_margin="3dp"
	android:textStyle="bold" />

Here we display some informative text using a string we defined in the strings XML file. After the Text View, add a button as follows:

<Button
	android:id="@+id/capture_btn"
	android:layout_width="wrap_content"
	android:layout_height="wrap_content"
	android:text="@string/capture" />

The ID value will allow us to identify the button in Java, so that we can respond to clicks. Again, we use a string we already defined in XML. Finally, after the button, add an Image View:

<ImageView
	android:id="@+id/picture"
	android:layout_width="wrap_content"
	android:layout_height="wrap_content"
	android:contentDescription="@string/picture"
	android:layout_margin="5dp"
	android:background="@drawable/pic_border" />

We will place the image captured by the user with their device camera inside this Image View, using the ID value to identify it in Java. We use one of the strings as a content description and a background drawable resource we will create next. If you want the Image View to stretch to fill the available space, alter the width and height attributes to “fill_parent” instead of “wrap_content” – remember that this may make the image displayed appear poor quality.

For the background drawable, create a new XML file in each of your app drawable folders, naming it “pic_border.xml” to match the value we used in the Image View layout section. The easiest way to do this is to create the file in one drawable folder, copy the XML code into it, save it, then copy it into the other drawable folders.

Use the following XML in your new “pic_border” drawable file:

<shape xmlns:android="http://schemas.android.com/apk/res/android"
	android:dither="true">
	<gradient
		android:startColor="#99ffffff"
		android:endColor="#99ffffff"
		android:centerColor="#00000000"
		android:angle="90" />
	<padding android:left="10dp" android:top="10dp"
		android:right="10dp" android:bottom="10dp" />
	<corners android:radius="5dp" />
	<stroke
		android:width="2dp"
		android:color="#ccffffff" />
</shape>

Using a drawable background resource is entirely optional, so feel free to omit this part. This is how the app will look when it is launched:

Initial App Interface

Step 3: Respond to User Clicks

In your app’s Activity class, extend the opening class declaration line as follows:

public class ShootAndCropActivity extends Activity implements OnClickListener {

Alter the class name to suit your own. Inside the Activity “onCreate” method, add the following after the existing code calling the superclass method and setting the content layout, which Eclipse should have populated:

//retrieve a reference to the UI button
Button captureBtn = (Button)findViewById(R.id.capture_btn);
//handle button clicks
captureBtn.setOnClickListener(this);

Here we simply instruct the class to handle button clicks. The user will press the button to launch the camera. Now we need to provide an “onClick” method. Add it as follows, after the “onCreate” method:

public void onClick(View v) {
	if (v.getId() == R.id.capture_btn) {
	}
}

Inside the “if” statement, we will implement using the camera.


Step 4: Launch the Camera

At the top of your class declaration, before the “onCreate” method, add the following instance variables:

//keep track of camera capture intent
final int CAMERA_CAPTURE = 1;
//captured picture uri
private Uri picUri;

We will use the first variable to keep track of the user’s interaction as they navigate to the camera app and back. The second variable will store the URI of the captured image. Inside the “if” statement in your “onClick” method, add the following code to launch the camera Intent, including it in a “try” block:

try {
	//use standard intent to capture an image
	Intent captureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
	//we will handle the returned data in onActivityResult
	startActivityForResult(captureIntent, CAMERA_CAPTURE);
}

When this code executes, the user’s camera app will start up and they will be able to take a photo. We will handle the user returning from the camera app inside the “onActivityResult” method. From there we will be able to check that the user is returning from this Intent using the “CAMERA_CAPTURE” variable we pass when starting the Activity. However, before we do that we need to handle the situation in which the user device does not support the image capture intent we have attempted to launch here. After the “try” block, add a “catch” as follows:

catch(ActivityNotFoundException anfe){
	//display an error message
	String errorMessage = "Whoops - your device doesn't support capturing images!";
	Toast toast = Toast.makeText(this, errorMessage, Toast.LENGTH_SHORT);
	toast.show();
}

Whenever you attempt to launch an Intent outside of your own app, this is a precaution you may wish to take. This is particularly the case with the cropping action which we will be exploring later, however this code pattern is a good habit to adopt in general, as user devices vary greatly. When the user accepts the photo they have captured, they will return to the app.

The Camera App

Step 5: Retrieve the Captured Image

We launched the camera app using “startActivityForResult” so we now need to handle the result. Add the “onActivityResult” method after the “onClick” method as follows:

protected void onActivityResult(int requestCode, int resultCode, Intent data) {
	if (resultCode == RESULT_OK) {
	}
}

Inside the “if” statement, add another to check that we are returning from the camera app, using the variable we passed:

//user is returning from capturing an image using the camera
if(requestCode == CAMERA_CAPTURE){
}

We will also return to the “onActivityResult” method after the user crops their image, so we will add an “else if” later. Inside this “if” statement, add the following code to retrieve the URI of the captured photo:

//get the Uri for the captured image
picUri = data.getData();

Now we need to pass this URI to an app that can crop it. We will use a helper method to achieve this, so add the following method call:

//carry out the crop operation
performCrop();

Step 6: Crop the Captured Image

Add the helper method we called after the “onActivityResult” method:

private void performCrop(){
}

Inside this method we are going to call an Intent to perform the crop, so let’s add “try” and “catch” blocks in case the user device does not support the crop operation:

try {
}
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();
}

We use the same technique we used when launching the camera Intent. If the user device does not support the cropping Intent, they will see an error message. Inside the “try” block, launch the Intent as follows:

	//call the standard crop action intent (the user device may not support it)
Intent cropIntent = new Intent("com.android.camera.action.CROP");
	//indicate image type and Uri
cropIntent.setDataAndType(picUri, "image/*");
	//set crop properties
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", 256);
cropIntent.putExtra("outputY", 256);
	//retrieve data on return
cropIntent.putExtra("return-data", true);
	//start the activity - we handle returning in onActivityResult
startActivityForResult(cropIntent, PIC_CROP);

Here we set various properties for the cropped image, instructing the app to retrieve the resulting image data when the crop is complete. If you want the cropped image dimensions to differ from this, alter the “outputX” and “outputY” lines accordingly. We call the Intent using “startActivityForResult”, so will retrieve the result inside “onActivityResult” again. As with the camera Intent, we pass a variable to keep track of which Intent we are returning from, so add a variable declaration at the top of the class, next to the other instance variables:

//keep track of cropping intent
final int PIC_CROP = 2;
Image Cropping

As well as cropping, the user can select an area of the image.

Crop Detail

Step 7: Display the Cropped Image

Finally we can retrieve the cropped image and display it within the app UI. Inside your “onActivityResult” method, after the “if” statement in which you check for the “CAMERA_CAPTURE” request code, add an “if else” statement checking for the “PIC_CROP” code, in which case we are returning from the crop operation:

//user is returning from cropping the image
else if(requestCode == PIC_CROP){
}

Inside this statement, we can retrieve the returned cropped image as follows:

//get the returned data
Bundle extras = data.getExtras();
//get the cropped bitmap
Bitmap thePic = extras.getParcelable("data");

We now have the user’s cropped image as a Bitmap. Let’s display it in the Image View as follows:

//retrieve a reference to the ImageView
ImageView picView = (ImageView)findViewById(R.id.picture);
//display the returned cropped image
picView.setImageBitmap(thePic);

Now the cropped image will appear inside the app UI as soon as the user returns from cropping. Save and run your app on an actual device to test it.

Displaying the Image in the App

Conclusion

In this tutorial we have explored the basic capture and crop process within the Android SDK. However, the crop action in particular can be a little unpredictable on the various user devices in operation. Lots of different apps can handle the crop operation, so some developers adopt a more complex algorithm to resolve the user choices, presenting these apps to the user as a list of options to choose from. Whatever apps the user environment provides, the basic process of capture and crop remains the same.

Note: Want to add some source code? Type <pre><code> before it and </code></pre> after it. Find out more
  • http://www.oxiane.com/blog alain

    Pretty straightforward … nothing wrong about this tut !
    Actually, I have been testing this technique for a while and I have the feeling that outputX and outputY have limitations … do you know about that ?
    I mean when trying to use higher values, the crop activity freezzes …

    What is noticeable in the Android system is that crop is much simpler when used from direct selection in gallery … and that’s not consistent in my humble opinion :)

    • http://benormal.info/ Sue Smith (author)
      Author

      Hi Alain
      Thanks for your comment. I completely agree about the general lack of reliability with cropping. The crop action is a particular area of concern in terms of availability, what should be standard is unfortunately not at the moment – hopefully this will change in future APIs..!

  • Shiva Kumar B

    wow… this tutorial is pretty straight forward and easy to understand
    thanks for this tutorial, keep up the good work

  • Girish Iyer

    Hi..I have copied your code without any changes, but still getting Force Close at run time. Can you guide me as to what could be the problem behind this?? Please excuse as I am a beginner in android platform..Thanks

    • http://benormal.info/ Sue Smith (author)
      Author

      Hi Girish
      You need to look at the error log for your project to gain an insight into why it’s crashing. You can view the error log in Eclipse using the LogCat window.

      • Mahy

        i have this same problem.. i have a null pointer exception when the app returns from the camera intent as soon as i press (OK) after capturing.. by debugging i pointed out that the uri is NULL and dont return the image taken, nor it is saved in the gallery.. i changed absolutely NOTHING in ur code.. any clue why is that please?

  • kartheeswaran

    Camera is not working in emulator…

  • http://adikumkum.blogspot.com adi zean

    Hii.. i want ask something about this croping..
    i use the same way to crop an image… in my case, i want the resolution of output croped image 800x800px.. i had set the intent.putExtra(“outputX”, 800); intent.putExtra(“outputY”, 800);
    but I had crash when i run the program…
    any idea about that??
    thx before… :D

  • Mirko

    The cropped picture disappears when I rotate my device….

    Any suggestion?

    • Mayur Sharma

      You need to put in one attribute in your Activity tag inside the manifest file.
      The attribute will be as : android:configChanges=”orientation”.
      This will surely solve your problem.

      Sample code :

      < application android:icon=”@drawable/icon” android:label=”@string/app_name” >
      < activity android:name=”.MainActivity” android:configChanges=”orientation”
      android:label=”@string/app_name”>
      < intent-filter>
      < action android:name=”android.intent.action.MAIN” />
      < category android:name=”android.intent.category.LAUNCHER” />
      < /intent-filter>
      < /activity>

      < /application>

  • Bruno Almeida

    I’m testing this in the Galaxy Nexus, and is not working.

    After take the photo, just show a message: “Loading imagem…” and stay in this forever.

    I think the variable uriPic is null. Someone can help me?

    Thankyou!

  • Taseen
    • Bruno Almeida

      @Taseen, Thank you for your help,

      but now I’m with another error, when it goes to the crop imagem, there is another image and this image is in the gallery. If I Cancel ou Done the crop, the application “Unfortunately, has stopped”.

      I got the two tutorials, made the if statement and changed this line:

      Uri uriLargeImage = Uri.withAppendedPath(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, String.valueOf(imageId));

      to this:

      picUri = Uri.withAppendedPath(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, String.valueOf(imageId));

      Is there anything I messed up?

      • Bruno Almeida

        I tested right now in a Samsung galaxy 5 and worked fine!

        But in my galaxy nexus, there is the problem I told.

        Anyway, thank you again.

  • soni

    Hi I have this issue with samsung galaxy .After I save the image I get this message
    “The application Gallery (process com.cooliris.media) has stopped unexpectedly. Please try again ”
    and also the crop never opens. Gallery seems to be working fine other than in this application. Can someone suggest .
    Thanks

    • soni

      Also picture never shows up

      • Mahy

        i have your both same problems.. did u manage to solve any?

  • ahmed

    Thank you for your help but i ask how to save the cropping image????????

  • Raghupathi

    hi i am new to android. i want coding for cropping the image irregularly.Thanks in advance.

  • cesco

    very good tutorial,

    It is a pleasure to have a tutorial, that you can just follow it, and at the end, it executes the way it is intended.

    Bravo! Looking forward to other ones from you.

  • alex belex

    good tutorial,

    but , force close in my device, my device is speedata mt35a from china. force close when i running a camera . the logcat is nullpointerexception.

  • Smitha Kamath

    Very good tutorial. Explains each and every step in great detail.
    Thank you.

  • Chandrika

    Hi,
    First of all very good tutorial and very helpful.
    Secondly I need your help,I am making an application in which I need to add photo tagging option.
    I don’t know how to implement this functionality on various Image view animations like Image View Flipper or Page Curl.
    Any help on this topic will be appreciated.
    Thank you,
    Chandrika.

  • Mahy

    i have a null pointer exception when the app returns from the camera intent as soon as i press (OK) after capturing.. by debugging i pointed out that the uri is NULL and dont return the image taken, nor it is saved in the gallery.. i changed absolutely NOTHING in ur code.. any clue why is that please?

  • Binod singh

    Awesome worked perfectly as stated in the tutorial.

  • Shen

    after I take the picture, I am stuck at “Loading Image”, what do I do about that ???

    pls pls pls help me

  • Frank “The kid”

    This tutorial definitely won’t work.

  • Shenjie Lin

    I am using Motorola RAZR HD LTE, and my app stuck at “loading image”, help me pls?

  • guest

    Greate tutotial. Thanks

  • Jayant Umrani

    I tried this and the crop part worked really well.There is issue with Camera capture on some devices, Samsung is where I got issues. I have solved that. So if anyone else if looking for the soln let me know. jayant.umrani@gmail.com

    • Syahirul Alim M

      How do you solve this problem sir? It didn’t work on Samsung Devices

  • AndroidLover

    how, how can I save the cropped image into my gallery? please help me please

  • Mariam

    i m doing same but having problem with my layout most of the time my layout gets cropped from above can you help with this

  • sandy

    exactly what i needed, thanks a lot

  • anon

    could you show the full code for it

  • Mukund

    Hey one question.Can I crop the image using dp rather than actual pixels?