Question

I am attempting to add GPS data to a TIFF file I am creating in Java. I am using the JAI-ImageIO libraries, although if there is a better library for doing both GPS metadata and custom metadata, I am willing to look into it.

I have attempted to add the GPS metadata to the nodes directly, but it seems to strip off the GPS IDF tag. I have attempted to add the GPS IFD to the TIFFIFD object (from the TIFFIMageMetadata object), but that doesn't seem to save the data properly.

Basically, I am struggling to get it to save the GPS data properly, and trying to figure out how to get the data in there. Hours of searching on the internet have yielded little in the way of tutorials or help, and I don't see anything helpful on Stack Overflow, but my search abilities may be lacking.

Some code from my attempt at doing it by manipulating the metadata nodes directly:

RenderedImage img = generateImageSomehow();
File writeTarget = new File("blah.tiff");
//Get the image writer
Iterator<ImageWriter> writers = ImageIO.getImageWritersByFormatName("tiff");
ImageTypeSpecifier specifier = new ImageTypeSpecifier(renderedImage);
ImageWriter writer = writers.next();
//Get the metadata
IIOMetadata metadata = writer.getDefaultImageMetadata(specifier, writers.getDefaultWriteParam());
Node root = metadata.getAsTree(FileConstants.TIFF_METADATA_FORMAT);
Node ifd = root.getFirstChild();
//Create a new IFD node for the GPS data, and add some GPS data to it
IIOMetadataNode gpsRootNode = new IIOMetadataNode("TIFFIFD");
gpsRootNode.setAttribute(FileConstants.TIFF_FIELD_NUMBER_ATTRIBUTE, "34853");
gpsRootNode.setAttribute(FileConstants.TIFF_FIELD_NAME_ATTRIBUTE, "GPS");
gpsRootNode.setAttribute("tagSets", "com.sun.media.imageio.plugins.tiff.EXIFGPSTagSet");
IIOMetadataNode childNode = new IIOMetadataNode(FileConstants.TIFF_FIELD_TAG);
childNode.setAttribute(FileConstants.TIFF_FIELD_NUMBER_ATTRIBUTE, "1");
childNode.setAttribute(FileConstants.TIFF_FIELD_NAME_ATTRIBUTE, "GPSLatitudeRef");
IIOMetadataNode asciiNode = new IIOMetadataNode("TIFFAsciis");
IIOMetadataNode childAsciiNode = new IIOMetadataNode("TIFFAscii");
childAsciiNode.setAttribute(FileConstants.TIFF_FIELD_VALUE_ATTRIBUTE, "N");
asciiNode.appendChild(childAsciiNode);
childNode.appendChild(asciiNode);
gpsRootNode.appendChild(childNode);
ifd.appendChild(gpsRootNode);
//Update metadata with new tree
metadata.setFromTree(FileConstants.TIFF_METADATA_FORMAT, root);
ImageOutputStream outstr = ImageIO.createImageOutputStream(writeTarget);
writer.setOutput(outstr);
//Write the image
IIOImage img = new IIOImage(renderedImage, Collections.<BufferedImage> emptyList(), metadata);
writer.write(img);
outstr.close();

I am attempting to join the GPS root node in, along with a (currently hardcoded) value for the direction. Am I attaching at the wrong level, in the wrong place, in the wrong way, etc? I am fine doing it this way - although using the TIFF objects might be nicer.

Updated to add additional code, to show how I am creating the image, as well as how I am saving it.


ETA:

This line here:

ifd.appendChild(gpsRootNode);

Should actually be:

root.appendChild(gpsRootNode);

This was something I was trying out, but when I do the ifd node as the node where I add the GPS node, I get an exception:

Exception in thread "Thread-2" java.lang.ClassCastException: com.sun.media.imageioimpl.plugins.tiff.TIFFIFD cannot be cast to [J

Not sure if that is expected there - it looks like it is trying to cast the IFD node to a Long array (as per the standard JNI types) - when I attach it to the root, it just seems to remove it from the metadata nodes.

Was it helpful?

Solution

The problem is most likely that the metadata tree representation you are manipulating, is only a working copy. When you later write an image and pass it metadata, your changes to the tree representation are lost.

After you are done updating the metadata tree (root) with your GPS specific tags, you have to either call metadata.setFromTree(TIFF_METADATA_FORMAT, root) or metadata.mergeTree(TIFF_METADATA_FORMAT, root) to set/merge your changes back to the metadata instance. As you start out with metadata.getAsTree(..) rather than an empty structure, you probably want to use setFromTree(..).

PS: If this is not the problem, please add the code where you update your metadata and write the image. :-)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top