安卓利用CameraX 拍照获这张照片的exif信息

一、首先导入相关权限

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /><uses-featureandroid:name="android.hardware.camera"android:required="true" /><uses-permission android:name="android.permission.CAMERA" /><!--  这个权限允许应用程序录制音频。  --><uses-permission android:name="android.permission.RECORD_AUDIO" />

二、导入依赖

// CameraX 相关依赖def cameraxVersion = "1.1.0-alpha05"implementation "androidx.camera:camera-core:${cameraxVersion}"implementation "androidx.camera:camera-camera2:${cameraxVersion}"implementation "androidx.camera:camera-lifecycle:${cameraxVersion}"implementation 'androidx.camera:camera-view:1.0.0-alpha25'

三、Activity

import android.Manifest;
import android.annotation.SuppressLint;
import android.content.ContentValues;
import android.content.pm.PackageManager;
import android.media.ExifInterface;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.camera.core.CameraSelector;
import androidx.camera.core.ImageCapture;
import androidx.camera.core.ImageCaptureException;
import androidx.camera.core.Preview;
import androidx.camera.core.VideoCapture;
import androidx.camera.lifecycle.ProcessCameraProvider;
import androidx.camera.view.PreviewView;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;import com.google.common.util.concurrent.ListenableFuture;import org.json.JSONException;
import org.json.JSONObject;import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;public class MainActivity extends AppCompatActivity implements View.OnClickListener {private static final int REQUEST_CODE_RECORD_AUDIO_PERMISSION = 1001;private static final int REQUEST_CODE_CAMERA_PERMISSION = 1002;private static final int REQUEST_CODE_STORAGE_PERMISSION = 1003;private ListenableFuture<ProcessCameraProvider> processCameraProviderListenableFuture;private PreviewView previewView;private Button btn_photograph; //拍照private ImageCapture imageCapture;private CameraSelector cameraSelector;private TextView tv;private boolean isUsingFrontCamera = false; // 默认使用前置摄像头@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);previewView = findViewById(R.id.previewView);btn_photograph = findViewById(R.id.btn_photograph);tv = findViewById(R.id.tv);btn_photograph.setOnClickListener(this);// 检查权限if (ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED ||ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED ||ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.RECORD_AUDIO, Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_CODE_RECORD_AUDIO_PERMISSION);} else {initializeCamera();}}// 初始化相机private void initializeCamera() {processCameraProviderListenableFuture = ProcessCameraProvider.getInstance(this);processCameraProviderListenableFuture.addListener(() -> {try {ProcessCameraProvider processCameraProvider = processCameraProviderListenableFuture.get();start(processCameraProvider);} catch (Exception e) {throw new RuntimeException(e);}}, ContextCompat.getMainExecutor(this));}@SuppressLint("RestrictedApi")private void start(ProcessCameraProvider processCameraProvider) {processCameraProvider.unbindAll();cameraSelector = new CameraSelector.Builder().requireLensFacing(isUsingFrontCamera ? CameraSelector.LENS_FACING_FRONT : CameraSelector.LENS_FACING_BACK).build();Preview preview = new Preview.Builder().build();preview.setSurfaceProvider(previewView.getSurfaceProvider());imageCapture = new ImageCapture.Builder().setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY).build();processCameraProvider.bindToLifecycle(this, cameraSelector, preview, imageCapture);}@SuppressLint("RestrictedApi")@Overridepublic void onClick(View view) {if (view.getId() == R.id.btn_photograph) {captureImage();}}// 拍照private void captureImage() {long timeStamp = System.currentTimeMillis();ContentValues contentValues = new ContentValues();contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, timeStamp);contentValues.put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg");imageCapture.takePicture(new ImageCapture.OutputFileOptions.Builder(getContentResolver(),MediaStore.Images.Media.EXTERNAL_CONTENT_URI,contentValues).build(),ContextCompat.getMainExecutor(this),new ImageCapture.OnImageSavedCallback() {@Overridepublic void onImageSaved(@NonNull ImageCapture.OutputFileResults outputFileResults) {Toast.makeText(MainActivity.this, "拍照保存成功", Toast.LENGTH_SHORT).show();Uri savedUri = outputFileResults.getSavedUri();if (savedUri != null) {try {InputStream inputStream = getContentResolver().openInputStream(savedUri); // 打开输入流if (inputStream != null) {ExifInterface exifInterface = new ExifInterface(inputStream); // 创建ExifInterface对象String datetime = exifInterface.getAttribute(ExifInterface.TAG_DATETIME); // 获取拍摄时间String make = exifInterface.getAttribute(ExifInterface.TAG_MAKE); // 获取相机制造商String model = exifInterface.getAttribute(ExifInterface.TAG_MODEL); // 获取相机型号String focalLength = exifInterface.getAttribute(ExifInterface.TAG_FOCAL_LENGTH); // 获取焦距String aperture = exifInterface.getAttribute(ExifInterface.TAG_APERTURE); // 获取光圈Log.d("EXIF Info", "获取拍摄时间: " + datetime);Log.d("EXIF Info", "获取相机制造商: " + make);Log.d("EXIF Info", "获取相机型号: " + model);Log.d("EXIF Info", "获取焦距: " + focalLength);Log.d("EXIF Info", " 获取光圈: " + aperture);tv.setText("获取拍摄时间: " + datetime+"\n"+"获取相机制造商: " + make+"\n"+"获取相机型号: " + model+"\n"+"获取焦距: " + focalLength+"\n"+" 获取光圈: " + aperture);inputStream.close(); // 关闭输入流}} catch (IOException e) {e.printStackTrace();}}}@Overridepublic void onError(@NonNull ImageCaptureException exception) {Toast.makeText(MainActivity.this, "拍照保存失败: " + exception.getMessage(), Toast.LENGTH_SHORT).show();}});}@Overridepublic void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {super.onRequestPermissionsResult(requestCode, permissions, grantResults);if (requestCode == REQUEST_CODE_RECORD_AUDIO_PERMISSION) {for (int i = 0; i < permissions.length; i++) {if (permissions[i].equals(Manifest.permission.RECORD_AUDIO) && grantResults[i] == PackageManager.PERMISSION_GRANTED) {// 录音权限已授予if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED ||ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_CODE_CAMERA_PERMISSION);} else {initializeCamera();}} else if (permissions[i].equals(Manifest.permission.RECORD_AUDIO) && grantResults[i] != PackageManager.PERMISSION_GRANTED) {Toast.makeText(this, "录音权限被拒绝", Toast.LENGTH_SHORT).show();}}} else if (requestCode == REQUEST_CODE_CAMERA_PERMISSION) {for (int i = 0; i < permissions.length; i++) {if ((permissions[i].equals(Manifest.permission.CAMERA) || permissions[i].equals(Manifest.permission.WRITE_EXTERNAL_STORAGE)) &&grantResults[i] != PackageManager.PERMISSION_GRANTED) {Toast.makeText(this, "相机或存储权限被拒绝", Toast.LENGTH_SHORT).show();}}}}
}

注意:这点只是简单获取 ,想要获取更多信息,可以自行修改

四、布局代码

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:divider="@color/black"android:orientation="vertical"tools:context=".MainActivity"><androidx.camera.view.PreviewViewandroid:id="@+id/previewView"android:layout_width="match_parent"android:layout_height="200dp"/><Buttonandroid:id="@+id/btn_photograph"android:layout_width="match_parent"android:layout_height="100dp"android:text="拍照" /><TextViewandroid:id="@+id/tv"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="111"/></LinearLayout>

效果图

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

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

相关文章

蓝桥杯练习题总结(三)线性dp题(摆花、数字三角形加强版)

目录 一、摆花 思路一&#xff1a; 确定状态&#xff1a; 初始化&#xff1a; 思路二&#xff1a; 确定状态&#xff1a; 初始化&#xff1a; 循环遍历&#xff1a; 状态转移方程&#xff1a; 二、数字三角形加强版 一、摆花 题目描述 小明的花店新开张&#xff0c;为了吸…

Uni-app/Vue/Js本地模糊查询,匹配所有字段includes和some方法结合使用e

天梦星服务平台 (tmxkj.top)https://tmxkj.top/#/ 1.第一步 需要一个数组数据 {"week": "全部","hOutName": null,"weekendPrice": null,"channel": "门市价","hOutId": 98,"cTime": "…

【Redis】Redis 内存管理,Redis事务,bigkey和hotkey

目录 Redis 内存管理 缓存数据设置过期时间&#xff1f; Redis 是如何判断数据是否过期的呢&#xff1f; 过期删除策略 内存淘汰机制 主从模式下对过期键的处理&#xff1f; LRU和LFU的区别 Redis事务 定义和原理 Redis 事务的注意点&#xff1f; 为什么不支持回滚&a…

SQLite数据库文件损坏的可能几种情况(一)

返回&#xff1a;SQLite—系列文章目录 上一篇&#xff1a;SQLiteC/C接口详细介绍sqlite3_stmt类&#xff08;十三&#xff09; 下一篇&#xff1a;SQLite使用的临时文件&#xff08;二&#xff09; 概述 SQLite数据库具有很强的抗损坏能力。如果应用程序崩溃&#xff0c…

指针数组的有趣程序【C语言】

文章目录 指针数组的有趣程序指针数组是什么&#xff1f;指针数组的魅力指针数组的应用示例&#xff1a;命令行计算器有趣的颜色打印 结语 指针数组的有趣程序 在C语言的世界里&#xff0c;指针是一种强大的工具&#xff0c;它不仅能够指向变量&#xff0c;还能指向数组&#…

HBase Shell基本操作

一、进入Hbase Shell客户端 先在Linux Shell命令行终端执行start-dfs.sh脚本启动HDFS&#xff0c;再执行start-hbase.sh脚本启动HBase。如果Linux系统已配置HBase环境变量&#xff0c;可直接在任意目录下执行hbase shell脚本命令&#xff0c;就可进入HBase Shell的命令行终端环…

Unity Mobile Notifications推送问题

1.在部分机型点击通知弹窗进不去游戏 把这里改成自己的Activity 2.推送的时候没有横幅跟icon红点 主要是第一句话 注册的时候选项可以选择 defaultNotificationChannel new AndroidNotificationChannel(“default_channel”, “Default Channel”, “For Generic notifica…

LinkedIn 互联网架构扩展简史

LinkedIn成立于 2003 年&#xff0c;其目标是连接到您的网络以获得更好的工作机会。第一周只有 2,700 名会员。时间快进了很多年&#xff0c;LinkedIn 的产品组合、会员基础和服务器负载都取得了巨大的增长。 如今&#xff0c;LinkedIn 在全球运营&#xff0c;拥有超过 3.5 亿会…

今日AI热点:科技前沿新动态

引言&#xff1a; 人工智能领域日新月异&#xff0c;每天都有令人振奋的新进展。从苹果到谷歌&#xff0c;从OpenAI到Meta&#xff0c;各大科技巨头纷纷推出创新产品和技术&#xff0c;不断推动着人工智能的发展。让我们一起来看看今日AI热点&#xff0c;探索这个充满活力和激情…

C++从入门到精通——命名空间

命名空间 前言一、命名空间引例什么是命名空间 二、命名空间定义正常的命名空间定义嵌套的命名空间多个相同名称的命名空间 三、命名空间使用加命名空间名称及作用域限定符使用using将命名空间中某个成员引入使用using namespace 命名空间名称引用引用命名空间和引用头文件有什…

Mac安装minio

Mac安装minio 本文介绍使用 mac 安装 MinIO。 所有软件安装优先参考官网&#xff1a;MinIO Object Storage for MacOS — MinIO Object Storage for MacOS #使用 brew 安装 minio brew install minio/stable/minio#找到 minio tong ~ $ brew list minio /opt/homebrew/Cella…

【ssh连接】奇奇怪怪报错记录

gitlab配置ssh连接&#xff0c;先跟着教程生成密钥&#xff0c;上传公钥&#xff0c;将服务器信息存入config文件&#xff0c;但是ssh连接超时&#xff0c;很急&#xff0c;想用服务器&#xff0c;各种搜索尝试&#xff0c;搞了两三天别的什么都没干&#xff0c;还是没解决&…

深度学习pytorch——激活函数损失函数(持续更新)

论生物神经元与神经网络中的神经元联系——为什么使用激活函数&#xff1f; 我们将生物体中的神经元与神经网络中的神经元共同分析。从下图可以看出神经网络中的神经元与生物体中的神经元有很多相似之处&#xff0c;由于只有刺激达到一定的程度人体才可以感受到刺激&#xff0c…

硬件6、AD设计PcbLib之引脚间如何设置距离及设置PCB元器件丝印

设置引脚间的距离 一个器件有两个引脚&#xff0c;在制作这个器件的pcblib时&#xff0c;需要设置两个引脚之间的距离 1、先选中其中一个引脚 2、然后拖动至两个引脚重叠 3、按下M键&#xff0c;通过X&#xff0c;Y移动选中对象 4、输入两个引脚中心点之间的距离 5、然后两…

【随笔】Git -- 基本概念和使用方式(五)

&#x1f48c; 所属专栏&#xff1a;【Git】 &#x1f600; 作  者&#xff1a;我是夜阑的狗&#x1f436; &#x1f680; 个人简介&#xff1a;一个正在努力学技术的CV工程师&#xff0c;专注基础和实战分享 &#xff0c;欢迎咨询&#xff01; &#x1f496; 欢迎大…

排序C++

题目 法1 sort升序排序&#xff0c;再逆序输出 #include<iostream> #include<algorithm> using namespace std;const int N 5e53;//注意const&#xff0c;全局 int a[N]; int main() {//错误int N5e53;//错误const int a[N];int n;cin >> n;for (int i 1;…

水电站生态流量监测解决方案:亲历水电站生态监控改造

​记得那是在2022年夏天,我所在的环保咨询公司接到了一项非常具有挑战性的监测项目。某省的环保部门要求对辖区内所有水电站的生态流量情况进行评估,并给出整改建议。作为项目负责人,我深知这项工作的重要意义。&#xff08;选自&#xff1a;智慧水务数字孪生安全监测解决方案提…

正式发布:VitePress 1.0 现代化静态站点生成器!

大家好&#xff0c;我是奇兵&#xff0c;今天介绍一下现代化静态站点生成器!&#xff0c;希望能帮到大家。 3 月 21 日&#xff0c; 由 Vue 团队出品的现代化静态站点生成器 VitePress 正式发布 1.0 版本&#xff01;它专为构建快速、以内容为中心的网站而生&#xff0c;能够轻…

Wagtail-基于Python Django的内容管理系统CMS实现公网访问

目录 前言 1. 安装并运行Wagtail 1.1 创建并激活虚拟环境 2. 安装cpolar内网穿透工具 3. 实现Wagtail公网访问 4. 固定Wagtail公网地址 前言 Wagtail是一个用Python编写的开源CMS&#xff0c;建立在Django Web框架上。Wagtail 是一个基于 Django 的开源内容管理系统&…

python知识点总结(十)

python知识点总结十 1、装饰器的理解、并实现一个计时器记录执行性能&#xff0c;并且将执行结果写入日志文件中2、队列和栈的区别&#xff0c;并且用python实现3、设计实现遍历目录与子目录4、CPU处理进程最慢的情况通常发生在以下几种情况下&#xff1a;5、CPU处理线程最慢的…