From 6aeda415e085fc623af25753bf71ab15289152c1 Mon Sep 17 00:00:00 2001
From: Even Rouault <[EMAIL REDACTED]>
Date: Tue, 11 Jul 2023 19:25:54 +0200
Subject: [PATCH] WebP codec: turn exact mode when creating lossless files to
avoid altering R,G,B values in areas where alpha=0
Fixes https://github.com/OSGeo/gdal/issues/8038
---
libtiff/tif_webp.c | 29 ++++++++++++++++++++++++++---
libtiff/tiff.h | 3 ++-
2 files changed, 28 insertions(+), 4 deletions(-)
diff --git a/libtiff/tif_webp.c b/libtiff/tif_webp.c
index 5ed4194d..bf9d77eb 100644
--- a/libtiff/tif_webp.c
+++ b/libtiff/tif_webp.c
@@ -47,9 +47,11 @@ typedef struct
{
uint16_t nSamples; /* number of samples per pixel */
- int lossless; /* lossy/lossless compression */
- int quality_level; /* compression level */
- WebPPicture sPicture; /* WebP Picture */
+ int lossless; /* lossy/lossless compression */
+ int lossless_exact; /* lossless exact mode. If TRUE, R,G,B values in areas
+ with alpha = 0 will be preserved */
+ int quality_level; /* compression level */
+ WebPPicture sPicture; /* WebP Picture */
WebPConfig sEncoderConfig; /* WebP encoder config */
uint8_t *pBuffer; /* buffer to hold raw data on encoding */
unsigned int buffer_offset; /* current offset into the buffer */
@@ -519,6 +521,9 @@ static int TWebPSetupEncode(TIFF *tif)
if (sp->lossless)
{
sp->sPicture.use_argb = 1;
+#if WEBP_ENCODER_ABI_VERSION >= 0x0209
+ sp->sEncoderConfig.exact = sp->lossless_exact;
+#endif
}
#endif
@@ -753,6 +758,17 @@ static int TWebPVSetField(TIFF *tif, uint32_t tag, va_list ap)
"Need to upgrade WEBP driver, this version doesn't support "
"lossless compression.");
return 0;
+#endif
+ case TIFFTAG_WEBP_LOSSLESS_EXACT:
+#if WEBP_ENCODER_ABI_VERSION >= 0x0209
+ sp->lossless_exact = va_arg(ap, int);
+ return 1;
+#else
+ TIFFErrorExtR(
+ tif, module,
+ "Need to upgrade WEBP driver, this version doesn't support "
+ "lossless compression.");
+ return 0;
#endif
default:
return (*sp->vsetparent)(tif, tag, ap);
@@ -772,6 +788,9 @@ static int TWebPVGetField(TIFF *tif, uint32_t tag, va_list ap)
case TIFFTAG_WEBP_LOSSLESS:
*va_arg(ap, int *) = sp->lossless;
break;
+ case TIFFTAG_WEBP_LOSSLESS_EXACT:
+ *va_arg(ap, int *) = sp->lossless_exact;
+ break;
default:
return (*sp->vgetparent)(tif, tag, ap);
}
@@ -784,6 +803,9 @@ static const TIFFField TWebPFields[] = {
{TIFFTAG_WEBP_LOSSLESS, 0, 0, TIFF_ANY, 0, TIFF_SETGET_INT,
TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, TRUE, FALSE, "WEBP lossless/lossy",
NULL},
+ {TIFFTAG_WEBP_LOSSLESS_EXACT, 0, 0, TIFF_ANY, 0, TIFF_SETGET_INT,
+ TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, TRUE, FALSE, "WEBP exact lossless",
+ NULL},
};
int TIFFInitWebP(TIFF *tif, int scheme)
@@ -822,6 +844,7 @@ int TIFFInitWebP(TIFF *tif, int scheme)
/* Default values for codec-specific fields */
sp->quality_level = 75; /* default comp. level */
sp->lossless = 0; /* default to false */
+ sp->lossless_exact = 1; /* exact lossless mode (if lossless enabled) */
sp->state = 0;
sp->nSamples = 0;
sp->psDecoder = NULL;
diff --git a/libtiff/tiff.h b/libtiff/tiff.h
index b2d11866..d8da33dc 100644
--- a/libtiff/tiff.h
+++ b/libtiff/tiff.h
@@ -646,7 +646,7 @@ typedef enum
#define TIFFTAG_EP_EXPOSUREINDEX 37397 /* Exposure index */
#define TIFFTAG_EP_STANDARDID 37398 /* TIFF/EP standard version, n.n.n.n */
#define TIFFTAG_EP_SENSINGMETHOD 37399 /* Type of image sensor */
-/*
+/*
* TIFF/EP tags equivalent to EXIF tags
* Note that TIFF-EP and EXIF use nearly the same metadata tag set, but TIFF-EP stores the tags in IFD 0,
* while EXIF store the tags in a separate IFD. Either location is allowed by DNG, but the EXIF location is preferred.
@@ -761,6 +761,7 @@ typedef enum
#define TIFFTAG_LERC_MAXZERROR 65567 /* LERC maximum error */
#define TIFFTAG_WEBP_LEVEL 65568 /* WebP compression level */
#define TIFFTAG_WEBP_LOSSLESS 65569 /* WebP lossless/lossy */
+#define TIFFTAG_WEBP_LOSSLESS_EXACT 65571 /* WebP lossless exact mode. Set-only mode. Default is 1. Can be set to 0 to increase compression rate, but R,G,B in areas where alpha = 0 will not be preserved */
#define TIFFTAG_DEFLATE_SUBCODEC 65570 /* ZIP codec: to get/set the sub-codec to use. Will default to libdeflate when available */
#define DEFLATE_SUBCODEC_ZLIB 0
#define DEFLATE_SUBCODEC_LIBDEFLATE 1