Built-in Camera, using the extra MediaStore.EXTRA_OUTPUT stores pictures twice (in my folder, and in the default)

27,465

Solution 1

Another way, tested on android 2.1, is take the ID or Absolute path of the gallery last image, then you can delete the duplicated image.

It can be done like that:

/**
 * Gets the last image id from the media store
 * @return
 */
private int getLastImageId(){
    final String[] imageColumns = { MediaStore.Images.Media._ID, MediaStore.Images.Media.DATA };
    final String imageOrderBy = MediaStore.Images.Media._ID+" DESC";
    Cursor imageCursor = managedQuery(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, imageColumns, null, null, imageOrderBy);
    if(imageCursor.moveToFirst()){
        int id = imageCursor.getInt(imageCursor.getColumnIndex(MediaStore.Images.Media._ID));
        String fullPath = imageCursor.getString(imageCursor.getColumnIndex(MediaStore.Images.Media.DATA));
        Log.d(TAG, "getLastImageId::id " + id);
        Log.d(TAG, "getLastImageId::path " + fullPath);
        imageCursor.close();
        return id;
    }else{
        return 0;
    }
}

And to remove the file:

private void removeImage(int id) {
   ContentResolver cr = getContentResolver();
   cr.delete(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, MediaStore.Images.Media._ID + "=?", new String[]{ Long.toString(id) } );
}

This code was based on the post: Deleting a gallery image after camera intent photo taken

Solution 2

While the answer from "Ilango J" provides the basic idea.. I thought I'd actually write in how I actually did it. The temporary file path that we were setting in intent.putExtra() should be avoided as it's a non standard way across different hardwares. On HTC Desire (Android 2.2) it did not work, And i've heard it works on other phones. It's best to have a neutral approach which works every where.

Please note that this solution (using the Intent) requires that the phone's SD Card is available and is not mounted onto the PC. Even the normal Camera app wouldn't work when the SD Card is connected to the PC.

1) Initiate the Camera Capture intent. Note, I disabled temporary file writes (non-standard across different hardware)

    Intent camera = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    startActivityForResult(camera , 0);

2) Handle callback and retrieve the captured picture path from the Uri object and pass it to step#3

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    switch (requestCode) {
    case CAPTURE_PIC: {
        if (resultCode == RESULT_OK && data != null) {
            Uri capturedImageUri = data.getData();
            String capturedPicFilePath = getRealPathFromURI(capturedImageUri);
            writeImageData(capturedImageUri, capturedPicFilePath);
            break;
        }
    }
    }
}

public String getRealPathFromURI(Uri contentUri) {
    String[] projx = { MediaStore.Images.Media.DATA };
    Cursor cursor = managedQuery(contentUri, projx, null, null, null);
    int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
    cursor.moveToFirst();
    return cursor.getString(column_index);
}

3) Clone and delete the file. See that I used the Uri's InputStream to read the content. The same can be read from the File of the capturedPicFilePath too.

public void writeImageData(Uri capturedPictureUri, String capturedPicFilePath) {

    // Here's where the new file will be written
    String newCapturedFileAbsolutePath = "something" + JPG;

    // Here's how to get FileInputStream Directly.
    try {
        InputStream fileInputStream = getContentResolver().openInputStream(capturedPictureUri);
        cloneFile(fileInputStream, newCapturedFileAbsolutePath);
    } catch (FileNotFoundException e) {
        // suppress and log that the image write has failed. 
    }

    // Delete original file from Android's Gallery
    File capturedFile = new File(capturedPicFilePath);
    boolean isCapturedCameraGalleryFileDeleted = capturedFile.delete();
}

  public static void cloneFile(InputStream currentFileInputStream, String newPath) {
    FileOutputStream newFileStream = null;

    try {

        newFileStream = new FileOutputStream(newPath);

        byte[] bytesArray = new byte[1024];
        int length;
        while ((length = currentFileInputStream.read(bytesArray)) > 0) {
            newFileStream.write(bytesArray, 0, length);
        }

        newFileStream.flush();

    } catch (Exception e) {
        Log.e("Prog", "Exception while copying file " + currentFileInputStream + " to "
                + newPath, e);
    } finally {
        try {
            if (currentFileInputStream != null) {
                currentFileInputStream.close();
            }

            if (newFileStream != null) {
                newFileStream.close();
            }
        } catch (IOException e) {
            // Suppress file stream close
            Log.e("Prog", "Exception occured while closing filestream ", e);
        }
    }
}
Share:
27,465

Related videos on Youtube

darksider
Author by

darksider

Updated on July 31, 2020

Comments

  • darksider
    darksider almost 4 years

    I'm currently developing an app which uses the built-in Camera. I call this snippet by clicking a button :

    Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
    //Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    
    String path = Environment.getExternalStorageDirectory().getAbsolutePath();
    path += "/myFolder/myPicture.jpg";
    File file = new File( path );
    //file.mkdirs();
    Uri outputFileUri = Uri.fromFile( file );
    //String absoluteOutputFileUri = file.getAbsolutePath();
    
    intent.putExtra(MediaStore.EXTRA_OUTPUT, outputFileUri);
    startActivityForResult(intent, 0);
    

    After taking the picture with the camera, the jpg is well stored in sdcard/myFolder/myPicture.jpg, but it is also stored in /sdcard/DCIM/Camera/2011-06-14 10.36.10.jpg, which is the default path.

    Is there a way to prevent the built-in Camera to store the picture in the default folder?

    Edit : I think I will use the Camera class directly

    • RajeshVijayakumar
      RajeshVijayakumar almost 11 years
      keep it up........thnks
  • Swaroop
    Swaroop almost 13 years
    How is this different from the source given above. After all the constant MediaStore.EXTRA_OUTPUT resolves to String "output" too
  • ilango j
    ilango j almost 13 years
    do one thing after captured image delete myPicture.jpg image. using file.delete() function.
  • Somatik
    Somatik over 12 years
    activity result data is null on my android galaxy S II
  • Swaroop
    Swaroop over 12 years
    Yes, there is a problem with Samsung Manufactured phones. I'll post the approach as soon as I find a workaround. I just ordered a couple of Nexus S phones which have the Samsung Camera Issue too.. Google it.. Others are facing the issue too.
  • Alex
    Alex over 12 years
    This works but when picture is taken metadata is registered with MediaStorage so when you go to browse Gallery the thumb for then picture still going to be there even though file is gone. How do you remove that?
  • Alex
    Alex over 12 years
    Sorry I should add that this is on Desire 2.2
  • Ashish Mishra
    Ashish Mishra about 11 years
    its working good.but in my case it delete images from SD card folder.I am using Sony Ericsson phone.In my app I capture images and save to SD card folder and back to the activity where i added grid view which get the images from sd card and add to the grid view.your code working good but it delete from my folder.any help will be appreciable.
  • Derzu
    Derzu about 11 years
    @AshishMishra I'm not sure if I understand you right. If you don't wanna to dele just don't call removeImage.
  • Admin
    Admin over 10 years
    @Derzu Don't you think it will delete wrong images in which the duplicate images are not created
  • Derzu
    Derzu over 10 years
    @FatalError Yes... there is this risk, if the new image is not really saved.
  • Admin
    Admin over 10 years
    @Derzu is there any process to know which device creates the duplicate images and which doesn't
  • Derzu
    Derzu over 10 years
    @user2730944, I don't know how to be sure that the duplicated image was created. But the image name has the date and hour. You can try to parse this info, and see if it is near to the actual time.
  • ashishduh
    ashishduh about 10 years
    This is the right idea but to make it work on all devices you should first store off the most recent MediaStore.Images.Media._ID before calling the capture intent. Then delete any file that has a higher ID when the intent returns. See this answer
  • kos
    kos over 5 years
    This is not a good solution. The last taken image could easily be a different image than what you intend to delete.