2011年5月17日火曜日

AndroidStudyMemo=Capturing Still Images Using the Camera

The Camera object (android.hardware.Camera) controls the camera on handsets that
have camera support enabled.The preview feature of the camera relies on the assignment
of a SurfaceHolder of an appropriate type.This enables applications to control the placement
and size of the preview area that the camera can use.
Follow these steps to add camera capture capability to an application without having to
draw preview frames (the CameraSurfaceView displays the camera view):
1. Create a new class extending SurfaceView and implement
SurfaceHolder.Callback. For this example,we name this class
CameraSurfaceView.
2. In the surfaceCreated() method, get an instance of the Camera object.
3. In the surfaceChanged() method, configure and apply the Camera.Parameters;
then call the startPreview() method.
4. Add a method in CameraSurfaceView for capturing images.
5. Add the CameraSurfaceView to an appropriate layout.
6. Include some way, such as a button, for the user to trigger the capturing of images.
7. Implement a PictureCallback class to handle storing of the captured image.
8. Add the android.permission.CAMERA permission to the AndroidManifest.xml
file.
9. Release the Camera object in the surfaceDestroyed() method.

Let's start by looking at the CameraSurfaceView class:
import android.hardware.Camera;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
private class CameraSurfaceView extends SurfaceView
implements SurfaceHolder.Callback {
private SurfaceHolder mHolder;
private Camera camera = null;
public CameraSurfaceView(Context context) {
super(context);
mHolder = getHolder();
mHolder.addCallback(this);
mHolder.setType(
SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}

public void surfaceChanged(SurfaceHolder holder,
int format, int width, int height) {
}

public void surfaceCreated(SurfaceHolder holder) {
}

public void surfaceDestroyed(SurfaceHolder holder) {
}

public boolean capture(Camera.PictureCallback
jpegHandler) {
}
}

The constructor for the CameraSurfaceView configures the SurfaceHolder, including
setting the SurfaceHolder type to SURFACE_TYPE_PUSH_BUFFERS, which is used by the
camera internals.The constructor is appropriate for calling from an activity's onCreate()
method.When the display is ready, the surfaceCreated() method is called. Here we instantiate
the Camera object:

public void surfaceCreated(SurfaceHolder holder) {
camera = Camera.open();
camera.setPreviewDisplay(mHolder);
}

The Camera object has a static method to retrieve a usable instance. Because the
Surface is now available, the configured holder can now be assigned to it. Information
about the Surface might not yet be available, but at the next call to the
surfaceChanged() method, the camera parameters will be assigned and the preview will
start, as shown here:

public void surfaceChanged(SurfaceHolder holder,
int format, int width, int height) {
List<Camera.Size> sizes = params.getSupportedPreviewSizes();
Camera.Size pickedSize = getBestFit(sizes, width, height);
if (pickedSize != null) {
params.setPreviewSize(pickedSize.width, pickedSize.height);
camera.setParameters(params);
}
camera.startPreview();
}

The surfaceChanged() method provides the application with the proper width and
height for use with the camera preview. After assigning this to the Camera object, the preview
starts. At this point, the users see whatever is in front of the camera on their device.
If, however, you debug this within the emulator, you see a black-and-white checkerboard
with an animated square on it, as shown in Figure 15.1.This is the simulated camera preview,
so camera testing can take place, to some extent, on the emulator.
When the Surface is no longer displayed, the surfaceDestroyed() method is called.
Here is an implementation of the surfaceDestroyed() method suitable for this example:

public void surfaceDestroyed(SurfaceHolder holder) {
camera.stopPreview();
camera.release();
camera = null;
}

In the surfaceDestroyed() method, the application stops the preview and releases the
Camera object. If the CameraSurfaceView is used again, the surfaceCreated() method is
called again, so this is the appropriate place to perform this operation.
The final step required to capture a still image is to add some way to call the
takePicture() method of the Camera object. CameraSurfaceView could provide public
access to the Camera object, but in this example,we provide a method to perform this
within the CameraSurfaceView class:
public boolean capture(Camera.PictureCallback jpegHandler) {
if (camera != null) {
camera.takePicture(null, null, jpegHandler);
return true;
} else {
return false;
}
}

You can also use the takePicture() method to assign a callback suitable to play a shutter
sound, or any other action just before the image is collected from the sensor. In addition,
you can assign a PictureCallback to get raw data from the camera.

The CameraSurfaceView object is now ready for use within an Activity. For this example,
an Activity with a layout that contains a FrameLayout widget for positioning
the preview is used. Here is a sample implementation of assigning the cameraView to
the layout:

final CameraSurfaceView cameraView = new
CameraSurfaceView(getApplicationContext());
FrameLayout frame = (FrameLayout) findViewById(R.id.frame);
frame.addView(cameraView);

Next, a button click handler calls the capture() method of the CameraSurfaceView
object.A sample implementation is shown here:

public void onClick(View v) {
cameraView.capture(new Camera.PictureCallback() {
public void onPictureTaken(byte[] data,
Camera camera) {
FileOutputStream fos;
try {
String filename = "capture.jpg";
fos = openFileOutput("capture.jpg",
MODE_WORLD_READABLE);
fos.write(data);
fos.close();
} catch (Exception e) {
Log.e("Still", "Error writing file", e);
}
}
});
}
The data that comes back from the callback can be written out directly to a JPEG file
within the application file directory. If written as shown, though, the captured image is usable
only by the application. In some cases, this might be suitable.However, the application
might want to share the image with the rest of the handset, for example, by including it
within the Pictures application, which uses the MediaStore content provider.You do this
by using the ContentResolver object to place an entry for the image in the media library.

0 件のコメント:

コメントを投稿