2000.04.14 18:01 "tiff with jpeg (unknown tag 33918)", by Alex Catchpaugh

2000.04.17 00:03 "libtiff crash with tiled jpeg (was: unknown tag 33918)", by Tom Lane

Tiffcp creates files it does not read correctly.

To reproduce:

Create a tiled RGB JPEG with tiffcp, then try to convert that file to some other type. tiffcp will crash. Note that the file created seems to be good, it is just that tiffcp cannot read files of this type correctly.

Ed,

This jogged my memory a little bit. I think I fixed the problem in my private copy a long time ago, and then forgot to submit the patch :-(. Mea maxima culpa. Try the attached patch and see if it helps.

This diff is against three-year-old sources, but it looks like tiffcp hasn't changed too much...

regards, tom lane
organizer, Independent JPEG Group

*** tools/tiffcp.c.orig Tue Sep  2 13:54:39 1997
--- tools/tiffcp.c      Fri Oct  3 00:10:22 1997
***************
*** 42,47 ****
--- 42,49 ----
  #define    TRUE    1
  #define      FALSE   0

+ /* working copies of encoding parameters: these can change for each image */
+
  static  int outtiled = -1;
  static  uint32 tilewidth;
  static  uint32 tilelength;
***************
*** 52,61 ****
  static      uint16 fillorder;
  static       uint32 rowsperstrip;
  static    uint32 g3opts;
  static  int ignore = FALSE;             /* if true, ignore read errors */
  static       uint32 defg3opts = (uint32) -1;
  static int quality = 75;               /* JPEG quality */
! static      int jpegcolormode = JPEGCOLORMODE_RGB;
  static  uint16 defcompression = (uint16) -1;
  static    uint16 defpredictor = (uint16) -1;

--- 54,67 ----
  static      uint16 fillorder;
  static       uint32 rowsperstrip;
  static    uint32 g3opts;
+ static  int jpegcolormode;
+
+ /* encoding parameters given by user switches: these do not change per image */
+
  static   int ignore = FALSE;             /* if true, ignore read errors */
  static       uint32 defg3opts = (uint32) -1;
  static int quality = 75;               /* JPEG quality */
! static      int defjpegcolormode = JPEGCOLORMODE_RGB;
  static       uint16 defcompression = (uint16) -1;
  static    uint16 defpredictor = (uint16) -1;

***************
*** 171,176 ****
--- 177,183 ----
                     tilewidth = deftilewidth;
                       tilelength = deftilelength;
                     g3opts = defg3opts;
+                    jpegcolormode = defjpegcolormode;
                       if (!tiffcp(in, out) || !TIFFWriteDirectory(out)) {
                             (void) TIFFClose(out);
                                  return (1);
***************
*** 183,188 ****
--- 190,209 ----
  }

  static void
+ processJPEGOptions(char* cp)
+ {
+  while (cp = strchr(cp, ':')) {
+                 cp++;
+          if (isdigit(*cp))
+                      quality = atoi(cp);
+            else if (*cp == 'r')
+                   defjpegcolormode = JPEGCOLORMODE_RAW;
+          else
+                   usage();
+       }
+ }
+
+ static void
  processG3Options(char* cp)
  {
       if (cp = strchr(cp, ':')) {
***************
*** 210,220 ****
      } else if (streq(opt, "packbits")) {
            defcompression = COMPRESSION_PACKBITS;
          } else if (strneq(opt, "jpeg", 4)) {
!           char* cp = strchr(opt, ':');
!           if (cp && isdigit(cp[1]))
!                      quality = atoi(cp+1);
!          if (cp && strchr(cp, 'r'))
!                     jpegcolormode = JPEGCOLORMODE_RAW;
              defcompression = COMPRESSION_JPEG;
      } else if (strneq(opt, "g3", 2)) {
              processG3Options(opt);
--- 231,237 ----
          } else if (streq(opt, "packbits")) {
            defcompression = COMPRESSION_PACKBITS;
          } else if (strneq(opt, "jpeg", 4)) {
!           processJPEGOptions(opt);
                defcompression = COMPRESSION_JPEG;
      } else if (strneq(opt, "g3", 2)) {
              processG3Options(opt);
***************
*** 426,431 ****
--- 443,449 ----
   uint16 bitspersample, samplesperpixel;
          copyFunc cf;
    uint32 w, l;
+   uint16 sourcephoto;
     struct cpTag* p;

      CopyField(TIFFTAG_IMAGEWIDTH, w);
***************
*** 436,449 ****
                TIFFSetField(out, TIFFTAG_COMPRESSION, compression);
    else
            CopyField(TIFFTAG_COMPRESSION, compression);
!   if (compression == COMPRESSION_JPEG && jpegcolormode == JPEGCOLORMODE_RGB)
!             TIFFSetField(out, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_YCBCR);
!     else if (compression == COMPRESSION_SGILOG || compression == COMPRESSION_SGILOG24)
              TIFFSetField(out, TIFFTAG_PHOTOMETRIC,
                      samplesperpixel == 1 ?
                      PHOTOMETRIC_LOGL : PHOTOMETRIC_LOGLUV);
!        else
!           CopyTag(TIFFTAG_PHOTOMETRIC, 1, TIFF_SHORT);
    if (fillorder != 0)
             TIFFSetField(out, TIFFTAG_FILLORDER, fillorder);
        else
--- 454,482 ----
            TIFFSetField(out, TIFFTAG_COMPRESSION, compression);
    else
            CopyField(TIFFTAG_COMPRESSION, compression);
!   CopyField(TIFFTAG_PHOTOMETRIC, sourcephoto);
!   /*
!      * Certain combinations of compression and colorspace are overridden;
!   * essentially we provide free colorspace conversion in these cases.
!    */
!    if (compression == COMPRESSION_JPEG) {
!                 /* If RGB->YCbCr conversion is enabled and appropriate,
!                 * change PhotometricInterpretation to suit.
!            * Otherwise, set JPEGCOLORMODE_RAW so that the JPEG codec
!              * isn't fooled if, say, the input Photometric is YCbCr.
!                */
!            if (jpegcolormode == JPEGCOLORMODE_RGB &&
!                  sourcephoto == PHOTOMETRIC_RGB &&
!              samplesperpixel == 3)
!                      TIFFSetField(out, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_YCBCR);
!             else
!                   jpegcolormode = JPEGCOLORMODE_RAW;
!     } else if (compression == COMPRESSION_SGILOG ||
!                   compression == COMPRESSION_SGILOG24) {
               TIFFSetField(out, TIFFTAG_PHOTOMETRIC,
                      samplesperpixel == 1 ?
                      PHOTOMETRIC_LOGL : PHOTOMETRIC_LOGLUV);
!        }
       if (fillorder != 0)
             TIFFSetField(out, TIFFTAG_FILLORDER, fillorder);
        else