2003.11.17 00:45 "[Tiff] TIFF, v3.6.0. Fetching "custom" tags", by Chris Losinger

2003.11.18 15:05 "[Tiff] TIFF, v3.6.0. Fetching "custom" tags", by Ross Finlayson

Going back to the _TIFFextender variables, _TIFFextender is the identifier of a static variable declared in tif_dir.c. It is defined as a TIFFExtendProc. The TIFFDefaultDirectory function calls the non-null function pointer installed at the _TIFFextender static variable. The TIFFExtendProc function pointer is installed in the _TIFFextender static (global) variable using the TIFFSetTagExtender function.

Then, the user implementation of the TIFFExtendProc function that is patched into the _TIFFextender static variable, when it is called by the TIFFDefaultDirectory function, may call TIFFMergeFieldInfo on whatever private or "custom" tags that it wants to to be handled by TIFFGetField and TIFFSetField. It can also call other functions on the TIFF pointer.

A problem with this is that the _TIFFextender function is called each time the TIFFDefaultDirectory function is called, where if the _TIFFextender function is to be used for adding the custom tag definitions that it would be called multiple times as directories were added from TIFFCreateDirectory calling TIFFDefaultDirectory. The TIFFFieldInfo and the nfields members are of the TIFF struct, not the TIFFDirectory struct.

Perhaps a better place for _TIFFextender to be called would be in TIFFClientOpen.

The Nota Bene in _TIFFFindFieldInfo suggest that as the table of TIFFFieldInfo pointers grows that it would be more efficient to use binary search instead of plain search. The list of TIFFFieldInfo pointers is already sorted by _TIFFMergeFieldInfo. I turn to a C book around here and read about bsearch, I think it can use the same compare function as qsort, and is also defined in stdlib.h. Yet, _TIFFFiindFieldInfo should return the TIFFFieldInfo struct with the greatest precision width, and specification is by the tag. The bsearch can be implemented when the data type is not TIFF_ANY. It could be implemented for all but I don't know if bsearch is stable.

if(dt != TIFF_ANY){
     const TIFFFieldInfo key={tag, 0, 0, dt, 0, 0, 0, 0};
    return( (const TIFFFieldInfo *) bsearch(
                        &key,
                   tif->tif_fieldinfo,
                     tif->tif_nfields,
                       sizeof(TIFFFieldInfo),
                  tagCompare);
}

Now the problem with that is that tagCompare doesn't return zero if the tag and data type of the TIFFFieldInfo are equal.

I'd modify line 311 of tagCompare from "return(tb->field_type < ta->field_type? -1: 1)" to "return(tb->field_type - ta->field_type)", yet TIFFDataType is an enum. As enum is unsigned, maybe, "return((int)tb->field_type - (int)ta->field_type)". Hopefully, that won't slow the compare function to a crawl or be worthless for 99% of the cases.

So anyways if the _TIFFextender function is to be used to add private or custom tags definitions to the TIFF, which it does, then it should be called from somewhere besides in TIFFDefaultDirectory. Imagine generating a thousand page output file, with thousands of calls to _TIFFextender, instead it should only be one.

Here I'll edit tif_dirinfo.c locally here and the output of diff follows.

Is it worthwhile to use bsearch on the array of TIFFFieldInfo structs or is the array not worth it? It's probably worth it because the array of info structs is all known fields.

What do you think about the _TIFFextender? I don't understand its justification for being called from TIFFDefaultDirectory. Instead, I think it should be called in TIFFClientOpen, around line 313 of tif_open.c, right before TIFFClientOpen calls TIFFDefaultDirectory, instead of line 1189 of tif_dir.c. Then, if there is to be a separate function to extend the TIFFDefaultDirectory, then have that, too. Then, besides _TIFFextender there could be _TIFFDirectoryExtender.

Then, I'm still trying to figure out a good way to copy each of the tags from a read mode directory to a write mode directory.

Let me know if I'm unclear. Having a fresh pair of eyes makes a big difference. The doxygen output really helps to browse the source code.

Ross F.

--- tif_dirinfo.c.orig  Tue Nov 18 06:12:48 2003
+++ tif_dirinfo.c       Tue Nov 18 06:23:53 2003
@@ -308,7 +308,7 @@
         if (ta->field_tag != tb->field_tag)
                 return (ta->field_tag < tb->field_tag ? -1 : 1);
         else
-               return (tb->field_type < ta->field_type ? -1 : 1);
+               return ((int)tb->field_type - (int)ta->field_type);
  }

  void
@@ -419,7 +419,17 @@
             (dt == TIFF_ANY || dt == last->field_type))
                 return (last);
         /* NB: if table gets big, use sorted search (e.g. binary
search) */
-       for (i = 0, n = tif->tif_nfields; i < n; i++) {
+       if(dt != TIFF_ANY){
+            TIFFFieldInfo key={0, 0, 0, 0, 0, 0, 0, 0};
+            key.field_tag=tag;
+            key.field_type=dt;
+            return( (const TIFFFieldInfo *) bsearch(
+                       &key,
+                       tif->tif_fieldinfo,
+                       tif->tif_nfields,
+                       sizeof(TIFFFieldInfo),
+                       tagCompare));
+        } else for (i = 0, n = tif->tif_nfields; i < n; i++) {
                 const TIFFFieldInfo* fip = tif->tif_fieldinfo[i];
                 if (fip->field_tag == tag &&
                     (dt == TIFF_ANY || fip->field_type == dt))