android sdk的作用的Camera中SCENE_MODE_BARCODE的作用

问题对人有帮助,内容完整,我也想知道答案
问题没有实际价值,缺少关键内容,没有改进余地
最近在做二维码相关的开发,网上都是清一色的Zxing。我用Zxing的时候把扫描框的位置调了之后不自动对焦,无法扫描二维码。在看Zxing源码的时候偶然发现Android中的Camera中有个SCENE_ MODE_BARCODE的参数,不知道有没有人用过。用这个能不能实现二维码扫描呢?
答案对人有帮助,有参考价值
答案没帮助,是错误的答案,答非所问
-0- 评论把我引来了。SCENE_MODE_BARCODE 支持这个场景的有限,貌似只是场景的设置吧? 起码。。。Nexus5就不支持这个mode。自动对焦需要AutoFocusManager这个类去支持,你可以去看下这个类的源码~~谢
分享到微博?
关闭理由:
删除理由:
忽略理由:
推广(招聘、广告、SEO 等)方面的内容
与已有问题重复(请编辑该提问指向已有相同问题)
答非所问,不符合答题要求
宜作评论而非答案
带有人身攻击、辱骂、仇恨等违反条款的内容
无法获得确切结果的问题
非开发直接相关的问题
非技术提问的讨论型问题
其他原因(请补充说明)
我要该,理由是:
在 SegmentFault,解决技术问题
每个月,我们帮助 1000 万的开发者解决各种各样的技术问题。并助力他们在技术能力、职业生涯、影响力上获得提升。
一线的工程师、著名开源项目的作者们,都在这里:
获取验证码
已有账号?博客分类:
package myj.
import java.io.F
import java.io.FileOutputS
import java.io.IOE
import android.app.A
import android.app.N
import android.content.I
import android.content.pm.ActivityI
import android.graphics.B
import android.graphics.BitmapF
import android.graphics.PixelF
import android.hardware.C
import android.hardware.Camera.PictureC
import android.hardware.Camera.ShutterC
import android.os.B
import android.os.E
import android.util.L
import android.view.MotionE
import android.view.SurfaceH
import android.view.SurfaceV
import android.view.V
import android.view.W
import android.view.WindowM
import android.view.View.OnTouchL
import android.widget.B
import android.widget.ImageB
import android.widget.T
public class CameraTest extends Activity implements SurfaceHolder.Callback{
/** Called when the activity is first created. */
private Bitmap[] bmps = new Bitmap[6];
private Camera mC
private ImageButton mButton,mButton1,mButton2;
private Button returnT
private SurfaceView mSurfaceV
private SurfaceH
private AutoFocusCallback mAutoFocusCallback =
new AutoFocusCallback();
private String path="CameraTest";
private Bitmap bmp =
private int cnt=1;
private boolean isFocused =
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
/* 隐藏标题栏 */
requestWindowFeature(Window.FEATURE_NO_TITLE);
/* 设定屏幕显示为横向 */
this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
setContentView(R.layout.main);
Bundle bl = new Bundle();
mSurfaceView = (SurfaceView) findViewById(R.id.mSurfaceView);
holder = mSurfaceView.getHolder();
holder.addCallback(CameraTest.this);
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
mButton = (ImageButton)findViewById(R.id.myButton);
mButton1 = (ImageButton)findViewById(R.id.myButton1);
//搜索按钮(1、保存文件,读取上传)
mButton2 = (ImageButton)findViewById(R.id.myButton2);
//重拍按钮(放弃保存文件,并重新拍照)
/* 按钮效果处理 */
mButton.setOnTouchListener(new OnTouchListener() {
//@Override
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
if(event.getAction() == MotionEvent.ACTION_DOWN){
//更改为按下时的背景图片
bmps[0] = BitmapFactory.decodeResource(getResources(), R.drawable.takepicture2);
mButton.setImageBitmap(bmps[0]);
v.setBackgroundResource(R.drawable.barcodesearch2);//这行经测试不好使
}else if(event.getAction() == MotionEvent.ACTION_UP){
//改为抬起时的图片
bmps[1] = BitmapFactory.decodeResource(getResources(), R.drawable.takepicture);
mButton.setImageBitmap(bmps[1]);
v.setBackgroundResource(R.drawable.barcodesearch);
mButton1.setOnTouchListener(new OnTouchListener() {
//@Override
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
if(event.getAction() == MotionEvent.ACTION_DOWN){
//更改为按下时的背景图片
bmps[2] = BitmapFactory.decodeResource(getResources(), R.drawable.search2);
mButton1.setImageBitmap(bmps[2]);
v.setBackgroundResource(R.drawable.barcodesearch2);//这行经测试不好使
}else if(event.getAction() == MotionEvent.ACTION_UP){
//改为抬起时的图片
bmps[3] = BitmapFactory.decodeResource(getResources(), R.drawable.search);
mButton1.setImageBitmap(bmps[3]);
v.setBackgroundResource(R.drawable.barcodesearch);
mButton2.setOnTouchListener(new OnTouchListener() {
//@Override
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
if(event.getAction() == MotionEvent.ACTION_DOWN){
//更改为按下时的背景图片
bmps[4] = BitmapFactory.decodeResource(getResources(), R.drawable.takepicture2);
mButton2.setImageBitmap(bmps[4]);
v.setBackgroundResource(R.drawable.barcodesearch2);//这行经测试不好使
}else if(event.getAction() == MotionEvent.ACTION_UP){
//改为抬起时的图片
bmps[5] = BitmapFactory.decodeResource(getResources(), R.drawable.takepicture);
mButton2.setImageBitmap(bmps[5]);
v.setBackgroundResource(R.drawable.barcodesearch);
/* 拍照Button的事件处理 */
mButton.setOnClickListener(new Button.OnClickListener()
//@Override
public void onClick(View arg0)
/* 关闭闪光灯并拍照 */
mButton.setVisibility(View.GONE);
if(bmps[0] != null && !bmps[0].isRecycled())
bmps[0].recycle();
mCamera.autoFocus(mAutoFocusCallback);
Notification notification = new Notification();
notification.ledOffMS = 0;
notification.ledOnMS = 0;
notification.flags = notification.flags | Notification.FLAG_SHOW_LIGHTS;
takePicture();
/*搜索按钮的事件处理 */
mButton1.setOnClickListener(new Button.OnClickListener()
//@Override
public void onClick(View arg0)
Bitmap newBmp = ImageTool.imageZoom(bmp, 720, 480);
mButton1.setVisibility(View.GONE);
mButton2.setVisibility(View.GONE);
if(bmps[2] != null && !bmps[2].isRecycled())
bmps[2].recycle();
if(bmps[4] != null && !bmps[4].isRecycled())
bmps[4].recycle();
Bitmap newBmp =
Bitmap newBmp = ImageTool.imageZoom(bmp, 960, 640);
if(!bmp.isRecycled())
bmp.recycle();
/* 保存文件 */
if(bmp!=null)
Log.i("aaaaaaaaaaaaa", "nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn");
/* 检查SDCard是否存在 */
if (!Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()))
/* SD卡不存在,显示Toast信息 */
Toast.makeText(CameraTest.this,"SD卡不存在!上传失败!",
Toast.LENGTH_LONG).show();
/* 文件不存在就创建 */
File f=new File
Environment.getExternalStorageDirectory(),path
if(!f.exists())
f.mkdir();
/* 保存相片文件 */
File n=new File(f,Constant.state + ".jpg");
Bitmap newBmp = ImageTool.imageZoom(bmp, 720, 480);
File n=new File(f,".jpg");
FileOutputStream bos =
new FileOutputStream(n.getAbsolutePath());
/* 文件转换 */
pressFormat.JPEG, 100, bos);
/* 调用flush()方法,更新BufferStream */
bos.flush();
/* 结束OutputStream */
bos.close();
Toast.makeText(CameraTest.this,cnt+".jpg保存成功!",
Toast.LENGTH_LONG).show();
if(!newBmp.isRecycled())
newBmp.recycle();
Constant.upLoadFile = "/sdcard/MyPhoto/" + Constant.state + ".jpg";
Constant.upLoadFile = "/sdcard/MyPhoto/3E.jpg";
Constant.newFileName = Constant.state + ".jpg";
Constant.newFileName = "3E.jpg";
catch (Exception e)
e.printStackTrace();
if(!bmp.isRecycled())
bmp.recycle();
mButton.setVisibility(View.VISIBLE);
/* 重新设定Camera */
stopCamera();
initCamera();
/* 重拍按钮的事件处理 */
mButton2.setOnClickListener(new Button.OnClickListener()
//@Override
public void onClick(View arg0)
mButton.setVisibility(View.VISIBLE);
mButton1.setVisibility(View.GONE);
mButton2.setVisibility(View.GONE);
/* 重新设定Camera */
if(!bmp.isRecycled())
bmp.recycle();
stopCamera();
initCamera();
public void surfaceCreated(SurfaceHolder surfaceholder)
/* 打开相机 */
mCamera = mCamera.open();
mCamera.setPreviewDisplay(holder);
catch (IOException exception)
mCamera.release();
public void surfaceChanged(SurfaceHolder surfaceholder,
int format,int w,int h)
/* 相机初始化 */
initCamera();
Log.i("changed", count + "times");
//@Override
public void surfaceDestroyed(SurfaceHolder surfaceholder)
stopCamera();
mCamera.release();
private void takePicture()
if (mCamera != null)
mCamera.takePicture(shutterCallback, rawCallback,jpegCallback);
private ShutterCallback shutterCallback = new ShutterCallback()
public void onShutter()
/* 按快门瞬间呼叫这里的程序 */
private PictureCallback rawCallback = new PictureCallback()
public void onPictureTaken(byte[] _data, Camera _camera)
/* 要处理raw data?写?否 */
private PictureCallback jpegCallback = new PictureCallback()
public void onPictureTaken(byte[] _data, Camera _camera)
/* 取得相片 */
/* 设定Button可视性 */
mButton.setVisibility(View.GONE);
mButton1.setVisibility(View.VISIBLE);
mButton2.setVisibility(View.VISIBLE);
/* 取得相片Bitmap对象 */
bmp = BitmapFactory.decodeByteArray(_data, 0,_data.length);
catch (Exception e)
e.printStackTrace();
public final class AutoFocusCallback implements android.hardware.Camera.AutoFocusCallback
public void onAutoFocus(boolean focused, Camera camera)
/* 对到焦点拍照 */
if (focused)
takePicture();
mButton.setVisibility(View.VISIBLE);
/* 相机初始化的method */
private void initCamera()
if (mCamera != null)
Camera.Parameters parameters = mCamera.getParameters();
parameters.setPictureFormat(PixelFormat.JPEG);
parameters.setPictureSize();
parameters.setPictureSize();
parameters.setPictureSize(720, 480);
mCamera.setParameters(parameters);
mCamera.startPreview();
catch (Exception e)
e.printStackTrace();
/* 停止相机的method */
private void stopCamera()
if (mCamera != null)
/* 停止预览 */
mCamera.stopPreview();
catch(Exception e)
e.printStackTrace();
protected void onDestroy()
super.onDestroy();
for(int i = 0; i & 6; i ++)
if(bmps[i] != null && !bmps[i].isRecycled())
bmps[i].recycle();
Log.i("&&&&&&&&&&", "**************");
package myj.
import java.io.F
import java.io.FileOutputS
import java.util.C
import java.util.D
import android.graphics.B
import android.graphics.M
import android.os.E
import android.util.L
public class ImageTool {
//切割图片的一部分
public static Bitmap imageCut(Bitmap bmp, int left, int top, int right, int bottom)
Bitmap resultBmp =
int resultWidth = right - left + 1;
int resultHeight = bottom - top + 1;
int colors[] = new int[resultWidth * resultHeight];
bmp.getPixels(colors, 0, resultWidth, left, top, resultWidth, resultHeight);
if(bmp.isRecycled())
bmp.recycle();
resultBmp = Bitmap.createBitmap(colors, resultWidth, resultHeight, Bitmap.Config.ARGB_8888);
return resultB
//把图片按固定比例缩小
public static Bitmap imageZoom(Bitmap bmp, int iWidth, int iHeight)
Bitmap newBmp =
int imageHeight = bmp.getHeight();
int imageWidth = bmp.getWidth();
float scaleW = 1;
float scaleH = 1;
double scalex = (float)iWidth/imageW
double scaley = (float)iHeight/imageH
scaleW = (float)(scaleW * scalex);
scaleH = (float)(scaleH * scaley);
Matrix matrix = new Matrix();
matrix.postScale(scaleW, scaleH);
newBmp = Bitmap.createBitmap(bmp, 0, 0, imageWidth, imageHeight, matrix, true);
if(!bmp.isRecycled())
bmp.recycle();
return newB
//图片合并
public static Bitmap imageMerge(Bitmap[] bmps)
Bitmap resultBmp =
//判断bmps中有没有值为null的bmp,有的话将其初始化为一张960*80的空白图片
int bmp_null[] = new int[960 * 80];
for(int i = 0; i & 960 * 80; i ++)
bmp_null[i] = 0
for(int i = 0; i & bmps. i ++)
if(bmps[i] == null)
bmps[i] = Bitmap.createBitmap(960, 80, Bitmap.Config.ARGB_8888);
bmps[i].setPixels(bmp_null, 0, 960, 0, 0, 960, 80);
int devideLineHeight = 5;
int resultWidth = 0;
//合并完的图像的宽度;
int resultHeight = 0;
//合并完的图像的高度;
for(int i = 0; i & bmps. i ++)
if(i != (bmps.length - 1))
if(bmps[i].getWidth() & resultWidth)
resultWidth = bmps[i].getWidth();
resultHeight = resultHeight + bmps[i].getHeight() + devideLineH
//不同图片之间用一条宽度为5像素的红线隔开
if(bmps[i].getWidth() & resultWidth)
resultWidth = bmps[i].getWidth();
resultHeight = resultHeight + bmps[i].getHeight();
resultWidth = 960;
//暂时将宽度定义为960
Log.i("Width & Height", "******* " + resultWidth + " * " + resultHeight + " ********");
//定义各图片之间分割线的像素数组
int devideLine[] = new int[resultWidth * devideLineHeight];
for(int i = 0; i & resultWidth * devideLineH i ++)
devideLine[i] = 0xffff0000;
//生成了一张resultWidth*resultHeight的黑色图片
resultBmp = Bitmap.createBitmap(resultWidth, resultHeight, Bitmap.Config.ARGB_8888);
//为了识别方便,将这张黑色图片变为纯白色
int originalColors[] = new int[resultWidth * resultHeight];
for(int i = 0; i & resultWidth * resultH i ++)
originalColors[i] = 0
resultBmp.setPixels(originalColors, 0, resultWidth, 0, 0, resultWidth, resultHeight); //一张纯白色的图片
//下面的循环用图片数组中各个图片的像素数组及分割线的像素数组填充最终图片
int y = 0;
int len = bmps.
for(int i = 0; i & i ++)
int iWidth = bmps[i].getWidth();
int iHeight = bmps[i].getHeight();
int colors[] = new int[iWidth * iHeight];
bmps[i].getPixels(colors, 0, iWidth, 0, 0, iWidth, iHeight);
if(i != (len - 1))
resultBmp.setPixels(colors, 0, iWidth, 0, y, iWidth, iHeight);
y = y + iH
resultBmp.setPixels(devideLine, 0, resultWidth, 0, y, resultWidth, devideLineHeight);
y = y + devideLineH
resultBmp.setPixels(colors, 0, iWidth, 0, y, iWidth, iHeight);
if(!bmps[i].isRecycled())
bmps[i].recycle();
return resultB
//保存图片
public static void saveImage(Bitmap bmp, String path, String filename, int quality)
String time = callTime();
if (bmp != null) {
/* 文件不存在就创建 */
File f = new File(Environment.getExternalStorageDirectory(),
if (!f.exists()) {
f.mkdir();
/* 保存相片文件 */
if(path.equals("MyPhoto"))
n = new File(f, filename + tOfMyPhoto + ".jpg");
tOfMyPhoto ++;
n = new File(f, filename + tOfTemp + ".jpg");
tOfTemp ++;
Constant.fileNameOfTemp = filename + tOfT
n = new File(f, filename + time + ".jpg");
Constant.fileNameOfTemp = filename +
FileOutputStream bos = new FileOutputStream(n.getAbsolutePath());
/* 文件转换 */
pressFormat.JPEG, quality, bos);
/* 调用flush()方法,更新BufferStream */
bos.flush();
/* 结束OutputStream */
bos.close();
Constant.upLoadFile = "/sdcard/MyPhoto/" + filename + sTime + ".jpg";
Constant.upLoadFile = "/sdcard/MyPhoto/" + filename + time + ".jpg";
Constant.newFileName = filename + time + ".jpg";
} catch (Exception e) {
e.printStackTrace();
if(!bmp.isRecycled())
bmp.recycle();
//重置选择框的初始位置
public static void resetRect()
Constant.left = 200;
Constant.top = 140;
Constant.right = 280;
Constant.bottom = 170;
//获取系统时间
public static String callTime() {
long backTime = new Date().getTime();
Calendar cal = Calendar.getInstance();
cal.setTime(new Date(backTime));
int year = cal.get(Calendar.YEAR);
int month = cal.get(Calendar.MONTH) + 1;
int date = cal.get(Calendar.DAY_OF_MONTH);
int hour = cal.get(Calendar.HOUR_OF_DAY);
int minute = cal.get(Calendar.MINUTE);
int second = cal.get(Calendar.SECOND);
String time = "" + year + month + date + hour + minute +
Log.i("CurrentTime", "^^^^^^^^^^^^^" + time + "^^^^^^^^^^^^^");
return date + 100 * (month + 1) + 10000 *
&uses-permission android:name="android.permission.CAMERA" /&
&uses-feature android:name="android.hardware.camera" /&
&uses-feature android:name="android.hardware.camera.autofocus" /&
浏览: 28878 次
来自: 常熟
(window.slotbydup=window.slotbydup || []).push({
id: '4773203',
container: s,
size: '200,200',
display: 'inlay-fix'Android camera相机开发拍照功能 - jing__jie的博客 - CSDN博客
Android camera相机开发拍照功能
Android--基础
在Android 5.0(SDK 21)中,Google使用Camera2替代了Camera接口。Camera2在接口和架构上做了巨大的变动,但是基于众所周知的原因,我们还必须基于 Android 4.+ 系统进行开发。本文介绍的是Camera接口开发及其使用方法,全面地学会Camera接口的开发流程。
一、调用系统相机/其它App完成拍摄操作
如果你的App的需求只是调用摄像头拍照并拿到照片,老司机的建议是别自己实现拍照模块,这里面坑多水深。你完全可以使用Intent来调用系统相机或第三方具备拍照功能的App来拍照并获取返回照片数据。
创建一个Intent,指定两个拍摄类型之一:
MediaStore.ACTION_IMAGE_CAPTURE 拍摄照片;
MediaStore.ACTION_VIDEO_CAPTURE 拍摄视频;
Intent intent = new Intent(MediaStore.ACTION_IMAGE/VIDEO_CAPTURE)
通用流程startActivityForResult()和onActivityResult()就不表述了。说说拍摄照片的Intent参数吧。
首先是设置拍摄后返回数据的地址:
intent.putExtra(MediaStore.EXTRA_OUTPUT, your-store-uri)
MediaStore.EXTRA_OUTPUT 参数用于指定拍摄完成后的照片/视频的储存路径。你可以使用Android默认的储存照片目录来保存:
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURE)
也可以是其它任意你喜欢的储存目录。如果你使用了App内部目录,某些临时文件如拍摄并上传的头像文件,在处理完成后,要记得将它删除。这样做的好处是减少App占用储存空间,手机用户特别喜欢对占用大储存空间的App下重手删除和清理空间。如果你必须保存大体积的文件,可以使用公共空间来储存,把包袱丢出去,私有空间仅保存应用配置数据。
相机其它设置,如指定拍摄照片的尺寸大小,照片质量等,待以后文章更新吧。
// TODO 是程序界最大的谎言
使用Camera开发照相功能
使用Camera API来开发拍照模块需要费一番大功夫。下面是介绍我在开发NextQRCode项目中使用Camera API的方法和流程。
1.在 Android Manifest.xml 中声明相机权限
开发第一步是在 Android Manifest.xml 文件中声明使用相机的权限:
android:name="android.permission.CAMERA" /&
android:name="android.hardware.camera" android:required="true"/&
android:name="android.hardware.camera.autofocus" android:required="false"/&
required属性是说明这个特性是否必须满足。比方说示例的设置就是要求必须拥有相机设备但可以没有自动对焦功能。
这两个声明是可选的,它们用于应用商店(Google Play)过滤不支持相机和不支持自动对焦的设备。
另外在保存照片时需要写入储存器的权限,也需要加上读写储存器的权限声明:
android:name="android.permission.WEITE_EXTERNAL_STORAGE" /&
2 . 打开相机设备
现在市面上销售的手机/平板等消费产品基本标配两个摄像头。如华为P9,更有前置双摄像头。讲真,我很好奇开发双摄像头的App是怎样的体验。在打开相机设备前,先获取当前设备有多少个相机设备。如果你的开发需求里包含切换前后摄像头功能,可以获取摄像头数量来判断是否存在后置摄像头。
int cameras = Camera.getNumberOfCameras();
这个接口返回值为摄像头的数量:非负整数。对应地,摄像头序号为: cameras - 1。例如在拥有前后摄像头的手机设备上,其返回结果是2,则第一个摄像头的cameraId是0,通常对应手机背后那个大摄像头;第二个摄像头的cameraId是1,通常对应着手机的前置自拍摄像头;
相机是一个硬件设备资源,在使用设备资源前需要将它打开,可以通过接口Camera.open(cameraId)来打开。参考以下代码:
public static Camera openCamera(int cameraId) {
return Camera.open(cameraId);
}catch(Exception e) {
return null;
打开相机设备可能会失败,你一定要检查打开操作是否成功。打开失败的可能原因有两种:一是安装App的设备上根本没有摄像头,例如某些平板或特殊Android设备;二是cameraId对应的摄像头正被使用,可能某个App正在后台使用它录制视频。
配置相机参数
在打开相机设备后,你将获得一个Camera对象,并独占相机设备资源。
通过Camera.getParameters()接口可以获取当前相机设备的默认配置参数。下面列举一些我能理解的参数:
闪光灯配置参数,可以通过Parameters.getFlashMode()接口获取当前相机的闪光灯配置参数:
Camera.Parameters.FLASH_MODE_AUTO 自动模式,当光线较暗时自动打开闪光灯;
Camera.Parameters.FLASH_MODE_OFF 关闭闪光灯;
Camera.Parameters.FLASH_MODE_ON 拍照时闪光灯;
Camera.Parameters.FLASH_MODE_RED_EYE 闪光灯参数,防红眼模式,科普一下:防红眼;
对焦模式配置参数,可以通过Parameters.getFocusMode()接口获取:
Camera.Parameters.FOCUS_MODE_AUTO 自动对焦模式,摄影小白专用模式;
Camera.Parameters.FOCUS_MODE_FIXED 固定焦距模式,拍摄老司机模式;
Camera.Parameters.FOCUS_MODE_EDOF 景深模式,文艺女青年最喜欢的模式;
Camera.Parameters.FOCUS_MODE_INFINITY 远景模式,拍风景大场面的模式;
Camera.Parameters.FOCUS_MODE_MACRO 微焦模式,拍摄小花小草小蚂蚁专用模式;
场景模式配置参数,可以通过Parameters.getSceneMode()接口获取:
Camera.Parameters.SCENE_MODE_BARCODE 扫描条码场景,NextQRCode项目会判断并设置为这个场景;
Camera.Parameters.SCENE_MODE_ACTION 动作场景,就是抓拍跑得飞快的运动员、汽车等场景用的;
Camera.Parameters.SCENE_MODE_AUTO 自动选择场景;
Camera.Parameters.SCENE_MODE_HDR 高动态对比度场景,通常用于拍摄晚霞等明暗分明的照片;
Camera.Parameters.SCENE_MODE_NIGHT 夜间场景;
Camera API提供了非常多的参数接口供开发者设置,有必要的话,可以翻阅相关API文档。
在NextQRCode项目中,需要使用到自动对焦的特性。在一些机型上可能是没有的自动对焦(虽然比较少见),需要对这种情况进行处理。
4 . 设置相机预览方向
相机预览图需要设置正确的预览方向才能正常地显示预览画面,否则预览画面会被挤压得很惨。
在通常情况下,如果我们需要知道设备的屏幕方向,可以通过Resources.Configuration.orientation来获取。Android屏幕方向有“竖屏”和“横屏”两种,对应的值分别是ORIENTATION_PORTRAIT和ORIENTATION_LANDSCAPE。但相机设备的方向却有些特别,设置预览方向的接口Camera.setDisplayOrientaion(int)的参数是以角度为单位的,而且只能是0,90,180,270其中之一,默认为0,是指手机的左侧为摄像头顶部画面。记得只能是[0、90、180、270]其中之一,输入其它角度数值会报错。
如果你想让相机跟随设备的方向,预览界面顶部一直保持正上方,以下代码供参考:
public static void followScreenOrientation(Context context, Camera camera){
final int orientation = context.getResources().getConfiguration().
if(orientation == Configuration.ORIENTATION_LANDSCAPE) {
camera.setDisplayOrientation(180);
}else if(orientation == Configuration.ORIENTATION_PORTRAIT) {
camera.setDisplayOrientation(90);
5 . 预览View与拍照
我们一般使用SurfaceView作为相机预览View,你也可以使用Texture。在SurfaceView中获取得SurfaceHolder,并通过setPreviewDisplay()接口设置预览。在设置预览View后,一定要记得以下两点:
调用startPreview()方法启动预览,否则预览View不会显示任何内容;
拍照操作需要在startPreview()方法执行之后调用;
每次拍照后,预览View会停止预览。所以连续拍照,需要重新调用startPreview()来恢复预览;
Camera接受一个SurfaceHolder接口,这个接口可以通过SurfaceHolder.Callback获得。我们可以通过继承SurfaceView来实现相机预览效果。在NextQRCode项目中,实现了LiveCameraView类,它内部已实现了相机预览所需要的处理过程,很简洁的类,以下是它的全部源码:
public class LiveCameraView extends SurfaceView implements SurfaceHolder.Callback {
private final static String TAG = LiveCameraView.class.getSimpleName();
private Camera mC
private SurfaceHolder mSurfaceH
public LiveCameraView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mSurfaceHolder = this.getHolder();
mSurfaceHolder.addCallback(this);
public void surfaceCreated(SurfaceHolder holder) {
Log.d(TAG, "Start preview display[SURFACE-CREATED]");
startPreviewDisplay(holder);
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
if (mSurfaceHolder.getSurface() == null){
Cameras.followScreenOrientation(getContext(), mCamera);
Log.d(TAG, "Restart preview display[SURFACE-CHANGED]");
stopPreviewDisplay();
startPreviewDisplay(mSurfaceHolder);
public void setCamera(Camera camera) {
final Camera.Parameters params = mCamera.getParameters();
params.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
params.setSceneMode(Camera.Parameters.SCENE_MODE_BARCODE);
private void startPreviewDisplay(SurfaceHolder holder){
checkCamera();
mCamera.setPreviewDisplay(holder);
mCamera.startPreview();
} catch (IOException e) {
Log.e(TAG, "Error while START preview for camera", e);
private void stopPreviewDisplay(){
checkCamera();
mCamera.stopPreview();
} catch (Exception e){
Log.e(TAG, "Error while STOP preview for camera", e);
private void checkCamera(){
if(mCamera == null) {
throw new IllegalStateException("Camera must be set when start/stop preview, call &setCamera(Camera)& to set");
public void surfaceDestroyed(SurfaceHolder holder) {
Log.d(TAG, "Stop preview display[SURFACE-DESTROYED]");
stopPreviewDisplay();
从上面代码可以看出LiveCameraView的核心代码是SurfaceHolder.Callback的回调:在创建/销毁时启动/停止预览动作。在LiveCameraView类中,我们利用了View的生命周期回调来实现自动管理预览生命周期控制:
当SurfaceView被创建后自动开启预览;
当SurfaceView被销毁时关闭预览;
当SurfaceView尺寸被改变时重置预览;
预览View需要注意预览输出画面的尺寸。相机输出画面只支持部分尺寸。关于尺寸部分,后面再更新。
在启用预览View后,就可以通过Camera.takePicture()方法拍摄一张照片,返回的照片数据通过Callback接口获取。takePicture()接口可以获取三个类型的照片:
第一个,ShutterCallback接口,在拍摄瞬间瞬间被回调,通常用于播放“咔嚓”这样的音效;
第二个,PictureCallback接口,返回未经压缩的RAW类型照片;
第三个,PictureCallback接口,返回经过压缩的JPEG类型照片;
我们使用第三个参数,JPEG类型的照片的图片精度即可满足识别二维码的需求。在NextQRCode项目中,ZXing识别二维码的数据格式为Bitmap,通过BitmapFactory可以很方便方便地将byte数组转换成Bitmap。
public abstract class BitmapCallback implements Camera.PictureCallback {
public void onPictureTaken(byte[] data, Camera camera) {
onPictureTaken(BitmapFactory.decodeByteArray(data, 0, data.length));
public abstract void onPictureTaken(Bitmap bitmap);
详细关于Android中Bitmap的说明,请参见文章Android: Bitmap与Drawable这件小事。
如果你需要将照片保存为文件,可以参考这个类的实现:FilePhotoCallback.java
6 . 释放相机设备
在打开一个相机设备后,意味着你的App就独占了这个设备,其它App将无法使用它。因此在你不需要相机设备时,记得调用release()方法释放设备,再使用时可以重新打开,这并不需要多大的成本。可以选择在stopPreview()后即释放相机设备。
附加工具性代码实现
1 - 判断手机设备是否有相机设备
public static boolean hasCameraDevice(Context ctx) {
return ctx.getPackageManager()
.hasSystemFeature(PackageManager.FEATURE_CAMERA);
2 - 判断是否支持自动对焦
public static boolean isAutoFocusSupported(Camera.Parameters params) {
List&String& modes = params.getSupportedFocusModes();
return modes.contains(Camera.Parameters.FOCUS_MODE_AUTO);
相关文章推荐}

我要回帖

更多关于 android category作用 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信