Community » Forums » Android - Examples > Using Camera API
November 18, 2009 11:36:31 AM PST (36 weeks ago). Seen 11,440 times.
Photo Marko Gargenta
Marakana, Inc.
Member since Jan 19, 2007
Location: San Francisco
Posts: 90
Android SDK supports the connectivity to the built-in camera. Using the camera to take photos is relatively easy. It is somewhat harder to setup the camera preview to work properly.

In our main activity, we create the Preview object. This object will create the Camera object and return it to the CameraDemo activity.


Next we register couple of call-back method with the Camera to be performed when the user takes a photo.

shutterCallback is called when the shutter is opened and picture is taken. rawCallback and jpegCallback will get the data for the raw and jpeg encoding of the photo. It's up to you to do something with this data, such as save it to the SD card.

CameraDemo.java
Code:

package com.example;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

import android.app.Activity;
import android.hardware.Camera;
import android.hardware.Camera.PictureCallback;
import android.hardware.Camera.ShutterCallback;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.FrameLayout;

public class CameraDemo extends Activity {
private static final String TAG = "CameraDemo";
Camera camera;
Preview preview;
Button buttonClick;

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);

preview = new Preview(this);
((FrameLayout) findViewById(R.id.preview)).addView(preview);

buttonClick = (Button) findViewById(R.id.buttonClick);
buttonClick.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
preview.camera.takePicture(shutterCallback, rawCallback,
jpegCallback);
}
});

Log.d(TAG, "onCreate'd");
}

ShutterCallback shutterCallback = new ShutterCallback() {
public void onShutter() {
Log.d(TAG, "onShutter'd");
}
};

/** Handles data for raw picture */
PictureCallback rawCallback = new PictureCallback() {
public void onPictureTaken(byte[] data, Camera camera) {
Log.d(TAG, "onPictureTaken - raw");
}
};

/** Handles data for jpeg picture */
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");
}
};

}



Preview class handles the preview from the camera. It subclasses SurfaceView class so that it can be placed in the UI itself. It also implements the SurfaceHolder.Callback interface so it gets the callbacks when the UI becomes available.

Preview.java
Code:

package com.example;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.hardware.Camera;
import android.hardware.Camera.PreviewCallback;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

class Preview extends SurfaceView implements SurfaceHolder.Callback {
private static final String TAG = "Preview";

SurfaceHolder mHolder;
public Camera camera;

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.
camera = Camera.open();
try {
camera.setPreviewDisplay(holder);

camera.setPreviewCallback(new PreviewCallback() {

public void onPreviewFrame(byte[] data, Camera arg1) {
FileOutputStream outStream = null;
try {
outStream = new FileOutputStream(String.format(
"/sdcard/%d.jpg", System.currentTimeMillis()));
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) {
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.
camera.stopPreview();
camera = null;
}

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 = camera.getParameters();
parameters.setPreviewSize(w, h);
camera.setParameters(parameters);
camera.startPreview();
}

@Override
public void draw(Canvas canvas) {
super.draw(canvas);
Paint p = new Paint(Color.RED);
Log.d(TAG, "draw");
canvas.drawText("PREVIEW", canvas.getWidth() / 2,
canvas.getHeight() / 2, p);
}
}


The layout is fairly straight forward. We have the FrameLayout as the placeholder for the Preview to be attached to. This is done programmatically in CameraDemo.onCreate().

/res/layout/main.xml

Code:

<?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:id="@+id/preview"
android:layout_weight="1" android:layout_width="fill_parent"
android:layout_height="fill_parent">
</FrameLayout>

<Button android:layout_width="wrap_content"
android:layout_height="wrap_content" android:id="@+id/buttonClick"
android:text="Click" android:layout_gravity="center"></Button>

</LinearLayout>



And finally remember to add <uses-permission android:name="android.permission.CAMERA" /> to your AndroidManifest.xml file.

The final app looks like this:



Source Code:
/static/tutorials/CameraDemo.zip
Edited 7 times. Last edit by Marko Gargenta on Jul 26, 2010 at 3:56:04 PM (about 5 weeks ago).
January 21, 2010 1:32:37 PM PST (27 weeks ago)
Photo Me Me
Me
Member since Jan 21, 2010
Posts: 1
Thanks, that was very helpful.
It is better to call camera.release() when finishing the activity.
February 1, 2010 1:20:03 AM PST (25 weeks ago)
Photo Me Me
Org
Member since Feb 1, 2010
Posts: 1
Where you save the image with FileOutputStream, I get "java.lang.IllegalArgumentException: File /sdcard/whatever.jpg contains a path separator". Any ideas?
March 1, 2010 9:17:01 AM PST (21 weeks ago)
Photo A Member
Org
Member since Mar 1, 2010
Posts: 3
Thanks, I tried the code on my android phone. I am seeing a picture orientation problem. On focus I see on the phone screen a picture that is inverted. I am trying to figure why this happens. If you have an answer to this, please let me know.
March 5, 2010 2:22:45 AM PST (20 weeks ago)
Photo SeungHun Lee
Iconlab
Member since Mar 4, 2010
Posts: 1
How to use OCR??
March 5, 2010 9:16:36 AM PST (20 weeks ago)
Photo A Member
Org
Member since Mar 1, 2010
Posts: 3
OCR?? What does it stand for?
April 11, 2010 10:07:34 PM PDT (15 weeks ago)
Photo Chun Ming Chin
UIUC
Member since Apr 11, 2010
Posts: 2
This code only allows us to take a snap shot once before it freezes over. How could we make it take multiple shots and save it onto a file system or SD card?
April 11, 2010 10:07:56 PM PDT (15 weeks ago)
Photo Chun Ming Chin
UIUC
Member since Apr 11, 2010
Posts: 2
Optical Character Recognition
July 14, 2010 9:29:12 AM PDT (2 weeks ago)
Photo Nan Z
GoldSequence
Member since Jul 14, 2010
Posts: 1
First of all, it is really appreciated that you can post this sample application.

I tried to bring up this app in OS 2.2 and run in Nexus one phone. However, the app crashes and DDMS shows the following message:
ERROR/QualcommCameraHardware(59): Invalid preview size requested: 480x604


The problem can be fixed by using getOptimalPreviewSize() function and surfaceChanged() function provided in an Android sample program CameraPreview.java. It can be found at
http://developer.android.com/resources/samples/ApiDemos/src/com/example/android/apis/graphics/CameraPreview.html (retrieved today)

However, I still observe camera orentation and image size distortion problems.

Edited one time. Last edit by Nan Z on Jul 14, 2010 at 9:40:29 AM (about 5 weeks ago).
July 14, 2010 9:50:37 AM PDT (2 weeks ago)
Photo Marko Gargenta
Marakana, Inc.
Member since Jan 19, 2007
Location: San Francisco
Posts: 90
Hmm, I'll have to test this on an actual NexusOne. I do have a newer version of the code here:
https://marakana.com/static/courseware/android/Camera.zip
July 18, 2010 1:25:12 PM PDT (one week ago)
Photo Luka Divac Krnic
Me
Member since Jul 18, 2010
Posts: 1
Hello Marko. The last one Camera.zip works fine on my HTC with Android 2.1 (the last code somehow never did). There is only one peculiarity: once I activate your new Camera Demo, I can not start the Camera App of HTC Corpotion or any other App that uses the cam. When I restart the Phone, everything is again OK. Seems some resources stay allocated "forever".

Greetings, Luka
July 18, 2010 6:36:04 PM PDT (one week ago)
Photo Marko Gargenta
Marakana, Inc.
Member since Jan 19, 2007
Location: San Francisco
Posts: 90
Hi Luka,

You may want to try this new and improved version of Camera app. Here is the code: https://marakana.com/static/courseware/android/Camera.zip.

It is possible that in the old code camera object was not released properly so other apps weren't able to get a hold of the camera.

Cheers,
Marko
July 22, 2010 4:23:20 AM PDT (one week ago)
Photo Sai Kiran Veluri
Lead Engineer
Incube
Member since Jul 22, 2010
Posts: 1
Hi,

i am new bee to android development, and we have a requirement that we need to take a picture, but we should not show the camera preview. Is it possible with Android camera API's?, if yes, could you please let me know, how to achieve this.

Thanks & Regards,
Sai Kiran V.
July 26, 2010 3:56:04 PM PDT (3 days ago)
Photo Marko Gargenta
Marakana, Inc.
Member since Jan 19, 2007
Location: San Francisco
Posts: 90
Yes, it's possible. The CameraDemo does that, ++.