LCOV - code coverage report
Current view: top level - frmts/gtiff/libtiff - tif_color.c (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 110 116 94.8 %
Date: 2026-08-22 15:37:05 Functions: 7 7 100.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 1988-1997 Sam Leffler
       3             :  * Copyright (c) 1991-1997 Silicon Graphics, Inc.
       4             :  *
       5             :  * Permission to use, copy, modify, distribute, and sell this software and
       6             :  * its documentation for any purpose is hereby granted without fee, provided
       7             :  * that (i) the above copyright notices and this permission notice appear in
       8             :  * all copies of the software and related documentation, and (ii) the names of
       9             :  * Sam Leffler and Silicon Graphics may not be used in any advertising or
      10             :  * publicity relating to the software without the specific, prior written
      11             :  * permission of Sam Leffler and Silicon Graphics.
      12             :  *
      13             :  * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
      14             :  * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
      15             :  * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
      16             :  *
      17             :  * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
      18             :  * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
      19             :  * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
      20             :  * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
      21             :  * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
      22             :  * OF THIS SOFTWARE.
      23             :  */
      24             : 
      25             : /*
      26             :  * CIE L*a*b* to CIE XYZ and CIE XYZ to RGB conversion routines are taken
      27             :  * from the VIPS library (http://www.vips.ecs.soton.ac.uk) with
      28             :  * the permission of John Cupitt, the VIPS author.
      29             :  */
      30             : 
      31             : /*
      32             :  * TIFF Library.
      33             :  *
      34             :  * Color space conversion routines.
      35             :  */
      36             : 
      37             : #include "tiffiop.h"
      38             : #include <math.h>
      39             : 
      40             : /*
      41             :  * Convert color value from the CIE L*a*b* 1976 space to CIE XYZ.
      42             :  */
      43             : TIFF_NOSANITIZE_UNSIGNED_INT_OVERFLOW
      44           1 : void TIFFCIELabToXYZ(TIFFCIELabToRGB *cielab, uint32_t l, int32_t a, int32_t b,
      45             :                      float *X, float *Y, float *Z)
      46             : {
      47             :     /*
      48             :      * Keep the historical signed a * 256 and b * 256 scaling. Out-of-range
      49             :      * callers may trigger UBSan signed-overflow reports here, but this
      50             :      * per-pixel path intentionally does not add extra handling; see !926 for
      51             :      * details.
      52             :      */
      53           1 :     TIFFCIELab16ToXYZ(cielab, l * 257U, a * 256, b * 256, X, Y, Z);
      54           1 : }
      55             : 
      56             : /*
      57             :  * For CIELab encoded in 16 bits, L is an unsigned integer range [0,65535].
      58             :  * The a* and b* components are signed integers range [-32768,32767]. The 16
      59             :  * bit chrominance values are encoded as 256 times the 1976 CIE a* and b*
      60             :  * values
      61             :  */
      62           1 : void TIFFCIELab16ToXYZ(TIFFCIELabToRGB *cielab, uint32_t l, int32_t a,
      63             :                        int32_t b, float *X, float *Y, float *Z)
      64             : {
      65           1 :     float L = (float)l * 100.0f / 65535.0f;
      66             :     float cby, tmp;
      67             : 
      68           1 :     if (L < 8.856f)
      69             :     {
      70           0 :         *Y = (L * cielab->Y0) / 903.292f;
      71           0 :         cby = 7.787f * (*Y / cielab->Y0) + 16.0f / 116.0f;
      72             :     }
      73             :     else
      74             :     {
      75           1 :         cby = (L + 16.0f) / 116.0f;
      76           1 :         *Y = cielab->Y0 * cby * cby * cby;
      77             :     }
      78             : 
      79           1 :     tmp = (float)a / 256.0f / 500.0f + cby;
      80           1 :     if (tmp < 0.2069f)
      81           0 :         *X = cielab->X0 * (tmp - 0.13793f) / 7.787f;
      82             :     else
      83           1 :         *X = cielab->X0 * tmp * tmp * tmp;
      84             : 
      85           1 :     tmp = cby - (float)b / 256.0f / 200.0f;
      86           1 :     if (tmp < 0.2069f)
      87           0 :         *Z = cielab->Z0 * (tmp - 0.13793f) / 7.787f;
      88             :     else
      89           1 :         *Z = cielab->Z0 * tmp * tmp * tmp;
      90           1 : }
      91             : 
      92             : #define RINT(R) ((uint32_t)((R) > 0 ? ((R) + 0.5f) : ((R) - 0.5f)))
      93             : /*
      94             :  * Convert color value from the XYZ space to RGB.
      95             :  */
      96           1 : void TIFFXYZToRGB(TIFFCIELabToRGB *cielab, float X, float Y, float Z,
      97             :                   uint32_t *r, uint32_t *g, uint32_t *b)
      98             : {
      99             :     size_t i;
     100             :     float Yr, Yg, Yb;
     101           1 :     float *matrix = &cielab->display.d_mat[0][0];
     102             : 
     103             :     /* Multiply through the matrix to get luminosity values. */
     104           1 :     Yr = matrix[0] * X + matrix[1] * Y + matrix[2] * Z;
     105           1 :     Yg = matrix[3] * X + matrix[4] * Y + matrix[5] * Z;
     106           1 :     Yb = matrix[6] * X + matrix[7] * Y + matrix[8] * Z;
     107             : 
     108             :     /* Clip input */
     109           1 :     Yr = TIFFmax(Yr, cielab->display.d_Y0R);
     110           1 :     Yg = TIFFmax(Yg, cielab->display.d_Y0G);
     111           1 :     Yb = TIFFmax(Yb, cielab->display.d_Y0B);
     112             : 
     113             :     /* Avoid overflow in case of wrong input values */
     114           1 :     Yr = TIFFmin(Yr, cielab->display.d_YCR);
     115           1 :     Yg = TIFFmin(Yg, cielab->display.d_YCG);
     116           1 :     Yb = TIFFmin(Yb, cielab->display.d_YCB);
     117             : 
     118             :     /* Turn luminosity to colour value. */
     119           1 :     i = (size_t)((Yr - cielab->display.d_Y0R) / cielab->rstep);
     120           1 :     i = TIFFmin((size_t)cielab->range, i);
     121           1 :     *r = RINT(cielab->Yr2r[i]);
     122             : 
     123           1 :     i = (size_t)((Yg - cielab->display.d_Y0G) / cielab->gstep);
     124           1 :     i = TIFFmin((size_t)cielab->range, i);
     125           1 :     *g = RINT(cielab->Yg2g[i]);
     126             : 
     127           1 :     i = (size_t)((Yb - cielab->display.d_Y0B) / cielab->bstep);
     128           1 :     i = TIFFmin((size_t)cielab->range, i);
     129           1 :     *b = RINT(cielab->Yb2b[i]);
     130             : 
     131             :     /* Clip output. */
     132           1 :     *r = TIFFmin(*r, cielab->display.d_Vrwr);
     133           1 :     *g = TIFFmin(*g, cielab->display.d_Vrwg);
     134           1 :     *b = TIFFmin(*b, cielab->display.d_Vrwb);
     135           1 : }
     136             : #undef RINT
     137             : 
     138             : /*
     139             :  * Allocate conversion state structures and make look_up tables for
     140             :  * the Yr,Yb,Yg <=> r,g,b conversions.
     141             :  */
     142           1 : int TIFFCIELabToRGBInit(TIFFCIELabToRGB *cielab, const TIFFDisplay *display,
     143             :                         float *refWhite)
     144             : {
     145             :     size_t i;
     146             :     double dfGamma;
     147             : 
     148           1 :     cielab->range = CIELABTORGB_TABLE_RANGE;
     149             : 
     150           1 :     _TIFFmemcpy(&cielab->display, display, sizeof(TIFFDisplay));
     151             : 
     152             :     /* Red */
     153           1 :     dfGamma = 1.0 / (double)cielab->display.d_gammaR;
     154           1 :     cielab->rstep =
     155           1 :         (cielab->display.d_YCR - cielab->display.d_Y0R) / (float)cielab->range;
     156        1502 :     for (i = 0; i <= (size_t)cielab->range; i++)
     157             :     {
     158        1501 :         cielab->Yr2r[i] = (float)cielab->display.d_Vrwr *
     159        1501 :                           ((float)pow((double)i / cielab->range, dfGamma));
     160             :     }
     161             : 
     162             :     /* Green */
     163           1 :     dfGamma = 1.0 / (double)cielab->display.d_gammaG;
     164           1 :     cielab->gstep =
     165           1 :         (cielab->display.d_YCR - cielab->display.d_Y0R) / (float)cielab->range;
     166        1502 :     for (i = 0; i <= (size_t)cielab->range; i++)
     167             :     {
     168        1501 :         cielab->Yg2g[i] = (float)cielab->display.d_Vrwg *
     169        1501 :                           ((float)pow((double)i / cielab->range, dfGamma));
     170             :     }
     171             : 
     172             :     /* Blue */
     173           1 :     dfGamma = 1.0 / (double)cielab->display.d_gammaB;
     174           1 :     cielab->bstep =
     175           1 :         (cielab->display.d_YCR - cielab->display.d_Y0R) / (float)cielab->range;
     176        1502 :     for (i = 0; i <= (size_t)cielab->range; i++)
     177             :     {
     178        1501 :         cielab->Yb2b[i] = (float)cielab->display.d_Vrwb *
     179        1501 :                           ((float)pow((double)i / cielab->range, dfGamma));
     180             :     }
     181             : 
     182             :     /* Init reference white point */
     183           1 :     cielab->X0 = refWhite[0];
     184           1 :     cielab->Y0 = refWhite[1];
     185           1 :     cielab->Z0 = refWhite[2];
     186             : 
     187           1 :     return 0;
     188             : }
     189             : 
     190             : /*
     191             :  * Convert color value from the YCbCr space to RGB.
     192             :  * The colorspace conversion algorithm comes from the IJG v5a code;
     193             :  * see below for more information on how it works.
     194             :  */
     195             : #define SHIFT 16
     196             : #define FIX(x) ((int32_t)((double)(x) * (1L << SHIFT) + 0.5))
     197             : #define ONE_HALF ((int32_t)(1 << (SHIFT - 1)))
     198             : #define Code2V(c, RB, RW, CR)                                                  \
     199             :     (((float)((c) - (int32_t)(RB)) * (float)(CR)) /                            \
     200             :      ((!TIFF_FLOAT_EQ((RW), (RB))) ? ((RW) - (RB)) : 1.0f))
     201             : /* !((f)>=(min)) written that way to deal with NaN */
     202             : #define CLAMP(f, min, max)                                                     \
     203             :     ((!((f) >= (min))) ? (min) : (f) > (max) ? (max) : (f))
     204             : #define HICLAMP(f, max) ((f) > (max) ? (max) : (f))
     205             : 
     206       65097 : void TIFFYCbCrtoRGB(TIFFYCbCrToRGB *ycbcr, uint32_t Y, int32_t Cb, int32_t Cr,
     207             :                     uint32_t *r, uint32_t *g, uint32_t *b)
     208             : {
     209             :     int32_t i;
     210             : 
     211             :     /* XXX: Only 8-bit YCbCr input supported for now */
     212       65097 :     Y = HICLAMP(Y, 255);
     213       65097 :     Cb = CLAMP(Cb, 0, 255);
     214       65097 :     Cr = CLAMP(Cr, 0, 255);
     215             : 
     216       65097 :     i = ycbcr->Y_tab[Y] + ycbcr->Cr_r_tab[Cr];
     217       65097 :     *r = (uint32_t)CLAMP(i, 0, 255);
     218       65097 :     i = ycbcr->Y_tab[Y] +
     219       65097 :         ((ycbcr->Cb_g_tab[Cb] + ycbcr->Cr_g_tab[Cr]) >> SHIFT);
     220       65097 :     *g = (uint32_t)CLAMP(i, 0, 255);
     221       65097 :     i = ycbcr->Y_tab[Y] + ycbcr->Cb_b_tab[Cb];
     222       65097 :     *b = (uint32_t)CLAMP(i, 0, 255);
     223       65097 : }
     224             : 
     225             : /* Clamp function for sanitization purposes. Normally clamping should not */
     226             : /* occur for well behaved chroma and refBlackWhite coefficients */
     227       13056 : static float CLAMPw(float v, float vmin, float vmax)
     228             : {
     229       13056 :     if (v < vmin)
     230             :     {
     231             :         /* printf("%f clamped to %f\n", v, vmin); */
     232           0 :         return vmin;
     233             :     }
     234       13056 :     if (v > vmax)
     235             :     {
     236             :         /* printf("%f clamped to %f\n", v, vmax); */
     237           0 :         return vmax;
     238             :     }
     239       13056 :     return v;
     240             : }
     241             : 
     242             : /*
     243             :  * Initialize the YCbCr->RGB conversion tables.  The conversion
     244             :  * is done according to the 6.0 spec:
     245             :  *
     246             :  *    R = Y + Cr*(2 - 2*LumaRed)
     247             :  *    B = Y + Cb*(2 - 2*LumaBlue)
     248             :  *    G =   Y
     249             :  *        - LumaBlue*Cb*(2-2*LumaBlue)/LumaGreen
     250             :  *        - LumaRed*Cr*(2-2*LumaRed)/LumaGreen
     251             :  *
     252             :  * To avoid floating point arithmetic the fractional constants that
     253             :  * come out of the equations are represented as fixed point values
     254             :  * in the range 0...2^16.  We also eliminate multiplications by
     255             :  * pre-calculating possible values indexed by Cb and Cr (this code
     256             :  * assumes conversion is being done for 8-bit samples).
     257             :  */
     258          17 : int TIFFYCbCrToRGBInit(TIFFYCbCrToRGB *ycbcr, float *luma, float *refBlackWhite)
     259             : {
     260             :     TIFFRGBValue *clamptab;
     261             :     int i;
     262             : 
     263             : #define LumaRed luma[0]
     264             : #define LumaGreen luma[1]
     265             : #define LumaBlue luma[2]
     266             : 
     267          17 :     clamptab =
     268             :         (uint8_t *)ycbcr + TIFFroundup_32(sizeof(TIFFYCbCrToRGB), sizeof(long));
     269          17 :     _TIFFmemset(clamptab, 0, 256); /* v < 0 => 0 */
     270          17 :     ycbcr->clamptab = (clamptab += 256);
     271        4369 :     for (i = 0; i < 256; i++)
     272        4352 :         clamptab[i] = (TIFFRGBValue)i;
     273          17 :     _TIFFmemset(clamptab + 256, 255, 2 * 256); /* v > 255 => 255 */
     274          17 :     ycbcr->Cr_r_tab = (int *)(clamptab + 3 * 256);
     275          17 :     ycbcr->Cb_b_tab = ycbcr->Cr_r_tab + 256;
     276          17 :     ycbcr->Cr_g_tab = (int32_t *)(ycbcr->Cb_b_tab + 256);
     277          17 :     ycbcr->Cb_g_tab = ycbcr->Cr_g_tab + 256;
     278          17 :     ycbcr->Y_tab = ycbcr->Cb_g_tab + 256;
     279             : 
     280             :     {
     281          17 :         float f1 = 2 - 2 * LumaRed;
     282          17 :         int32_t D1 = FIX(CLAMP(f1, 0.0f, 2.0f));
     283          17 :         float f2 = LumaRed * f1 / LumaGreen;
     284          17 :         int32_t D2 = -FIX(CLAMP(f2, 0.0f, 2.0f));
     285          17 :         float f3 = 2 - 2 * LumaBlue;
     286          17 :         int32_t D3 = FIX(CLAMP(f3, 0.0f, 2.0f));
     287          17 :         float f4 = LumaBlue * f3 / LumaGreen;
     288          17 :         int32_t D4 = -FIX(CLAMP(f4, 0.0f, 2.0f));
     289             :         int x;
     290             : 
     291             : #undef LumaBlue
     292             : #undef LumaGreen
     293             : #undef LumaRed
     294             : 
     295             :         /*
     296             :          * i is the actual input pixel value in the range 0..255
     297             :          * Cb and Cr values are in the range -128..127 (actually
     298             :          * they are in a range defined by the ReferenceBlackWhite
     299             :          * tag) so there is some range shifting to do here when
     300             :          * constructing tables indexed by the raw pixel data.
     301             :          */
     302        4369 :         for (i = 0, x = -128; i < 256; i++, x++)
     303             :         {
     304        4352 :             int32_t Cr = (int32_t)CLAMPw(Code2V(x, refBlackWhite[4] - 128.0f,
     305             :                                                 refBlackWhite[5] - 128.0f, 127),
     306             :                                          -128.0f * 32, 128.0f * 32);
     307        4352 :             int32_t Cb = (int32_t)CLAMPw(Code2V(x, refBlackWhite[2] - 128.0f,
     308             :                                                 refBlackWhite[3] - 128.0f, 127),
     309             :                                          -128.0f * 32, 128.0f * 32);
     310             : 
     311        4352 :             ycbcr->Cr_r_tab[i] = (int32_t)((D1 * Cr + ONE_HALF) >> SHIFT);
     312        4352 :             ycbcr->Cb_b_tab[i] = (int32_t)((D3 * Cb + ONE_HALF) >> SHIFT);
     313        4352 :             ycbcr->Cr_g_tab[i] = D2 * Cr;
     314        4352 :             ycbcr->Cb_g_tab[i] = D4 * Cb + ONE_HALF;
     315        4352 :             ycbcr->Y_tab[i] = (int32_t)CLAMPw(
     316        4352 :                 Code2V(x + 128, refBlackWhite[0], refBlackWhite[1], 255),
     317             :                 -128.0f * 32, 128.0f * 32);
     318             :         }
     319             :     }
     320             : 
     321          17 :     return 0;
     322             : }
     323             : #undef HICLAMP
     324             : #undef CLAMP
     325             : #undef Code2V
     326             : #undef SHIFT
     327             : #undef ONE_HALF
     328             : #undef FIX

Generated by: LCOV version 1.14