Android图像调整大小并保留EXIF数据(方向,旋转等)
如果您的Android应用使用设备相机拍摄照片然后调整大小(这是非常常见的做法,可以减小上传大小),那么您可能不会意识到此调整大小操作会剥离Exif元数据。
这可能会导致问题,特别是如果所涉及的设备依靠“ Orientation”标签来正确显示图像。
不同的Android设备以不同的方式处理摄像头/图像旋转-我信任的旧Nexus One似乎总是在捕获后立即旋转图像,因此在查看文件时,文件的本机内容始终是“竖直的”。
但是,其他设备(尤其是我测试中的三星手机)不会旋转图像文件的内容-而是设置Exif'Orientation'标签。 每当以后显示图像时,相关的图像代码应检测到方向“标签”的存在并适当旋转图像。 但是,如果您对图像进行了任何位图处理并将其保存到新文件中,则所有该Exif数据都会丢失。
除了方向数据,您还可能会丢失其他有价值的元数据,例如品牌/型号等。
这让我感到困惑了几个星期(当图像显示在电话画廊中时,图像看起来是直立的,但是到达时我的服务器方向不好,没有明显的元数据)。 我在这里添加这个自我问题以帮助他人。 这篇博客文章非常有帮助:
Android调整图片大小而不会丢失EXIF信息
4个解决方案
43 votes
据我所知,没有一种机制可以自动保存元数据,甚至可以快照所有内容并批量传输。
相反,似乎您必须显式检查特定属性,然后使用ExifInterface将它们自己复制到新的图像文件中。
[HTTP://developer.Android.com/reference/Android/Media/EXIF interface.HTML]
所以像这样:
ExifInterface oldExif = new ExifInterface(oldImagePath);
String exifOrientation = oldExif.getAttribute(ExifInterface.TAG_ORIENTATION);
if (exifOrientation != null) {
ExifInterface newExif = new ExifInterface(imagePath);
newExif.setAttribute(ExifInterface.TAG_ORIENTATION, exifOrientation);
newExif.saveAttributes();
}
Mike Repass answered 2020-02-20T21:58:38Z
31 votes
对于懒惰的人,这是一个可重用的函数:
public static void copyExif(String oldPath, String newPath) throws IOException
{
ExifInterface oldExif = new ExifInterface(oldPath);
String[] attributes = new String[]
{
ExifInterface.TAG_APERTURE,
ExifInterface.TAG_DATETIME,
ExifInterface.TAG_DATETIME_DIGITIZED,
ExifInterface.TAG_EXPOSURE_TIME,
ExifInterface.TAG_FLASH,
ExifInterface.TAG_FOCAL_LENGTH,
ExifInterface.TAG_GPS_ALTITUDE,
ExifInterface.TAG_GPS_ALTITUDE_REF,
ExifInterface.TAG_GPS_DATESTAMP,
ExifInterface.TAG_GPS_LATITUDE,
ExifInterface.TAG_GPS_LATITUDE_REF,
ExifInterface.TAG_GPS_LONGITUDE,
ExifInterface.TAG_GPS_LONGITUDE_REF,
ExifInterface.TAG_GPS_PROCESSING_METHOD,
ExifInterface.TAG_GPS_TIMESTAMP,
ExifInterface.TAG_IMAGE_LENGTH,
ExifInterface.TAG_IMAGE_WIDTH,
ExifInterface.TAG_ISO,
ExifInterface.TAG_MAKE,
ExifInterface.TAG_MODEL,
ExifInterface.TAG_ORIENTATION,
ExifInterface.TAG_SUBSEC_TIME,
ExifInterface.TAG_SUBSEC_TIME_DIG,
ExifInterface.TAG_SUBSEC_TIME_ORIG,
ExifInterface.TAG_WHITE_BALANCE
};
ExifInterface newExif = new ExifInterface(newPath);
for (int i = 0; i < attributes.length; i++)
{
String value = oldExif.getAttribute(attributes[i]);
if (value != null)
newExif.setAttribute(attributes[i], value);
}
newExif.saveAttributes();
}
prom85 answered 2020-02-20T21:58:58Z
18 votes
正如其他人指出的那样,您必须将Exif数据从原始图像复制到最终调整大小的图像。 Sanselan Android库通常最适合此功能。 根据Android操作系统的版本,ExifInterface有时会破坏Exifdata。
另外,ExifInterface还处理有限数量的Exif标签,即仅处理它“知道”的标签。 另一方面,Sanselan将保留所有Exiftag和标记注释。
这是一篇博客文章,显示了如何使用Sanselan复制图像数据:
使用Sanselan复制Exif元数据
顺便说一句,在Android上,我也倾向于旋转图像并删除Orientation Exiftag。 例如,在具有Android 4.03的Nexus S上,摄像头在Exifmetadata中设置了方向标签,但网络视图忽略了该信息并错误地显示了图像。 可悲的是,旋转实际图像数据并删除Exiforientation标签是使每个程序正确显示图像的唯一方法。
Theo answered 2020-02-20T21:58:04Z
0 votes
已经是2019年了,没有比@ prom85,Mike Repass和Theo提出的更好的答案了。
在2016年,Android团队引入了ExifInterface支持库,如果您希望在Android版本之间保持一致的行为,那是最好的选择。 我最终创建了标签ExifInterface#EXIF_TAGS(源代码)的子集,然后仅对该子集进行迭代以从输入文件中提取元数据并将其设置为输出。 如果您需要复制所有标签,我建议您不要这样做! 无论如何,某些标签的值都需要相应地进行更新(例如TAG_IMAGE_LENGTH和TAG_IMAGE_WIDTH)。 就我个人而言,我一直在问一个问题,为什么我们首先需要保留所有metedata数据(无论如何,设备和相机之间的差异还是存在的),我们意识到gps位置和日期/时间数据也需要保留。
Krzysztof Skrzynecki answered 2020-02-20T21:59:25Z