前言
我们在应用程序中广泛使用图像。对于某些图像相关应用程序,需要图像的所有详细信息。但是我们不能总是直接从图像中读取图像的细节。可能需要了解图像详细信息,例如 GPS 位置、日期/时间、拍摄时的设置、方向等。
以前我们很难获取图像信息,为此我们必须从不同的方法中分别提取元数据并读取它以了解图像属性。即使当我们阅读时,对图像的更改(例如删除 GPS 标签或更改方向)也将是一项具有挑战性的任务。
这些的解决方案是 Exif 文件和 ExifInterface。
让我们了解一下EXIF是什么?
什么是Exif?
Exif 代表可交换图像文件格式。这是一个标准,它定义了与相机捕获的图像或其他媒体相关的特定信息。它能够存储相机曝光、拍摄图像的日期/时间,甚至 GPS 位置等重要数据。示例 Exif 文件看起来像,
安卓中的ExifInterface
我们了解什么是 Exif 及其包含的内容。让我们看看如何从 Android 中的图像中提取 Exif 数据。ExifInterface 自 25.1.0 起已在 android 支持库中引入。尽管这自 7.1 以来就已经存在,但从 android 9+ 开始,它具有提供给界面的所有功能。添加了 100 多个属性来读取图像的 Exif 标签,包括有关相机本身、相机设置、方向和 GPS 坐标的信息。目前,它只能读取 JPEG 文件或 RAW 图像文件的 Exif。支持的格式有 JPEG、DNG、CR2、NEF、NRW、ARW、RW2、ORF、PEF、SRW、RAF 和 HEIF。
如果您想使用 ExifInterface,您需要将以下依赖项添加到您的 build.gradle。
implementation "androidx.exifinterface:exifinterface:1.3.1"
了解 Exif 数据的重要一件事是没有必需的标签:每个标签都是可选的 - 有些服务甚至专门剥离 Exif 数据。因此,在整个代码中,您应该始终处理没有 Exif 数据的情况,因为没有特定属性的数据或根本不支持 Exif 数据的图像格式(例如,无处不在的 PNG 或 WebP 图像)。
如何读取 Exif 属性?
现在让我们了解如何读取不同来源的 EXIF 属性以及使用 ExifInterface 的一些用例。对于大多数属性,您只需根据需要使用 getAttributeInt()、getAttributeDouble() 或 getAttribute()(对于字符串)方法。
从内容 Uri 中提取信息
Uri uri; // the URI you've received from the other app
InputStream in;
try {
in = getContentResolver().openInputStream(uri);
ExifInterface exifInterface = new ExifInterface(in);
// Now you can extract any Exif tag you want
// Assuming the image is a JPEG or supported raw format
} catch (IOException e) {
// Handle any errors
} finally {
if (in != null) {
try {
in.close();
} catch (IOException ignored) {}
}
}
注意:ExifInterface 不适用于远程 InputStream,例如从 HttpURLConnection 返回的那些。强烈建议仅将它们与 content:// 或 file:// URI 一起使用。
对于相机应用
对于Camera 应用程序,捕获图像后的写入属性更为重要。到目前为止,它仍然仅限于 JPEG 图像。使用ExifInterface,我们可以轻松更改已设置的 JPEG_ORIENTATION、JPEG_GPS_LOCATION 或等效项。我们还可以根据用户的请求移除这些属性。
var exif : ExifInterface = ExifInterface(pictureFile.getAbsolutePath())
exif.setAttribute(ExifInterface.TAG_ORIENTATION, "" + getPhotoOrientation(configurationProvider.getSensorPosition()))
exif.saveAttributes()
处理方向
显示图像时最重要的属性之一是图像方向,存储在恰当命名的TAG_ORIENTATION中,它返回ORIENTATION_常量之一。要将其转换为旋转角度,您可以对该值进行后处理。
int rotation = 0;
int orientation = exifInterface.getAttributeInt(
ExifInterface.TAG_ORIENTATION,
ExifInterface.ORIENTATION_UNDEFINED);
switch (orientation) {
case ExifInterface.ORIENTATION_ROTATE_90:
rotation = 90;
break;
case ExifInterface.ORIENTATION_ROTATE_180:
rotation = 180;
break;
case ExifInterface.ORIENTATION_ROTATE_270:
rotation = 270;
break;
}
使用 Exif 旋转角度进行位图旋转
首先,创建 ExifInterface:
ExifInterface exif = new ExifInterface(uri.getPath());
接下来,找到当前旋转:
int rotation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_UNDEFINED);
将 Exif 旋转转换为度数:
int rotationInDegrees = exifToDegrees(rotation);
在哪里
private fun exifToDegrees(exifOrientation: Int): Int {
if (exifOrientation == ExifInterface.ORIENTATION_ROTATE_90) {
return 90
} else if (exifOrientation == ExifInterface.ORIENTATION_ROTATE_180) {
return 180
} else if (exifOrientation == ExifInterface.ORIENTATION_ROTATE_270) {
return 270
}
return 0
}
然后使用图像的实际旋转作为参考点,使用 Matrix 旋转图像。
Matrix matrix = new Matrix();
if (rotation != 0) {
matrix.postRotate(rotationInDegrees);
}
您可以使用将 Matrix 作为参数的 Bitmap.createBitmap 方法创建新的旋转图像:
Bitmap.createBitmap(Bitmap source, int x, int y, int width, int height, Matrix m, boolean filter)
哪里matrix有新的轮换:
Bitmap adjustedBitmap = Bitmap.createBitmap(sourceBitmap, 0, 0, width, height, matrix, true)
我们如何使用 ExifInterface 的一些用例。
- ExifInterface 用于在拍照时写入图像信息。在将图像保存到手机存储时处理方向也很有帮助。
- 我们可能需要减小图像大小并更新 Exif 信息,为此,我们必须获取 Exif 信息并将更新的信息保存回图像。
- ExifInterface 还用于获取和解析图像标题。
- 旋转设备时保持设备的视图方向不变。
- 从图库中获取图像并以正确的方向和保存图像的其他属性显示它。
这都是关于 ExifInterface 的。今天我们学习了ExifInterface。希望对这个话题有所了解。
这里我就分享一份资料,希望可以帮助到大家提升进阶。
内容包含:Android学习PDF+架构视频+面试文档+源码笔记,高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料 这几块的内容。分享给大家,非常适合近期有面试和想在技术道路上继续精进的朋友。
如果你有需要的话,可以扫描下方二维码,免费获取Android学习PDF+架构视频+面试文档+源码笔记领取方式