Android自定義Camera實(shí)現(xiàn)拍照功能
本文記錄了用自定義Camera實(shí)現(xiàn)的簡(jiǎn)單拍照功能。
Camera類在5.0以后不推薦使用了,取而代之的是android.hardware.camera2包下的類,本文使用Camera。
我們首先自定義一個(gè)View去繼承SurfaceView:
public class CameraSurfaceView extends SurfaceView implements SurfaceHolder.Callback, Camera.AutoFocusCallback {
private SurfaceHolder mHolder;
private Camera mCamera;
private static final int ORIENTATION = 90;
private int mScreenWidth;
private int mScreenHeight;
private boolean isOpen;
public CameraSurfaceView(Context context, AttributeSet attrs) {
super(context, attrs);
getScreenMatrix(context);
mHolder = getHolder();
mHolder.addCallback(this);
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
private void getScreenMatrix(Context context) {
WindowManager WM = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics outMetrics = new DisplayMetrics();
WM.getDefaultDisplay().getMetrics(outMetrics);
mScreenWidth = outMetrics.widthPixels;
mScreenHeight = outMetrics.heightPixels;
}
public void takePicture(Camera.ShutterCallback mShutterCallback, Camera.PictureCallback rawPictureCallback, Camera.PictureCallback jpegPictureCallback) {
if (mCamera != null)
mCamera.takePicture(mShutterCallback, rawPictureCallback, jpegPictureCallback);
}
public void startPreview() {
mCamera.startPreview();
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
if (!checkCameraHardware(getContext()))
return;
if (mCamera == null) {
isOpen = safeCameraOpen(Camera.CameraInfo.CAMERA_FACING_BACK);
}
if (!isOpen) {
return;
}
mCamera.setDisplayOrientation(ORIENTATION);
try {
mCamera.setPreviewDisplay(holder);
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
if (mCamera != null) {
setCameraParams(mScreenWidth, mScreenHeight);
mCamera.startPreview();
}
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
releaseCameraAndPreview();
}
private boolean safeCameraOpen(int id) {
boolean qOpened = false;
try {
releaseCameraAndPreview();
mCamera = Camera.open(id);
qOpened = (mCamera != null);
} catch (Exception e) {
e.printStackTrace();
}
return qOpened;
}
private void releaseCameraAndPreview() {
if (mCamera != null) {
mCamera.stopPreview();
mCamera.release();
mCamera = null;
}
}
private boolean checkCameraHardware(Context context) {
if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)) {
return true;
} else {
return false;
}
}
@Override
public void onAutoFocus(boolean success, Camera camera) {
}
private void setCameraParams(int width, int height) {
Camera.Parameters parameters = mCamera.getParameters();
// 獲取攝像頭支持的PictureSize列表
List<Camera.Size> pictureSizeList = parameters.getSupportedPictureSizes();
/**從列表中選取合適的分辨率*/
Camera.Size picSize = getProperSize(pictureSizeList, ((float) height / width));
if (null == picSize) {
picSize = parameters.getPictureSize();
}
// 根據(jù)選出的PictureSize重新設(shè)置SurfaceView大小
float w = picSize.width;
float h = picSize.height;
parameters.setPictureSize(picSize.width, picSize.height);
this.setLayoutParams(new RelativeLayout.LayoutParams((int) (height * (h / w)), height));
// 獲取攝像頭支持的PreviewSize列表
List<Camera.Size> previewSizeList = parameters.getSupportedPreviewSizes();
Camera.Size preSize = getProperSize(previewSizeList, ((float) height) / width);
if (null != preSize) {
parameters.setPreviewSize(preSize.width, preSize.height);
}
parameters.setJpegQuality(100); // 設(shè)置照片質(zhì)量
if (parameters.getSupportedFocusModes().contains(android.hardware.Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {
parameters.setFocusMode(android.hardware.Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);// 連續(xù)對(duì)焦模式
}
mCamera.setDisplayOrientation(90);// 設(shè)置PreviewDisplay的方向,效果就是將捕獲的畫面旋轉(zhuǎn)多少度顯示
mCamera.setParameters(parameters);
}
/**
* 選取合適的分辨率
*/
private Camera.Size getProperSize(List<Camera.Size> pictureSizeList, float screenRatio) {
Camera.Size result = null;
for (Camera.Size size : pictureSizeList) {
float currentRatio = ((float) size.width) / size.height;
if (currentRatio - screenRatio == 0) {
result = size;
break;
}
}
if (null == result) {
for (Camera.Size size : pictureSizeList) {
float curRatio = ((float) size.width) / size.height;
if (curRatio == 4f / 3) {// 默認(rèn)w:h = 4:3
result = size;
break;
}
}
}
return result;
}
}代碼沒(méi)什么難度,在View創(chuàng)建的時(shí)候完成Camera的初始化,然后對(duì)Camera進(jìn)行參數(shù)的設(shè)置(圖片尺寸,質(zhì)量之類的),最后別忘了在View銷毀的時(shí)候?qū)Y源進(jìn)行釋放。
控件定義完了之后我們就要去使用它,在布局文件中添加就OK:
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/activity_main" android:layout_width="match_parent" android:layout_height="match_parent" > <com.padoon.cameratest.CameraSurfaceView android:id="@+id/sv_camera" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_weight="4"/> <ImageView android:id="@+id/img_take_photo" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_alignParentRight="true" android:layout_gravity="bottom" android:layout_marginBottom="10dp" android:layout_marginRight="10dp" android:src="@mipmap/icon_camera"/> </RelativeLayout>
然后在Activity中去完成拍照功能:
public class CameraActivity extends AppCompatActivity {
private boolean isClick = true;
private static final String PATH_IMAGES = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "easy_check";
private CameraSurfaceView mCameraSurfaceView;
//拍照快門的回調(diào)
private Camera.ShutterCallback mShutterCallback = new Camera.ShutterCallback() {
@Override
public void onShutter() {
}
};
//拍照完成之后返回原始數(shù)據(jù)的回調(diào)
private Camera.PictureCallback rawPictureCallback = new Camera.PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
}
};
//拍照完成之后返回壓縮數(shù)據(jù)的回調(diào)
private Camera.PictureCallback jpegPictureCallback = new Camera.PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
mCameraSurfaceView.startPreview();
saveFile(data);
Toast.makeText(CameraActivity.this, "拍照成功", Toast.LENGTH_SHORT).show();
isClick = true;
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ImageView img_take_photo = (ImageView) findViewById(R.id.img_take_photo);
mCameraSurfaceView = (CameraSurfaceView) findViewById(R.id.sv_camera);
img_take_photo.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
takePhoto();
}
});
}
public void takePhoto() {
if (isClick) {
isClick = false;
mCameraSurfaceView.takePicture(mShutterCallback, rawPictureCallback, jpegPictureCallback);
}
}
//保存圖片到硬盤
public void saveFile(byte[] data) {
String fileName = UUID.randomUUID().toString() + ".jpg";
FileOutputStream outputStream = null;
try {
File file = new File(PATH_IMAGES);
if (!file.exists()) {
file.mkdirs();
}
outputStream = new FileOutputStream(PATH_IMAGES + File.separator + fileName);
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(outputStream);
bufferedOutputStream.write(data, 0, data.length);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}最后記得添加拍照跟磁盤操作權(quán)限:
<uses-permission android:name="android.permission.CAMERA"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
到這一個(gè)非常簡(jiǎn)單的拍照Demo就完成了,只能當(dāng)做Demo使用,離開(kāi)發(fā)正式使用還有一段的距離,再次特地記錄一下。
下載:源碼
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- android自定義Camera實(shí)現(xiàn)錄像和拍照
- Android實(shí)現(xiàn)Camera2預(yù)覽和拍照效果
- android自定義Camera拍照并查看圖片
- Android Camera實(shí)現(xiàn)毫秒級(jí)拍照實(shí)例
- Android中使用Camera類編寫手機(jī)拍照App的實(shí)例教程
- android系統(tǒng)在靜音模式下關(guān)閉camera拍照聲音的方法
- Android實(shí)現(xiàn)拍照、選擇圖片并裁剪圖片功能
- Android啟動(dòng)相機(jī)拍照并返回圖片
- Android拍照保存在系統(tǒng)相冊(cè)不顯示的問(wèn)題解決方法
- Android自定義Camera實(shí)現(xiàn)拍照小功能
相關(guān)文章
android中實(shí)現(xiàn)手機(jī)號(hào)碼的校驗(yàn)的示例代碼
本篇文章主要介紹了android中實(shí)現(xiàn)手機(jī)號(hào)碼的校驗(yàn)的示例代碼,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-09-09
Android EditText實(shí)現(xiàn)輸入表情
editText是TextView的子類,TextView能用的工具EditText都能用,接下來(lái)通過(guò)實(shí)例代碼給大家分享Android EditText實(shí)現(xiàn)輸入表情功能,感興趣的朋友一起看看吧2017-08-08
Android 對(duì)話框 Dialog使用實(shí)例講解
對(duì)話框是在當(dāng)前的頁(yè)面之上彈出的小窗口, 用于顯示一些重要的提示信息, 提示用戶的輸入,確認(rèn)信息,或顯示某種狀態(tài).如 : 顯示進(jìn)度條對(duì)話框, 退出提示.接下來(lái)通過(guò)本文給大家介紹android dialog對(duì)話框知識(shí),感興趣的朋友一起看看吧2016-09-09
Android?內(nèi)存優(yōu)化知識(shí)點(diǎn)梳理總結(jié)
這篇文章主要介紹了Android?內(nèi)存優(yōu)化知識(shí)點(diǎn)梳理總結(jié),Android?操作系統(tǒng)給每個(gè)進(jìn)程都會(huì)分配指定額度的內(nèi)存空間,App?使用內(nèi)存來(lái)進(jìn)行快速的文件訪問(wèn)交互,長(zhǎng)時(shí)間如此便需要優(yōu)化策略,文章分享優(yōu)化知識(shí)點(diǎn)總結(jié),需要的朋友可以參考一下2022-06-06
Android判斷某個(gè)權(quán)限是否開(kāi)啟的方法
今天小編就為大家分享一篇Android判斷某個(gè)權(quán)限是否開(kāi)啟的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-07-07
Kotlin中?和!!的區(qū)別詳細(xì)對(duì)比
這篇文章主要給大家介紹了關(guān)于Kotlin中?和!!區(qū)別的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-05-05

