Android Camera开发实现可复用的相机组件
作者:三大小龙 时间:2023-04-08 20:34:56
本文实例为大家分享了Android Camera实现可复用相机组件的具体代码,供大家参考,具体内容如下
若自己的应用需要使用camera,有两种解决方案。
1. 使用Intent调用自带的Camera程序
2. 使用Camera API在程序中构造自己的Camera。
本文主要讲解第二种。
构造一个相机APP,通常需要六个步骤
1. 声明Manifest的相机权限
2. 创建一个相机预览类(继承SurfaceView)
3. 创建一个类实现相机拍照之后的回调函数
本文将一步步带你实现上述三个步骤。
1. 声明Manifest的相机权限。
应为我们需要写文件与调用相机,所以在你的manifest文件中加上。
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
2. 创建一个相机预览类
由于相机的预览是使用的SurfaceView,所以这里我们创建一个SurfaceView的子类。
为了让这个View所见即所得,我们将其设置为4/3的比例。重写它的onMeasure方法
代码如下:
package com.example.cameratutorial;
import android.content.Context;
import android.util.Log;
import android.view.SurfaceView;
/**
* @author CTGU小龙同学 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. 现在我们使用一个实现了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小龙同学 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();
}
/**
* 获得可用的相机,并设置前后摄像机的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;
}
}
}
/**
* 当相机拍照时会回调该方法
*/
@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();
}
/**
* 让预览跟照片符合正确的方向。<br/>
* 因为预览默认是横向的。如果是一个竖向的应用,就需要把预览转90度<br/>
* 比如横着时1280*960的尺寸时,1280是宽.<br/>
* 竖着的时候1280就是高了<br/>
* 这段代码来自官方API。意思就是让拍出照片的方向和预览方向正确的符合设备当前的方向(有可能是竖向的也可能使横向的)
*
*/
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的比例设置预览图片
*/
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以及相应的布局文件
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>
这样,我们一个可以复用的相机组件就完成了。
来源:https://blog.csdn.net/ctgulong/article/details/33318331
标签:Android,Camera,相机组件
0
投稿
猜你喜欢
java时区转换的理解及示例详解
2022-01-19 08:35:20
Android选择与上传图片之ImagePicker教程
2021-06-29 08:39:43
java中对List分段操作的实例
2022-12-05 18:38:48
Java数据结构之单链表详解
2023-11-04 17:02:20
C# 清除cookies的代码
2021-08-14 20:10:10
Java 8新特性方法引用详细介绍
2023-06-22 08:31:50
Android Studio真机无线连接USB设备调试运行详解流程
2023-12-13 00:37:37
基于Java数组实现循环队列的两种方法小结
2023-06-30 16:09:01
Java springboot 配置文件与多环境配置与运行优先级
2022-08-03 03:36:01
spring boot配置ssl实现HTTPS的方法
2022-03-27 01:27:49
Java 爬虫工具Jsoup详解
2022-04-11 03:46:16
Mybatis配置文件之动态SQL配置备忘录
2023-11-21 00:13:02
Java多线程下的单例模式参考
2023-11-09 00:40:15
解析C# 程序结构
2021-11-15 05:22:59
SpringMVC中的几个模型对象
2021-09-01 19:25:44
C#字符串加密解密方法实例
2022-01-11 23:30:14
举例讲解Java设计模式编程中Decorator装饰者模式的运用
2023-01-13 03:17:00
utf8编码检测方法分享
2023-05-18 12:34:27
Java经典面试题汇总:Mybatis
2021-09-20 07:42:44
jmeter添加自定函数的实例(jmeter5.3+IntelliJ IDEA)
2023-04-14 00:20:54