.:: CODE SNIPPET ::.

"Your time is limited, so don't waste it living someone else's life"

Sử dụng android.hardware.Camera để khai thác camera của android


Sau vài ngày tìm hiểu, mình muốn hướng dẫn phương pháp sử dụng android.hardware.Camera để khai thác Camera của các thiết bị android. Với cách này, mình có thể hiểu rõ hơn cách thức hoạt đông của camera và từ đó, mình có thể điều chỉnh, thêm thắt vào như ý mình muốn.:)
Android SDK cung cấp một kết nối đến Camera của máy. Sau đó sử dụng nó để chụp ảnh cách dễ dàng. Tuy nhiên, phần khó hơn một tí là làm sao để người dùng có thể xem được mình đang chuẩn bị chụp cái gì. Nghĩa là người dùng có thể thấy được camera đang bắt được hình ảnh gì. Điều này được thực hiện bằng cách nhúng một Preview của camera vào trong ứng dụng sử dụng camera của bạn.
Để khái quát về ví dụ mình tóm tắt trước như sau:
+Đầu tiên mình có một project tên là CameraControl, project này bao gồm một Activity cùng tên như vậy, và một lớp Preview.
+Lớp Preview là một surface và được đặt vào bên trong của activity CameraControl

Đầu tiên mình xây dựng lớp Preview như sau:

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);
	}

	/*
	 * (non-<a class="zem_slink" title="Javadoc" href="http://en.wikipedia.org/wiki/Javadoc" target="_blank" rel="wikipedia">Javadoc</a>) This is called immediately after the surface is first
	 * created. Implementations of this should start up whatever rendering code
	 * they desire. Note that only one thread can ever draw into a Surface, so
	 * you should not draw into the Surface here if your normal rendering will
	 * be in another thread.
	 * android.view.SurfaceHolder.Callback#surfaceCreated(android.view.SurfaceHolder
	 * )
	 */
	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.setPreviewCallback(null);
        camera.release();
		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);
	}
}

Giải thích một tí, lớp này kế thừa lại SurfaceView vì mình muốn sử dụng lớp Preview này là một surface (có khả năng vẻ các hình ảnh). Surface này được nhúng vào bên trong hệ thống thể hiện của chương trình. Bạn có thể quản lý được format của surface này. Để quản lý được các surface đang tồn tại, chúng ta sử dụng SurfaceHolder. Một trong những lý do quan trọng khi phải sử dụng kế thừa từ SurfaceView là vì như các bạn đã biết, trong android, chỉ có luồng chính được vẽ lên màn hình, thì bằng cách này chúng ta sẽ tạo ra một bề mặt mà một luồng thứ có thể vẽ lên màn hình được những hình ảnh. Bên cạnh đó, lơp cũng thực thi interface SurfaceHolder.Callback nhằm để nó có thể nhận những Callback từ UI.

Tiếp theo là chúng ta tạo ra activity CameraControl như sau:

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

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

		preview = new Preview(this);

		((FrameLayout) findViewById(R.id.preview)).addView(preview);

		buttonClick = (Button) findViewById(R.id.buttonClick);
		OnClickListener lstn=new OnClickListener() {

			public void onClick(View v) {
				// TODO Auto-generated method stub

				preview.camera.takePicture(shutterCallback, rawCallback, jpegCallback);
				preview.camera.release();
			}
		};
		buttonClick.setOnClickListener(lstn);

		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(//"/sdcard/IT/%d.jpg"
						String.format("/sdcard/IT/%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");
		}
	};

}

Activity này có ba thực thể interface là:

  • shutterCallback: dùng để tạo ra những cài đặt lúc shutter của máy ảnh mở ra, và hình ảnh được chụp.
  • rawCallbackjpegCallback dùng để lấy dữ liệu mã hóa và dữ liệu thô của hình ảnh.

Việc xử lý ảnh lấy được thì tùy bạn đi nhé.

Trong đó, main layout của chúng ta sẽ như sau:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/layout"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <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_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_weight="1" >
    </FrameLayout>

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

</LinearLayout>

Một điều không thể thiếu là bạn phải thêm quyền vào Manifest để cấp quyền sử dung camera cho chương trình

<uses-permission android:name="android.permission.CAMERA" />
Advertisements

3 responses to “Sử dụng android.hardware.Camera để khai thác camera của android

  1. Pingback: Lựa chọn và Cắt hình ảnh trong Android « .:: Hoàng Minh ::.

  2. Pingback: Vẽ hình chữ nhật để khoanh vùng ảnh cần chụp trên camera « .:: Hoàng Minh ::.

  3. Pingback: Tạo option menu trong android « .:: Hoàng Minh ::.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: