• android入门:zxing学习笔记(四)


    Camera取景后显示于屏幕上,是个挺简单的过程,但这会出现各种意料不到的问题,例如之前说的屏幕横竖屏与预览图片之间的方向,图片拉伸,还有在Barcode Scanner中,简单的旋转了图片预览方向后,会出现特征点标记错位,等等。

         第三篇简单的完成了相机的取景,还没有将取景的图片拍照存储下来。若想实现拍照的效果,则需要实现回调函数:Camera.PreviewCallback接口。接上一篇的代码,在此实现拍照的功能,将图片显示出来。之前一直在看Barcode Scanner的源码,并只是在其代码上修剪。当昨天自己来实现Camera的自动聚焦时,并遇到比较纠结的问题。在不出意外的情况下,Camera的使用还是挺简单的。

         先在此贴出代码,最简单,代码经过了测试,正常运行,测试机是HTC MyTouch 3G slide。

         需要的权限:

    1 <uses-permission android:name="android.permission.CAMERA" />
    2 <uses-feature android:name="android.hardware.camera" />
    3 <uses-feature android:name="android.hardware.camera.autofocus" />

        整个代码:

    复制代码
      1 import java.io.ByteArrayOutputStream;
    2 import java.io.IOException;
    3 import java.util.Timer;
    4 import java.util.TimerTask;
    5
    6 import android.app.Activity;
    7 import android.content.Context;
    8 import android.graphics.Bitmap;
    9 import android.graphics.BitmapFactory;
    10 import android.graphics.ImageFormat;
    11 import android.graphics.Rect;
    12 import android.graphics.YuvImage;
    13 import android.hardware.Camera;
    14 import android.os.Bundle;
    15 import android.util.Log;
    16 import android.view.Display;
    17 import android.view.SurfaceHolder;
    18 import android.view.SurfaceView;
    19 import android.view.WindowManager;
    20 import android.widget.ImageView;
    21
    22 public class CameraTestActivity extends Activity implements SurfaceHolder.Callback {
    23 private static String TAG = CameraTestActivity.class.getSimpleName();
    24 private SurfaceHolder surfaceHolder;
    25 private Camera camera;
    26 private ImageView imageView;
    27 private Timer mTimer;
    28 private TimerTask mTimerTask;
    29
    30 private Camera.AutoFocusCallback mAutoFocusCallBack;
    31 private Camera.PreviewCallback previewCallback;
    32
    33 /** Called when the activity is first created. */
    34 @Override
    35 public void onCreate(Bundle savedInstanceState) {
    36 super.onCreate(savedInstanceState);
    37 setContentView(R.layout.main);
    38 SurfaceView surfaceView = (SurfaceView) findViewById(R.id.preview_view);
    39 imageView = (ImageView) findViewById(R.id.image_view);
    40 surfaceHolder = surfaceView.getHolder();
    41 surfaceHolder.addCallback(this);
    42 surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    43 mAutoFocusCallBack = new Camera.AutoFocusCallback() {
    44 @Override
    45 public void onAutoFocus(boolean success, Camera camera) {
    46 if (success) {
    47 // isAutoFocus = true;
    48 camera.setOneShotPreviewCallback(previewCallback);
    49 Log.d(TAG, "onAutoFocus success");
    50 }
    51 }
    52 };
    53
    54 previewCallback = new Camera.PreviewCallback() {
    55 @Override
    56 public void onPreviewFrame(byte[] data, Camera arg1) {
    57 if (data != null)
    58 {
    59 Camera.Parameters parameters = camera.getParameters();
    60 int imageFormat = parameters.getPreviewFormat();
    61 Log.i("map", "Image Format: " + imageFormat);
    62
    63 Log.i("CameraPreviewCallback", "data length:" + data.length);
    64 if (imageFormat == ImageFormat.NV21)
    65 {
    66 // get full picture
    67 Bitmap image = null;
    68 int w = parameters.getPreviewSize().width;
    69 int h = parameters.getPreviewSize().height;
    70
    71 Rect rect = new Rect(0, 0, w, h);
    72 YuvImage img = new YuvImage(data, ImageFormat.NV21, w, h, null);
    73 ByteArrayOutputStream baos = new ByteArrayOutputStream();
    74 if (img.compressToJpeg(rect, 100, baos))
    75 {
    76 image = BitmapFactory.decodeByteArray(baos.toByteArray(), 0, baos.size());
    77 imageView.setImageBitmap(image);
    78 }
    79
    80 }
    81 }
    82 }
    83 };
    84
    85 mTimer = new Timer();
    86 mTimerTask = new CameraTimerTask();
    87 mTimer.schedule(mTimerTask, 0, 500);
    88 }
    89
    90 @Override
    91 public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
    92 // TODO Auto-generated method stub
    93 }
    94
    95 @Override
    96 public void surfaceCreated(SurfaceHolder arg0) {
    97 // TODO Auto-generated method stub
    98 initCamera();
    99 }
    100
    101 @Override
    102 public void surfaceDestroyed(SurfaceHolder arg0) {
    103 // TODO Auto-generated method stub
    104 if (camera != null) {
    105 camera.stopPreview();
    106 camera.release();
    107 camera = null;
    108 }
    109 previewCallback = null;
    110 mAutoFocusCallBack = null;
    111 }
    112
    113 public void initCamera() {
    114 camera = Camera.open();
    115 Camera.Parameters parameters = camera.getParameters();
    116 WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE); // 获取当前屏幕管理器对象
    117 Display display = wm.getDefaultDisplay(); // 获取屏幕信息的描述类
    118 parameters.setPreviewSize(display.getWidth(), display.getHeight());
    119 camera.setParameters(parameters);
    120 try {
    121 camera.setPreviewDisplay(surfaceHolder);
    122 } catch (IOException e) {
    123 System.out.println(e.getMessage());
    124 }
    125 camera.startPreview();
    126 }
    127
    128 class CameraTimerTask extends TimerTask {
    129 @Override
    130 public void run() {
    131 if (camera != null) {
    132 camera.autoFocus(mAutoFocusCallBack);
    133 }
    134 }
    135 }
    136 }
    复制代码

         与上一篇的简单预览相比,这篇增加了两个内容,一个是自动聚焦,一个是拍照。代码看上去很简单,没多少内容。但不亲自测试下,还会发现不少。

         刚开始在Samsung S5570 galaxy mini上测试,总是不能成功的拍照。调试跟踪后,发现自动聚焦总是失败,聚焦失败就没有进行拍照操作。后面并尝试将自动聚焦代码注释掉,直接拍照,发现也是无法显示拍照的结果。之前的PreviewCallback的代码如下:

    1 Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);

        这行代码返回的总是null,即bitmap没有成功生成。对这些代码本来就是拿来用,功能实现了,就行,对这些都只是简单的了解,当遇到bug后并百思不得其解。后来在网上几经查找发现原来是BitmapFactory.decodeByteArray只支持一定的格式,camara支持的previewformat格式为NV21,所以在获得bitmap时,需要进行转换。通过YuvImage类来转换成JPEG格式,再显示出来。具体讨论,请点这里。

        解决照片的显示问题后,还有一个问题便是自动聚焦失败。上面特意强调了使用的事HTC 的手机测试成功,是因为之前在samsung s5570 上测试总是失败,拿到HTC的那款手机上立马成功。应该是三星的这款手机不支持自动聚焦。之前在这个三星手机上跑过Barcode Scanner,就自以为这手机能够自动聚焦,并一直在查找自己代码的原因。后面在仔细的读了Barcode Scanner的代码后,发现他得处理方式是:

    1 CameraManager.get().requestPreviewFrame(decodeThread.getHandler(), R.id.decode);//实现拍照
    2 CameraManager.get().requestAutoFocus(this, R.id.auto_focus);//实现聚焦

         首先实现拍照,再是实现聚焦,并且重载的聚焦回调函数是隔一段时间再次发出聚焦的请求,实现不断的聚焦。

    复制代码
     1 public void onAutoFocus(boolean success, Camera camera) {
    2 if (autoFocusHandler != null) {
    3 Message message = autoFocusHandler.obtainMessage(autoFocusMessage, success);
    4 // Simulate continuous autofocus by sending a focus request every
    5 // AUTOFOCUS_INTERVAL_MS milliseconds.
    6 //Log.d(TAG, "Got auto-focus callback; requesting another");
    7 autoFocusHandler.sendMessageDelayed(message, AUTOFOCUS_INTERVAL_MS);
    8 autoFocusHandler = null;
    9 } else {
    10 Log.d(TAG, "Got auto-focus callback, but no handler for it");
    11 }
    12 }
    复制代码

        聚焦于拍照之前没有先后的逻辑关系,聚焦为了拍照更清晰。这样,关于camera取景聚焦拍照的简单过程并如上了。

        还有一个关键的点幷是回调函数。以前没有接触java代码,在看到很多接口监听处理的代码时,总是很困惑。譬如一段简单的button:

    1 private final Button.OnClickListener addCardListener = new TextView.OnClickListener() {
    2 @Override
    3 public void onClick(View v) {
    4 //在此实现button点击后的操作
    5 }
    6 };

        如上的代码实现了点击监听,通过回调函数,当有点击操作时,并执行onClick函数。这就是一个简单的回调函数的使用。

        关于回调函数请看这里,还有回调函数在android中得体现点这里
        大家的分享方便你我。

  • 相关阅读:
    android 网络请求Volley的简单使用
    数据加密,android客户端和服务器端可共用
    非常有用的GitHub链接
    android开发——Android开发中的47个小知识
    EditText禁用系统键盘,光标可以继续使用
    Android Studio 快速开发
    Android系统拍照之后回显并且获取文件路径
    Android为TV端助力 doc里面adb连接出现问题的解决方法
    Android为TV端助力 自定义view中findViewById为空的解决办法
    Android为TV端助力 VelocityTracker 速度追踪器的使用及创建
  • 原文地址:https://www.cnblogs.com/weinyzhou/p/4983455.html
Copyright © 2020-2023  润新知