一、概述
本章節主要講述使用android.hardware.Camera類來實現自定義相機的流程,雖然在api21中該類已被廢棄,有了一套新的CameraDevice方法,但是爲了向下兼容我們還是可以學習一下Camera1的使用。
如有錯誤或優化之處,歡迎留言指導。
二、具體實現
首先介紹下如何判斷是否支持照相機功能,代碼如下:
private boolean checkCamera(Context context) {
// 可修改參數來判斷設備是否支持ble等其他功能
if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)) {
return true; // 支持Camera功能
} else {
return false;
}
}
獲取一個Camera對象
private Camera getCamera() {
Camera camera = null;
try {
camera = Camera.open();
} catch (Exception e) {
Log.e(TAG, "getCamera: Camera.open failed!");
}
return camera;
}
我們通過SurfaceView來預覽照相機畫面,需要獲取SurfaceHolder並添加回調
mPreView = (SurfaceView) findViewById(R.id.preview);
mHolder = mPreView.getHolder();
mHolder.addCallback(this); // 實現SurfaceHolder.Callback接口
mPreView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mCamera != null) {
// 照相機自動對焦功能
mCamera.autoFocus(null);
}
}
});
綁定Camera和SurfaceHolder,然後開始預覽畫面
private void setStartPreview(Camera camera, SurfaceHolder holder) {
try {
camera.setPreviewDisplay(holder); // 綁定Camera和SurfaceHolder
camera.setDisplayOrientation(90); // 旋轉90度纔是正常畫面
camera.startPreview();
} catch (IOException e) {
Log.e(TAG, "setStartPreview: setPreviewDisplay error");
}
}
在使用完相機後需要釋放相機資源,同時我們要注意把相機和活動的生命週期綁定,在onResume中獲取相機並預覽,在onPause中釋放相機資源,防止其他應用調用相機時出錯
private void releaseCamera() {
if (mCamera != null) {
mCamera.setPreviewCallback(null);
mCamera.stopPreview();
mCamera.release();
mCamera = null;
}
}
SurfaceHolder.Callback接口有create,change,destroy三個方法,我們在create中初始化,在change中預覽畫面,在destroy前釋放相機資源
@Override
public void surfaceCreated(SurfaceHolder holder) {
if (mCamera != null && mHolder != null) {
setStartPreview(mCamera, mHolder);
}
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
if (mCamera != null) {
mCamera.stopPreview();
if (mHolder != null) {
setStartPreview(mCamera, mHolder);
}
}
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
releaseCamera();
}
最後就是點擊拍照並獲取圖片,這裏我們可以設置Camera.Parameters屬性作用於我們要拍攝的照片,調用tackPicture方法進行拍照
Camera.Parameters parameters = mCamera.getParameters();
parameters.setPictureFormat(ImageFormat.JPEG); // 相片保存的格式
parameters.setPictureSize(800, 400); // 相片保存的尺寸,因爲是橫屏所以長>高
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO); // 自動對焦
mCamera.autoFocus(new Camera.AutoFocusCallback() {
@Override
public void onAutoFocus(boolean success, Camera camera) {
if (success) {
// 拍照
mCamera.takePicture(null, null, mPictureCallback);
}
}
});
takePicture的第一個參數是快門的回調,後面兩個都是圖像數據的回調,通常我們只需要實現第三個存儲照片的回調就可以了
private Camera.PictureCallback mPictureCallback = new Camera.PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
// 存儲的路徑及文件名
mFilePath = mFilePath + "/" + System.currentTimeMillis() + ".png";
File tempFile = new File(mFilePath);
try {
if (tempFile != null) {
FileOutputStream fos = new FileOutputStream(tempFile);
fos.write(data);
fos.close();
Intent intent = new Intent(CameraActivity.this, PictureActivity.class);
// 傳給下一個顯示照片的activity
intent.putExtra("picPath", tempFile.getAbsolutePath());
startActivity(intent);
finish();
}
} catch (FileNotFoundException e) {
Log.e(TAG, "onPictureTaken: " + e.getMessage());
} catch (IOException e) {
Log.e(TAG, "onPictureTaken: " + e.getMessage() );
}
}
};
存儲完照片後,我們可以從傳遞的路徑獲取到圖片並顯示
mImageView = (ImageView) findViewById(R.id.iv_picture);
mPath = getIntent().getStringExtra("picPath");
try {
FileInputStream fis = new FileInputStream(new File(mPath));
Bitmap bitmap = BitmapFactory.decodeStream(fis);
// 因爲畫面預覽時是旋轉後顯示的,所以保存的圖片也需要旋轉90度
Matrix matrix = new Matrix();
matrix.setRotate(90);
// 創建一個新的Bitmap
bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
mImageView.setImageBitmap(bitmap);
} catch (FileNotFoundException e) {
Log.e(TAG, "onCreate: FileInputStream error");
}
PS:自定義時請勿忘記申明權限
<uses-feature android:name="android.hardware.Camera" android:required="true" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
三、後言
本章節實現步驟就介紹到這邊,有錯誤歡迎指出,源碼會在後續的綜合demo中放出。下一章節準備學習記錄一下Camera2的使用。