Android - How to take a picture from camera or gallery

26,667

Solution 1

based on @yurezcv's answer, here's what I came up with (Most importantly how to retrieve image in onActivityResult):

private List<File> cameraImageFiles;

private void popImageChooser(){
    // Camera.
    final List<Intent> cameraIntents = new ArrayList<Intent>();
    final Intent captureIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
    final PackageManager packageManager = getPackageManager();
    final List<ResolveInfo> listCam = packageManager.queryIntentActivities(captureIntent, 0);

    cameraImageFiles = new ArrayList<File>();

    int i=0;
    for(ResolveInfo res : listCam) {
        final String packageName = res.activityInfo.packageName;
        final Intent intent = new Intent(captureIntent);
        intent.setComponent(new ComponentName(res.activityInfo.packageName, res.activityInfo.name));
        intent.setPackage(packageName);
        intent.putExtra(MediaStore.MEDIA_IGNORE_FILENAME, ".nomedia");

        File cameraImageOutputFile = new File(
                Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),
                createCameraImageFileName());
        cameraImageFiles.add(cameraImageOutputFile);
        intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(cameraImageFiles.get(i)));
        i++;

        cameraIntents.add(intent);
    }

    // Filesystem.
    final Intent galleryIntent = new Intent();
    galleryIntent.setType("image/*");
    galleryIntent.setAction(Intent.ACTION_GET_CONTENT);

    // Chooser of filesystem options.
    final Intent chooserIntent = Intent.createChooser(galleryIntent, getString(R.string.attach_images_title));

    // Add the camera options.
    chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, cameraIntents.toArray(new Parcelable[]{}));
    startActivityForResult(chooserIntent, ACTIVITY_REQUEST_CODE_IMAGE);
}


protected void onActivityResult(int requestCode, int resultCode, 
           Intent imageReturnedIntent) {
    super.onActivityResult(requestCode, resultCode, imageReturnedIntent); 

    switch(requestCode) { 
    case ACTIVITY_REQUEST_CODE_IMAGE:
        if(resultCode == RESULT_OK){

            Uri uri = null;
            if(imageReturnedIntent == null){   //since we used EXTRA_OUTPUT for camera, so it will be null

                for(int i=0;i<cameraImageFiles.size();i++){
                    if(cameraImageFiles.get(i).exists()){
                        uri = Uri.fromFile(cameraImageFiles.get(i));
                        break;
                    }
                }
                Log.d("attachimage", "from camera: "+uri);
            }
            else {  // from gallery
                uri = imageReturnedIntent.getData();
                Log.d("attachimage", "from gallery: "+uri.toString());
            }

            if(uri != null){
                attachImage(uri);
            }
        }
    }
}

Solution 2

This solution works for me:

private void addPhoto() {   
       // Camera.
    final List<Intent> cameraIntents = new ArrayList<Intent>();
    final Intent captureIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);     
    final PackageManager packageManager = getPackageManager();
    final List<ResolveInfo> listCam = packageManager.queryIntentActivities(captureIntent, 0);
    for(ResolveInfo res : listCam) {
        final String packageName = res.activityInfo.packageName;
        final Intent intent = new Intent(captureIntent);
        intent.setComponent(new ComponentName(res.activityInfo.packageName, res.activityInfo.name));
        intent.setPackage(packageName);
        intent.putExtra(MediaStore.MEDIA_IGNORE_FILENAME, ".nomedia");

        cameraIntents.add(intent);
    }

    // Filesystem.
    final Intent galleryIntent = new Intent();
    galleryIntent.setType("image/*");
    galleryIntent.setAction(Intent.ACTION_GET_CONTENT);

    // Chooser of filesystem options.
    final Intent chooserIntent = Intent.createChooser(galleryIntent, getString(R.string.add_new));

    // Add the camera options.
    chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, cameraIntents.toArray(new Parcelable[]{}));
    startActivityForResult(chooserIntent, YOUR_REQUEST_CODE);
}

It creates one intent dialog with all possible variants for select image from camera, filesystem, etc.

Solution 3

Hay un detalle que no se ha dicho y es que actualmente el tema de la orientación de la cámara es un desastre cuando lo que se hace es guardar la captura y luego leerla de disco para mostrarla. Esto es así porque los fabricantes, como HTC, Samsung, etc no se ponen de acuerdo en seguir el standard. En este caso, puede (y depende del dispositivo), ser necesario corregir la imagen usando la información EXIF de la misma para que no se muestre rotada por ejemplo, en un ImageView.

Si la imagen de la cámara no la guardamos sino que en la vuelta leemos del Bundle los datos guardados en la key "data", la imagen se mostrará bien.

Otra cosa que yo haría si guardamos la foto en disco, es hacer que esta se vea en la galería para que el usuario la pueda ver y borrar directamente (ver MediaScannerConnectionClient)

Yo lo he hecho tal como se ve en el código que pongo abajo. Permite hacerlo bien por la galería ó, tomando una captura con la cámara. (para algunas tareas he usado la librería pública en GitHub https://github.com/javocsoft/javocsoft-toolbox/)

package com.example.getpicture;

import java.io.File;

import android.app.Activity;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;
import es.javocsoft.android.lib.toolbox.ToolBox;
import es.javocsoft.android.lib.toolbox.media.MediaScannerNotifier;

public class MainActivity extends Activity {

private final int PICTURE_TAKEN_FROM_CAMERA = 1;
private final int PICTURE_TAKEN_FROM_GALLERY = 2;

private Button btncamera = null;
private Button btngallery = null;
private ImageView pictureZone = null;
private boolean storeImage = false;
private File outFile = null;


@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    pictureZone = (ImageView)findViewById(R.id.pictureZone);
    btncamera = (Button)findViewById(R.id.btncamera);
    btngallery = (Button)findViewById(R.id.btngallery);


    addEvents();
}


private void addEvents(){
    btncamera.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {
            getPictureFromCamera();         
        }
    });

    btngallery.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {
            getPictureFromGallery();            
        }
    });
}   

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

    Bitmap takenPictureData = null;

    switch(requestCode){

        case PICTURE_TAKEN_FROM_CAMERA:             
            if(resultCode==Activity.RESULT_OK) {
                takenPictureData = handleResultFromCamera(data);
            }               
            break;
        case PICTURE_TAKEN_FROM_GALLERY:                
            if(resultCode==Activity.RESULT_OK) {
                takenPictureData = handleResultFromChooser(data);                   
            }
            break;          
    }

    //And show the result in the image view.
    if(takenPictureData!=null){
        pictureZone.setImageBitmap(takenPictureData);
    }       
}


//AUXILIAR

private Bitmap handleResultFromChooser(Intent data){
    Bitmap takenPictureData = null;

    Uri photoUri = data.getData();
    if (photoUri != null){
        try {
            //We get the file path from the media info returned by the content resolver
            String[] filePathColumn = {MediaStore.Images.Media.DATA};
            Cursor cursor = getContentResolver().query(photoUri, filePathColumn, null, null, null); 
            cursor.moveToFirst();
            int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
            String filePath = cursor.getString(columnIndex);
            cursor.close();

            takenPictureData = ToolBox.media_getBitmapFromFile(new File(filePath));

        }catch(Exception e){
            ToolBox.dialog_showToastAlert(this, "Error getting selected image.", false);
        }
    }

    return takenPictureData;
}

private Bitmap handleResultFromCamera(Intent data){
    Bitmap takenPictureData = null;

    if(data!=null){
        //Android sets the picture in extra data.
        Bundle extras = data.getExtras();
        if(extras!=null && extras.get("data")!=null){
            takenPictureData = (Bitmap) extras.get("data");
        }
    }else{
        //If we used EXTRA_OUTPUT we do not have the data so we get the image
        //from the output.
        try{
            takenPictureData = ToolBox.media_getBitmapFromFile(outFile);
            takenPictureData = ToolBox.media_correctImageOrientation(outFile.getAbsolutePath());
        }catch(Exception e){
            ToolBox.dialog_showToastAlert(this, "Error getting saved taken picture.", false);
        }
    }

    if(storeImage){
        //We add the taken picture file to the gallery so user can see the image directly                   
        new MediaScannerNotifier(this,outFile.getAbsolutePath(),"image/*", false);
    }

    return takenPictureData;
}

private void getPictureFromCamera(){
    boolean cameraAvailable = ToolBox.device_isHardwareFeatureAvailable(this, PackageManager.FEATURE_CAMERA);
    if(cameraAvailable && 
        ToolBox.system_isIntentAvailable(this, MediaStore.ACTION_IMAGE_CAPTURE)){

        Intent takePicIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);

        //We prepare the intent to store the taken picture
        try{
            File outputDir = ToolBox.storage_getExternalPublicFolder(Environment.DIRECTORY_PICTURES, "testApp", true);
            outFile = ToolBox.storage_createUniqueFileName("cameraPic", ".jpg", outputDir);

            takePicIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(outFile));             
            storeImage = true;
        }catch(Exception e){
            ToolBox.dialog_showToastAlert(this, "Error setting output destination.", false);
        }

        startActivityForResult(takePicIntent, PICTURE_TAKEN_FROM_CAMERA);
    }else{
        if(cameraAvailable){
            ToolBox.dialog_showToastAlert(this, "No application that can receive the intent camera.", false);
        }else{
            ToolBox.dialog_showToastAlert(this, "No camera present!!", false);
        }
    }
}

private void getPictureFromGallery(){
    /*
    //This allows to select the application to use when selecting an image.
    Intent i = new Intent(Intent.ACTION_GET_CONTENT);
    i.setType("image/*");
    startActivityForResult(Intent.createChooser(i, "Escoge una foto"), PICTURE_TAKEN_FROM_GALLERY);
    */

    //This takes images directly from gallery
    Intent gallerypickerIntent = new Intent(Intent.ACTION_PICK);
    gallerypickerIntent.setType("image/*");
    startActivityForResult(gallerypickerIntent, PICTURE_TAKEN_FROM_GALLERY); 
}

}

El layout es:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:background="#f2f2f2"    
tools:context=".MainActivity" >

<ImageView
    android:id="@+id/pictureZone"
    android:layout_width="280dp"
    android:layout_height="280dp"
    android:layout_alignParentTop="true"
    android:layout_centerHorizontal="true"

    android:src="@drawable/ic_launcher" />

<Button
    android:id="@+id/btncamera"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginTop="36dp"
    android:layout_alignParentBottom="true"
    android:layout_alignParentLeft="true"
    android:text="Camera" />

<Button
    android:id="@+id/btngallery"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignParentBottom="true"
    android:layout_alignParentRight="true"
    android:text="Pick it" />

<TextView
    android:id="@+id/textView1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_above="@+id/btngallery"
    android:layout_centerHorizontal="true"
    android:text="Choose an option"
    android:textStyle="bold"
    android:textAppearance="?android:attr/textAppearanceMedium" />

Y por último en el manifest hace falta como no, los permisos adecuados:

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

Un saludo.

Solution 4

  1. Create in your layout a button (by clicking on this button will open a dialog where you can choose whether to choose the camera or galleria).

  2. Now initializes the button in its class:

    - Before onCreate:

    Button btu;

    - Inside onCreate:

    btu = (Button) findViewById(R.id.BtUp);

  3. Methods call camera and gallery

- Before onCreate boot

int CAMERA_REQUEST = 1;

- Method Call camera

public void callCamera() {
    Intent cameraIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
    cameraIntent.putExtra("crop", "true");
    cameraIntent.putExtra("aspectX", 0);
    cameraIntent.putExtra("aspectY", 0);
    cameraIntent.putExtra("outputX", 200);
    cameraIntent.putExtra("outputY", 150);
    startActivityForResult(cameraIntent, CAMERA_REQUEST);
}

- Method Call gallery

public void callGallery() {
    Intent intent = new Intent(Intent.ACTION_PICK,
                               MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
    startActivityForResult(intent,0);
}
  1. Create a method to show the AlertDialog, which appear to choose:

    public void showAlertDialog(Context context) {
    this.context = context;
    final String items[] = {getString(R.string.TextTakeCam), getString(R.string.TextTakeGal)};
    
    AlertDialog.Builder ab = new AlertDialog.Builder(MainActivity.this);
    ab.setTitle(getString(R.string.TextTitleDia));
    AlertDialog.Builder builder = ab.setItems(items, new DialogInterface.OnClickListener() {
        public void onClick(DialogInterface d, int choice) {
            if (choice == 0) {
                callCamera();
            } else if (choice == 1) {
                image.setVisibility(View.INVISIBLE);
                callGallery();
            }
        }});
    ab.show();
    

    }

  2. Call AlertDialog in button

    btu.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        String title = getString(R.string.TextUp);
        String msg = getString(R.string.TextUp2);
        showAlertDialog2(MainActivity.this,title,msg,true);
        //maneger.UpdateC(edname.getText().toString(),edfoto.getText().toString(),ednum. getText().toString());
        }
    });
    

Inside AndroidManifest.xml

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

Solution 5

I found a better and easy way to take picture from camera or gallery i.e. using this library https://android-arsenal.com/details/1/3623

You can follow the link above or follow these steps:

Steps to use this library in your project are:

  1. Add dependency to Gradle:

    compile 'com.frosquivel:magicalcamera:4.4'

  2. Implementation Code:

    PermissionGranted permissionGranted = new PermissionGranted(this); MagicalCamera magicalCamera = new MagicalCamera(this, permissionGranted); //The parameter this, is the current activity //permission for take photo, it is false if the user check deny permissionGranted.checkCameraPermission(); //for search and write photoss in device internal memory //normal or SD memory permissionGranted.checkReadExternalPermission(); permissionGranted.checkWriteExternalPermission();

  3. Call to Take Photo From Camera:

    magicalCamera.takePhoto();

  4. Call to Select Photo From Gallery:

    magicalCamera.selectedPicture("my_header_name");

  5. Override OnActivityResult(); method to get Bitmap and Path:

    public void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    magicalCamera.resultPhoto(requestCode, resultCode, data);//with this form you obtain the bitmap
    Bitmap bitmap = magicalCamera.getPhoto();
    imageView.setImageBitmap(bitmap);
    //if you need path of bitmap use this code
    String path = magicalCamera.savePhotoInMemoryDevice(magicalCamera.getPhoto(),"myPhotoName","myDirectoryName", MagicalCamera.JPEG, true);
    

    if(path != null){ Toast.makeText(MainActivity.this, "The photo is save in device, please check this path: " + path, Toast.LENGTH_SHORT).show(); }else{ Toast.makeText(MainActivity.this, "Sorry your photo dont write in devide, please contact with fabian7593@gmail and say this error", Toast.LENGTH_SHORT).show(); } }

For more details refer to the link above

Share:
26,667
Ferran Maylinch
Author by

Ferran Maylinch

Developer at Yandex, and sometimes a teacher.

Updated on January 18, 2020

Comments

  • Ferran Maylinch
    Ferran Maylinch over 4 years

    I would like to ask the user to take a picture, either from camera or from the existing pictures in the device (gallery or whatever). How can I do that?

    I have implemented the solution below, which seems to work fine, but the documentation is quite confusing so I would like to know if there are better solutions.

    Also, check out this related post. There you will see how to get the image path or Bitmap: Get/pick an image from Android's built-in Gallery app programmatically

    So, in my solution you would create a TakePictureHelper object and do the following.

    Let's say you display a dialog where the user can choose "camera" or "other". When the user chooses an option you would call either takeFromCamera() or takeFromOther(). When the picture is taken (or not) the onActivityResult() method will be called. There you would call retrievePicture, which will return the Uri of the picture or null if no picture was taken.

    Please let me know what you think, share ideas or ask me anything if I wasn't clear.

    Thank you very much!

    import android.app.Activity;
    import android.content.Intent;
    import android.net.Uri;
    import android.os.Environment;
    import android.provider.MediaStore;
    import java.io.File;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    
    public class TakePictureHelper {
    
        public final static int REQUEST_CAMERA = 1;
        public final static int REQUEST_OTHER = 2;
    
        private Uri cameraImageUri;
    
        /**
         * Request picture from camera using the given title
         */
        public void takeFromCamera(Activity activity, String title)
        {
            Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
            File cameraImageOutputFile = new File(
                    Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),
                    createCameraImageFileName());
            cameraImageUri = Uri.fromFile(cameraImageOutputFile);
            intent.putExtra(MediaStore.EXTRA_OUTPUT, cameraImageUri);
            activity.startActivityForResult(Intent.createChooser(intent, title), REQUEST_CAMERA);
        }
    
        /**
         * Request picture from any app (gallery or whatever) using the given title
         */
        public void takeFromOther(Activity activity, String title)
        {
            Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
            intent.setType("image/*");
            activity.startActivityForResult(Intent.createChooser(intent, title), REQUEST_OTHER);
        }
    
        /**
         * Retrieve the picture, taken from camera or gallery.
         *
         * @return the picture Uri, or null if no picture was taken.
         */
        public Uri retrievePicture(Activity activity, int requestCode, int resultCode, Intent data)
        {
            Uri result = null;
    
            if (resultCode == Activity.RESULT_OK) {
    
                if (requestCode == REQUEST_OTHER) {
                    result = data.getData();
                } else if (requestCode == REQUEST_CAMERA) {
                    result = cameraImageUri;
                }
            }
    
            return result;
        }
    
        private String createCameraImageFileName() {
            String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
            return timeStamp + ".jpg";
        }
    }
    
  • Ferran Maylinch
    Ferran Maylinch over 10 years
    Thank you. How do you get the image file in onActivityResult? Do you do the same if it comes from the camera or other app?
  • Anas Azeem
    Anas Azeem almost 10 years
    Where is createCameraImageFileName(), and what does it do?
  • OatsMantou
    OatsMantou almost 10 years
    @AnasAzeem it just generates a String name for the new image file taken from camera. You can write it whatever the way you like
  • Neon Warge
    Neon Warge over 7 years
    we don't speak your language. English please