網(wǎng)站首頁 編程語言 正文
本文實例為大家分享了Android Camera實現(xiàn)可復(fù)用相機組件的具體代碼,供大家參考,具體內(nèi)容如下
若自己的應(yīng)用需要使用camera,有兩種解決方案。
1. 使用Intent調(diào)用自帶的Camera程序
2. 使用Camera API在程序中構(gòu)造自己的Camera。
本文主要講解第二種。
構(gòu)造一個相機APP,通常需要六個步驟
1. 聲明Manifest的相機權(quán)限
2. 創(chuàng)建一個相機預(yù)覽類(繼承SurfaceView)
3. 創(chuàng)建一個類實現(xiàn)相機拍照之后的回調(diào)函數(shù)
本文將一步步帶你實現(xiàn)上述三個步驟。
1. 聲明Manifest的相機權(quán)限。
應(yīng)為我們需要寫文件與調(diào)用相機,所以在你的manifest文件中加上。
<uses-permission android:name="android.permission.CAMERA" /> ?<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
2. 創(chuàng)建一個相機預(yù)覽類
由于相機的預(yù)覽是使用的SurfaceView,所以這里我們創(chuàng)建一個SurfaceView的子類。
為了讓這個View所見即所得,我們將其設(shè)置為4/3的比例。重寫它的onMeasure方法
代碼如下:
package com.example.cameratutorial;
?
import android.content.Context;
?
import android.util.Log;
import android.view.SurfaceView;
?
/**
?* @author CTGU小龍同學(xué) 2014-6-21
?*/
public class CameraSurfaceView extends SurfaceView {
?? ?private static final String TAG = "CameraSurfaceView";
?? ?// 用四比三的比例
?? ?public static double RATIO = 3.0 / 4.0;
?
?? ?/**
?? ? * @param context
?? ? */
?? ?public CameraSurfaceView(Context context) {
?? ??? ?super(context);
?
?? ?}
?
?? ?@Override
?? ?protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
?? ??? ?
?? ??? ?int height = MeasureSpec.getSize(heightMeasureSpec);
?? ??? ?int width = MeasureSpec.getSize(widthMeasureSpec);
?? ??? ?Log.d("Measured", "before width" + width + "height" + height);
?
?? ??? ?boolean isWidthLonger;
?? ??? ?int longSide;
?? ??? ?int shortSide;
?? ??? ?// 以短邊為準確定一下長邊
?? ??? ?if (width < height) {
?? ??? ??? ?height = (int) (width / RATIO);
?? ??? ??? ?isWidthLonger = false;
?
?? ??? ?} else {
?? ??? ??? ?width = (int) (height / RATIO);
?? ??? ??? ?isWidthLonger = true;
?? ??? ?}
?
?? ??? ?Log.d("Measured", "after width" + width + "height" + height);
?? ??? ?setMeasuredDimension(width, height);
?
?? ?}
?
}
3. 現(xiàn)在我們使用一個實現(xiàn)了SurfaceHolder.Callback, Camera.PictureCallback 的Fragment來把我們需要的組件都封裝起來。
代碼如下:
package com.example.cameratutorial;
?
import java.io.*;
import java.util.*;
import android.app.Activity;
import android.app.Fragment;
import android.graphics.*;
?
import android.graphics.Bitmap.CompressFormat;
import android.hardware.Camera;
import android.hardware.Camera.CameraInfo;
import android.hardware.Camera.Size;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.*;
?
?
import android.widget.RelativeLayout;
import android.widget.Toast;
?
/**
?* @author CTGU小龍同學(xué) 2014-6-21
?*/
public class CameraFragment extends Fragment implements SurfaceHolder.Callback, Camera.PictureCallback {
?? ?private Camera mCamera;
?? ?// CameraPreview的holder
?? ?private SurfaceHolder mSurfaceHolder;
?? ?private CameraSurfaceView preview;
?? ?private int mFrontCameraId = -1;
?? ?private int mBackCameraId = -1;
?
?? ?@Override
?? ?public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
?
?? ??? ?preview = new CameraSurfaceView(getActivity());
?? ??? ?preview.getHolder().addCallback(this);
?
?? ??? ?RelativeLayout layout = new RelativeLayout(getActivity());
?? ??? ?layout.addView(preview);
?
?? ??? ?return layout;
?
?? ?}
?
?? ?@Override
?? ?public void onAttach(Activity activity) {
?? ??? ?super.onAttach(activity);
?? ??? ?findAvailableCameras();
?
?? ?}
?
?? ?@Override
?? ?public void onResume() {
?
?? ??? ?super.onResume();
?? ??? ?Log.d("camera", "mFrontCameraId" + mFrontCameraId);
?? ??? ?Log.d("camera", "mbackCameraId" + mBackCameraId);
?? ??? ?if (mBackCameraId != -1) {
?
?? ??? ??? ?mCamera = Camera.open(mBackCameraId);
?
?? ??? ?} else {
?? ??? ??? ?Toast.makeText(getActivity(), "fialed to open camera", Toast.LENGTH_SHORT).show();
?? ??? ?}
?
?? ?}
?
?? ?@Override
?? ?public void onPause() {
?? ??? ?super.onPause();
?
?? ??? ?mCamera.stopPreview();
?? ??? ?mCamera.release();
?? ?}
?
?? ?/**
?? ? * 獲得可用的相機,并設(shè)置前后攝像機的ID
?? ? */
?? ?private void findAvailableCameras() {
?
?? ??? ?Camera.CameraInfo info = new CameraInfo();
?? ??? ?int numCamera = Camera.getNumberOfCameras();
?? ??? ?for (int i = 0; i < numCamera; i++) {
?? ??? ??? ?Camera.getCameraInfo(i, info);
?? ??? ??? ?// 找到了前置攝像頭
?? ??? ??? ?if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
?? ??? ??? ??? ?mFrontCameraId = info.facing;
?? ??? ??? ?}
?? ??? ??? ?// 招到了后置攝像頭
?? ??? ??? ?if (info.facing == Camera.CameraInfo.CAMERA_FACING_BACK) {
?? ??? ??? ??? ?mBackCameraId = info.facing;
?? ??? ??? ?}
?
?? ??? ?}
?
?? ?}
?
?? ?/**
?? ? * 當相機拍照時會回調(diào)該方法
?? ? */
?? ?@Override
?? ?public void onPictureTaken(byte[] data, Camera camera) {
?? ??? ?final Bitmap bitmap;
?
?? ??? ?final String path;
?? ??? ?try {
?? ??? ??? ?// /storage/emulated/0/Pictures/XXX.jpg
?
?? ??? ??? ?path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).getAbsolutePath() + "/" + new Date().toLocaleString() + ".jpg";
?? ??? ??? ?Log.d("Path", path);
?? ??? ??? ?bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
?? ??? ??? ?camera.stopPreview();
?
?? ??? ??? ?final int displayOrientation = getCorrectOrientation();
?? ??? ??? ?new Thread(new Runnable() {
?
?? ??? ??? ??? ?@Override
?? ??? ??? ??? ?public void run() {
?? ??? ??? ??? ??? ?FileOutputStream fos;
?? ??? ??? ??? ??? ?Matrix matrix = new Matrix();
?? ??? ??? ??? ??? ?matrix.postRotate(displayOrientation);
?? ??? ??? ??? ??? ?Bitmap rotaBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, false);
?
?? ??? ??? ??? ??? ?try {
?? ??? ??? ??? ??? ??? ?fos = new FileOutputStream(path);
?? ??? ??? ??? ??? ??? ?rotaBitmap.compress(CompressFormat.JPEG, 100, fos);
?? ??? ??? ??? ??? ??? ?fos.close();
?? ??? ??? ??? ??? ?} catch (Exception e) {
?? ??? ??? ??? ??? ??? ?// TODO Auto-generated catch block
?? ??? ??? ??? ??? ??? ?e.printStackTrace();
?? ??? ??? ??? ??? ?}
?
?? ??? ??? ??? ?}
?? ??? ??? ?}).start();
?
?? ??? ?} catch (Exception e) {
?
?? ??? ?}
?? ??? ?camera.startPreview();
?? ?}
?
?? ?/**
?? ? * 讓預(yù)覽跟照片符合正確的方向。<br/>
?? ? * 因為預(yù)覽默認是橫向的。如果是一個豎向的應(yīng)用,就需要把預(yù)覽轉(zhuǎn)90度<br/>
?? ? * 比如橫著時1280*960的尺寸時,1280是寬.<br/>
?? ? * 豎著的時候1280就是高了<br/>
?? ? * 這段代碼來自官方API。意思就是讓拍出照片的方向和預(yù)覽方向正確的符合設(shè)備當前的方向(有可能是豎向的也可能使橫向的)
?? ? *?
?? ? */
?? ?private int getCorrectOrientation() {
?? ??? ?android.hardware.Camera.CameraInfo info = new android.hardware.Camera.CameraInfo();
?? ??? ?android.hardware.Camera.getCameraInfo(mBackCameraId, info);
?? ??? ?int rotation = getActivity().getWindowManager().getDefaultDisplay().getRotation();
?? ??? ?int degrees = 0;
?? ??? ?switch (rotation) {
?? ??? ?case Surface.ROTATION_0:
?? ??? ??? ?degrees = 0;
?? ??? ??? ?break;
?? ??? ?case Surface.ROTATION_90:
?? ??? ??? ?degrees = 90;
?? ??? ??? ?break;
?? ??? ?case Surface.ROTATION_180:
?? ??? ??? ?degrees = 180;
?? ??? ??? ?break;
?? ??? ?case Surface.ROTATION_270:
?? ??? ??? ?degrees = 270;
?? ??? ??? ?break;
?? ??? ?}
?
?? ??? ?int result;
?? ??? ?if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
?? ??? ??? ?result = (info.orientation + degrees) % 360;
?? ??? ??? ?result = (360 - result) % 360; // compensate the mirror
?? ??? ?} else { // back-facing
?? ??? ??? ?result = (info.orientation - degrees + 360) % 360;
?? ??? ?}
?? ??? ?Log.d("orientationResult", result + "");
?? ??? ?return result;
?? ?}
?
?? ?public void takePicture() {
?? ??? ?mCamera.takePicture(null, null, this);
?? ?}
?
?? ?@Override
?? ?public void surfaceCreated(SurfaceHolder holder) {
?? ??? ?mSurfaceHolder = holder;
?
?? ??? ?startPreView();
?
?? ?}
?
?? ?private void startPreView() {
?? ??? ?try {
?? ??? ??? ?mCamera.setPreviewDisplay(mSurfaceHolder);
?? ??? ??? ?setPreviewSize();
?? ??? ??? ?setDisplayOrientation();
?? ??? ??? ?mCamera.startPreview();
?? ??? ?} catch (IOException e) {
?? ??? ??? ?// TODO Auto-generated catch block
?? ??? ??? ?e.printStackTrace();
?? ??? ?}
?
?? ?}
?
?? ?private void setDisplayOrientation() {
?? ??? ?int displayOrientation = getCorrectOrientation();
?
?? ??? ?mCamera.setDisplayOrientation(displayOrientation);
?? ?}
?
?? ?/**
?? ? * 我們用4比3的比例設(shè)置預(yù)覽圖片
?? ? */
?? ?private void setPreviewSize() {
?? ??? ?Camera.Parameters params = mCamera.getParameters();
?? ??? ?List<Size> sizes = params.getSupportedPreviewSizes();
?? ??? ?for (Size size : sizes) {
?? ??? ??? ?Log.d("previewSize", "width:" + size.width + " height " + size.height);
?? ??? ?}
?? ??? ?for (Size size : sizes) {
?? ??? ??? ?if (size.width / 4 == size.height / 3) {
?? ??? ??? ??? ?params.setPreviewSize(size.width, size.height);
?? ??? ??? ??? ?Log.d("previewSize", "SET width:" + size.width + " height " + size.height);
?? ??? ??? ??? ?break;
?? ??? ??? ?}
?? ??? ?}
?
?? ??? ?// params一定要記得寫回Camera
?? ??? ?mCamera.setParameters(params);
?
?? ?}
?
?? ?private void setPictureSize() {
?? ??? ?Camera.Parameters params = mCamera.getParameters();
?? ??? ?List<Size> sizes = params.getSupportedPictureSizes();
?? ??? ?for (Size size : sizes) {
?? ??? ??? ?Log.d("picSize", "width:" + size.width + " height " + size.height);
?? ??? ?}
?? ??? ?for (Size size : sizes) {
?? ??? ??? ?if (size.width / 4 == size.height / 3) {
?? ??? ??? ??? ?params.setPictureSize(size.width, size.height);
?? ??? ??? ??? ?break;
?? ??? ??? ?}
?? ??? ?}
?
?? ?}
?
?? ?@Override
?? ?public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
?
?? ?}
?
?? ?@Override
?? ?public void surfaceDestroyed(SurfaceHolder holder) {
?? ??? ?mCamera.release();
?? ?}
?
}
4. 程序的Mainactivity以及相應(yīng)的布局文件
package com.example.cameratutorial;
?
import android.os.Bundle;
import android.app.Activity;
import android.app.FragmentManager;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
?
public class MainActivity extends Activity {
?? ?
?? ?@Override
?? ?protected void onCreate(Bundle savedInstanceState) {
?? ??? ?super.onCreate(savedInstanceState);
?? ??? ?setContentView(R.layout.activity_main);
?? ??? ?final CameraFragment fragment=(CameraFragment) getFragmentManager().findFragmentById(R.id.camera_fragment);
?? ??? ?Button button=(Button) findViewById(R.id.TakePic);
?? ??? ?button.setOnClickListener(new OnClickListener() {
?? ??? ??? ?
?? ??? ??? ?@Override
?? ??? ??? ?public void onClick(View v) {
?? ??? ??? ??? ?fragment.takePicture();
?? ??? ??? ??? ?
?? ??? ??? ?}
?? ??? ?});
?? ??? ?
?? ?}
?
}
布局文件
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" ? ? xmlns:tools="http://schemas.android.com/tools" ? ? android:layout_width="match_parent" ? ? android:layout_height="match_parent"? ? ? android:orientation="vertical" ? ? > ? ? ? <fragment ? ? ? ? android:id="@+id/camera_fragment" ? ? ? ? android:name="com.example.cameratutorial.CameraFragment" ? ? ?? ? ? ? ? android:layout_width="match_parent" ? ? ? ? android:layout_height="match_parent" ? ? ? ? /> ? ? ? <Button ? ? ? ? android:id="@+id/TakePic" ? ? ? ? android:layout_width="match_parent" ? ? ? ? android:layout_height="wrap_content" ? ? ? ? android:layout_alignParentBottom="true" ? ? ? ? android:text="capture" /> ? </RelativeLayout>
這樣,我們一個可以復(fù)用的相機組件就完成了。
原文鏈接:https://blog.csdn.net/ctgulong/article/details/33318331
相關(guān)推薦
- 2022-04-11 python寫入Excel表格的方法詳解_python
- 2022-10-01 Python利用Bokeh進行數(shù)據(jù)可視化的教程分享_python
- 2022-10-11 ArrayList源碼中的MAX_ARRAY_SIZE
- 2022-04-04 git: master (pre-receive hook declined)
- 2023-01-23 python操作excel之openpyxl模塊讀寫xlsx格式使用方法詳解_python
- 2022-09-15 Python基本結(jié)構(gòu)之判斷語句的用法詳解_python
- 2022-05-02 Shell命令中的特殊替換、模式匹配替換、字符串提取和替換的實現(xiàn)_linux shell
- 2022-07-30 Linux secure 日志分析
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡單動態(tài)字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支