Skip to main content

How do I add private TIFF IFDs and IFD Pointers to TIFF image metadata?

1 reply [Last post]
frederr
Offline
Joined: 2009-10-06

Hi!

I'm working on a project to add private TIFF tags to images. We would like to use a single tag as an IFD Pointer in the «reusable range» 65000-65535 as defined in the TIFF manual.

We would then like to add several fields inside this private IFD.

The problem is that I am unsure of how to merge the pointer / private IFD to the root IFD of the IIOMetadata object.

We have defined a class MyTIFFTagSet and a class MyParentTIFFTagSet similar to the EXIFTIFFTagSet and EXIFParentTIFFTagSet, added addAllowedTagSet(MyParentTIFFTagSet.getInstance()); in the constructor of the TIFFImageReadParam and rebuilt the API.

The numbers of the private tags we construct are the same as defined in MyTIFFTagSet, according to the TIFF manual : "If you need more than 10 tags, we suggest that you reserve a single private tag, define it as a LONG TIFF data type, and use its value as a pointer (offset) to a private IFD or other data structure of your choosing. Within that IFD, you can use whatever tags you want, since no one else will know that it is an IFD unless you tell
them" on page 9.

On running I get the following ClassCastException at the line
IIOMetadataNode newRoot = (IIOMetadataNode) newdata.getAsTree(formatName) in the source code (provided at the bottom):

Error: [J cannot be cast to com.sun.media.imageioimpl.plugins.tiff.TIFFIFD
java.lang.ClassCastException: [J cannot be cast to com.sun.media.imageioimpl.plugins.tiff.TIFFIFD at com.sun.media.imageioimpl
.plugins.tiff.TIFFImageMetadata.getIFDAsTree(Unknown Source) at com.sun.media.imageioimpl.plugins.tiff.TIFFImageMetadata.getNativeTree
(Unknown Source) at com.sun.media.imageioimpl.plugins.tiff.TIFFImageMetadata
.getAsTree(Unknown Source)

I would be very thankful if anybody could provide me with some hints on what I'm doing wrong. The code:

private IIOMetadata addTIFFMetadata(IIOMetadata m, String formatName)
throws IIOInvalidTreeException {

// Get the root IFD
TIFFDirectory rootifd = TIFFDirectory.createFromMetadata(m);

// Gets a reference to the private pointer tag
TIFFTag pointerTag = MyParentTIFFTagSet.getInstance().getTag(
"MyIFDPointer");

// Gets a reference to the tagset of the private subIFD
TIFFTagSet myprivatetagset = MyTIFFTagSet.getInstance();

/*
* Create some new tags with values.
*/
TIFFTag mytag1 = new TIFFTag("MyTagName1", 257, TIFFTag.TIFF_ASCII,
myprivatetagset);
String[] myValues1 = { "MyValue1" };
TIFFTag mytag2 = new TIFFTag("MyTagName2", 258, TIFFTag.TIFF_ASCII,
myprivatetagset);
String[] myValues2 = { "MyValue2" };

// Create TIFFFields from the tags
TIFFField myfield1 = new TIFFField(mytag1, TIFFTag.TIFF_ASCII,
myValues1.length, myValues1);

TIFFField myfield2 = new TIFFField(mytag2, TIFFTag.TIFF_ASCII,
myValues2.length, myValues2);

// Creates a private IFD - and adds Tagset
List mytagsets = new ArrayList();
mytagsets.add(myprivatetagset);
TIFFIFD myifd = new TIFFIFD(mytagsets, pointerTag);

myifd.addTIFFField(myfield1);
myifd.addTIFFField(myfield2);

/*
* If I here go
*
* IIOMetadataNode node = (IIOMetadataNode) myifd.getAsMetadata()
* .getAsTree(formatName);
*
* and then print the node object I get something like, which is what I
* would like to see also written to the image as metadata:
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/

System.out.println("Pointer Tag Name : " + pointerTag.getName());
System.out.println("Pointer Tag Number : " + pointerTag.getNumber());

if (pointerTag.isIFDPointer())
System.out.println("PointerTag is IFD-pointer");

System.out.println("MyIFD's Parent Tag Name : "
+ myifd.getParentTag().getName());
System.out.println("MyIFD's Parent Tag Number : "
+ myifd.getParentTag().getNumber());

/*
*
* Output from here (seems OK to me)
*
* Pointer Tag Name : MyIFDPointer
* Pointer Tag Number : 65001
* PointerTag is IFD-pointer
* MyIFD's Parent Tag Name : MyIFDPointer
* MyIFD's Parent Tag Number : 65001
*/

/*
* From the Javadoc of the Class TIFFDirectory:
* "Note that a TIFFDirectory instance which has a non-null parent tag
* will be contained in the data field of a TIFFField instance which has
* a tag field equal to the contained directory's parent tag."
*/

TIFFField field = new TIFFField(pointerTag, TIFFTag.TIFF_IFD_POINTER, 1);

rootifd.addTIFFField(field);

IIOMetadata newdata = rootifd.getAsMetadata();
IIOMetadataNode newRoot = (IIOMetadataNode) newdata
.getAsTree(formatName);

m.mergeTree(formatName, newRoot);

newRoot = (IIOMetadataNode) m.getAsTree(formatName);
MetadataManager.printMetadatas(newRoot);

return m;

}

/**
The class MyTIFFTagSet

*/
public class MyTIFFTagSet extends TIFFTagSet {

private static MyTIFFTagSet theInstance = null;

public static final int TAG_MyTagName1 = 257;

public static final int TAG_MyTagName2 = 258;

static class MyTagName1 extends TIFFTag {

public MyTagName1() {
super("MyTagName1", TAG_MyTagName1, 1 << TIFFTag.TIFF_ASCII);
}
}

static class MyTagName2 extends TIFFTag {

public MyTagName2() {
super("MyTagName2", TAG_MyTagName2, 1 << TIFFTag.TIFF_ASCII);
}
}

private static List tags;

private static void initTags() {
tags = new ArrayList(2);

tags.add(new MyTIFFTagSet.MyTagName1());
tags.add(new MyTIFFTagSet.MyTagName2());

}

private MyTIFFTagSet() {
super(tags);
}

public synchronized static MyTIFFTagSet getInstance() {
if (theInstance == null) {
initTags();
theInstance = new MyTIFFTagSet();
tags = null;
}
return theInstance;
}
}

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
frederr
Offline
Joined: 2009-10-06

**
* The class MyParentTIFFTagSet
*/
public class MyParentTIFFTagSet extends TIFFTagSet {

private static MyParentTIFFTagSet theInstance = null;

// 34665 - My IFD Pointer (LONG/1)
/** Tag pointing to the My IFD (type LONG). */
public static final int TAG_MY_IFD_POINTER = 65001;

// To be inserted into parent (root) TIFFTagSet
static class MyIFDPointer extends TIFFTag {

public MyIFDPointer() {
super("MyIFDPointer", TAG_MY_IFD_POINTER, 1 << TIFFTag.TIFF_LONG,
MyTIFFTagSet.getInstance());
}
}

private static List tags;

private static void initTags() {
tags = new ArrayList(1);
tags.add(new MyParentTIFFTagSet.MyIFDPointer());

}

private MyParentTIFFTagSet() {
super(tags);
}

public synchronized static MyParentTIFFTagSet getInstance() {
if (theInstance == null) {
initTags();
theInstance = new MyParentTIFFTagSet();
tags = null;
}
return theInstance;
}
}