57. 【Android教程】相机:Camera

2024-05-09 04:44
文章标签 android 教程 相机 camera 57

本文主要是介绍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,但是如果你只是一个简单的拍照获取图片,那么第一种会让你事半功倍。

这篇关于57. 【Android教程】相机:Camera的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/972426

相关文章

windos server2022的配置故障转移服务的图文教程

《windosserver2022的配置故障转移服务的图文教程》本文主要介绍了windosserver2022的配置故障转移服务的图文教程,以确保服务和应用程序的连续性和可用性,文中通过图文介绍的非... 目录准备环境:步骤故障转移群集是 Windows Server 2022 中提供的一种功能,用于在多个

龙蜥操作系统Anolis OS-23.x安装配置图解教程(保姆级)

《龙蜥操作系统AnolisOS-23.x安装配置图解教程(保姆级)》:本文主要介绍了安装和配置AnolisOS23.2系统,包括分区、软件选择、设置root密码、网络配置、主机名设置和禁用SELinux的步骤,详细内容请阅读本文,希望能对你有所帮助... ‌AnolisOS‌是由阿里云推出的开源操作系统,旨

PyTorch使用教程之Tensor包详解

《PyTorch使用教程之Tensor包详解》这篇文章介绍了PyTorch中的张量(Tensor)数据结构,包括张量的数据类型、初始化、常用操作、属性等,张量是PyTorch框架中的核心数据结构,支持... 目录1、张量Tensor2、数据类型3、初始化(构造张量)4、常用操作5、常用属性5.1 存储(st

Java操作PDF文件实现签订电子合同详细教程

《Java操作PDF文件实现签订电子合同详细教程》:本文主要介绍如何在PDF中加入电子签章与电子签名的过程,包括编写Word文件、生成PDF、为PDF格式做表单、为表单赋值、生成文档以及上传到OB... 目录前言:先看效果:1.编写word文件1.2然后生成PDF格式进行保存1.3我这里是将文件保存到本地后

windows系统下shutdown重启关机命令超详细教程

《windows系统下shutdown重启关机命令超详细教程》shutdown命令是一个强大的工具,允许你通过命令行快速完成关机、重启或注销操作,本文将为你详细解析shutdown命令的使用方法,并提... 目录一、shutdown 命令简介二、shutdown 命令的基本用法三、远程关机与重启四、实际应用

python库fire使用教程

《python库fire使用教程》本文主要介绍了python库fire使用教程,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录1.简介2. fire安装3. fire使用示例1.简介目前python命令行解析库用过的有:ar

LinuxMint怎么安装? Linux Mint22下载安装图文教程

《LinuxMint怎么安装?LinuxMint22下载安装图文教程》LinuxMint22发布以后,有很多新功能,很多朋友想要下载并安装,该怎么操作呢?下面我们就来看看详细安装指南... linux Mint 是一款基于 Ubuntu 的流行发行版,凭借其现代、精致、易于使用的特性,深受小伙伴们所喜爱。对

使用Nginx来共享文件的详细教程

《使用Nginx来共享文件的详细教程》有时我们想共享电脑上的某些文件,一个比较方便的做法是,开一个HTTP服务,指向文件所在的目录,这次我们用nginx来实现这个需求,本文将通过代码示例一步步教你使用... 在本教程中,我们将向您展示如何使用开源 Web 服务器 Nginx 设置文件共享服务器步骤 0 —

Golang使用minio替代文件系统的实战教程

《Golang使用minio替代文件系统的实战教程》本文讨论项目开发中直接文件系统的限制或不足,接着介绍Minio对象存储的优势,同时给出Golang的实际示例代码,包括初始化客户端、读取minio对... 目录文件系统 vs Minio文件系统不足:对象存储:miniogolang连接Minio配置Min

Android数据库Room的实际使用过程总结

《Android数据库Room的实际使用过程总结》这篇文章主要给大家介绍了关于Android数据库Room的实际使用过程,详细介绍了如何创建实体类、数据访问对象(DAO)和数据库抽象类,需要的朋友可以... 目录前言一、Room的基本使用1.项目配置2.创建实体类(Entity)3.创建数据访问对象(DAO