2002.04.08 15:45 "writing tiff incrementally", by Moshe

2002.04.08 19:50 "Re: writing tiff incrementally", by Daniel McCoy

I would like to write a tiff image incrementally: I have a program that writes a tiff file, and I would like to allow users to view the tiles I wrote so far (using standard tiff viewers). Does the library support something like this?

I tried TIFFFlush, but it doesn't allow me to go on writing tiles to the image. If the library does not support it, is there some standard or easy wat to do it?

Here is a patch to the 3.5.7 tif_dirwrite to add TIFFCheckpointDirectory(). (You might want to also add an "extern" for it in tiffio.h, right next to the one for TIFFWriteDirectory().)

Once this is in, you need only call TIFFCheckpointDirectory(tif) to write out the current state of the tiff directory into the file to make what is currently in the file readable. Unlike TIFFWriteDirectory, TIFFCheckpointDirectory does not free up the directory data structures in memory, so they can be updated (as strips/tiles are written) and written again.

Reading such a partial file you will at worst get a tiff read error for the first strip/tile encountered that is incomplete, but you will at least get all the valid data in the file before that.

When the file is complete, just use TIFFWriteDirectory as usual to finish it off cleanly.

(The changes are not really as extensive as it looks, a couple of sections of code got pulled into conditionals so the indentation changed. Try a diff that ignores whitespace after the patch to see what really changed.)

Could someone else give this a try and merge it into the library? (I've already spent more time on it than I'm supposed to at this point.)

Daniel McCoy    Pixar

*************Beginning of patch************************
--- tif_dirwrite.c       Mon Apr  8 12:29:59 2002
+++ tif_dirwrite.c.new  Mon Apr  8 12:30:06 2002
@@ -87,8 +87,8 @@
  * handle overwriting a directory with auxiliary
  * storage that's been changed.
  */
-int
-TIFFWriteDirectory(TIFF* tif)
+static int
+TIFFWriteDirectory1(TIFF* tif, int done)
 {
  uint16 dircount;
        toff_t diroff;
@@ -108,31 +108,34 @@
      * different characteristics get the right buffers
       * setup for them.
       */
-    if (tif->tif_flags & TIFF_POSTENCODE) {
-                tif->tif_flags &= ~TIFF_POSTENCODE;
-            if (!(*tif->tif_postencode)(tif)) {
-                    TIFFError(tif->tif_name,
-                           "Error post-encoding before directory write");
-                     return (0);
-            }
-      }
-      (*tif->tif_close)(tif);                 /* shutdown encoder */
- /*
-      * Flush any data that might have been written
-  * by the compression close+cleanup routines.
-   */
-    if (tif->tif_rawcc > 0 && !TIFFFlushData1(tif)) {
-              TIFFError(tif->tif_name,
-                   "Error flushing data before directory write");
-             return (0);
-    }
-      if ((tif->tif_flags & TIFF_MYBUFFER) && tif->tif_rawdata) {
-            _TIFFfree(tif->tif_rawdata);
-           tif->tif_rawdata = NULL;
-               tif->tif_rawcc = 0;
-                tif->tif_rawdatasize = 0;
+  if (done)
+      {
+          if (tif->tif_flags & TIFF_POSTENCODE) {
+                tif->tif_flags &= ~TIFF_POSTENCODE;
+                    if (!(*tif->tif_postencode)(tif)) {
+                            TIFFError(tif->tif_name,
+                           "Error post-encoding before directory write");
+                     return (0);
+                    }
+      }
+      (*tif->tif_close)(tif);             /* shutdown encoder */
+     /*
+      * Flush any data that might have been written
+          * by the compression close+cleanup routines.
+           */
+            if (tif->tif_rawcc > 0 && !TIFFFlushData1(tif)) {
+              TIFFError(tif->tif_name,
+                   "Error flushing data before directory write");
+             return (0);
+            }
+      if ((tif->tif_flags & TIFF_MYBUFFER) && tif->tif_rawdata) {
+                    _TIFFfree(tif->tif_rawdata);
+                   tif->tif_rawdata = NULL;
+               tif->tif_rawcc = 0;
+                    tif->tif_rawdatasize = 0;
+      }
+      tif->tif_flags &= ~(TIFF_BEENWRITING|TIFF_BUFFERSETUP);
     }
-      tif->tif_flags &= ~(TIFF_BEENWRITING|TIFF_BUFFERSETUP);

        td = &tif->tif_dir;
     /*
@@ -351,22 +354,48 @@
                 TIFFError(tif->tif_name, "Error writing directory link");
               goto bad;
       }
-      TIFFFreeDirectory(tif);
-        _TIFFfree(data);
-       tif->tif_flags &= ~TIFF_DIRTYDIRECT;
-   (*tif->tif_cleanup)(tif);
+      if (done) {
+            TIFFFreeDirectory(tif);
+                tif->tif_flags &= ~TIFF_DIRTYDIRECT;
+           (*tif->tif_cleanup)(tif);

-     /*
-      * Reset directory-related state for subsequent
-         * directories.
-         */
-        TIFFCreateDirectory(tif);
+          /*
+             * Reset directory-related state for subsequent
+         * directories.
+         */
+             TIFFCreateDirectory(tif);
+      }
+      _TIFFfree(data);
        return (1);
 bad:
        _TIFFfree(data);
        return (0);
 }
 #undef WriteRationalPair
+
+int
+TIFFWriteDirectory(TIFF* tif)
+{
+    return TIFFWriteDirectory1(tif, 1);
+}
+
+/*
+ * Similar to TIFFWriteDirectory(), writes the directory out
+ * but leaves all data structures in memory so that it can be
+ * written again.  This will make a partially written TIFF file
+ * readable before it is successfully completed/closed.
+ */
+int
+TIFFCheckpointDirectory(TIFF* tif)
+{
+      int rc;
+        /* Setup the strips arrays, if they haven't already been. */
+   if (tif->tif_dir.td_stripoffset == NULL)
+           (void) TIFFSetupStrips(tif);
+       rc = TIFFWriteDirectory1(tif, 0);
+      (void) TIFFSetWriteOffset(tif, TIFFSeekFile(tif, 0, SEEK_END));
+        return rc;
+}

 /*
  * Process tags that are not special cased.
*************End of patch************************