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);