2

I just got started in Android Programming and I am creating an android application in which the user is allowed to key in information, take a picture with ImageView implemented and SAVE the information. I've gotten up to the point where I am able to display the image taken into ImageView. However, I am unable to save the image taken into my phone's internal storage. Which means, whenever I try to save the information, including the ImageView (image from camera), only the image disappears. I've followed this guide on http://www.androidhive.info/2013/09/android-working-with-camera-api/ but it does not work as my phone has no SD card storage.

I've read a bunch of questions on here but they do not fix the problem.

So if anyone could give me a detailed procedure on how to edit this code in such a way that I can save/read the image into/from my INTERNAL storage that would be great! Thank you.

/**
 * returning image / video
 */
private static File getOutputMediaFile(int type) {

    // External sdcard location
    File mediaStorageDir = new File(
            Environment
                    .getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),
            IMAGE_DIRECTORY_NAME);

    // Create the storage directory if it does not exist
    if (!mediaStorageDir.exists()) {
        if (!mediaStorageDir.mkdirs()) {
            Log.d(IMAGE_DIRECTORY_NAME, "Oops! Failed create "
                    + IMAGE_DIRECTORY_NAME + " directory");
            return null;
        }
    }
}

This is my current code:

private static final String IMAGE_DIRECTORY_NAME = "Hello Camera";
private Uri fileUri; // file url to store image/video
private ImageView ItemPic;
private static final int CAMERA_CAPTURE_IMAGE_REQUEST_CODE = 100;
public static final int MEDIA_TYPE_IMAGE = 1;

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

    date = (EditText) findViewById(R.id.date);
    amount = (EditText) findViewById(R.id.amount);
    item = (EditText) findViewById(R.id.item);

    add = (Button) findViewById(R.id.add_b);
    add.setOnClickListener(onAdd);

    camera = (ImageButton) findViewById(R.id.camera);
    camera.setOnClickListener(new View.OnClickListener() {
       @Override
       public void onClick(View v) {
           // capture picture
           captureImage();
          //  Intent cameraIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
           // startActivityForResult(cameraIntent, CAMERA_REQUEST);
       }
   });

    ItemPic = (ImageView) findViewById(R.id.itempic);

    entryId = getIntent().getStringExtra("ID");
    if (entryId != null) {
        load();
    }
}

    /*
 * Capturing Camera Image will lauch camera app requrest image capture
*/
private void captureImage() {
    Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);

    fileUri = getOutputMediaFileUri(MEDIA_TYPE_IMAGE);

    intent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri);

    // start the image capture Intent
    startActivityForResult(intent, CAMERA_CAPTURE_IMAGE_REQUEST_CODE);
}

/**
 * Here we store the file url as it will be null after returning from camera
 * app
 */
@Override
protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);

    // save file url in bundle as it will be null on scren orientation
    // changes
    outState.putParcelable("file_uri", fileUri);
}

@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
    super.onRestoreInstanceState(savedInstanceState);

    // get the file url
    fileUri = savedInstanceState.getParcelable("file_uri");
}

/**
 * Receiving activity result method will be called after closing the camera
 * */
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    // if the result is capturing Image
    if (requestCode == CAMERA_CAPTURE_IMAGE_REQUEST_CODE) {
        if (resultCode == RESULT_OK) {
            // successfully captured the image
            // display it in image view
            previewCapturedImage();
        } else if (resultCode == RESULT_CANCELED) {
            // user cancelled Image capture
            Toast.makeText(getApplicationContext(),
                    "User cancelled image capture", Toast.LENGTH_SHORT)
                    .show();
        } else {
            // failed to capture image
            Toast.makeText(getApplicationContext(),
                    "Sorry! Failed to capture image", Toast.LENGTH_SHORT)
                    .show();
        }
    }
}

/**
 * Display image from a path to ImageView
 */
private void previewCapturedImage() {
    try {
        ItemPic.setVisibility(View.VISIBLE);

        // bimatp factory
        BitmapFactory.Options options = new BitmapFactory.Options();

        // downsizing image as it throws OutOfMemory Exception for larger
        // images
        options.inSampleSize = 8;

        final Bitmap bitmap = BitmapFactory.decodeFile(fileUri.getPath(),
                options);

        ItemPic.setImageBitmap(bitmap);

    }  catch (NullPointerException e) {
        e.printStackTrace();
    }
}

/**
 * ------------ Helper Methods ----------------------
 * */

/**
 * Creating file uri to store image/video
 */
public Uri getOutputMediaFileUri(int type) {
    return Uri.fromFile(getOutputMediaFile(type));
}


/**
 * returning image / video
 */
private static File getOutputMediaFile(int type) {

    // External sdcard location
    File mediaStorageDir = new File(
            Environment
                    .getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),
            IMAGE_DIRECTORY_NAME);

    // Create the storage directory if it does not exist
    if (!mediaStorageDir.exists()) {
        if (!mediaStorageDir.mkdirs()) {
            Log.d(IMAGE_DIRECTORY_NAME, "Oops! Failed create "
                    + IMAGE_DIRECTORY_NAME + " directory");
            return null;
        }
    }

    // Create a media file name
    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss",
            Locale.getDefault()).format(new Date());
    File mediaFile;
    if (type == MEDIA_TYPE_IMAGE) {
        mediaFile = new File(mediaStorageDir.getPath() + File.separator
                + "IMG_" + timeStamp + ".jpg");
    } else {
        return null;
    }

    return mediaFile;
}
undorealize
  • 33
  • 1
  • 1
  • 4
  • "it does not work as my phone has no SD card storage" -- [external storage](https://commonsware.com/blog/2014/04/08/storage-situation-external-storage.html) is rarely [removable storage](https://commonsware.com/blog/2014/04/09/storage-situation-removable-storage.html) on Android devices made in the past five years. If you plug in your USB cable to your phone, and a volume named "Internal Storage" shows up on your development machine, that is what the Android SDK refers to as external storage. – CommonsWare Jul 28 '15 at 13:52
  • Ah I see, thanks for clearing that up. The image taken from my camera doesn't get saved into my created directory at all, which I assume is the cause of my image not displaying when I return to that activity.. – undorealize Jul 28 '15 at 14:14
  • "The image taken from my camera doesn't get saved into my created directory at all" -- since we don't have your code where you are using the camera and saving the image, we cannot really help you with that. – CommonsWare Jul 28 '15 at 14:16
  • Sorry about that, I've edited my original post with the coding I've used. – undorealize Jul 28 '15 at 14:22

1 Answers1

8

getOutputMediaFile() is returning a directory, not a file. You need to specify a path to a (not-yet-existing) file where you want the image to be written.

This is illustrated in this activity from this sample application:

package com.commonsware.android.camcon;

import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import java.io.File;

public class CameraContentDemoActivity extends Activity {
  private static final int CONTENT_REQUEST=1337;
  private File output=null;

  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    Intent i=new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    File dir=
        Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM);

    output=new File(dir, "CameraContentDemo.jpeg");
    i.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(output));

    startActivityForResult(i, CONTENT_REQUEST);
  }

  @Override
  protected void onActivityResult(int requestCode, int resultCode,
                                  Intent data) {
    if (requestCode == CONTENT_REQUEST) {
      if (resultCode == RESULT_OK) {
        Intent i=new Intent(Intent.ACTION_VIEW);

        i.setDataAndType(Uri.fromFile(output), "image/jpeg");
        startActivity(i);
        finish();
      }
    }
  }
}
CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
  • Thank you! I've tried your code and was able to preview the image in my gallery after capturing the image, however, it still does not save... – undorealize Jul 28 '15 at 14:46
  • @undorealize: By definition, if the activity started by `onActivityResult()` can show you the image, the image saved. However, bear in mind that the image may not have been indexed by the `MediaStore`, and what you see over your USB cable connection is what `MediaStore` knows about. Use `MediaScannerConnection` and `scanFile()` to update the `MediaStore` in real time. – CommonsWare Jul 28 '15 at 14:51
  • I was able to save the image taken from the camera however, I've noticed that when I take consecutive shots, the previous photo gets overwritten. How do I change that? – undorealize Jul 28 '15 at 15:16
  • 1
    @undorealize: Provide a different value for `EXTRA_OUTPUT`. You are the one indicating where the images should be written. It is your job to recognize that you are taking consecutive shots, and it is your job to use different filenames for those shots if you want all the files to be saved. – CommonsWare Jul 28 '15 at 15:21