最近需要写入 曝光时间 到exif中,使用ExifInterface.setAttribute(ExifInterface.TAG_EXPOSURE_TIME,mExposureTime)
当我传入的值为 1/4000 的时候,这个原生接口导致精度丢失,这是原生接口代码
public void setAttribute(@NonNull String tag, @Nullable String value) {
if (tag == null) {
throw new NullPointerException("tag shouldn't be null");
}
// Convert the given value to rational values for backwards compatibility.
if (value != null && sTagSetForCompatibility.contains(tag)) {
if (tag.equals(TAG_GPS_TIMESTAMP)) {
Matcher m = sGpsTimestampPattern.matcher(value);
if (!m.find()) {
Log.w(TAG, "Invalid value for " + tag + " : " + value);
return;
}
value = Integer.parseInt(m.group(1)) + "/1," + Integer.parseInt(m.group(2)) + "/1,"
+ Integer.parseInt(m.group(3)) + "/1";
} else {
try {
double doubleValue = Double.parseDouble(value);
value = (long) (doubleValue * 10000L) + "/10000"; // 精度丢失原因
} catch (NumberFormatException e) {
Log.w(TAG, "Invalid value for " + tag + " : " + value);
return;
}
}
}
。。。
}
因为这里有一个类型强转:value = (long) (doubleValue * 10000L) + "/10000";
当我的 doubleValue 为 0.00025,乘以 10000 就是 2.5,但是 long 强转之后就变成了 2 ,导致最后 value = 1/5000,与一开始的1/4000不一致了。
有什么其他接口可以让我写入曝光时间 (TAG_EXPOSURE_TIME)时不丢失精度吗?
该回答引用GPTᴼᴾᴱᴺᴬᴵ
ExifInterface是Android系统提供的API,其setAttribute方法内部将浮点数值转化为分数表示的有限小数,因此可能存在精度损失的问题。为了避免精度损失,您可以使用第三方库Metadata-extractor进行Exif信息的读取与写入,该库支持处理更多的Exif数据类型,例如浮点数值。以下是一个使用Metadata-extractor库进行Exif信息写入的示例代码:
// 导入库
import com.drew.imaging.ImageMetadataReader;
import com.drew.imaging.ImageProcessingException;
import com.drew.metadata.Directory;
import com.drew.metadata.Metadata;
import com.drew.metadata.exif.ExifSubIFDDirectory;
import com.drew.metadata.exif.ExifSubIFDDescriptor;
import com.drew.metadata.exif.ExifIFD0Directory;
import com.drew.metadata.exif.ExifIFD0Descriptor;
// 读取Exif信息
File imageFile = new File("path/to/image");
Metadata metadata = ImageMetadataReader.readMetadata(imageFile);
// 获取Exif子标签信息
ExifSubIFDDirectory subIFDDirectory = metadata.getFirstDirectoryOfType(ExifSubIFDDirectory.class);
ExifSubIFDDescriptor subIFDDescriptor = new ExifSubIFDDescriptor(subIFDDirectory);
// 写入曝光时间
subIFDDirectory.setObject(ExifSubIFDDirectory.TAG_EXPOSURE_TIME, new Rational(1, 4000));
// 保存Exif信息到文件
FileOutputStream fos = new FileOutputStream(imageFile);
fos.write(metadata.getByteArray());
fos.close();
该示例代码使用Metadata-extractor库读取了图片文件中的Exif信息,然后使用ExifSubIFDDirectory和ExifSubIFDDescriptor对象获取到了Exif信息的子标签信息,最后使用Rational对象将曝光时间写入到图片的Exif信息中,并将Exif信息保存到文件中。如果您需要写入其他类型的Exif数据,可以参考Metadata-extractor库的文档进行操作。
可以尝试使用 ExifInterface.setAttribute(String tag, long value) 方法来设置曝光时间 (TAG_EXPOSURE_TIME),这将允许您以 long 类型的形式指定标签的值,从而避免使用 double 强制转换到 long 时发生精度丢失的问题。
以下是示例代码:
```c
ExifInterface exif = new ExifInterface(filePath);
exif.setAttribute(ExifInterface.TAG_EXPOSURE_TIME, 1L/4000);
exif.saveAttributes();
请注意,在这个例子中,1L/4000将被视为 long 类型的值,并且将保留精度,从而正确地设置标签的值。