57. 【Android教程】相机:Camera

相机现在已经不仅仅是手机必备神器了,甚至相机的拍照质量已经是很多人买手机的首选条件了。而对于相机而言主要有两大功能:拍照片和拍视频。Android 为此两种方式:

  • 相机 intent
  • 相机 API
    本节我们就一起来看看相机的具体用法。

1. 打开 Camera 的两大方式

目前市面上绝大多数的 Android 手机是有前后两个摄像头,当然有部分特殊机型会存在其他的情况,本节主要针对双摄像头设备做解析。
在前面有提到过,通常使用相机有两大方式:“Intent”和“API”。最大的差别就是“Intent”是跳转到系统提供的相机页面,而使用“API”是封闭在自己的 App 中使用相机。我们可以通过“Intent”直接打开系统提供的相机 Activity,在用户拍摄完成之后系统 Activity 会通知我们拍摄结果,然后拿到拍摄的图片或者视频。而直接通过 API 就需要我们去开发一整套相机的控制页面,自行完成照片 / 视频的拍摄进而直接拿到用户拍摄的结果。

2. Camera 的基本用法

我们分别看看这两种打开方式的使用方法:

2.1 使用 Intent 打开

通过使用 MediaStore 类提供的两个 Intnet 常量,可以直接将相机操作托管给 Android 系统而无需创建 Camera 实例:

  • ACTION_IMAGE_CAPTURE:
    拍摄照片
  • ACTION_VIDEO_CAPTURE:
    拍摄视频

2.2 使用 API 打开

采用 API 打开会让整个相机程序都封闭在自己的 APP 中完成,这里需要明确几个概念:

  1. Camera 类
    使用 API 之前需要创建 Camera 实例,然后通过 API 来初始化 Camera 进而拿到实时拍摄的画面

  2. SurfaceView
    用来渲染视频实时画面的 View

采用 Intent 打开相机的方法非常简单,接下来我们全程使用 Camera API 来实现一下相机功能。

3. Camera 使用示例

使用 API 来拍照会相对比较麻烦一点,首先需要获取权限,那么对于 Android 6.0 版本以上的系统除了要在 Manifest 里面加入 Camera 权限之外,还需要动态获取权限,这个可能大家在用一些比较老的教程示例时会踩坑。
获取到权限就可以打开 Camera 了,然后拿到 Camera 实例设置一个 SurfaceView 来渲染预览页面,在用户需要拍照的时候调用 Camera 的takePicture()方法获取当前帧,最后保存输出到文件中或者在新的 Activity 中展示,这样就算完成了一次拍照闭环。

3.1 Camera 拍照逻辑

首先看看整个拍照的代码如下:


package com.emercy.myapplication;import android.Manifest;
import android.app.Activity;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.hardware.Camera;
import android.os.Build;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;public class MainActivity extends Activity {public static final String CAMERA_PATH = "path";public static final String CAMERA_IMG = "img";private SurfaceView mSurfaceView;private Button mTakePhoto;private Camera mCamera = null;private SurfaceHolder.Callback mCallback = new SurfaceHolder.Callback() {@Overridepublic void surfaceCreated(SurfaceHolder holder) {startPreview();}@Overridepublic void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {}@Overridepublic void surfaceDestroyed(SurfaceHolder holder) {stopPreview();}};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);getPermission();bindViews();}/*** 获取权限*/private void getPermission() {if (Build.VERSION.SDK_INT > 22) {if (checkSelfPermission(android.Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {//先判断有没有权限 ,没有就在这里进行权限的申请requestPermissions(new String[]{Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE}, 100);} else {//说明已经获取到摄像头权限了Log.i("Camera", "已经获取了权限");}} else {//这个说明系统版本在6.0之下,不需要动态获取权限。Log.i("Camera", "这个说明系统版本在6.0之下,不需要动态获取权限。");}}private void bindViews() {mSurfaceView = (SurfaceView) findViewById(R.id.sfv_preview);mTakePhoto = (Button) findViewById(R.id.btn_take);mSurfaceView.getHolder().addCallback(mCallback);mTakePhoto.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {mCamera.takePicture(null, null, new Camera.PictureCallback() {@Overridepublic void onPictureTaken(byte[] data, Camera camera) {String path;if (TextUtils.isEmpty(path = savePhoto(data))) {Intent it = new Intent(MainActivity.this, PreviewActivity.class);it.putExtra(CAMERA_PATH, path);startActivity(it);} else {Toast.makeText(MainActivity.this, "拍照失败", Toast.LENGTH_SHORT).show();}}});}});}private String savePhoto(byte[] bytes) {try {File file = File.createTempFile(CAMERA_IMG, "");FileOutputStream fos = new FileOutputStream(file);fos.write(bytes);fos.flush();fos.close();return file.getAbsolutePath();} catch (IOException e) {e.printStackTrace();}return "";}private void startPreview() {mCamera = Camera.open();try {mCamera.setPreviewDisplay(mSurfaceView.getHolder());mCamera.setDisplayOrientation(90);   // 让相机旋转90度mCamera.startPreview();} catch (IOException e) {e.printStackTrace();}}private void stopPreview() {mCamera.stopPreview();mCamera.release();mCamera = null;}
}

里面涉及到的几个新概念大家需要注意,然后记得在SurfaceHolder.Callback()surfaceCreated()中启动预览,在surfaceDestroyed()方法中要停止预览,其他的基本上按照步骤来不会有什么问题。

3.2 相机布局

目前市面上有很多相机 App,各种布局千变万化,大家完全可以按照自己的喜好来进行设计。这里只做一个拍照预览和拍照按钮。

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><SurfaceViewandroid:id="@+id/sfv_preview"android:layout_width="match_parent"android:layout_height="match_parent" /><Buttonandroid:id="@+id/btn_take"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="bottom|center"android:text="拍照" /></FrameLayout>

3.3 照片回看页面

点击“拍照” Button 获取到当前画面之后,我们可以就可以按照自己的逻辑对图片进行操作了。比如可以通过 Http 上传、通过 Socket 发送给其他设备、保存到本地、或者传递给其他 App 等。本例子中将图片传递给另一个 Activity 专门用于查看图片,下面是 PhotoActivity 的代码:

package com.emercy.myapplication;import android.app.Activity;
import android.net.Uri;
import android.os.Bundle;
import android.widget.ImageView;import java.io.File;import static com.emercy.myapplication.MainActivity.CAMERA_PATH;public class PhotoActivity extends Activity {@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);ImageView img = new ImageView(this);String path = getIntent().getStringExtra(CAMERA_PATH);if (path != null) {img.setImageURI(Uri.fromFile(new File(path)));}setContentView(img);}
}

通过 Intent 接收图片路径,然后展示在 ImageView 上,需要注意的是PhotoActivity 中是直接将 ImageView 作为参数直接设置给了 SetContentView(),这样相当于布局文件中只有一个 ImageView 的写法。

最后别忘了在 Manifest 当中添加权限:

    <uses-permission android:name="android.permission.CAMERA"/><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

编译运行效果如下:

点击拍照进入 PhotoActivity,展示的就是我们拍照的画面。

4. 小结

本节学习了一个手机上必不可少的设备,通过相机我们可以拍摄照片或者视频,Android 系统提供了两大打开方式:Intent 调用系统相机 Activitiy或者用 Camera API 自行实现拍照功能。第一种非常简单,将所有的相机操作都托管给系统,我们只关心最终用户拍摄的结果;而第二种就需要我们自己初始化 Camera 对象从而实现拍摄,在实际开发中如果你的功能是和拍摄强相关,需要一些定制化的拍摄体验,那么一定要使用第二种方式来自己实现 Camera,但是如果你只是一个简单的拍照获取图片,那么第一种会让你事半功倍。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/836037.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C# Linq中的自定义排序

1.开发过程中&#xff0c;会遇到OrderBy/OrderByDescending排序无法满足的情况&#xff0c;此时就需要自定义排序&#xff0c;按照想要的排序规则取排序&#xff0c;比如订单的状态等等。 2.自定义泛型比较器代码如下&#xff1a; /// <summary>/// 自定义泛型比较器(用…

train_gpt2_fp32.cu - layernorm_forward_kernel3

源码 __global__ void layernorm_forward_kernel3(float* __restrict__ out, float* __restrict__ mean, float* __restrict__ rstd,const float* __restrict__ inp, const float* __restrict__ weight,const float* __restrict__ bias, int N, int C) {cg::thread_block bl…

【北京迅为】《iTOP-3588从零搭建ubuntu环境手册》-第8章 安装编译所需要的依赖包

RK3588是一款低功耗、高性能的处理器&#xff0c;适用于基于arm的PC和Edge计算设备、个人移动互联网设备等数字多媒体应用&#xff0c;RK3588支持8K视频编解码&#xff0c;内置GPU可以完全兼容OpenGLES 1.1、2.0和3.2。RK3588引入了新一代完全基于硬件的最大4800万像素ISP&…

多个文件 import 的相同模块里的对象

多个文件 import 的相同模块里的对象&#xff0c;是否永远都是同一个对象&#xff1f; 在store的index.js中 import vue from ‘vue’ import Vuex from ‘vuex’ 并配置有关对象 然后再app.vue中配置vm 在不同的文件中 import一个vue对象&#xff0c;在任何情况下&#…

vue2项目升级到vue3经历分享5

写到第5篇了&#xff0c;解决了很多问题&#xff0c;还有一些需要调整 1 el-input-number指令兼容性调整 下面这个可编辑的表格&#xff0c;全是0&#xff0c;于是需要一个指令&#xff0c;让它自己实现如果是0&#xff0c;就置空&#xff1b;如果是数字就是格式化为千分位&…

使用docker安装seafile

使用docker安装seafile 1 介绍seafile Seafile 是一款开源的企业云盘&#xff0c;支持全平台&#xff08;浏览器、Windows、Mac、Linux、Android、IPhone等&#xff09;客户端。Seafile 内置协同文档 SeaDoc &#xff0c;让协作撰写、管理和发布文档更便捷。最重要的这是国产…

【网站项目】SpringBoot796水产养殖系统

&#x1f64a;作者简介&#xff1a;拥有多年开发工作经验&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。&#x1f339;赠送计算机毕业设计600个选题excel文件&#xff0c;帮助大学选题。赠送开题报告模板&#xff…

【JavaEE初阶系列】——Cookie和Session应用之实现登录页面

目录 &#x1f6a9;本章目标 1.登录页面 2.servlet处理上述的登录请求 3.网站主页(成功登录之后的页面&#xff09; &#x1f6a9;实现过程 &#x1f393;登录页面 &#x1f393;Servlet处理登录请求 &#x1f388;获取请求传来的参数(用户名和密码) &#x1f388;验证…

一件事做了十年

目录 一、背景二、过程1.贫困山区的心理悲哀2.基础差的客观转变3.对于教育的思考4.持续做这件事在路上5.同行人有很早就完成的&#xff0c;有逐渐放弃的&#xff0c;你应该怎么办&#xff1f;6.回头看&#xff0c;什么才是最终留下的东西? 三、总结 一、背景 在哪里出生我们无…

《Linux运维总结:ARM64架构CPU基于docker-compose一离线部署rabbitmq 3.10.25容器版镜像模式集群》

总结&#xff1a;整理不易&#xff0c;如果对你有帮助&#xff0c;可否点赞关注一下&#xff1f; 更多详细内容请参考&#xff1a;《Linux运维篇&#xff1a;Linux系统运维指南》 一、部署背景 由于业务系统的特殊性&#xff0c;我们需要面向不通的客户安装我们的业务系统&…

【ubuntu】ubuntu-18.04开机卡在Starting User Manager for UID 120....问题解决方案

错误截图 解决方案 启动系统&#xff0c;开机界面单击按键esc键&#xff0c;注意需要将鼠标定位到菜单界面&#xff0c;移动键盘上下键选择Advanced options for Ubuntu 进入如下菜单&#xff0c;选择recovery mode 回车之后会弹出如下界面&#xff0c;选择如下root&#xff0…

超详细的胎教级Stable Diffusion使用教程(四)

这套课程分为五节课&#xff0c;会系统性的介绍sd的全部功能和实操案例&#xff0c;让你打下坚实牢靠的基础 一、为什么要学Stable Diffusion&#xff0c;它究竟有多强大&#xff1f; 二、三分钟教你装好Stable Diffusion 三、小白快速上手Stable Diffusion 四、Stable dif…

【C语言/Python】嵌入式常用数据滤波处理:卡尔曼滤波器的简易实现方式(Kalman Filter)

【C语言/Python】嵌入式常用数据滤波处理&#xff1a;卡尔曼滤波器的简易实现方式&#xff08;Kalman Filter&#xff09; 文章目录 卡尔曼滤波卡尔曼滤波公式卡尔曼滤波数据处理效果C语言的卡尔曼滤波实现附录&#xff1a;压缩字符串、大小端格式转换压缩字符串浮点数压缩Pack…

Spring-Cloud-OpenFeign源码解析-01-OpenFeign简介

OpenFeign简介 OpenFeign是一种声明式、模板化的HTTP客户端(仅在Application Client中使用)。声明式调用是指&#xff0c;就像调用本地方法一样调用远程方法&#xff0c;无需感知操作远程http请求。 OpenFeign和Feign的区别 Feign是Spring Cloud组件中一个轻量级RESTful的HT…

亚信安全发布《2024年第一季度网络安全威胁报告》

亚信安全2024年第一季度网络安全威胁报告 一季度威胁概览 《亚信安全2024年第一季度网络安全威胁报告》的发布旨在从一个全面的视角解析当前的网络安全威胁环境。此报告通过详尽梳理和总结2024年第一季度的网络攻击威胁&#xff0c;目的是提供一个准确和直观的终端威胁感知。…

LNMP环境部署WordPress——使用源码包安装方式部署环境

目录 一.前提准备 二.源码安装Mysql 1.MySQL类型 2.MySQL 版本说明 3.MySQL 安装方式 3.1 yum 安装 3.2 编译安装 3.3 二进制安装 3.4 rpm 安装 4. 编译安装MySQL5.7 4.1 清理安装环境 4.2 创建mysql用户 4.3 从官网下载tar包 4.4 安装编译工具 4.5 解压 4.6 …

【教学类-55-01】20240511图层顺序挑战(四格长条纸)(4*4)和“手工纸自制参考图”

作品展示 背景需求 空间思维图层挑战2|逻辑推理|空间想象力 - 小红书 (xiaohongshu.com)https://www.xiaohongshu.com/discovery/item/62cbf6c60000000010026aa0?app_platformandroid&ignoreEngagetrue&app_version8.35.0&share_from_user_hiddentrue&typevi…

Django项目运行报错:ModuleNotFoundError: No module named ‘MySQLdb‘

解决方法&#xff1a; 在__init__.py文件下&#xff0c;新增下面这段代码 import pymysql pymysql.install_as_MySQLdb() 注意&#xff1a;确保你的 python 有下载 pymysql 库&#xff0c;没有的话可以使用 pip install pymysql安装 原理&#xff1a;用pymysql来代替mysqlL…

探索人类意识的多样性:从安全感到语感、节奏感的差异

在我们的日常生活中&#xff0c;人类意识表现出多种多样的特点&#xff0c;这些特点往往与个体的天生禀赋和生活经历密切相关。从安全感到语感、节奏感&#xff0c;每个人的表现都有所不同。今天&#xff0c;让我们一起来探索这些差异&#xff0c;感受人类意识的多样性。 首先&…

stable diffusion WebUi本地安装

一、stable diffusion 介绍 Stable Diffusion是一种先进的文本到图像的生成模型&#xff0c;它可以根据给定的文本输入生成高度逼真的图像。 Stable Diffusion模型因其高效性和灵活性&#xff0c;在AI图像生成领域引起了广泛关注&#xff0c;并在实际应用中展示了其强大的能力…