我需要能够更新图像元数据(即标签,创建者,描述,评论)并在常规Exif和XMP中进行更新。最有可能的是,我将阅读Exif,并编写XMP。
在经常搜索一个可以写作的图书馆之后,我遇到了十二只猴子。
https://github.com/haraldk/TwelveMonkeys
这看起来很有希望。事实上,通过很少的努力,我已经能够在我的一张图片中阅读包含Exif的描述。请注意,不是使用标准的javax API,而是使用12monkeys API。这对我来说没问题。无论什么都有效!
在这一点上,我很高兴尽可能避免使用标准API,因为它看起来非常复杂和低效。我开始阅读我的Exif,并为我的概念验证编写修改代码。想法是,实现我想要的最有效的方法(快速和安全地修改JPEG文件中的元数据)是执行以下步骤:
然而,当我发现似乎没有实现时,我有点沮丧
com.twelvemonkeys.imageio.metadata.Directory
它实现了方法
add(Entry)
和
remove(Object)
除了一个以外的任何东西
throw new UnsupportedOperationException("Directory is read-only");
如果这不是有效(和安全)实现我想要做的事情的方式......有没有人建议如何在纯Java中,我能做到这一点?
免责声明:我设计并编写了各种元数据读取器/编写器,主要供我的ImageIO
库内部使用,并没有仔细考虑第三方使用。出于这个原因,API在这个意义上可能不是“完美的”。但你想做的事应该是完全可行的。 :-)
虽然特定的Directory
实现确实是只读的,但您可以轻松地创建自己的可变的AbstractDirectory
子类。或者只是使用你喜欢的任何Collection<? extends Entry>
并在写入之前将其包装在TIFFDirectory
或IFD
中。我更喜欢后者,所以我先说明一下。
请注意,典型的JPEG Exif段包含两个IFD,主JPEG图像的IFD0和缩略图的IFD1。所以你需要把它作为一个CompoundDirectory
:
CompoundDirectory exif = (CompoundDirectory) new TIFFReader().read(input);
List<Directory> ifds = new ArrayList<>;
for (int i = 0; i < exif.directoryCount(); i++) {
List<Entry> entries = new ArrayList<>();
for (Entry entry : exif.getDirectory(i)) {
entries.add(entry);
}
// TODO: Do stuff with entries, remove, add, change, etc...
ifds.add(new IFD(entries));
}
// Write Exif
new TIFFWriter().write(new TIFFDirectory(ifds), output);
你也可以创建自己的可变Directory
:
public final class MutableDirectory extends AbstractDirectory {
public MutableDirectory (final Collection<? extends Entry> entries) {
super(entries);
}
public boolean isReadOnly() {
return false;
}
// NOTE: While the above is all you need to make it *mutable*,
// TIFF/Exif does not allow entries with duplicate IDs,
// you need to handle this somehow. The below code is untested...
@Override
public boolean add(Entry entry) {
Entry existing = getEntryById(entry.getIdentifier());
if (existing != null) {
remove(existing);
}
super.add(entry);
}
}
不实现可变目录的原因恰恰在于如何处理条目的语义可能因格式而异。