libtiff: Merge branch 'fix_571_alternative' into 'master'

From ef4a936e3e662ac508044589e6051b1949cc7259 Mon Sep 17 00:00:00 2001
From: Even Rouault <[EMAIL REDACTED]>
Date: Wed, 4 Oct 2023 22:21:13 +0200
Subject: [PATCH 1/2] tiffcp: Setting the correct photometric interpretation
 for the output image when converting JPEG-YCBCR to JPEG-RGB images.

Closes #571
---
 tools/tiffcp.c | 22 ++++++++++------------
 1 file changed, 10 insertions(+), 12 deletions(-)

diff --git a/tools/tiffcp.c b/tools/tiffcp.c
index 2628bdbb..2b3aa1df 100644
--- a/tools/tiffcp.c
+++ b/tools/tiffcp.c
@@ -87,7 +87,7 @@ static uint32_t g3opts;
 static int ignore = FALSE; /* if true, ignore read errors */
 static uint32_t defg3opts = (uint32_t)-1;
 static int quality = 75; /* JPEG quality */
-static int jpegcolormode = JPEGCOLORMODE_RGB;
+static int jpeg_photometric = PHOTOMETRIC_YCBCR;
 static uint16_t defcompression = (uint16_t)-1;
 static uint16_t defpredictor = (uint16_t)-1;
 static int defpreset = -1;
@@ -490,7 +490,7 @@ static int processCompressOptions(char *opt)
             if (isdigit((int)cp[1]))
                 quality = atoi(cp + 1);
             else if (cp[1] == 'r')
-                jpegcolormode = JPEGCOLORMODE_RAW;
+                jpeg_photometric = PHOTOMETRIC_RGB;
             else
                 usage(EXIT_FAILURE);
 
@@ -871,9 +871,11 @@ static int tiffcp(TIFF *in, TIFF *out)
     }
     if (compression == COMPRESSION_JPEG)
     {
-        if (input_photometric == PHOTOMETRIC_RGB &&
-            jpegcolormode == JPEGCOLORMODE_RGB)
-            TIFFSetField(out, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_YCBCR);
+        if (input_photometric == PHOTOMETRIC_RGB ||
+            input_photometric == PHOTOMETRIC_YCBCR)
+        {
+            TIFFSetField(out, TIFFTAG_PHOTOMETRIC, jpeg_photometric);
+        }
         else
             TIFFSetField(out, TIFFTAG_PHOTOMETRIC, input_photometric);
     }
@@ -882,12 +884,6 @@ static int tiffcp(TIFF *in, TIFF *out)
         TIFFSetField(out, TIFFTAG_PHOTOMETRIC,
                      samplesperpixel == 1 ? PHOTOMETRIC_LOGL
                                           : PHOTOMETRIC_LOGLUV);
-    else if (input_compression == COMPRESSION_JPEG && samplesperpixel == 3)
-    {
-        /* RGB conversion was forced above
-        hence the output will be of the same type */
-        TIFFSetField(out, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
-    }
     else
         CopyTag(TIFFTAG_PHOTOMETRIC, 1, TIFF_SHORT);
     if (fillorder != 0)
@@ -954,7 +950,9 @@ static int tiffcp(TIFF *in, TIFF *out)
     {
         case COMPRESSION_JPEG:
             TIFFSetField(out, TIFFTAG_JPEGQUALITY, quality);
-            TIFFSetField(out, TIFFTAG_JPEGCOLORMODE, jpegcolormode);
+            /* For 3 sample images, the input data provided to libtiff is
+             * always RGB, not YCbCr subsampled. */
+            TIFFSetField(out, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB);
             break;
         case COMPRESSION_JBIG:
             CopyTag(TIFFTAG_FAXRECVPARAMS, 1, TIFF_LONG);

From 8c6676d883e138d357cf9bae357e3ac8406d2063 Mon Sep 17 00:00:00 2001
From: Even Rouault <even.rouault@spatialys.com>
Date: Wed, 4 Oct 2023 22:34:33 +0200
Subject: [PATCH 2/2] tiffcp: do not copy tags YCBCRCOEFFICIENTS,
 YCBCRSUBSAMPLING, YCBCRPOSITIONING, REFERENCEBLACKWHITE. Only set
 TIFFTAG_YCBCRSUBSAMPLING when generating YCbCr JPEG

---
 tools/tiffcp.c | 18 ++++++++++++++----
 1 file changed, 14 insertions(+), 4 deletions(-)

diff --git a/tools/tiffcp.c b/tools/tiffcp.c
index 2b3aa1df..8a660481 100644
--- a/tools/tiffcp.c
+++ b/tools/tiffcp.c
@@ -808,10 +808,6 @@ static const struct cpTag
     {TIFFTAG_DOTRANGE, 2, TIFF_SHORT},
     {TIFFTAG_TARGETPRINTER, 1, TIFF_ASCII},
     {TIFFTAG_SAMPLEFORMAT, 1, TIFF_SHORT},
-    {TIFFTAG_YCBCRCOEFFICIENTS, (uint16_t)-1, TIFF_RATIONAL},
-    {TIFFTAG_YCBCRSUBSAMPLING, 2, TIFF_SHORT},
-    {TIFFTAG_YCBCRPOSITIONING, 1, TIFF_SHORT},
-    {TIFFTAG_REFERENCEBLACKWHITE, (uint16_t)-1, TIFF_RATIONAL},
     {TIFFTAG_EXTRASAMPLES, (uint16_t)-1, TIFF_SHORT},
     {TIFFTAG_SMINSAMPLEVALUE, 1, TIFF_DOUBLE},
     {TIFFTAG_SMAXSAMPLEVALUE, 1, TIFF_DOUBLE},
@@ -875,6 +871,18 @@ static int tiffcp(TIFF *in, TIFF *out)
             input_photometric == PHOTOMETRIC_YCBCR)
         {
             TIFFSetField(out, TIFFTAG_PHOTOMETRIC, jpeg_photometric);
+            if (jpeg_photometric == PHOTOMETRIC_YCBCR)
+            {
+                uint16_t subsamplinghor = 2, subsamplingver = 2;
+                if (input_compression == COMPRESSION_JPEG &&
+                    input_photometric == PHOTOMETRIC_YCBCR)
+                {
+                    TIFFGetFieldDefaulted(in, TIFFTAG_YCBCRSUBSAMPLING,
+                                          &subsamplinghor, &subsamplingver);
+                }
+                TIFFSetField(out, TIFFTAG_YCBCRSUBSAMPLING, subsamplinghor,
+                             subsamplingver);
+            }
         }
         else
             TIFFSetField(out, TIFFTAG_PHOTOMETRIC, input_photometric);
@@ -1112,7 +1120,9 @@ static int tiffcp(TIFF *in, TIFF *out)
     }
 
     for (p = tags; p < &tags[NTAGS]; p++)
+    {
         CopyTag(p->tag, p->count, p->type);
+    }
 
     cf = pickCopyFunc(in, out, bitspersample, samplesperpixel);
     return (cf ? (*cf)(in, out, length, width, samplesperpixel) : FALSE);