How do I save image from Camera?

13,336

Solution 1

pre.camera.takePicture(shutterCallback, rawCallback,
                            jpegCallback);
            PictureCallback rawCallback = new PictureCallback() {
            public void onPictureTaken(byte[] data, Camera camera) {
                System.out.println( "onPictureTaken - raw");
            }
        };

        /** Handles data for jpeg picture */
        PictureCallback jpegCallback = new PictureCallback() {
            public void onPictureTaken(byte[] data, Camera camera) {


                 BitmapFactory.Options options=new BitmapFactory.Options();
                    options.inSampleSize = 5;

                m=BitmapFactory.decodeByteArray(data,0,data.length,options);

Solution 2

Just glancing at your code, You need to pass your callbacks into the takePicture method mPreview.getCamera().takePicture(shutterCallback, rawCallback, null, jpegCallback); Take a look here for more details.

Your stack trace seems to suggest that it doesn't know what to do once it has taken the photo.

Also I suspect you may be pointing at the wrong root directory for writing... try this: Environment.getExternalStorageDirectory().toString()

Solution 3

Here it is:

public class PictureSaver {

private static final String TAG = "PictureSaver";

public static final int MEDIA_TYPE_IMAGE = 1;
public static final int MEDIA_TYPE_VIDEO = 2;

/** null if unable to save the file */
public static File savePicture(byte[] data, String folder_name) throws SaveFileException {
    File pictureFile = getOutputMediaFile(MEDIA_TYPE_IMAGE, folder_name);
    if (pictureFile == null){
        Log.d(TAG, "Error creating media file, check storage permissions!");
        throw new SaveFileException(TAG, "Error creating media file, check storage permissions!");
    }

    try {
        FileOutputStream fos = new FileOutputStream(pictureFile);
        fos.write(data);
        fos.close();
    } catch (FileNotFoundException e) {
        Log.d(TAG, "File not found: " + e.getMessage());
        throw new SaveFileException(TAG, "File not found: " + e.getMessage());
    } catch (IOException e) {
        Log.d(TAG, "Error accessing file: " + e.getMessage());
        throw new SaveFileException(TAG, "Error accessing file: " + e.getMessage());
    }
    return pictureFile;
}

/** Create a File for saving an image or video 
 *  null if unable to create the file */
private static File getOutputMediaFile(int type, String folder_name) throws SaveFileException {
    // To be safe, you should check that the SDCard is mounted
    // using Environment.getExternalStorageState() before doing this.

    File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(
              Environment.DIRECTORY_PICTURES), folder_name);
    // This location works best if you want the created images to be shared
    // between applications and persist after your app has been uninstalled.

    // Create the storage directory if it does not exist
    if (! mediaStorageDir.exists()){
        if (! mediaStorageDir.mkdirs()){
            Log.d(TAG, "Unable to create directory!");
            throw new SaveFileException(TAG, "Unable to create directory!");
        }
    }

    // Create a media file name
    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
    File mediaFile;
    if (type == MEDIA_TYPE_IMAGE){
        mediaFile = new File(mediaStorageDir.getPath() + File.separator +
        "IMG_"+ timeStamp + ".jpg");
    } else if(type == MEDIA_TYPE_VIDEO) {
        mediaFile = new File(mediaStorageDir.getPath() + File.separator +
        "VID_"+ timeStamp + ".mp4");
    } else {
        throw new SaveFileException(TAG, "Unkknown media type!");
    }
    Log.d(TAG,mediaStorageDir.getPath() + File.separator +
            "IMG_"+ timeStamp + ".jpg");
    return mediaFile;
}}

Remember also to do something like:

sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED,
                         Uri.parse("file://"+ Environment.getExternalStorageDirectory())));
sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE,
                         Uri.parse("file://"+ Environment.getExternalStorageDirectory())));

if the picture was correctly saved. This way the next time the user opens the gallery or any other media brwsing application, your newly taken image will be listed correctly.

Share:
13,336
Willem Ellis
Author by

Willem Ellis

I solve problems using technology.

Updated on June 04, 2022

Comments

  • Willem Ellis
    Willem Ellis almost 2 years

    Here is my code:

    package com.commonsware.android.skeleton;
    
    import android.app.Activity;
    import android.content.Context;
    import android.hardware.Camera;
    import android.hardware.Camera.*;
    import android.os.Bundle;
    import android.os.Environment;
    import android.util.Log;
    import android.view.Display;
    import android.view.Surface;
    import android.view.SurfaceHolder;
    import android.view.SurfaceView;
    import android.view.Window;
    import android.view.WindowManager;
    import android.widget.FrameLayout;
    
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.util.List;
    
    // ----------------------------------------------------------------------
    
    public class SimpleBulbActivity extends Activity {
        private Preview mPreview;
        private static final String TAG = "CameraDemo";
        FrameLayout preview;
        Camera mCamera;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
    
            // Hide the window title.
            requestWindowFeature(Window.FEATURE_NO_TITLE);
            setContentView(R.layout.main);
        }
    
        protected void onResume() {
            super.onResume();
            //Setup the FrameLayout with the Camera Preview Screen
            mPreview = new Preview(this);
            preview = (FrameLayout)findViewById(R.id.preview); 
            preview.addView(mPreview);
        }
    
        public void snap() {
            mCamera.takePicture(shutterCallback, rawCallback, jpegCallback);
        }
        ShutterCallback shutterCallback = new ShutterCallback() {
          public void onShutter() {
              Log.d(TAG, "onShutter'd");
          }
        };
    
        PictureCallback rawCallback = new PictureCallback() {
          public void onPictureTaken(byte[] _data, Camera _camera) {
              Log.d(TAG, "onPictureTaken - raw");
          }
        };
    
        PictureCallback jpegCallback = new PictureCallback() {
          public void onPictureTaken(byte[] data, Camera _camera) {
              FileOutputStream outStream = null;
                try {
                    // write to local sandbox file system
                    // outStream =
                    // CameraDemo.this.openFileOutput(String.format("%d.jpg",
                    // System.currentTimeMillis()), 0);
                    // Or write to sdcard
                    outStream = new FileOutputStream(String.format(
                            "/sdcard/%d.jpg", System.currentTimeMillis()));
                    outStream.write(data);
                    outStream.close();
                    Log.d(TAG, "onPictureTaken - wrote bytes: " + data.length);
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                }
                Log.d(TAG, "onPictureTaken - jpeg");
          }
        };
    
     // ----------------------------------------------------------------------
    
        class Preview extends SurfaceView implements SurfaceHolder.Callback {
            SurfaceHolder mHolder;
    
            Preview(Context context) {
                super(context);
    
                // Install a SurfaceHolder.Callback so we get notified when the
                // underlying surface is created and destroyed.
                mHolder = getHolder();
                mHolder.addCallback(this);
                mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
            }
    
            public void surfaceCreated(SurfaceHolder holder) {
                // The Surface has been created, acquire the camera and tell it where
                // to draw.
                mCamera = Camera.open();
                try {
                   mCamera.setPreviewDisplay(holder);
                   mCamera.setPreviewCallback(new PreviewCallback() {
    
                    public void onPreviewFrame(byte[] data, Camera arg1) {
                        FileOutputStream outStream = null;
                        try {
                            outStream = new FileOutputStream(Environment.getExternalStorageDirectory().toString());
                            outStream.write(data);
                            outStream.close();
                            Log.d(TAG, "onPreviewFrame - wrote bytes: "
                                    + data.length);
                        } catch (FileNotFoundException e) {
                            e.printStackTrace();
                        } catch (IOException e) {
                            e.printStackTrace();
                        } finally {
                        }
                        Preview.this.invalidate();
                    }
                });
            } catch (IOException e) {
                    mCamera.release();
                    mCamera = null;
                    e.printStackTrace();
                }
            }
    
            public void surfaceDestroyed(SurfaceHolder holder) {
                // Surface will be destroyed when we return, so stop the preview.
                // Because the CameraDevice object is not a shared resource, it's very
                // important to release it when the activity is paused.
                mCamera.stopPreview();
                mCamera.release();
                mCamera = null;
            }
    
    
            private Size getOptimalPreviewSize(List<Size> sizes, int w, int h) {
                final double ASPECT_TOLERANCE = 0.05;
                double targetRatio = (double) w / h;
                if (sizes == null) return null;
    
                Size optimalSize = null;
                double minDiff = Double.MAX_VALUE;
    
                int targetHeight = h;
    
                // Try to find an size match aspect ratio and size
                for (Size size : sizes) {
                    double ratio = (double) size.width / size.height;
                    if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue;
                    if (Math.abs(size.height - targetHeight) < minDiff) {
                        optimalSize = size;
                        minDiff = Math.abs(size.height - targetHeight);
                    }
                }
    
                // Cannot find the one match the aspect ratio, ignore the requirement
                if (optimalSize == null) {
                    minDiff = Double.MAX_VALUE;
                    for (Size size : sizes) {
                        if (Math.abs(size.height - targetHeight) < minDiff) {
                            optimalSize = size;
                            minDiff = Math.abs(size.height - targetHeight);
                        }
                    }
                }
                return optimalSize;
            }
    
            public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
                // Now that the size is known, set up the camera parameters and begin
                // the preview.
                Camera.Parameters parameters = mCamera.getParameters();
    
                List<Size> sizes = parameters.getSupportedPreviewSizes();
                Size optimalSize = getOptimalPreviewSize(sizes, w, h);
    
                Display display = ((WindowManager)getSystemService(WINDOW_SERVICE)).getDefaultDisplay();
    
                if(display.getRotation() == Surface.ROTATION_0)
                {
                    parameters.setPreviewSize(optimalSize.height, optimalSize.width);                           
                    mCamera.setDisplayOrientation(90);
                }
    
                if(display.getRotation() == Surface.ROTATION_90)
                {
                    parameters.setPreviewSize(optimalSize.width, optimalSize.height);                         
                }
    
                if(display.getRotation() == Surface.ROTATION_180)
                {
                    parameters.setPreviewSize(optimalSize.width, optimalSize.height);               
                }
    
                if(display.getRotation() == Surface.ROTATION_270)
                {
                    parameters.setPreviewSize(optimalSize.width, optimalSize.height);
                    mCamera.setDisplayOrientation(0);
                }
    
                mCamera.setParameters(parameters);
                mCamera.startPreview();
            }
    
        }
    
    }
    

    Okay I have modified my code a bit.

    I have this in my main layout:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical" android:layout_width="fill_parent"
        android:layout_height="fill_parent" android:id="@+id/layout">
        <TextView android:layout_width="fill_parent"
            android:layout_height="wrap_content" android:text="Camera Demo"
            android:textSize="24sp" />
    
        <FrameLayout android:layout_weight="1" android:layout_width="fill_parent"
            android:layout_height="fill_parent">
    
        <FrameLayout android:id="@+id/preview"
            android:layout_weight="1" android:layout_width="fill_parent"
            android:layout_height="fill_parent">
        </FrameLayout>
    
        <ImageView android:src="@drawable/litbulb"
                       android:layout_width="match_parent"
                       android:layout_height="112dip" />
    
        </FrameLayout>
    
        <Button android:layout_width="wrap_content"
            android:layout_height="wrap_content" android:id="@+id/buttonClick"
            android:text="Snap!" android:layout_gravity="center"></Button>
    
    </LinearLayout>
    

    When I click the "Snap!" or buttonClick button, it's supposed to capture and save the image, but it's not. Can anyone help me modify this code so it does?

    Also, it crashes every time I leave the app. Here is the relevant logcat data:

    12-21 13:30:47.820: ERROR/AndroidRuntime(3906): FATAL EXCEPTION: main
    12-21 13:30:47.820: ERROR/AndroidRuntime(3906): java.lang.RuntimeException: Method called after release()
    12-21 13:30:47.820: ERROR/AndroidRuntime(3906):     at android.hardware.Camera.setHasPreviewCallback(Native Method)
    12-21 13:30:47.820: ERROR/AndroidRuntime(3906):     at android.hardware.Camera.access$600(Camera.java:114)
    12-21 13:30:47.820: ERROR/AndroidRuntime(3906):     at android.hardware.Camera$EventHandler.handleMessage(Camera.java:519)
    12-21 13:30:47.820: ERROR/AndroidRuntime(3906):     at android.os.Handler.dispatchMessage(Handler.java:99)
    12-21 13:30:47.820: ERROR/AndroidRuntime(3906):     at android.os.Looper.loop(Looper.java:123)
    12-21 13:30:47.820: ERROR/AndroidRuntime(3906):     at android.app.ActivityThread.main(ActivityThread.java:4627)
    12-21 13:30:47.820: ERROR/AndroidRuntime(3906):     at java.lang.reflect.Method.invokeNative(Native Method)
    12-21 13:30:47.820: ERROR/AndroidRuntime(3906):     at java.lang.reflect.Method.invoke(Method.java:521)
    12-21 13:30:47.820: ERROR/AndroidRuntime(3906):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:858)
    12-21 13:30:47.820: ERROR/AndroidRuntime(3906):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
    12-21 13:30:47.820: ERROR/AndroidRuntime(3906):     at dalvik.system.NativeStart.main(Native Method)
    
  • Reddy
    Reddy over 12 years
    u need to call callback then ur app wouldnt be crash
  • Willem Ellis
    Willem Ellis over 12 years
    When I try that, it says The method getCamera() is undefined for the type SimpleBulbActivity.Preview Where am I inserting that second line?
  • Willem Ellis
    Willem Ellis over 12 years
    Okay I modified the code the way I think you were meaning. The crash no longer occurs, but the image still isn't saving.
  • Willem Ellis
    Willem Ellis over 12 years
    Okay, I think I have it the way you are meaning, and the crash has stopped, but it's still not saving the image.
  • Willem Ellis
    Willem Ellis over 12 years
    Apologies, the crash is still occurring.
  • Willem Ellis
    Willem Ellis over 12 years
    Apologies, the crash is still occurring.
  • Willem Ellis
    Willem Ellis over 12 years
    I figured out why it wasn't taking the picture. I have it now taking the picture, but when I leave the app, I don't see the picture in my gallery. Any thoughts?
  • Yevgeny Simkin
    Yevgeny Simkin over 12 years
    It doesn't automatically go to your gallery. Google adding photos to your gallery to make that a reality.