当前位置: 首页 > news >正文

Android -- 调用系统相册之图片裁剪保存

前言

最近线上反馈,部分vivo手机更换头像时调用系统相册保存图片失败,经本人测试,确实有问题。

经修复后,贴出这块的代码供小伙伴们参考使用。

功能

更换头像选择图片:

  • 调用系统相机拍照,调用系统图片裁剪并保存。
  • 调用系统相册选择照片,调用系统图片裁剪并保存。

此功能需要动态申请 相机和读写外部存储的权限,此处省略了,请自行动态申请添加。

String[] permissions=new String[]{Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE};

1、布局文件activity_picture.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><Buttonandroid:id="@+id/takePictureFromCamera"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="拍照" /><Buttonandroid:id="@+id/takePictureFromLib"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="从相册选取" /><ImageViewandroid:id="@+id/img"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginTop="10dp"/>
</LinearLayout>

2、PictureActivity:

public class PictureActivity extends AppCompatActivity {public class Const {public static final int PHOTO_GRAPH = 1;// 拍照public static final int PHOTO_ZOOM = 2; // 相册public static final int PHOTO_RESOULT = 3;// 结果public static final String IMAGE_UNSPECIFIED = "image/*";}public String authority;private ImageView imageView;@Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_picture);authority = getApplicationContext().getPackageName() + ".fileprovider";imageView = findViewById(R.id.img);findViewById(R.id.takePictureFromCamera).setOnClickListener(v -> openCamera(Const.PHOTO_GRAPH));findViewById(R.id.takePictureFromLib).setOnClickListener(v -> openCamera(Const.PHOTO_ZOOM));}private void openCamera(int type) {Intent intent;if (type == Const.PHOTO_GRAPH) {//打开相机intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);//指定调用相机拍照后照片的储存路径File photoFile = new File(CoreConstants.getNurseDownloadFile(this), "temp.jpg");if (!photoFile.exists()) {photoFile.getParentFile().mkdirs();}Uri uri = FileUtil.getUri(this, authority, photoFile);intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);} else {//打开相册intent = new Intent(Intent.ACTION_PICK, null);intent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, Const.IMAGE_UNSPECIFIED);}startActivityForResult(intent, type);}/*** 调用系统的裁剪图片*/private void crop(Uri uri) {try {Intent intent = new Intent("com.android.camera.action.CROP");String contentURl = CoreConstants.getNurseDownloadFile(this)+ File.separator + "temp.jpg";File cropFile = new File(contentURl);Uri cropUri;//在7.0以上跨文件传输uri时候,需要用FileProviderif (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {cropUri = FileProvider.getUriForFile(this, getPackageName() + ".fileprovider", cropFile);intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);} else {cropUri = Uri.fromFile(cropFile);}intent.putExtra(MediaStore.EXTRA_OUTPUT, cropUri);intent.setDataAndType(uri, Const.IMAGE_UNSPECIFIED);intent.putExtra("crop", "true");// 裁剪框的比例,1:1intent.putExtra("aspectX", 1);intent.putExtra("aspectY", 1);// 裁剪后输出图片的尺寸大小intent.putExtra("outputX", 200);intent.putExtra("outputY", 200);intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());// 图片格式intent.putExtra("noFaceDetection", true);// 取消人脸识别intent.putExtra("return-data", true);//是否返回裁剪后图片的Bitmapintent.putExtra("output", cropUri);//重要!!!添加权限,不然裁剪完后报 “保存时发生错误,保存失败”List<ResolveInfo> resInfoList = getPackageManager().queryIntentActivities(intent,PackageManager.MATCH_DEFAULT_ONLY);for (ResolveInfo resolveInfo : resInfoList) {String packageName = resolveInfo.activityInfo.packageName;grantUriPermission(packageName, cropUri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);}ComponentName componentName = intent.resolveActivity(getPackageManager());if (componentName != null) {// 开启一个带有返回值的Activity,请求码为PHOTO_REQUEST_CUTstartActivityForResult(intent, Const.PHOTO_RESOULT);}} catch (Exception e) {String s = e.getMessage().toString();}}public Bitmap convertUriToBitmap(Uri uri) {ContentResolver contentResolver = getContentResolver();try {// 将Uri转换为字节数组return BitmapFactory.decodeStream(contentResolver.openInputStream(uri));} catch (Exception e) {e.printStackTrace();return null;}}@Overrideprotected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {super.onActivityResult(requestCode, resultCode, data);// 拍照if (requestCode == Const.PHOTO_GRAPH) {// 设置文件保存路径File picture = new File(CoreConstants.getNurseDownloadFile(this)+ File.separator + "temp.jpg");Uri uri = FileUtil.getUri(this, authority, picture);crop(uri);}if (data == null)return;//读取相册图片if (requestCode == Const.PHOTO_ZOOM) {crop(data.getData());}//处理裁剪后的结果if (requestCode == Const.PHOTO_RESOULT) {Bundle extras = data.getExtras();Bitmap photo = null;if(extras != null) {photo = extras.getParcelable("data");}if (photo == null && data.getData() != null) {//部分小米手机extras是个null,所以想拿到Bitmap要转下photo = convertUriToBitmap(data.getData());}if (photo != null) {//拿到Bitmap后直接显示在Image控件上imageView.setImageBitmap(photo);//将图片上传到服务器
//                String fileName = CommonCacheUtil.getUserId();
//                final File file = FileUtil.saveImgFile(this, photo, fileName);
//                final String fileKey = UUID.randomUUID().toString().replaceAll("-", "");//将file通过post上传到服务器//TODO:后续自行发挥}}}
}

3、FileUtil 工具类:

public class FileUtil {public static Uri getUri(Context context, String authority, File file) {Uri uri = null;if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {uri = FileProvider.getUriForFile(context, authority, file);} else {uri = Uri.fromFile(file);}return uri;}public static File saveImgFile(Context context, Bitmap bitmap, String fileName) {if (fileName == null) {System.out.println("saved fileName can not be null");return null;} else {fileName = fileName + ".png";String path = context.getFilesDir().getAbsolutePath();String lastFilePath = path + "/" + fileName;File file = new File(lastFilePath);if (file.exists()) {file.delete();}try {FileOutputStream outputStream = context.openFileOutput(fileName, 0);bitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream);outputStream.flush();outputStream.close();} catch (FileNotFoundException var7) {var7.printStackTrace();} catch (IOException var8) {var8.printStackTrace();}return file;}}
}

4、工具类 CoreConstants:

public class CoreConstants {public static String getNurseDownloadFile(Context context) {return context.getExternalFilesDir("").getAbsolutePath() + "/img";}
}

5、在 AndroidManifest.xml 中配置 FileProvider:

 <application....><providerandroid:name="androidx.core.content.FileProvider"android:authorities="${applicationId}.fileprovider"android:exported="false"android:grantUriPermissions="true" ><meta-dataandroid:name="android.support.FILE_PROVIDER_PATHS"android:resource="@xml/filepaths" /></provider></application>

6、filepaths.xml 文件:

<paths><external-path path="notePadRecorder/" name="notePadRecorder" /><external-path name="my_images" path="Pictures"/><external-path name="external_files" path="."/><root-path name="root_path" path="." />
</paths>

这部分代码在小米和vivo手机上测过,是正常的。

目前线上也没有反馈在其他机型上该功能有问题,如有问题,后续持续更新此文章。

相关文章:

Android -- 调用系统相册之图片裁剪保存

前言 最近线上反馈&#xff0c;部分vivo手机更换头像时调用系统相册保存图片失败&#xff0c;经本人测试&#xff0c;确实有问题。 经修复后&#xff0c;贴出这块的代码供小伙伴们参考使用。 功能 更换头像选择图片&#xff1a; 调用系统相机拍照&#xff0c;调用系统图片…...

读《道德经》让人感到心胸气闷?董仲舒篡改

为什么读《道德经》会让人感到心胸气闷&#xff1f;难道是董仲舒篡改所致&#xff1f; 作为世界智慧源头的《老子》&#xff0c;享誉古今中外&#xff0c;是世界历史上最伟大的著作之一。 然而&#xff0c;很多人读《道德经》时会感到心胸气闷&#xff0c;这究竟是为什么呢&am…...

D52【python 接口自动化学习】- python基础之模块与标准库

day52 标准库 学习日期&#xff1a;20241029 学习目标&#xff1a;模块与标准库 -- 67 标准库&#xff1a;Python默认提供的便携功能有哪些&#xff1f; 学习笔记 标准库中的常见组件 如何通过官方文档学习标准 from urllib.request import urlopen with urlopen(http://ww…...

基于yolov8的布匹缺陷检测系统,支持图像、视频和摄像实时检测【pytorch框架、python源码】

更多目标检测和图像分类识别项目可看我主页其他文章 功能演示&#xff1a; 基于yolov8的布匹缺陷检测系统&#xff0c;支持图像、视频和摄像实时检测【pytorch框架、python源码】_哔哩哔哩_bilibili &#xff08;一&#xff09;简介 基于yolov8的布匹缺陷检测系统是在 PyTo…...

SQL Server 中,将单行数据转换为多行数据

在 SQL Server 中&#xff0c;将单行数据转换为多行数据通常涉及到将某个字段中的逗号分隔的值拆分成多行。这种操作通常称为“拆分”或“展开”&#xff08;Explode&#xff09;。以下是一些常用的方法来实现这一目标&#xff1a; 1. 使用内置函数 STRING_SPLIT 从 SQL Serv…...

解决数组两数之和问题与逻辑推理找出谋杀案凶手

给定一个整数数组nums和一个整数目标值target(2<nums.length<10^4)&#xff0c;请你在该数组中找出和为目标值target 的那两个整数&#xff0c;并返回它们的数组下标。 你可以假设每种输入只会对应一个答案&#xff0c;并且你不能使用两次相同的元素。 你可以按任意顺序返…...

uniapp的IOS证书申请(测试和正式环境)及UDID配置流程

1.说明 本教程只提供uniapp在ios端的证书文件申请&#xff08;包含正式环境和开发环境&#xff09;、UDID配置说明&#xff0c;请勿用文档中的账号和其他隐私数据进行测试&#xff0c;请勿侵权&#xff01; 2.申请前准备 证书生成网站&#xff1a;苹果应用上传、解析&#x…...

windows 安装apex_Nvidia Apex安装

参见windows 安装apex_Nvidia Apex安装 重点&#xff1a; 1、在安装前先检查一下&#xff0c;电脑的cuda版本和pytorch内的cuda版本是否一样&#xff0c;不一样的话就把低版本的进行升级&#xff1b; $ git clone https://github.com/NVIDIA/apex$ cd apex2、在保证cuda版本一…...

Laravel5 抓取第三方网站图片,存储到本地

背景 近期发现&#xff0c;网站上的部分图片无法显示&#xff0c; 分析发现&#xff0c;是因为引用的第三方网站图片&#xff08;第三方服务器证书已过期&#xff09; 想着以后显示的方便 直接抓取第三方服务器图片&#xff0c;转存到本地服务器 思路 1. 查询数据表&#xff0…...

DevOps和CI/CD以及在微服务架构中的作用

DevOps 和 CI/CD 是现代软件开发和运维中两个重要的概念,它们之间有紧密的联系,但也有不同的侧重点。以下是对这两个概念的详细介绍和比较。 1. DevOps 定义: DevOps 是一种文化、运动和实践,旨在通过促进开发(Development)和运维(Operations)团队之间的协作,提升软…...

Rust 力扣 - 5. 最长回文子串

文章目录 题目描述题解思路题解代码题解链接 题目描述 题解思路 从中心点先寻找和中心点相等的左右端点&#xff0c;在基于左右端点进行往外扩散&#xff0c;直至左右端点不相等或者越界&#xff0c;然后左右端点这个范围内就是我们找寻的回文串&#xff0c;我们遍历中心点&am…...

DDOS防护介绍

DDoS攻击的基本概念 分布式拒绝服务攻击&#xff08;DDoS&#xff09;是一种网络攻击方式&#xff0c;攻击者通过控制多个被感染的计算机&#xff08;僵尸网络&#xff09;同时向目标服务器发送大量的网络请求&#xff0c;导致目标服务器资源耗尽&#xff0c;无法正常提供服务…...

深入了解 kotlinx-datetime:配置与使用指南

深入了解 kotlinx-datetime&#xff1a;配置与使用指南 在Kotlin多平台开发中&#xff0c;处理日期和时间是常见的需求。kotlinx-datetime库提供了强大且简洁的API来帮助开发者应对这一挑战。本文将详细介绍如何配置kotlinx-datetime库&#xff0c;并通过生动的示例演示其核心…...

Qt编程技巧小知识点(6)根据 *IDN? 对程控仪器连接状态进行确认

文章目录 Qt编程技巧小知识点&#xff08;6&#xff09;根据 *IDN? 对程控仪器连接状态进行确认小结 Qt编程技巧小知识点&#xff08;6&#xff09;根据 *IDN? 对程控仪器连接状态进行确认 确定仪器连接问题&#xff0c;常用的是监测仪器的连接状态&#xff0c;如下代码所示&…...

【Android】Kotlin教程(4)

文章目录 1.field2.计算属性3.主构造函数4.次构造函数5.默认参数6.初始化块7.初始化顺序7.延迟初始化lateinit8.惰性初始化 1.field field 关键字通常与属性的自定义 getter 和 setter 一起使用。当你需要为一个属性提供自定义的行为时&#xff0c;可以使用 field 来访问或设置…...

机票电子行程单如何批量查验?Java机票电子行程单查验接口示例-发票查验接口

机票电子行程单来了&#xff0c;它方便了人们的出行。现如今&#xff0c;随着旅游、差旅市场的回暖与线上业务的蓬勃发展&#xff0c;机票电子行程单的需求量急剧攀升&#xff0c;如何高效且准确地查验这些电子行程单成为许多企业和财务部门关注的焦点。传统的人工查验流程耗时…...

记录element-ui改造select显示为table,并支持多查询条件

最近遇到的一个需求 &#xff0c; 很有趣&#xff0c;是需要一个select组件&#xff0c;要求显示工号&#xff0c;员工姓名&#xff0c;以及区域 三个字段&#xff0c;并且要支持三个字段的查询。显然element原生的组件不适用&#xff0c;这时候我们需要改造一下&#xff0c;把…...

Spearman、Pearson、Euclidean、Cosine、Jaccard,用来衡量不同数据之间的相似性或差异性

1. Spearman相关系数&#xff1a; 用于衡量两个变量之间的排序关系的强度和方向。Spearman相关系数关注的是两个变量的排序一致性&#xff0c;而不关心具体的数值大小。值的范围为-1到1&#xff0c;1表示完全正相关&#xff0c;-1表示完全负相关&#xff0c;0表示无相关性。常…...

Suno 歌曲生成 API 对接说明

随着 AI 的应用变广&#xff0c;各类 AI 程序已逐渐普及。AI 已逐渐深入到人们的工作生活方方面面。而 AI 涉及的行业也越来越多&#xff0c;从最初的写作&#xff0c;到医疗教育&#xff0c;再到现在的音乐。 Suno 是一个专业高质量的 AI 歌曲和音乐创作平台&#xff0c;用户…...

详细且系统的Spring Boot应用开发

为了帮助大家更好地理解如何使用Spring Boot来构建一个基础的Web应用程序&#xff0c;我将通过一个简单的例子来进行说明。这个例子将是一个基本的RESTful API服务&#xff0c;用于管理图书信息。 项目准备 1. 开发环境设置&#xff08;这个我之前有发文&#xff0c;这里就不详…...

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…...

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具&#xff0c;该工具基于TUN接口实现其功能&#xff0c;利用反向TCP/TLS连接建立一条隐蔽的通信信道&#xff0c;支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式&#xff0c;适应复杂网…...

ESP32 I2S音频总线学习笔记(四): INMP441采集音频并实时播放

简介 前面两期文章我们介绍了I2S的读取和写入&#xff0c;一个是通过INMP441麦克风模块采集音频&#xff0c;一个是通过PCM5102A模块播放音频&#xff0c;那如果我们将两者结合起来&#xff0c;将麦克风采集到的音频通过PCM5102A播放&#xff0c;是不是就可以做一个扩音器了呢…...

令牌桶 滑动窗口->限流 分布式信号量->限并发的原理 lua脚本分析介绍

文章目录 前言限流限制并发的实际理解限流令牌桶代码实现结果分析令牌桶lua的模拟实现原理总结&#xff1a; 滑动窗口代码实现结果分析lua脚本原理解析 限并发分布式信号量代码实现结果分析lua脚本实现原理 双注解去实现限流 并发结果分析&#xff1a; 实际业务去理解体会统一注…...

三体问题详解

从物理学角度&#xff0c;三体问题之所以不稳定&#xff0c;是因为三个天体在万有引力作用下相互作用&#xff0c;形成一个非线性耦合系统。我们可以从牛顿经典力学出发&#xff0c;列出具体的运动方程&#xff0c;并说明为何这个系统本质上是混沌的&#xff0c;无法得到一般解…...

mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包

文章目录 现象&#xff1a;mysql已经安装&#xff0c;但是通过rpm -q 没有找mysql相关的已安装包遇到 rpm 命令找不到已经安装的 MySQL 包时&#xff0c;可能是因为以下几个原因&#xff1a;1.MySQL 不是通过 RPM 包安装的2.RPM 数据库损坏3.使用了不同的包名或路径4.使用其他包…...

分布式增量爬虫实现方案

之前我们在讨论的是分布式爬虫如何实现增量爬取。增量爬虫的目标是只爬取新产生或发生变化的页面&#xff0c;避免重复抓取&#xff0c;以节省资源和时间。 在分布式环境下&#xff0c;增量爬虫的实现需要考虑多个爬虫节点之间的协调和去重。 另一种思路&#xff1a;将增量判…...

WebRTC从入门到实践 - 零基础教程

WebRTC从入门到实践 - 零基础教程 目录 WebRTC简介 基础概念 工作原理 开发环境搭建 基础实践 三个实战案例 常见问题解答 1. WebRTC简介 1.1 什么是WebRTC&#xff1f; WebRTC&#xff08;Web Real-Time Communication&#xff09;是一个支持网页浏览器进行实时语音…...

破解路内监管盲区:免布线低位视频桩重塑停车管理新标准

城市路内停车管理常因行道树遮挡、高位设备盲区等问题&#xff0c;导致车牌识别率低、逃费率高&#xff0c;传统模式在复杂路段束手无策。免布线低位视频桩凭借超低视角部署与智能算法&#xff0c;正成为破局关键。该设备安装于车位侧方0.5-0.7米高度&#xff0c;直接规避树枝遮…...

elementUI点击浏览table所选行数据查看文档

项目场景&#xff1a; table按照要求特定的数据变成按钮可以点击 解决方案&#xff1a; <el-table-columnprop"mlname"label"名称"align"center"width"180"><template slot-scope"scope"><el-buttonv-if&qu…...