TwelveMonkeys: Unable to modify a JPEGImage10Metadata comment value
I am trying to modify the JFIF comment (note: not an EXIF tag, but the comment in the JFIF metadata) of an image and am running into the issue that the JPEGImage10Metadata object is readonly.
I am trying the approach of getting the metadata as a tree, walking the tree, replacing an attribute and setting the metadata as a tree, as outlined here: https://stackoverflow.com/a/9508479
Is there another way?
I have looked for ways to copy-and-mutate the JPEGImage10Metadata object, but not found any?
(I can see the existing value in the debugger so that it feels kind of annoying not to be able to change it… I’ve even considered using reflection… 😄 )
Here is the code that I’m trying to run:
File downloadImageUrlToTempFile(AlbumEntry albumEntry, Path tempDir) {
var imageUrl = albumEntry.getImageUrl();
if (imageUrl == null || imageUrl.isEmpty()) {
throw new OldAlbumException(String.format("Unable to download album entry matching id=%d, imageUrl is missing", albumEntry.getId()));
}
var fileName = findFileNamePartOfUrl(imageUrl);
var tempfile = tempDir.resolve(fileName).toFile();
IIOImage image = null;
ImageWriter writer = null;
try {
HttpURLConnection connection = getConnectionFactory().connect(imageUrl);
connection.setRequestMethod("GET");
try(var inputStream = ImageIO.createImageInputStream(connection.getInputStream())) {
var readers = ImageIO.getImageReaders(inputStream);
if (readers.hasNext()) {
var reader = readers.next();
writer = ImageIO.getImageWriter(reader);
reader.setInput(inputStream);
image = reader.readAll(0, null);
}
}
} catch (IOException e) {
throw new OldAlbumException(String.format("Unable to download album entry matching id=%d from url=\"%s\"", albumEntry.getId(), albumEntry.getImageUrl()), e);
}
var metadata = image.getMetadata();
var metadataAsTree = metadata.getAsTree("javax_imageio_1.0");
findJfifCommentNode(metadataAsTree)
.ifPresent(node -> node.setAttribute("value", albumEntry.getDescription()));
try {
metadata.setFromTree("javax_imageio_1.0", metadataAsTree);
} catch (IIOInvalidTreeException e) {
throw new OldAlbumException(String.format("Failed to replace comment in local copy of album entry matching id=%d from url=\"%s\"", albumEntry.getId(), albumEntry.getImageUrl()), e);
}
try (var outputStream = ImageIO.createImageOutputStream(new FileOutputStream(tempfile))){
writer.setOutput(outputStream);
writer.write(image);
Files.setLastModifiedTime(tempfile.toPath(), FileTime.from(albumEntry.getLastModified().toInstant()));
return tempfile;
} catch (IOException e) {
throw new OldAlbumException(String.format("Unable to save local copy of album entry matching id=%d from url=\"%s\"", albumEntry.getId(), albumEntry.getImageUrl()), e);
}
}
Optional<IIOMetadataNode> findJfifCommentNode(Node metadataAsTree) {
return StreamSupport.stream(iterable(metadataAsTree.getChildNodes()).spliterator(), false)
.filter(n -> "Text".equals(n.getNodeName()))
.findFirst()
.flatMap(n -> StreamSupport.stream(iterable(n.getChildNodes()).spliterator(), false).findFirst());
}
public static Iterable<IIOMetadataNode> iterable(final NodeList nodeList) {
return () -> new Iterator<IIOMetadataNode>() {
private int index = 0;
@Override
public boolean hasNext() {
return index < nodeList.getLength();
}
@Override
public IIOMetadataNode next() {
if (!hasNext())
throw new NoSuchElementException();
return (IIOMetadataNode) nodeList.item(index++);
}
};
}
About this issue
- Original URL
- State: closed
- Created 8 months ago
- Comments: 17 (17 by maintainers)
Sounds good!
I’ll close this issue as resolved, unless you have more questions about JPEG metadata? If so just reopen, or create a new, more specific issue.
Oooh! Nice! Thanks! Found it: copy-paste-error!
I ended up putting the comment as an attribute on markerSequence, because I had forgotten to change the name of the element I was searching for.
(I dumped out the tree before and after).
Now it is time to tidy up the code.
Current iteration (before tidying) looks like this: https://gist.github.com/steinarb/497c28d27f59e85614b0f221115199f4
I did this instead, and then I got further:
Now the EXIF metadata parses without throwing an EOFException.
Current problem: my replacement of the JFIF comment didn’t survive the addition of modifying EXIF comments: https://gist.github.com/steinarb/da81e5d71a6d9e44058ef02598972f3a#file-oldalbumserviceprovider-java-L30
Hi Steinar,
Short answer:
JPEGImage10Metadatais (currently) read-only, see theisReadOnlymethod. InvokingmergeTree/setFromTreeon an instance, will fail.Long answer: You should still be able to achieve what you want, see #668. 😀 Especially this comment where I try to outline a workaround. I think it worked for jAlbum.
Try that first, but if you can’t make it work, let me know, and we’ll see if I can help.