android中,通过相机获取预览界面的需求似乎很变态,好像也没有什么使用场景。但是,有一个场景需要获取预览界面的图像,就是扫码,比如微信,支付宝的扫一扫,就是需要获取预览界面的图像数据的。

实现逻辑比较简单,不过肯定比打开系统相机要麻烦一点的。

下面简单说一下实现步骤:

  1. 实例化一个SurfaceView
  2. surfaceCreated()回调中去实例化Camera对象,去自动对焦。
  3. onAutoFocus()回调中去调用camera.takePicture(null,null,callback);
  4. 在第3步的callback里面去获取预览图像数据int data[]
  5. (可选)将获取的数据换成成文件。
  6. (可选)将该文件对象加载成bitmap对象。
  7. 在不使用的使用释放相机资源。

代码细节:

  1. 清单文件:
    <uses-feature android:name="android.hardware.camera" /><uses-feature android:name="android.hardware.camera.autofocus" /><uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /><uses-permission android:name="android.permission.CAMERA" /><uses-permission android:name="android.permission.RECORD_AUDIO" />
  1. java代码:
package com.python.cat.testgradle;import android.Manifest;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.hardware.Camera;
import android.os.Bundle;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.Toast;import com.apkfuns.logutils.LogUtils;
import com.google.zxing.BinaryBitmap;
import com.google.zxing.ChecksumException;
import com.google.zxing.FormatException;
import com.google.zxing.NotFoundException;
import com.google.zxing.RGBLuminanceSource;
import com.google.zxing.Result;
import com.google.zxing.common.GlobalHistogramBinarizer;
import com.google.zxing.qrcode.QRCodeReader;
import com.yanzhenjie.permission.Action;
import com.yanzhenjie.permission.AndPermission;import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;public class UseCameraActivity extends Activity {private Activity get() {return this;}@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_asome);setTitle(getClass().getSimpleName());final FrameLayout frameLayout = findViewById(R.id.prev_content_layout);Button btn = findViewById(R.id.start_camera_preview);btn.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {AndPermission.with(get()).permission(Manifest.permission.CAMERA,Manifest.permission.WRITE_EXTERNAL_STORAGE).onDenied(new Action() {@Overridepublic void onAction(List<String> permissions) {LogUtils.e("error....." + permissions);}}).onGranted(new Action() {@Overridepublic void onAction(List<String> permissions) {LogUtils.w("you can do..");ScanView scanView = new ScanView(get());frameLayout.removeAllViews();frameLayout.addView(scanView);}}).start();}});}static class ScanView extends SurfaceView implements SurfaceHolder.Callback,Camera.AutoFocusCallback {private Camera mCamera;private final File fileImg;private ScanView self;public ScanView(Context context) {super(context);fileImg = new File(context.getCacheDir(), "prev_view.jpg");SurfaceHolder mHolder = getHolder();self = this;mHolder.addCallback(this);// deprecated setting, but required on Android versions prior to 3.0mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);}@Overridepublic void onAutoFocus(boolean success, Camera camera) {LogUtils.w("auto focus..." + success);if (mCamera != null) {mCamera.takePicture(null, null, null, new Camera.PictureCallback() {@Overridepublic void onPictureTaken(byte[] data, Camera camera) {mCamera.cancelAutoFocus();mCamera.stopPreview(); // 拿到数据就停止!!!LogUtils.w("========data========");LogUtils.w("----------data-----------------");
//                        camera.startPreview();File pictureFile = fileImg;if (pictureFile == null) {LogUtils.e("Error creating media file, check storage permissions: " +null);return;}if (data == null) {return;}try {LogUtils.d(data);FileOutputStream fos = new FileOutputStream(pictureFile);fos.write(data);fos.close();LogUtils.e("save preview complete###!!!");LogUtils.e("save preview complete###!!!" + pictureFile);BitmapFactory.Options options = new BitmapFactory.Options();options.inJustDecodeBounds = true;BitmapFactory.decodeFile(pictureFile.getAbsolutePath(), options);options.inJustDecodeBounds = false;int outWidth = options.outWidth;int outHeight = options.outHeight;if (outWidth >= getWidth() * 2) {options.inSampleSize = outWidth / getWidth();}if (outHeight >= getHeight() * 2) {options.inSampleSize = outHeight / getHeight();}Bitmap bmp = BitmapFactory.decodeFile(pictureFile.getAbsolutePath(), options);Result result = parseInfoFromBitmap(bmp);if (result != null) {Toast.makeText(getContext(), "INFO:" + result.getText(), Toast.LENGTH_SHORT).show();LogUtils.w("解析成功:" + result);} else {LogUtils.e("再次尝试中....");mCamera.startPreview();mCamera.autoFocus(self);// todo:这里也可以做最大重试次数的限制...}} catch (Exception e) {LogUtils.e("Error accessing file: " + e.getMessage());}}});}}public Result parseInfoFromBitmap(Bitmap bitmap) {int[] pixels = new int[bitmap.getWidth() * bitmap.getHeight()];bitmap.getPixels(pixels, 0, bitmap.getWidth(), 0, 0, bitmap.getWidth(), bitmap.getHeight());LogUtils.w("### pixels dest==" + Arrays.toString(pixels));RGBLuminanceSource source = new RGBLuminanceSource(bitmap.getWidth(),bitmap.getHeight(), pixels);GlobalHistogramBinarizer binarizer = new GlobalHistogramBinarizer(source);BinaryBitmap image = new BinaryBitmap(binarizer);Result result = null;try {result = new QRCodeReader().decode(image);return result;} catch (NotFoundException e) {e.printStackTrace();Toast.makeText(getContext(), "非二维码图片,不能解析", Toast.LENGTH_SHORT).show();} catch (ChecksumException e) {e.printStackTrace();} catch (FormatException e) {e.printStackTrace();}return null;}@Overridepublic void surfaceCreated(SurfaceHolder holder) {LogUtils.e("x surfaceCreated.. #####");try {mCamera = Camera.open();mCamera.setPreviewDisplay(holder);mCamera.setDisplayOrientation(90);Camera.Parameters parameters = mCamera.getParameters();
//                parameters.setPictureSize(1600, 1200);
//                parameters.setPreviewSize(640, 480);mCamera.setParameters(parameters);mCamera.startPreview();mCamera.autoFocus(this);LogUtils.e("surfaceCreated.. #####");} catch (IOException e) {LogUtils.e("Error setting camera preview: " + e.getMessage());}}@Overridepublic void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {LogUtils.w("--change-");}@Overridepublic void surfaceDestroyed(SurfaceHolder holder) {LogUtils.w("destroy--");if (mCamera != null) {mCamera.cancelAutoFocus();mCamera.stopPreview();mCamera.release();}}}
}
  1. 布局文件:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".UseCameraActivity"><Button
        android:id="@+id/start_camera_preview"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignParentBottom="true"android:text="@string/start_camera_preview" /><FrameLayout
        android:id="@+id/prev_content_layout"android:layout_width="match_parent"android:layout_height="match_parent"android:layout_above="@id/start_camera_preview"></FrameLayout>
</RelativeLayout>
  1. gradle配置(可选):
implementation 'com.yanzhenjie:permission:2.0.0-rc4' // 运行时权限语法糖
implementation 'com.google.zxing:core:3.3.1' // zxing 解析二维码图片

嗯,以上就是获取相机预览图像数据的代码了。不过,这里用的Camera接口是过时的了,不建议使用。不过可以运行。我目前的compileSdkVersion=26

就酱咯。 完整app代码也许有的吧。

=======

update: 关于Camera2,我选择放弃….

官方的说法是:

The android.hardware.camera2 package provides an interface to individual camera devices connected to an Android device. It replaces the deprecated Camera class.

This package models a camera device as a pipeline, which takes in input requests for capturing a single frame, captures the single image per the request, and then outputs one capture result metadata packet, plus a set of output image buffers for the request. The requests are processed in-order, and multiple requests can be in flight at once. Since the camera device is a pipeline with multiple stages, having multiple requests in flight is required to maintain full framerate on most Android devices.

反正是看懂了一句话,就是用来替代Camera的。

但是,真的很麻烦。我没有找到中文的,可以直接运行的案例,找到了两个外国人写的博客,里面给了完整的代码。不过估计不能直接访问。我把拷贝到我的项目里面去了。可以直接运行

完整app代码
因为每一篇代码都很长,我就不贴出来了,说一下路径。

  1. com.python.cat.testgradle.MainActivity.java[由于这个原始代码没有加动态权限申请,我手动添加了一下…]

  2. com.python.cat.testgradle.AndroidCameraApi.java
    我给的是我代码的路径,以及原始链接。


不清楚是出于什么考虑,camera2里面比camera多了好几类,复杂度也提升了不少。有需要的可以研究一下。上手难度大于camera。(目前我还是一头雾水,对于camera2)。

中文的找到一个:这个我并没有去下载运行验证,不过看博客里面写的挺多的。

android 使用 surfaceView 获取 camera 预览界面图像数据相关推荐

  1. Android stdio 实时获取相机预览图像(详细)

    activity_main.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout ...

  2. RK平台5640 camera预览界面帧率过低的分析

    hal 层 /hardware/rockchip/camera ├── AAL Android Abstraction Layer, 负责与 framework 交互 ├── common 公用文件, ...

  3. Camera2 打开相机预览界面

    camera2 是21之后的api用于代替Camera,提供更加牛X的对相机hardware操作的api 参考资料:http://www.jcodecraeer.com/a/anzhuokaifa/a ...

  4. android预览界面显示不全,Android SurfaceView Camera 预览显示不全(画面拉伸)

    释放双眼,带上耳机,听听看~! 项目当中遇到调整摄像头位置需要全屏显示摄像头预览界面,过程中发现预览界面存在无法显示全,画面被拉伸的问题.surfaceview的宽高比可能与camera设置的宽高比不 ...

  5. Android摄像头:只拍摄SurfaceView预览界面特定区域内容(矩形框)---完整实现(原理:底层SurfaceView+上层绘制ImageView)

    [后注:]下载代码的注意,我的手机是4.3寸的屏,华为U9200.如果不能运行的请修改参数.看前文的第四条.Y的,省的说我传的代码不能用  最近一直在审视以前做过的东西,关于android摄像头预览, ...

  6. Android摄像头 只拍摄SurfaceView预览界面特定区域内容(矩形框)---完整实现(原理 底层Surface

    [后注:]下载代码的注意,我的手机是4.3寸的屏,华为U9200.如果不能运行的请修改参数.看前文的第四条.Y的,省的说我传的代码不能用  最近一直在审视以前做过的东西,关于android摄像头预览, ...

  7. Android摄像头:只拍摄SurfaceView预览界面特定区域内容(矩形框)---完整(原理:底层SurfaceView+上层绘制ImageView)...

    Android摄像头:只拍摄SurfaceView预览界面特定区域内容(矩形框)---完整实现(原理:底层SurfaceView+上层绘制ImageView) 分类: Android开发 Androi ...

  8. android camera surfaceview 变形,使用Camera预览显示变形问题

    本人使用Camera显示预览图竖屏显示会有一些拉伸.感觉被拉长了. 本人已经选择了最接近的比例了,但是还是有拉伸. package com.example.zxing_android; import  ...

  9. 【流媒體】Android 实时视频采集—Camera预览采集

    [流媒體]Android 实时视频采集-Cameara预览采集 SkySeraph Mar 26th 2012  SZ Email:skyseraph00@163.com 更多精彩请直接访问SkySe ...

最新文章

  1. Windows下Python安装及pycharm,pip下载和安装第三方库
  2. [系统安全] 九.Windows漏洞利用之MS08-067远程代码执行漏洞复现及深度防御
  3. java 观察者模式_Java技术干货分享:深入理解观察者模式原理与技术
  4. namenode单节点解决方案
  5. 两年盗取 1000 万美元的 Xbox 礼品卡,这个人竟然是“内鬼”!
  6. python安装失败未指定_windows 7 32bit安装 python3.5.0 安装错误 0x80240017 -未指定错误...
  7. 【Java】 Java反射机制总结
  8. 富国基金:基金公司是如何进行数据架构规划与实践的
  9. 内网渗透学习-Windows信息收集
  10. 联想拯救者y9000k和y9000p的区别
  11. 51单片机控制的自动感应调光、坐姿矫正智能台灯
  12. IDEA报错:不支持发行版本
  13. Linux中如何新建用户
  14. 92.【SpringCloud NetFilx】
  15. axure9总是崩_axure9为何用着特别卡?
  16. 评估指标(Metric)(二)
  17. canvas动画效果之星球守护
  18. PFsense-tcp连接数相关配置优化
  19. 加了@CrossOrigin ,仍然报跨域错误
  20. linux之文件管理

热门文章

  1. 期市财盛:9月18日恒指/黄金/原油行情交易及布局
  2. JavaMail发送邮件到qq邮箱的过程中遇到的问题及解决办法
  3. JavaScript随机数(random)
  4. 搜索“无聊”的人激增3倍,自我隔离的网民有多空虚
  5. 新乡医学院2018计算机考试题,新乡医学院关于做好2018-2019学年第一学期本科学生期末考核工作的通知...
  6. 量子计算 5 量子货币
  7. otnm2000启动mysql服务_烽火OTN设备开通初始化指导手册.pdf
  8. springboot集成elasticsearch7.17.3
  9. android surface使用教程,Android:SurfaceView 的使用(附代码模板)
  10. 51单片机定时器及其应用(1)(时钟功能)