mirror of
				https://git.code.sf.net/p/libpng/code.git
				synced 2025-07-10 18:04:09 +02:00 
			
		
		
		
	
		
			
				
	
	
		
			6760 lines
		
	
	
		
			218 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			6760 lines
		
	
	
		
			218 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| 
 | |
| /* pngrtran.c - transforms the data in a row for PNG readers
 | |
|  *
 | |
|  * Last changed in libpng 1.7.0 [(PENDING RELEASE)]
 | |
|  * Copyright (c) 1998-2002,2004,2006-2015 Glenn Randers-Pehrson
 | |
|  * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
 | |
|  * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
 | |
|  *
 | |
|  * This code is released under the libpng license.
 | |
|  * For conditions of distribution and use, see the disclaimer
 | |
|  * and license in png.h
 | |
|  *
 | |
|  * This file contains functions optionally called by an application
 | |
|  * in order to tell libpng how to handle data when reading a PNG.
 | |
|  * Transformations that are used in both reading and writing are
 | |
|  * in pngtrans.c.
 | |
|  */
 | |
| 
 | |
| #include "pngpriv.h"
 | |
| #define PNG_SRC_FILE PNG_SRC_FILE_pngrtran
 | |
| 
 | |
| #ifdef PNG_READ_QUANTIZE_SUPPORTED
 | |
| typedef struct
 | |
| {
 | |
|    png_transform tr;
 | |
|    png_byte      map[256U]; /* Map of palette values */
 | |
|    png_byte      lut[1U <<  /* LUT for RGB values */
 | |
|       (PNG_QUANTIZE_RED_BITS+PNG_QUANTIZE_GREEN_BITS+PNG_QUANTIZE_BLUE_BITS)];
 | |
| }  png_transform_quantize;
 | |
| 
 | |
| #define PNG_QUANTIZE_MAP 1U /* map is present and not a 1:1 mapping */
 | |
| #define PNG_QUANTIZE_LUT 2U /* lut has been built */
 | |
| 
 | |
| static void
 | |
| do_quantize_rgb(png_transformp *transform, png_transform_controlp tc)
 | |
| {
 | |
| #  define png_ptr (tc->png_ptr)
 | |
|    png_transform_quantize *tr = png_transform_cast(png_transform_quantize,
 | |
|       *transform);
 | |
|    unsigned int channels = PNG_TC_CHANNELS(*tc);
 | |
|    png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp);
 | |
|    png_const_bytep ep = sp + PNG_TC_ROWBYTES(*tc) - channels/*safety*/;
 | |
|    png_bytep dp = png_voidcast(png_bytep, tc->dp);
 | |
| 
 | |
|    affirm(tc->bit_depth == 8 && (channels == 3 || channels == 4) &&
 | |
|           !(tc->format & PNG_FORMAT_FLAG_SWAPPED) &&
 | |
|           (tr->tr.args & PNG_QUANTIZE_LUT) != 0);
 | |
| 
 | |
|    tc->sp = dp;
 | |
|    tc->format |= PNG_FORMAT_FLAG_COLORMAP;
 | |
| 
 | |
|    while (sp <= ep)
 | |
|    {
 | |
|       unsigned int r = sp[0];
 | |
|       unsigned int g = sp[1];
 | |
|       unsigned int b = sp[2];
 | |
| 
 | |
|       /* This looks real messy, but the compiler will reduce
 | |
|        * it down to a reasonable formula.  For example, with
 | |
|        * 5 bits per color, we get:
 | |
|        * p = (((r >> 3) & 0x1f) << 10) |
 | |
|        *    (((g >> 3) & 0x1f) << 5) |
 | |
|        *    ((b >> 3) & 0x1f);
 | |
|        */
 | |
|       *dp++ = tr->lut[(((r >> (8 - PNG_QUANTIZE_RED_BITS)) &
 | |
|           ((1 << PNG_QUANTIZE_RED_BITS) - 1)) <<
 | |
|           (PNG_QUANTIZE_GREEN_BITS + PNG_QUANTIZE_BLUE_BITS)) |
 | |
|           (((g >> (8 - PNG_QUANTIZE_GREEN_BITS)) &
 | |
|           ((1 << PNG_QUANTIZE_GREEN_BITS) - 1)) <<
 | |
|           (PNG_QUANTIZE_BLUE_BITS)) |
 | |
|           ((b >> (8 - PNG_QUANTIZE_BLUE_BITS)) &
 | |
|           ((1 << PNG_QUANTIZE_BLUE_BITS) - 1))];
 | |
| 
 | |
|       sp += channels;
 | |
|    }
 | |
| 
 | |
|    affirm(sp == ep+channels);
 | |
|    UNTESTED
 | |
| #  undef png_ptr
 | |
| }
 | |
| 
 | |
| static void
 | |
| do_quantize_pal(png_transformp *transform, png_transform_controlp tc)
 | |
| {
 | |
| #  define png_ptr (tc->png_ptr)
 | |
|    png_transform_quantize *tr = png_transform_cast(png_transform_quantize,
 | |
|       *transform);
 | |
|    png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp);
 | |
|    png_const_bytep ep = sp + PNG_TC_ROWBYTES(*tc);
 | |
|    png_bytep dp = png_voidcast(png_bytep, tc->dp);
 | |
| 
 | |
|    affirm(tc->bit_depth == 8 && (tc->format & PNG_FORMAT_FLAG_COLORMAP) != 0 &&
 | |
|           !(tc->format & PNG_FORMAT_FLAG_SWAPPED) &&
 | |
|           (tr->tr.args & PNG_QUANTIZE_MAP) != 0);
 | |
| 
 | |
|    tc->sp = dp;
 | |
| 
 | |
|    while (sp < ep)
 | |
|       *dp++ = tr->map[*sp++];
 | |
| 
 | |
|    UNTESTED
 | |
| #  undef png_ptr
 | |
| }
 | |
| 
 | |
| static void
 | |
| png_init_quantize(png_transformp *transform, png_transform_controlp tc)
 | |
| {
 | |
|    if (tc->bit_depth == 8 && (tc->format & PNG_FORMAT_FLAG_COLOR) != 0)
 | |
|    {
 | |
|       /* Either colormapped input, RGB or RGBA: */
 | |
|       if (!(tc->format & PNG_FORMAT_FLAG_COLORMAP)) /* RGB, RGBA */
 | |
|       {
 | |
|          /* This must be a 'palette' lookup */
 | |
|          if (((*transform)->args & PNG_QUANTIZE_LUT) != 0)
 | |
|          {
 | |
|             /* This changes the format and invalidates pretty much everything in
 | |
|              * the info struct:
 | |
|              */
 | |
|             tc->format |= PNG_FORMAT_FLAG_COLORMAP;
 | |
| 
 | |
|             if (tc->init == PNG_TC_INIT_FINAL)
 | |
|             {
 | |
|                (*transform)->fn = do_quantize_rgb;
 | |
|                tc->invalid_info |= PNG_INFO_tRNS+PNG_INFO_hIST+PNG_INFO_pCAL+
 | |
|                   PNG_INFO_sBIT+PNG_INFO_bKGD;
 | |
|                tc->sBIT_R = tc->sBIT_G = tc->sBIT_B = tc->sBIT_A =
 | |
|                   png_check_byte(tc->png_ptr, tc->bit_depth);
 | |
|             }
 | |
| 
 | |
|             return;
 | |
|          }
 | |
|       }
 | |
| 
 | |
|       else /* colormapped */
 | |
|       {
 | |
|          /* This must be a 'quantize' lookup */
 | |
|          if (((*transform)->args & PNG_QUANTIZE_MAP) != 0)
 | |
|          {
 | |
|             /* This doesn't change the format, just the values: */
 | |
|             if (tc->init == PNG_TC_INIT_FINAL)
 | |
|             {
 | |
|                (*transform)->fn = do_quantize_pal;
 | |
|                tc->invalid_info |= PNG_INFO_sBIT+PNG_INFO_pCAL;
 | |
|                tc->sBIT_R = tc->sBIT_G = tc->sBIT_B = tc->sBIT_A =
 | |
|                   png_check_byte(tc->png_ptr, tc->bit_depth);
 | |
|             }
 | |
| 
 | |
|             return;
 | |
|          }
 | |
|       }
 | |
|    }
 | |
| 
 | |
|    /* Else not applicable */
 | |
|    (*transform)->fn = NULL;
 | |
| }
 | |
| 
 | |
| /* Dither file to 8-bit.  Supply a palette, the current number
 | |
|  * of elements in the palette, the maximum number of elements
 | |
|  * allowed, and a histogram if possible.  If the current number
 | |
|  * of colors is greater then the maximum number, the palette will be
 | |
|  * modified to fit in the maximum number.  "full_quantize" indicates
 | |
|  * whether we need a quantizing cube set up for RGB images, or if we
 | |
|  * simply are reducing the number of colors in a paletted image.
 | |
|  */
 | |
| typedef struct png_dsort_struct
 | |
| {
 | |
|    struct png_dsort_struct * next;
 | |
|    png_byte left;
 | |
|    png_byte right;
 | |
| } png_dsort;
 | |
| typedef png_dsort *   png_dsortp;
 | |
| typedef png_dsort * * png_dsortpp;
 | |
| 
 | |
| static void
 | |
| init_map(png_bytep map)
 | |
|    /* Initialize a mapping table to be 1:1 */
 | |
| {
 | |
|    png_byte b = 0U;
 | |
| 
 | |
|    do
 | |
|       map[b] = b;
 | |
|    while (b++ != 255U);
 | |
| }
 | |
| 
 | |
| /* Save typing and make code easier to understand */
 | |
| #define PNG_COLOR_DIST(c1, c2) (abs((int)((c1).red) - (int)((c2).red)) + \
 | |
|    abs((int)((c1).green) - (int)((c2).green)) + \
 | |
|    abs((int)((c1).blue) - (int)((c2).blue)))
 | |
| 
 | |
| void PNGAPI
 | |
| png_set_quantize(png_structrp png_ptr, png_colorp palette,
 | |
|     int num_palette, int maximum_colors, png_const_uint_16p histogram,
 | |
|     int full_quantize)
 | |
| {
 | |
|    png_debug(1, "in png_set_quantize");
 | |
| 
 | |
|    if (png_ptr != NULL)
 | |
|    {
 | |
|       png_transform_quantize *tr = png_transform_cast(png_transform_quantize,
 | |
|          png_add_transform(png_ptr, sizeof (png_transform_quantize),
 | |
|             png_init_quantize, PNG_TR_QUANTIZE));
 | |
| 
 | |
|       /* This is weird (consider what happens to png_set_background on a palette
 | |
|        * image with a tRNS chunk).
 | |
|        */
 | |
|       if (palette == png_ptr->palette)
 | |
|          png_app_warning(png_ptr, "png_set_quantize: PLTE will be damaged");
 | |
| 
 | |
|       if (maximum_colors <= 0 || num_palette > 256)
 | |
|       {
 | |
|          /* The spuriously allocated transform will be removed by the init
 | |
|           * code.
 | |
|           */
 | |
|          png_app_error(png_ptr, "png_set_quantize: invalid color count");
 | |
|          return;
 | |
|       }
 | |
| 
 | |
|       /* The app passed in a palette with too many colors, it's not clear why
 | |
|        * libpng is providing this functionality, it's nothing to do with PNG and
 | |
|        * can be done by the application without any PNG specific knowledge.
 | |
|        */
 | |
|       if (num_palette > maximum_colors)
 | |
|       {
 | |
|          int map_changed = 0;
 | |
| 
 | |
|          /* The map table must be preset to do no mapping initially: */
 | |
|          init_map(tr->map);
 | |
| 
 | |
|          if (histogram != NULL)
 | |
|          {
 | |
|             /* This is easy enough, just throw out the least used colors.
 | |
|              * Perhaps not the best solution, but good enough.
 | |
|              */
 | |
|             int i;
 | |
|             png_byte quantize_sort[256U];
 | |
| 
 | |
|             /* Initialize an array to sort colors */
 | |
|             init_map(quantize_sort);
 | |
| 
 | |
|             /* Find the least used palette entries by starting a
 | |
|              * bubble sort, and running it until we have sorted
 | |
|              * out enough colors.  Note that we don't care about
 | |
|              * sorting all the colors, just finding which are
 | |
|              * least used.
 | |
|              */
 | |
|             for (i = num_palette - 1; i >= maximum_colors; i--)
 | |
|             {
 | |
|                int done; /* To stop early if the list is pre-sorted */
 | |
|                int j;
 | |
| 
 | |
|                done = 1;
 | |
|                for (j = 0; j < i; j++)
 | |
|                {
 | |
|                   if (histogram[quantize_sort[j]] <
 | |
|                       histogram[quantize_sort[j+1]])
 | |
|                   {
 | |
|                      png_byte t = quantize_sort[j];
 | |
|                      quantize_sort[j] = quantize_sort[j+1];
 | |
|                      quantize_sort[j+1] = t;
 | |
|                      done = 0;
 | |
|                   }
 | |
|                }
 | |
| 
 | |
|                if (done != 0)
 | |
|                   break;
 | |
|             }
 | |
| 
 | |
|             /* Swap the palette around, and set up a table, if necessary */
 | |
|             if (full_quantize)
 | |
|             {
 | |
|                int j = num_palette;
 | |
| 
 | |
|                /* Put all the useful colors within the max, but don't
 | |
|                 * move the others.
 | |
|                 *
 | |
|                 * NOTE: if the app passes in the result of png_get_PLTE it will
 | |
|                 * be overwritten at this point, what is the API?
 | |
|                 */
 | |
|                for (i = 0; i < maximum_colors; i++)
 | |
|                {
 | |
|                   if (quantize_sort[i] >= maximum_colors)
 | |
|                   {
 | |
|                      do
 | |
|                         j--;
 | |
|                      while (quantize_sort[j] >= maximum_colors);
 | |
| 
 | |
|                      /* NOTE: NOT swapped, so the original palette[i] has been
 | |
|                       * lost.
 | |
|                       */
 | |
|                      palette[i] = palette[j];
 | |
|                   }
 | |
|                }
 | |
|             }
 | |
| 
 | |
|             else /* !full_quantize */
 | |
|             {
 | |
|                int j = num_palette;
 | |
| 
 | |
|                /* Move all the used colors inside the max limit, and
 | |
|                 * develop a translation table.
 | |
|                 */
 | |
|                for (i = 0; i < maximum_colors; i++)
 | |
|                {
 | |
|                   /* Only move the colors we need to */
 | |
|                   if (quantize_sort[i] >= maximum_colors)
 | |
|                   {
 | |
|                      png_color tmp_color;
 | |
| 
 | |
|                      do
 | |
|                         j--;
 | |
|                      while (quantize_sort[j] >= maximum_colors);
 | |
| 
 | |
|                      tmp_color = palette[j];
 | |
|                      palette[j] = palette[i];
 | |
|                      palette[i] = tmp_color;
 | |
|                      /* Indicate where the color went */
 | |
|                      tr->map[j] = png_check_byte(png_ptr, i);
 | |
|                      tr->map[i] = png_check_byte(png_ptr, j);
 | |
|                      map_changed = 1;
 | |
|                   }
 | |
|                }
 | |
| 
 | |
|                /* Find closest color for those colors we are not using */
 | |
|                for (i = 0; i < num_palette; i++)
 | |
|                {
 | |
|                   if (tr->map[i] >= maximum_colors)
 | |
|                   {
 | |
|                      int min_d, k, min_k, d_index;
 | |
| 
 | |
|                      /* Find the closest color to one we threw out */
 | |
|                      d_index = tr->map[i];
 | |
|                      min_d = PNG_COLOR_DIST(palette[d_index], palette[0]);
 | |
|                      for (k = 1, min_k = 0; k < maximum_colors; k++)
 | |
|                      {
 | |
|                         int d;
 | |
| 
 | |
|                         d = PNG_COLOR_DIST(palette[d_index], palette[k]);
 | |
| 
 | |
|                         if (d < min_d)
 | |
|                         {
 | |
|                            min_d = d;
 | |
|                            min_k = k;
 | |
|                         }
 | |
|                      }
 | |
| 
 | |
|                      /* Point to closest color */
 | |
|                      tr->map[i] = png_check_byte(png_ptr, min_k);
 | |
|                      map_changed = 1;
 | |
|                   }
 | |
|                }
 | |
|             } /* !full_quantize */
 | |
|          } /* have a histogram */
 | |
| 
 | |
|          else /* no histogram */
 | |
|          {
 | |
|             /* This is much harder to do simply (and quickly).  Perhaps
 | |
|              * we need to go through a median cut routine, but those
 | |
|              * don't always behave themselves with only a few colors
 | |
|              * as input.  So we will just find the closest two colors,
 | |
|              * and throw out one of them (chosen somewhat randomly).
 | |
|              * [We don't understand this at all, so if someone wants to
 | |
|              *  work on improving it, be our guest - AED, GRP]
 | |
|              */
 | |
|             int max_d;
 | |
|             int num_new_palette;
 | |
|             png_byte index_to_palette[256U];
 | |
|             png_byte palette_to_index[256U];
 | |
|             png_dsortp hash[769];
 | |
| 
 | |
|             /* Initialize palette index sort arrays */
 | |
|             init_map(index_to_palette);
 | |
|             init_map(palette_to_index);
 | |
|             memset(hash, 0, sizeof hash);
 | |
|             num_new_palette = num_palette;
 | |
| 
 | |
|             /* Initial wild guess at how far apart the farthest pixel
 | |
|              * pair we will be eliminating will be.  Larger
 | |
|              * numbers mean more areas will be allocated, Smaller
 | |
|              * numbers run the risk of not saving enough data, and
 | |
|              * having to do this all over again.
 | |
|              *
 | |
|              * I have not done extensive checking on this number.
 | |
|              */
 | |
|             max_d = 96;
 | |
| 
 | |
|             while (num_new_palette > maximum_colors)
 | |
|             {
 | |
|                int i;
 | |
|                png_dsortp t = NULL;
 | |
| 
 | |
|                for (i = 0; i < num_new_palette - 1; i++)
 | |
|                {
 | |
|                   int j;
 | |
| 
 | |
|                   for (j = i + 1; j < num_new_palette; j++)
 | |
|                   {
 | |
|                      int d = PNG_COLOR_DIST(palette[i], palette[j]);
 | |
| 
 | |
|                      if (d <= max_d)
 | |
|                      {
 | |
| 
 | |
|                         t = png_voidcast(png_dsortp, png_malloc_warn(png_ptr,
 | |
|                               sizeof (*t)));
 | |
| 
 | |
|                         if (t == NULL)
 | |
|                             break;
 | |
| 
 | |
|                         t->next = hash[d];
 | |
|                         t->left = png_check_byte(png_ptr, i);
 | |
|                         t->right = png_check_byte(png_ptr, j);
 | |
|                         hash[d] = t;
 | |
|                      }
 | |
|                   }
 | |
|                   if (t == NULL)
 | |
|                      break;
 | |
|                }
 | |
| 
 | |
|                if (t != NULL) for (i = 0; i <= max_d; i++)
 | |
|                {
 | |
|                   if (hash[i] != NULL)
 | |
|                   {
 | |
|                      png_dsortp p;
 | |
| 
 | |
|                      for (p = hash[i]; p != NULL; p = p->next)
 | |
|                      {
 | |
|                         if (index_to_palette[p->left] < num_new_palette &&
 | |
|                             index_to_palette[p->right] < num_new_palette)
 | |
|                         {
 | |
|                            int j, next_j;
 | |
| 
 | |
|                            if (num_new_palette & 0x01)
 | |
|                            {
 | |
|                               j = p->left;
 | |
|                               next_j = p->right;
 | |
|                            }
 | |
|                            else
 | |
|                            {
 | |
|                               j = p->right;
 | |
|                               next_j = p->left;
 | |
|                            }
 | |
| 
 | |
|                            num_new_palette--;
 | |
|                            /* NOTE: overwrites palette */
 | |
|                            palette[index_to_palette[j]] =
 | |
|                               palette[num_new_palette];
 | |
| 
 | |
|                            if (full_quantize == 0)
 | |
|                            {
 | |
|                               int k;
 | |
| 
 | |
|                               for (k = 0; k < num_palette; k++)
 | |
|                               {
 | |
|                                  if (tr->map[k] == index_to_palette[j])
 | |
|                                  {
 | |
|                                     tr->map[k] = index_to_palette[next_j];
 | |
|                                     map_changed = 1;
 | |
|                                  }
 | |
| 
 | |
|                                  if (tr->map[k] == num_new_palette)
 | |
|                                  {
 | |
|                                     tr->map[k] = index_to_palette[j];
 | |
|                                     map_changed = 1;
 | |
|                                  }
 | |
|                               }
 | |
|                            }
 | |
| 
 | |
|                            index_to_palette[palette_to_index[num_new_palette]] =
 | |
|                               index_to_palette[j];
 | |
| 
 | |
|                            palette_to_index[index_to_palette[j]] =
 | |
|                               palette_to_index[num_new_palette];
 | |
| 
 | |
|                            index_to_palette[j] =
 | |
|                               png_check_byte(png_ptr, num_new_palette);
 | |
| 
 | |
|                            palette_to_index[num_new_palette] =
 | |
|                               png_check_byte(png_ptr, j);
 | |
|                         }
 | |
| 
 | |
|                         if (num_new_palette <= maximum_colors)
 | |
|                            break;
 | |
|                      }
 | |
| 
 | |
|                      if (num_new_palette <= maximum_colors)
 | |
|                         break;
 | |
|                   }
 | |
|                }
 | |
| 
 | |
|                for (i = 0; i < 769; i++)
 | |
|                {
 | |
|                   if (hash[i] != NULL)
 | |
|                   {
 | |
|                      png_dsortp p = hash[i];
 | |
| 
 | |
|                      while (p)
 | |
|                      {
 | |
|                         t = p->next;
 | |
|                         png_free(png_ptr, p);
 | |
|                         p = t;
 | |
|                      }
 | |
| 
 | |
|                      hash[i] = NULL;
 | |
|                   }
 | |
|                }
 | |
| 
 | |
|                max_d += 96;
 | |
|             } /* while num_new_colors > maximum_colors */
 | |
|          } /* no histogram */
 | |
| 
 | |
|          num_palette = maximum_colors;
 | |
| 
 | |
|          if (map_changed) /* else the map is 1:1 */
 | |
|             tr->tr.args |= PNG_QUANTIZE_MAP;
 | |
|       } /* num_palette > maximum_colors */
 | |
| 
 | |
|       /* The palette has been reduced to the requested number of colors if it
 | |
|        * was over maximum colors before.
 | |
|        */
 | |
| 
 | |
|       /* TODO: what is this?  Apparently the png_struct::palette member gets
 | |
|        * updated if it didn't originally have a palette, but the update relies
 | |
|        * on the app not freeing the passed in palette.
 | |
|        */
 | |
|       if (png_ptr->palette == NULL)
 | |
|          png_ptr->palette = palette;
 | |
| 
 | |
|       png_ptr->num_palette = png_check_bits(png_ptr, num_palette, 9);
 | |
| 
 | |
|       if (full_quantize)
 | |
|       {
 | |
|          int i;
 | |
|          png_byte distance[1U << (PNG_QUANTIZE_RED_BITS+PNG_QUANTIZE_GREEN_BITS+
 | |
|             PNG_QUANTIZE_BLUE_BITS)];
 | |
| 
 | |
|          memset(distance, 0xff, sizeof distance);
 | |
| 
 | |
|          for (i = 0; i < num_palette; i++)
 | |
|          {
 | |
|             int ir;
 | |
|             int r = (palette[i].red >> (8 - PNG_QUANTIZE_RED_BITS));
 | |
|             int g = (palette[i].green >> (8 - PNG_QUANTIZE_GREEN_BITS));
 | |
|             int b = (palette[i].blue >> (8 - PNG_QUANTIZE_BLUE_BITS));
 | |
| 
 | |
|             for (ir = 0; ir < (1<<PNG_QUANTIZE_RED_BITS); ir++)
 | |
|             {
 | |
|                /* int dr = abs(ir - r); */
 | |
|                int ig;
 | |
|                int dr = ((ir > r) ? ir - r : r - ir);
 | |
|                int index_r = (ir << (PNG_QUANTIZE_BLUE_BITS +
 | |
|                    PNG_QUANTIZE_GREEN_BITS));
 | |
| 
 | |
|                for (ig = 0; ig < (1<<PNG_QUANTIZE_GREEN_BITS); ig++)
 | |
|                {
 | |
|                   /* int dg = abs(ig - g); */
 | |
|                   int ib;
 | |
|                   int dg = ((ig > g) ? ig - g : g - ig);
 | |
|                   int dt = dr + dg;
 | |
|                   int dm = ((dr > dg) ? dr : dg);
 | |
|                   int index_g = index_r | (ig << PNG_QUANTIZE_BLUE_BITS);
 | |
| 
 | |
|                   for (ib = 0; ib < (1<<PNG_QUANTIZE_BLUE_BITS); ib++)
 | |
|                   {
 | |
|                      int d_index = index_g | ib;
 | |
|                      /* int db = abs(ib - b); */
 | |
|                      int db = ((ib > b) ? ib - b : b - ib);
 | |
|                      int dmax = ((dm > db) ? dm : db);
 | |
|                      int d = dmax + dt + db;
 | |
| 
 | |
|                      if (d < distance[d_index])
 | |
|                      {
 | |
|                         distance[d_index] = png_check_byte(png_ptr, d);
 | |
|                         tr->lut[d_index] = png_check_byte(png_ptr, i);
 | |
|                      }
 | |
|                   } /* for blue */
 | |
|                } /* for green */
 | |
|             } /* for red */
 | |
|          } /* num_palette */
 | |
|       } /* full_quantize */
 | |
|    } /* png_ptr != NULL */
 | |
| }
 | |
| #endif /* READ_QUANTIZE */
 | |
| 
 | |
| #ifdef PNG_READ_PACK_SUPPORTED
 | |
| /* Unpack pixels of 1, 2, or 4 bits per pixel into 1 byte per pixel,
 | |
|  * without changing the actual values.  Thus, if you had a row with
 | |
|  * a bit depth of 1, you would end up with bytes that only contained
 | |
|  * the numbers 0 or 1.  If you would rather they contain 0 and 255, use
 | |
|  * png_set_expand_gray_1_2_4_to_8 instead.
 | |
|  */
 | |
| static void
 | |
| png_do_read_unpack(png_transformp *transform, png_transform_controlp tc)
 | |
| {
 | |
|    png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp);
 | |
|    png_const_bytep ep = png_voidcast(png_const_bytep, tc->dp);
 | |
|    png_bytep dp = png_voidcast(png_bytep, tc->dp);
 | |
| 
 | |
|    sp += PNG_TC_ROWBYTES(*tc) - 1; /* Start from end */
 | |
|    dp += tc->width; /* output bit depth is 8 */
 | |
| 
 | |
| #  define png_ptr (tc->png_ptr)
 | |
|    png_debug(1, "in png_do_unpack");
 | |
| 
 | |
|    switch (tc->bit_depth)
 | |
|    {
 | |
|       case 1:
 | |
|       {
 | |
|          /* Because we copy from the last pixel down the shift required
 | |
|           * at the start is 8-pixels_in_last_byte, which is just:
 | |
|           */
 | |
|          unsigned int shift = 7U & -tc->width;
 | |
| 
 | |
|          while (dp > ep)
 | |
|          {
 | |
|             *--dp = (*sp >> shift) & 1U;
 | |
|             shift = 7U & (shift+1U);
 | |
|             if (shift == 0U)
 | |
|                --sp;
 | |
|          }
 | |
| 
 | |
|          debug(shift == 0U);
 | |
|          break;
 | |
|       }
 | |
| 
 | |
|       case 2:
 | |
|       {
 | |
|          unsigned int shift = 7U & -(tc->width << 1);
 | |
| 
 | |
|          while (dp > ep)
 | |
|          {
 | |
|             *--dp = (*sp >> shift) & 3U;
 | |
|             shift = 7U & (shift+2U);
 | |
|             if (shift == 0U)
 | |
|                --sp;
 | |
|          }
 | |
| 
 | |
|          debug(shift == 0U);
 | |
|          break;
 | |
|       }
 | |
| 
 | |
|       case 4:
 | |
|       {
 | |
|          unsigned int shift = 7U & -(tc->width << 2);
 | |
| 
 | |
|          while (dp > ep)
 | |
|          {
 | |
|             *--dp = (*sp >> shift) & 15U;
 | |
|             shift = 7U & (shift+4U);
 | |
|             if (shift == 0U)
 | |
|                --sp;
 | |
|          }
 | |
| 
 | |
|          debug(shift == 0U);
 | |
|          break;
 | |
|       }
 | |
| 
 | |
|       default:
 | |
|          impossible("bit depth");
 | |
|    }
 | |
| 
 | |
|    debug(dp == ep && sp == png_upcast(png_const_bytep, tc->sp)-1U);
 | |
|    tc->sp = dp;
 | |
| 
 | |
|    if ((tc->format & PNG_FORMAT_FLAG_COLORMAP) == 0U)
 | |
|    {
 | |
|       tc->range++;
 | |
|       tc->format |= PNG_FORMAT_FLAG_RANGE;
 | |
|    }
 | |
| 
 | |
|    tc->bit_depth = 8U;
 | |
|    PNG_UNUSED(transform)
 | |
| #  undef png_ptr
 | |
| }
 | |
| 
 | |
| /* Called from the curiously named png_set_packing API in pngtrans.c; the read
 | |
|  * and write code is separated because read 'unpacks' (from PNG format) and
 | |
|  * write 'packs' (to PNG format.)
 | |
|  */
 | |
| void /* PRIVATE */
 | |
| png_init_read_pack(png_transformp *transform, png_transform_controlp tc)
 | |
| {
 | |
| #  define png_ptr tc->png_ptr
 | |
|    debug(tc->init);
 | |
| 
 | |
|    if (tc->bit_depth < 8) /* else no packing/unpacking */
 | |
|    {
 | |
|       /* For indexed images the pack operation does not invalidate the range; in
 | |
|        * fact the corresponding shift operation would!
 | |
|        */
 | |
|       if ((tc->format & PNG_FORMAT_FLAG_COLORMAP) == 0U)
 | |
|       {
 | |
|          tc->range++;
 | |
|          tc->format |= PNG_FORMAT_FLAG_RANGE;
 | |
|       }
 | |
| 
 | |
|       tc->bit_depth = 8U;
 | |
| 
 | |
|       if (tc->init == PNG_TC_INIT_FINAL)
 | |
|          (*transform)->fn = png_do_read_unpack/* sic: it unpacks */;
 | |
|    }
 | |
| 
 | |
|    else /* the transform is not applicable */
 | |
|       (*transform)->fn = NULL;
 | |
| 
 | |
| #  undef png_ptr
 | |
| }
 | |
| #endif /* READ_PACK */
 | |
| 
 | |
| #if defined(PNG_READ_EXPAND_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
 | |
| #  ifdef PNG_READ_tRNS_SUPPORTED
 | |
| static unsigned int
 | |
| fill_transparent_pixel(png_const_structrp png_ptr, png_byte *trans)
 | |
|    /* Fill a byte array according to the transparent pixel value and return a
 | |
|     * count of the number of bytes.  Low bit depth gray values are replicated in
 | |
|     * the first byte.  Writes from 1 to 6 bytes.
 | |
|     */
 | |
| {
 | |
|    /* There must be a tRNS chunk and this must not be a palette image: */
 | |
|    debug(png_ptr->num_trans == 1 &&
 | |
|       !(png_ptr->color_type & (PNG_COLOR_MASK_ALPHA+PNG_COLOR_MASK_PALETTE)));
 | |
| 
 | |
|    if (!(png_ptr->color_type & PNG_COLOR_MASK_COLOR)) /* gray */
 | |
|    {
 | |
|       unsigned int t = png_ptr->trans_color.gray;
 | |
|       unsigned int depth = png_ptr->bit_depth;
 | |
| 
 | |
|       if (depth < 16U)
 | |
|       {
 | |
|          /* ISO PNG 11.3.2.1 "tRNS Transparency": "If the image bit depth is
 | |
|           * less than 16, the least significant bits are used and the others are
 | |
|           * 0."  So mask out the upper bits.
 | |
|           */
 | |
|          t &= (1U<<depth)-1U;
 | |
| 
 | |
|          /* And replicate low bit-depth values across the byte: */
 | |
|          while (depth < 8U)
 | |
|          {
 | |
|             t |= t << depth;
 | |
|             depth <<= 1;
 | |
|          }
 | |
| 
 | |
|          trans[0] = PNG_BYTE(t);
 | |
|          return 1U;
 | |
|       }
 | |
| 
 | |
|       /* Else a 16 bit value: */
 | |
|       trans[0] = PNG_BYTE(t >> 8);
 | |
|       trans[1] = PNG_BYTE(t);
 | |
|       return 2U;
 | |
|    }
 | |
| 
 | |
|    else /* color */ switch (png_ptr->bit_depth)
 | |
|    {
 | |
|       case 8: /* 8-bit RGB */
 | |
|          trans[0] = PNG_BYTE(png_ptr->trans_color.red);
 | |
|          trans[1] = PNG_BYTE(png_ptr->trans_color.green);
 | |
|          trans[2] = PNG_BYTE(png_ptr->trans_color.blue);
 | |
|          return 3U;
 | |
| 
 | |
|       case 16: /* 16-bit RGB */
 | |
|          trans[0] = PNG_BYTE(png_ptr->trans_color.red >> 8);
 | |
|          trans[1] = PNG_BYTE(png_ptr->trans_color.red);
 | |
|          trans[2] = PNG_BYTE(png_ptr->trans_color.green >> 8);
 | |
|          trans[3] = PNG_BYTE(png_ptr->trans_color.green);
 | |
|          trans[4] = PNG_BYTE(png_ptr->trans_color.blue >> 8);
 | |
|          trans[5] = PNG_BYTE(png_ptr->trans_color.blue);
 | |
|          return 6U;
 | |
| 
 | |
|       default:
 | |
|          NOT_REACHED;
 | |
|          return 0U; /* safe */
 | |
|    }
 | |
| }
 | |
| #  endif /* READ_tRNS */
 | |
| #endif /* READ_EXPAND || READ_BACKGROUND */
 | |
| 
 | |
| #ifdef PNG_READ_EXPAND_SUPPORTED
 | |
| /* Flags for png_init_expand */
 | |
| #define PNG_EXPAND_PALETTE  1U /* palette images only, includes tRNS */
 | |
| #define PNG_EXPAND_LBD_GRAY 2U /* grayscale low-bit depth only */
 | |
| #define PNG_EXPAND_tRNS     4U /* non-palette images only */
 | |
| 
 | |
| /* This struct is only required for tRNS matching, but it is convenient to
 | |
|  * allocated it anyway even if READ_tRNS is not supported.
 | |
|  */
 | |
| typedef struct
 | |
| {
 | |
|    png_transform tr;
 | |
|    unsigned int  ntrans;               /* number of bytes below */
 | |
|    png_byte      transparent_pixel[6]; /* the transparent pixel value */
 | |
| }  png_expand;
 | |
| 
 | |
| #ifdef PNG_READ_tRNS_SUPPORTED
 | |
| /* Look for colors matching the trans_color in png_ptr, low bit depth gray is
 | |
|  * covered below so this only need handle 8 abd 16-bit channels.
 | |
|  */
 | |
| static void
 | |
| png_do_expand_tRNS(png_transformp *transform, png_transform_controlp tc)
 | |
| {
 | |
| #  define png_ptr (tc->png_ptr)
 | |
|    png_expand *tr = png_transform_cast(png_expand, *transform);
 | |
|    png_bytep dp = png_voidcast(png_bytep, tc->dp);
 | |
|    png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp);
 | |
|    const png_const_bytep ep = sp;
 | |
|    const unsigned int spixel_size = PNG_TC_PIXEL_DEPTH(*tc) >> 3;
 | |
|    unsigned int alpha_size;
 | |
| 
 | |
|    /* We expect opaque and transparent pixels to be interleaved but with long
 | |
|     * sequences of each.  Because we are adding an alpha channel we must copy
 | |
|     * down.
 | |
|     */
 | |
|    debug(!(tc->format & PNG_FORMAT_FLAG_ALPHA));
 | |
|    debug(spixel_size == tr->ntrans);
 | |
|    sp += PNG_TC_ROWBYTES(*tc);
 | |
|    tc->sp = dp;
 | |
|    tc->format |= PNG_FORMAT_FLAG_ALPHA;
 | |
|    tc->invalid_info |= PNG_INFO_tRNS;
 | |
|    tc->transparent_alpha = 1U;
 | |
|    alpha_size = (PNG_TC_PIXEL_DEPTH(*tc)>>3) - spixel_size;
 | |
|    debug(alpha_size == 1 || alpha_size == 2);
 | |
|    dp += PNG_TC_ROWBYTES(*tc);
 | |
| 
 | |
|    do
 | |
|    {
 | |
|       unsigned int i = spixel_size;
 | |
|       png_byte alpha = 0U;
 | |
| 
 | |
|       dp -= alpha_size;
 | |
|       alpha = 0U;
 | |
| 
 | |
|       /* Copy and check one source pixel (backwards, to avoid any
 | |
|        * overwrite):
 | |
|        */
 | |
|       do if ((*--dp = *--sp) != tr->transparent_pixel[--i]) /* pixel != tRNS */
 | |
|          alpha = 0xFFU;
 | |
|       while (i != 0U);
 | |
| 
 | |
|       /* i == 0 */
 | |
|       do
 | |
|          dp[spixel_size + i] = alpha;
 | |
|       while (++i < alpha_size);
 | |
|    } while (sp > ep);
 | |
| 
 | |
|    debug(sp == ep && dp == tc->dp); /* else overwrite */
 | |
| #  undef png_ptr
 | |
| }
 | |
| #endif /* READ_tRNS */
 | |
| 
 | |
| /* Expand grayscale images of less than 8-bit depth to 8 bits.
 | |
|  * libpng 1.7.0: this no longer expands everything, it just expands the low bit
 | |
|  * depth gray row.  It does *NOT* expand the tRNS into an alpha channel unless
 | |
|  * it is told to do so.
 | |
|  *
 | |
|  * API CHANGE: the function now does what it was always meant to do.
 | |
|  *
 | |
|  * This is like do_unpack except that the packed data is expanded to the full
 | |
|  * 8-bit range; scaled up.  This is not a good thing to do on an indexed image;
 | |
|  * the indices will be invalid.
 | |
|  *
 | |
|  * The tRNS handling is included here too; speed is not important because the
 | |
|  * result will always be cached unless the PNG is very small.
 | |
|  */
 | |
| static void
 | |
| png_do_expand_lbd_gray(png_transformp *transform, png_transform_controlp tc)
 | |
| {
 | |
| #  define png_ptr (tc->png_ptr)
 | |
|    png_bytep dp = png_voidcast(png_bytep, tc->dp);
 | |
|    const png_const_bytep ep = dp;
 | |
|    png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp);
 | |
|    const unsigned int bit_depth = tc->bit_depth;
 | |
| #  ifdef PNG_READ_sBIT_SUPPORTED
 | |
|    unsigned int insignificant_bits = 0U;
 | |
| #  endif /* READ_sBIT */
 | |
| #  ifdef PNG_READ_tRNS_SUPPORTED
 | |
|    unsigned int gray = 0xffffU; /* doesn't match anything */
 | |
|    unsigned int do_alpha = 0U;
 | |
| #  endif /* READ_tRNS */
 | |
| 
 | |
|    sp += PNG_TC_ROWBYTES(*tc); /* last byte +1 */
 | |
|    tc->bit_depth = 8U;
 | |
|    tc->invalid_info |= PNG_INFO_tRNS;
 | |
| #  ifdef PNG_READ_sBIT_SUPPORTED
 | |
|       if (bit_depth > 1U /* irrelevant for bit depth 1 */ &&
 | |
|           !(tc->invalid_info & PNG_INFO_sBIT) &&
 | |
|           tc->sBIT_G > 0U/*SAFETY*/ && tc->sBIT_G < bit_depth)
 | |
|          insignificant_bits = bit_depth - tc->sBIT_G;
 | |
| #  endif /* READ_sBIT */
 | |
| 
 | |
| #  ifdef PNG_READ_tRNS_SUPPORTED
 | |
|       if (((*transform)->args & PNG_EXPAND_tRNS) != 0)
 | |
|       {
 | |
|          tc->format |= PNG_FORMAT_FLAG_ALPHA;
 | |
|          tc->transparent_alpha = 1U;
 | |
|          gray = png_ptr->trans_color.gray & ((1U << bit_depth)-1U);
 | |
|          do_alpha = 1U;
 | |
|       }
 | |
| 
 | |
|       /* This helps avoid cluttering the code up with #ifdefs: */
 | |
| #     define check_tRNS if (do_alpha) *--dp = (pixel != gray) * 255U;
 | |
| #  else /* !READ_tRNS */
 | |
| #     define check_tRNS
 | |
| #  endif /* READ_tRNS */
 | |
| 
 | |
|    dp += PNG_TC_ROWBYTES(*tc); /* pre-decremented below */
 | |
| 
 | |
|    switch (bit_depth)
 | |
|    {
 | |
|       case 1:
 | |
|       {
 | |
|          unsigned int shift = 7U & -tc->width;
 | |
|          unsigned int s = *--sp;
 | |
| 
 | |
|          for(;;)
 | |
|          {
 | |
|             if (shift == 8U) s = *--sp, shift = 0;
 | |
| 
 | |
|             {
 | |
|                const unsigned int pixel = (s >> shift) & 1U;
 | |
| 
 | |
|                check_tRNS
 | |
|                *--dp = PNG_BYTE(pixel * 255U);
 | |
|                if (dp <= ep) break;
 | |
|             }
 | |
|             ++shift;
 | |
|          }
 | |
| 
 | |
|          debug(dp == ep && shift == 7U && sp == tc->sp);
 | |
|          break;
 | |
|       }
 | |
| 
 | |
|       case 2:
 | |
|       {
 | |
|          unsigned int shift = 7U & -(tc->width << 1)/*overflow ok*/;
 | |
|          unsigned int s = *--sp;
 | |
| 
 | |
|          for (;;)
 | |
|          {
 | |
|             if (shift == 8U) s = *--sp, shift = 0;
 | |
|             {
 | |
|                const unsigned int pixel = (s >> shift) & 3U;
 | |
| 
 | |
|                check_tRNS
 | |
| 
 | |
| #  ifdef PNG_READ_sBIT_SUPPORTED
 | |
|                /* 'sig_bits' must be 1 or 2 leaving insignificant_bits 0 or
 | |
|                 * 1.  This may look silly but it allows a compact representation
 | |
|                 * of 1 bit gray + 1 bit alpha (transparency):
 | |
|                 */
 | |
|                if (insignificant_bits /* only 1 bit significant */)
 | |
|                   *--dp = PNG_BYTE((pixel >> 1) * 255U);
 | |
| 
 | |
|                else
 | |
| #  endif
 | |
|                   *--dp = PNG_BYTE(pixel * 85U);
 | |
| 
 | |
|                if (dp <= ep) break;
 | |
|             }
 | |
|             shift += 2U;
 | |
|          }
 | |
| 
 | |
|          debug(dp == ep && shift == 6U && sp == tc->sp);
 | |
|          break;
 | |
|       }
 | |
| 
 | |
|       case 4:
 | |
|       {
 | |
|          unsigned int shift = 7U & -(tc->width << 2)/*overflow ok*/;
 | |
|          unsigned int s = *--sp;
 | |
| #  ifdef PNG_READ_sBIT_SUPPORTED
 | |
|          const unsigned int div = (1U << (4U-insignificant_bits)) - 1U;
 | |
| #  endif
 | |
| 
 | |
|          for (;;)
 | |
|          {
 | |
|             if (shift == 8U) s = *--sp, shift = 0;
 | |
|             {
 | |
|                unsigned int pixel = (s >> shift) & 15U;
 | |
| 
 | |
|                check_tRNS
 | |
| 
 | |
| #  ifdef PNG_READ_sBIT_SUPPORTED
 | |
|                /* insignificant_bits may be 0, 1, 2 or 3, requiring a multiply
 | |
|                 * by 17, 255/7, 85 or 255.  Since this operation is always
 | |
|                 * cached we don't much care about the time to do the divide
 | |
|                 * below.
 | |
|                 */
 | |
|                if (insignificant_bits)
 | |
|                   pixel = ((pixel>>insignificant_bits) * 255U + (div>>1)) / div;
 | |
| 
 | |
|                else
 | |
| #  endif
 | |
|                   pixel *= 17U;
 | |
| 
 | |
|                *--dp = PNG_BYTE(pixel);
 | |
|                if (dp <= ep) break;
 | |
|             }
 | |
| 
 | |
|             shift += 4U;
 | |
|          }
 | |
| 
 | |
|          debug(dp == ep && shift == 4U && sp == tc->sp);
 | |
|          break;
 | |
|       }
 | |
| 
 | |
|       default:
 | |
|          impossible("bit depth");
 | |
|    }
 | |
| 
 | |
|    tc->sp = ep;
 | |
| 
 | |
| #  undef check_tRNS
 | |
| #  undef png_ptr
 | |
| }
 | |
| 
 | |
| static void
 | |
| png_init_expand(png_transformp *transform, png_transform_controlp tc)
 | |
| {
 | |
| #  define png_ptr (tc->png_ptr)
 | |
|    /* The possible combinations are:
 | |
|     *
 | |
|     * 1) PALETTE: the 'palette' flag should be set on the transform control and
 | |
|     *    all that need be done is cancel this to cause the cache code to do the
 | |
|     *    expansion.
 | |
|     *
 | |
|     * 2) LBP_GRAY, LBP_GRAY+tRNS: use png_do_expand_lbd_gray to do the required
 | |
|     *    expand.  Can be cached.
 | |
|     *
 | |
|     * 3) tRNS: scan the row for the relevant tRNS value.
 | |
|     *
 | |
|     * Note that expanding 8 to 16 bits is a byte op in pngtrans.c (it just
 | |
|     * replicates bytes).
 | |
|     */
 | |
|    if (tc->palette)
 | |
|    {
 | |
|       debug(tc->caching && !(tc->format & PNG_FORMAT_FLAG_COLORMAP));
 | |
| 
 | |
|       if (((*transform)->args & PNG_EXPAND_PALETTE) != 0U)
 | |
|       {
 | |
|          tc->palette = 0U;
 | |
|          tc->invalid_info |= PNG_INFO_PLTE + PNG_INFO_tRNS;
 | |
|          tc->cost = PNG_CACHE_COST_LIMIT; /* the cache is required! */
 | |
|       }
 | |
| 
 | |
|       /* Note that this needs to happen when the row is processed (!tc->init) as
 | |
|        * well.
 | |
|        */
 | |
|    }
 | |
| 
 | |
|    else if (!(tc->format & PNG_FORMAT_FLAG_COLORMAP))
 | |
|    {
 | |
|       png_uint_32 args = (*transform)->args & PNG_BIC_MASK(PNG_EXPAND_PALETTE);
 | |
|       unsigned int bit_depth = tc->bit_depth;
 | |
| 
 | |
|       debug(tc->init);
 | |
| 
 | |
|       if (bit_depth >= 8U)
 | |
|          args &= PNG_BIC_MASK(PNG_EXPAND_LBD_GRAY);
 | |
| 
 | |
| #     ifdef PNG_READ_tRNS_SUPPORTED
 | |
|          if (png_ptr->num_trans == 0U ||
 | |
|              (tc->format & PNG_FORMAT_FLAG_ALPHA) != 0U ||
 | |
|              (tc->invalid_info & PNG_INFO_tRNS) != 0U)
 | |
| #     endif
 | |
|          args &= PNG_BIC_MASK(PNG_EXPAND_tRNS);
 | |
| 
 | |
|       (*transform)->args = args;
 | |
| 
 | |
|       switch (args)
 | |
|       {
 | |
|          case PNG_EXPAND_LBD_GRAY:
 | |
|             tc->bit_depth = 8U;
 | |
|             tc->invalid_info |= PNG_INFO_tRNS;
 | |
| 
 | |
|             if (tc->init == PNG_TC_INIT_FINAL)
 | |
|                (*transform)->fn = png_do_expand_lbd_gray;
 | |
|             break;
 | |
| 
 | |
| #     ifdef PNG_READ_tRNS_SUPPORTED
 | |
|          case PNG_EXPAND_LBD_GRAY + PNG_EXPAND_tRNS:
 | |
|             tc->bit_depth = 8U;
 | |
|             tc->format |= PNG_FORMAT_FLAG_ALPHA;
 | |
|             tc->invalid_info |= PNG_INFO_tRNS;
 | |
|             tc->transparent_alpha = 1U;
 | |
| 
 | |
|             /* In this case tRNS must be left unmodified for the expansion code
 | |
|              * to handle.
 | |
|              */
 | |
|             if (tc->init == PNG_TC_INIT_FINAL)
 | |
|                (*transform)->fn = png_do_expand_lbd_gray;
 | |
|             break;
 | |
| 
 | |
|          case PNG_EXPAND_tRNS:
 | |
|             if (tc->init == PNG_TC_INIT_FINAL)
 | |
|             {
 | |
|                png_expand *tr = png_transform_cast(png_expand, *transform);
 | |
| 
 | |
|                affirm((tc->bit_depth == 8U || tc->bit_depth == 16U) &&
 | |
|                       (tc->format &
 | |
|                        (PNG_FORMAT_FLAG_COLORMAP|PNG_FORMAT_FLAG_ALPHA)) == 0U);
 | |
| 
 | |
|                tr->ntrans = fill_transparent_pixel(png_ptr,
 | |
|                   tr->transparent_pixel);
 | |
|                tr->tr.fn = png_do_expand_tRNS;
 | |
|             } /* TC_INIT_FINAL */
 | |
| 
 | |
|             tc->format |= PNG_FORMAT_FLAG_ALPHA;
 | |
|             tc->invalid_info |= PNG_INFO_tRNS;
 | |
|             tc->transparent_alpha = 1U;
 | |
|             break;
 | |
| #     endif /* READ_tRNS */
 | |
| 
 | |
|          default: /* transform not applicable */
 | |
|             (*transform)->fn = NULL;
 | |
|             break;
 | |
|       }
 | |
| 
 | |
|       implies(tc->init == PNG_TC_INIT_FINAL,
 | |
|               (*transform)->fn != png_init_expand);
 | |
|    }
 | |
| 
 | |
|    else /* not applicable */
 | |
|    {
 | |
|       debug(tc->init);
 | |
|       (*transform)->fn = NULL;
 | |
|       NOT_REACHED;
 | |
|    }
 | |
| #  undef png_ptr
 | |
| }
 | |
| 
 | |
| void PNGAPI
 | |
| png_set_expand_gray_1_2_4_to_8(png_structrp png_ptr)
 | |
| {
 | |
|    if (png_ptr != NULL)
 | |
|       png_add_transform(png_ptr, sizeof (png_expand), png_init_expand,
 | |
|          PNG_TR_EXPAND)->args |= PNG_EXPAND_LBD_GRAY;
 | |
| }
 | |
| 
 | |
| /* Expand paletted images to 8-bit RGB or, if there is a tRNS chunk, RGBA.
 | |
|  * Note that this is effectively handled by the read code palette optimizations.
 | |
|  *
 | |
|  * API CHANGE: this used to have the completely unexpected side effect of
 | |
|  * turning on the above two optimizations.
 | |
|  */
 | |
| void PNGAPI
 | |
| png_set_palette_to_rgb(png_structrp png_ptr)
 | |
| {
 | |
|    if (png_ptr != NULL)
 | |
|       png_add_transform(png_ptr, sizeof (png_expand), png_init_expand,
 | |
|          PNG_TR_EXPAND)->args |= PNG_EXPAND_PALETTE;
 | |
| }
 | |
| 
 | |
| /* Expand paletted images to RGB, expand grayscale images of less than 8-bit
 | |
|  * depth to 8-bit depth, and expand tRNS chunks to alpha channels.  I.e. all the
 | |
|  * above.
 | |
|  */
 | |
| void PNGAPI
 | |
| png_set_expand(png_structrp png_ptr)
 | |
| {
 | |
|    if (png_ptr != NULL)
 | |
|    {
 | |
|       png_set_palette_to_rgb(png_ptr);
 | |
|       png_set_expand_gray_1_2_4_to_8(png_ptr);
 | |
|       png_set_tRNS_to_alpha(png_ptr);
 | |
|    }
 | |
| }
 | |
| #endif /* READ_EXPAND */
 | |
| 
 | |
| #if defined(PNG_READ_EXPAND_SUPPORTED) ||\
 | |
|     defined(PNG_READ_STRIP_ALPHA_SUPPORTED)
 | |
| 
 | |
| #define PNG_INIT_STRIP_ALPHA 1U
 | |
| #define PNG_INIT_EXPAND_tRNS 2U
 | |
| static void
 | |
| png_init_alpha(png_transformp *transform, png_transform_controlp tc)
 | |
| {
 | |
| #  define png_ptr (tc->png_ptr)
 | |
|    int required = 0;
 | |
| 
 | |
| #  if defined(PNG_READ_EXPAND_SUPPORTED) && defined(PNG_READ_tRNS_SUPPORTED)
 | |
|       if ((*transform)->args & PNG_INIT_EXPAND_tRNS)
 | |
|       {
 | |
|          /* Prior to 1.7 the alpha channel was stripped after expanding the tRNS
 | |
|           * chunk, so this effectively cancelled out the expand.
 | |
|           */
 | |
|          if (png_ptr->num_trans > 0 && !tc->palette &&
 | |
|              !((*transform)->args & PNG_INIT_STRIP_ALPHA))
 | |
|          {
 | |
|             debug((tc->format & PNG_FORMAT_FLAG_COLORMAP) == 0);
 | |
| 
 | |
|             required = 1;
 | |
|             tc->expand_tRNS = 1U;
 | |
| 
 | |
|             /* This happens as a result of an explicit API call to
 | |
|              * png_set_tRNS_to_alpha, so expand low-bit-depth gray too:
 | |
|              */
 | |
|             if (tc->init == PNG_TC_INIT_FORMAT)
 | |
|                png_add_transform(png_ptr, sizeof (png_expand), png_init_expand,
 | |
|                   PNG_TR_EXPAND)->args |= PNG_EXPAND_tRNS + PNG_EXPAND_LBD_GRAY;
 | |
|          }
 | |
| 
 | |
|          else
 | |
|             (*transform)->args &= PNG_BIC_MASK(PNG_INIT_EXPAND_tRNS);
 | |
|       }
 | |
| #  endif /* READ_EXPAND && READ_tRNS */
 | |
| 
 | |
| #  ifdef PNG_READ_STRIP_ALPHA_SUPPORTED
 | |
|       if ((*transform)->args & PNG_INIT_STRIP_ALPHA)
 | |
|       {
 | |
|          /* When compose is being done tRNS will be expanded regardless of the
 | |
|           * above test.  Rather that trying to work out if this will happen the
 | |
|           * code just inserts a strip operation; it will be removed later if it
 | |
|           * is not needed.
 | |
|           */
 | |
|          required = 1;
 | |
|          tc->strip_alpha = 1U;
 | |
| 
 | |
|          if (tc->init == PNG_TC_INIT_FORMAT)
 | |
|             png_add_strip_alpha_byte_ops(png_ptr);
 | |
|       }
 | |
| #  endif /* READ_STRIP_ALPHA */
 | |
| 
 | |
|    if (!required)
 | |
|       (*transform)->fn = NULL;
 | |
| #  undef png_ptr
 | |
| }
 | |
| #endif /* READ_EXPAND || READ_STRIP_ALPHA */
 | |
| 
 | |
| #ifdef PNG_READ_EXPAND_SUPPORTED
 | |
| /* Expand tRNS chunks to alpha channels.  This only expands the tRNS chunk on
 | |
|  * non-palette formats; call png_set_palette_to_rgb to get the corresponding
 | |
|  * effect for a palette.
 | |
|  *
 | |
|  * Note that this will expand low bit depth gray if there is a tRNS chunk, but
 | |
|  * if not nothing will happen.
 | |
|  *
 | |
|  * API CHANGE: this used to do all the expansions, it was rather pointless
 | |
|  * calling it.
 | |
|  */
 | |
| void PNGAPI
 | |
| png_set_tRNS_to_alpha(png_structrp png_ptr)
 | |
| {
 | |
|    if (png_ptr != NULL)
 | |
|       png_add_transform(png_ptr, 0/*size*/, png_init_alpha, PNG_TR_INIT_ALPHA)->
 | |
|          args |= PNG_INIT_EXPAND_tRNS;
 | |
| }
 | |
| #endif /* READ_EXPAND */
 | |
| 
 | |
| #ifdef PNG_READ_STRIP_ALPHA_SUPPORTED
 | |
| void PNGAPI
 | |
| png_set_strip_alpha(png_structrp png_ptr)
 | |
| {
 | |
|    if (png_ptr != NULL)
 | |
|       png_add_transform(png_ptr, 0/*size*/, png_init_alpha, PNG_TR_INIT_ALPHA)->
 | |
|          args |= PNG_INIT_STRIP_ALPHA;
 | |
| }
 | |
| #endif /* READ_STRIP_ALPHA */
 | |
| 
 | |
| #ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED
 | |
| static void
 | |
| png_do_chop_16_to_8(png_transformp *transform, png_transform_controlp tc)
 | |
|    /* This is actually a repeat of the byte transform, unnecessary code
 | |
|     * replication.
 | |
|     *
 | |
|     * TODO: remove this
 | |
|     */
 | |
| {
 | |
| #  define png_ptr (tc->png_ptr)
 | |
|    png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp); /* source */
 | |
|    png_const_bytep ep = sp + PNG_TC_ROWBYTES(*tc); /* end+1 */
 | |
|    png_bytep dp = png_voidcast(png_bytep, tc->dp); /* destination */
 | |
| 
 | |
|    debug(tc->bit_depth == 16U);
 | |
|    tc->sp = dp;
 | |
|    tc->bit_depth = 8U;
 | |
| 
 | |
|    while (sp < ep)
 | |
|       *dp++ = *sp, sp += 2;
 | |
| 
 | |
|    debug(sp == ep);
 | |
| #  undef png_ptr
 | |
| 
 | |
|    PNG_UNUSED(transform)
 | |
| }
 | |
| 
 | |
| /* A transform containing some useful scaling values... */
 | |
| typedef struct
 | |
| {
 | |
|    png_transform   tr;
 | |
|    png_uint_32     shifts; /* 4 4-bit values preceeded by a shibboleth (1) */
 | |
|    png_uint_32     channel_scale[4];
 | |
| } png_transform_scale_16_to_8;
 | |
| 
 | |
| /* Scale rows of bit depth 16 down to 8 accurately */
 | |
| static void
 | |
| png_do_scale_16_to_8(png_transformp *transform, png_transform_controlp tc)
 | |
| {
 | |
| #  define png_ptr (tc->png_ptr)
 | |
|    png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp); /* source */
 | |
|    png_const_bytep ep = sp + PNG_TC_ROWBYTES(*tc); /* end+1 */
 | |
|    png_bytep dp = png_voidcast(png_bytep, tc->dp); /* destination */
 | |
|    png_transform_scale_16_to_8 *tr =
 | |
|       png_transform_cast(png_transform_scale_16_to_8, *transform);
 | |
|    png_uint_32p scale = 0;
 | |
|    png_uint_32 shift = 1U; /* set the shibboleth at the start */
 | |
| 
 | |
|    debug(tc->bit_depth == 16U);
 | |
|    tc->sp = dp;
 | |
|    tc->bit_depth = 8U;
 | |
| 
 | |
|    while (sp < ep)
 | |
|    {
 | |
|       /* The input is an array of 16 bit components, these must be scaled to
 | |
|        * 8 bits each taking into account the sBIT setting.  The calculation
 | |
|        * requires that the insignificant bits be stripped from the input value
 | |
|        * via a shift then scaled back to 8 bits:
 | |
|        *
 | |
|        *      output = ((input >> shift) * scale + round) >> 24
 | |
|        *
 | |
|        * The shifts are packed into tr->shifts, with the end of the list marked
 | |
|        * by a shibboleth, 1, which is preset above.
 | |
|        */
 | |
|       png_uint_32 v = png_get_uint_16(sp);
 | |
| 
 | |
|       sp += 2;
 | |
| 
 | |
|       if (shift == 1U)
 | |
|       {
 | |
|          shift = tr->shifts;
 | |
|          scale = tr->channel_scale;
 | |
|       }
 | |
| 
 | |
|       *dp++ = PNG_BYTE(((v >> (shift & 0xFU)) * *scale++ + 0x800000U) >> 24);
 | |
|       shift >>= 4;
 | |
|    }
 | |
| 
 | |
|    affirm(sp == ep);
 | |
| #  undef png_ptr
 | |
| }
 | |
| 
 | |
| static int
 | |
| add_scale(png_transform_scale_16_to_8 *tr, unsigned int sBIT, unsigned int ch)
 | |
| {
 | |
|    /* This is the output max (255) scaled by 2^24 divided by the input max'
 | |
|     * (which is variable) and rounded.  It gives the exact 8-bit answer for all
 | |
|     * input sBIT depths when used in the calculation:
 | |
|     *
 | |
|     *    output = ((input >> shift) * scale + 0x800000U) >> 24
 | |
|     */
 | |
|    tr->channel_scale[ch] = (0xFF000000U + ((1U<<sBIT)>>1)) / ((1U<<sBIT)-1U);
 | |
|    tr->shifts |= ((16U-sBIT) & 0xFU) << (4U*ch);
 | |
| 
 | |
|    /* The result says whether there are 8 or fewer significant bits in the
 | |
|     * input value; if so we can just drop the low byte.
 | |
|     */
 | |
|    return sBIT <= 8U;
 | |
| }
 | |
| 
 | |
| static void
 | |
| png_init_scale_16_to_8(png_transformp *transform, png_transform_controlp tc)
 | |
| {
 | |
|    if (tc->bit_depth == 16U)
 | |
|    {
 | |
| #     define png_ptr (tc->png_ptr)
 | |
|       tc->bit_depth = 8U;
 | |
|       /* But this invalidates tRNS (a 16-bit tRNS cannot be updated to match
 | |
|        * 8-bit data correctly).
 | |
|        */
 | |
|       tc->invalid_info |= PNG_INFO_tRNS+PNG_INFO_hIST+PNG_INFO_pCAL;
 | |
|       /* TODO: These need further processing: PNG_INFO_bKGD */
 | |
| 
 | |
|       if (tc->init == PNG_TC_INIT_FINAL)
 | |
|       {
 | |
|          png_transform_scale_16_to_8 *tr =
 | |
|             png_transform_cast(png_transform_scale_16_to_8, *transform);
 | |
| 
 | |
|          /* Set the scale factors for each channel (up to 4), the factors are
 | |
|           * made so that:
 | |
|           *
 | |
|           *     ((channel >> shift) * factor + 0x800000U) >> 24
 | |
|           *
 | |
|           * Gives the required 8-bit value.  The 'shift' is stored in a single
 | |
|           * png_uint_32 with a shibboleth at the end.
 | |
|           */
 | |
|          unsigned int channels = 0U;
 | |
|          int chop_ok = 1;
 | |
| 
 | |
|          tr->shifts = 0U;
 | |
| 
 | |
|          /* This adds up to four scale factors, the remainder are left as 0
 | |
|           * which is safe and leads to obvious errors in the output images in
 | |
|           * the event of an (internal) error.
 | |
|           */
 | |
|          if (tc->format & PNG_FORMAT_FLAG_COLOR)
 | |
|             chop_ok &= add_scale(tr, tc->sBIT_R, channels++);
 | |
| 
 | |
|          chop_ok &= add_scale(tr, tc->sBIT_G, channels++);
 | |
| 
 | |
|          if (tc->format & PNG_FORMAT_FLAG_COLOR)
 | |
|             chop_ok &= add_scale(tr, tc->sBIT_B, channels++);
 | |
| 
 | |
|          if (tc->format & PNG_FORMAT_FLAG_ALPHA)
 | |
|             chop_ok &= add_scale(tr, tc->sBIT_A, channels++);
 | |
| 
 | |
|          if (chop_ok)
 | |
|             tr->tr.fn = png_do_chop_16_to_8;
 | |
| 
 | |
|          else
 | |
|          {
 | |
|             int handled = 1;
 | |
| 
 | |
|             /* Add the shibboleth at the end */
 | |
|             tr->shifts |= 1U << (4U*channels);
 | |
|             tr->tr.fn = png_do_scale_16_to_8;
 | |
| 
 | |
|             /* sBIT is a little tricky; it has to be processed in the scaling
 | |
|              * operation.  The result will have the same number of bits unless
 | |
|              * there were more than 8 before.  The sBIT flags in the transform
 | |
|              * control are left unchanged here because the data is still valid,
 | |
|              * unless all the values end up as 8 in which case there is no
 | |
|              * remaining sBIT info.
 | |
|              *
 | |
|              * Note that fields, such as alpha, which are not set for this row
 | |
|              * format will always have max values, so won't reset 'handled':
 | |
|              */
 | |
|             if (tc->sBIT_R >= 8U) tc->sBIT_R = 8U; else handled = 0;
 | |
|             if (tc->sBIT_G >= 8U) tc->sBIT_G = 8U; else handled = 0;
 | |
|             if (tc->sBIT_B >= 8U) tc->sBIT_B = 8U; else handled = 0;
 | |
|             if (tc->sBIT_A >= 8U) tc->sBIT_A = 8U; else handled = 0;
 | |
| 
 | |
|             /* If all the sBIT values were >= 8U all the bits are now
 | |
|              * significant:
 | |
|              */
 | |
|             if (handled)
 | |
|                tc->invalid_info |= PNG_INFO_sBIT;
 | |
|          }
 | |
|       }
 | |
| 
 | |
| #     undef png_ptr
 | |
|    }
 | |
| 
 | |
|    else /* not applicable */
 | |
|       (*transform)->fn = NULL;
 | |
| }
 | |
| 
 | |
| void PNGAPI
 | |
| png_set_scale_16(png_structrp png_ptr)
 | |
| {
 | |
|    if (png_ptr != NULL)
 | |
|       png_add_transform(png_ptr, sizeof (png_transform_scale_16_to_8),
 | |
|          png_init_scale_16_to_8, PNG_TR_SCALE_16_TO_8);
 | |
| }
 | |
| #endif /* READ_SCALE_16_TO_8 */
 | |
| 
 | |
| #ifdef PNG_READ_GAMMA_SUPPORTED
 | |
|    /* Code that depends on READ_GAMMA support; RGB to gray convertion and
 | |
|     * background composition (including the various alpha-mode handling
 | |
|     * operations which produce pre-multiplied alpha by composing on 0).
 | |
|     */
 | |
| /* Calculate a reciprocal, return 0 on div-by-zero or overflow. */
 | |
| static png_fixed_point
 | |
| png_reciprocal(png_fixed_point a)
 | |
| {
 | |
| #ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED
 | |
|    double r = floor(1E10/a+.5);
 | |
| 
 | |
|    if (r <= 2147483647. && r >= -2147483648.)
 | |
|       return (png_fixed_point)r;
 | |
| #else
 | |
|    png_fixed_point res;
 | |
| 
 | |
|    if (png_muldiv(&res, PNG_FP_1, PNG_FP_1, a) != 0)
 | |
|       return res;
 | |
| #endif
 | |
| 
 | |
|    return 0; /* error/overflow */
 | |
| }
 | |
| 
 | |
| /* This is the shared test on whether a gamma value is 'significant' - whether
 | |
|  * it is worth doing gamma correction.  'significant_bits' is the number of bits
 | |
|  * in the values to be corrected which are significant.
 | |
|  */
 | |
| static int
 | |
| png_gamma_significant(png_const_structrp png_ptr, png_fixed_point gamma_val,
 | |
|    unsigned int sbits)
 | |
| {
 | |
| #if 0
 | |
|    /* This seems to be wrong.  The issue is that when the app asks for a higher
 | |
|     * bit depth output than the input has significant bits it causes gamma
 | |
|     * correction to be skipped (this was the intent) however there's no
 | |
|     * particular guarantee that the app won't go on to do further gamma
 | |
|     * processing - pngstest does this - and this messes up the results
 | |
|     * completely.
 | |
|     *
 | |
|     * TODO: work out how to optimize this correctly.
 | |
|     */
 | |
|    /* The following table lists the threshold as a difference from PNG_FP_1 at
 | |
|     * which the gamma correction will make a change to at least an 'sbits'
 | |
|     * value.  There is no entry for 1 bit values; gamma correction is never
 | |
|     * significant.
 | |
|     */
 | |
|    static const png_uint_16 gamma_threshold_by_sbit[15][2] =
 | |
|    {
 | |
|       { 36907, 63092 }, /*  2 bits */
 | |
|       { 17812, 21518 }, /*  3 bits */
 | |
|       {  8675,  9496 }, /*  4 bits */
 | |
|       {  4290,  4484 }, /*  5 bits */
 | |
|       {  2134,  2181 }, /*  6 bits */
 | |
|       {  1064,  1075 }, /*  7 bits */
 | |
|       {   531,   534 }, /*  8 bits */
 | |
|       {   265,   266 }, /*  9 bits */
 | |
|       {   132,   132 }, /* 10 bits */
 | |
|       {    66,    66 }, /* 11 bits */
 | |
|       {    33,    33 }, /* 12 bits */
 | |
|       {    16,    16 }, /* 13 bits */
 | |
|       {     8,     8 }, /* 14 bits */
 | |
|       {     4,     4 }, /* 15 bits */
 | |
|       {     2,     2 }, /* 16 bits */
 | |
|    };
 | |
| 
 | |
|    /* Handle out of range values in release by doing the gamma correction: */
 | |
|    debug_handled(sbits > 0U && sbits <= 16U);
 | |
|    if (sbits == 0U || sbits > 16U)
 | |
|       return 1;
 | |
| 
 | |
|    /* 1 bit input or zero gamma, no correction possible/required: */
 | |
|    if (gamma_val == 0 || sbits < 2U)
 | |
|       return 0;
 | |
| 
 | |
|    if (gamma_val < PNG_FP_1 - gamma_threshold_by_sbit[sbits-2U][0U])
 | |
|       return gamma_val < PNG_FP_1 - png_ptr->gamma_threshold;
 | |
| 
 | |
|    else if (gamma_val > PNG_FP_1 + gamma_threshold_by_sbit[sbits-2U][1U])
 | |
|       return gamma_val > PNG_FP_1 + png_ptr->gamma_threshold;
 | |
| #else /* FIXUP */
 | |
|    if (gamma_val < PNG_FP_1)
 | |
|       return gamma_val < PNG_FP_1 - png_ptr->gamma_threshold;
 | |
| 
 | |
|    else if (gamma_val > PNG_FP_1)
 | |
|       return gamma_val > PNG_FP_1 + png_ptr->gamma_threshold;
 | |
| 
 | |
|    PNG_UNUSED(sbits)
 | |
| #endif /* FIXUP */
 | |
| 
 | |
|    return 0; /* not significant */
 | |
| }
 | |
| 
 | |
| static int
 | |
| png_gamma_equal(png_const_structrp png_ptr, png_fixed_point g1,
 | |
|    png_fixed_point g2, png_fixed_point *c, unsigned int sbits)
 | |
|    /* Gamma values are equal, or at least one is unknown; c is the correction
 | |
|     * factor from g1 to g2, i.e. g2/g1.
 | |
|     */
 | |
| {
 | |
|    return sbits == 1U || g1 == 0 || g2 == 0 || g1 == g2 ||
 | |
|       (png_muldiv(c, g2, PNG_FP_1, g1) &&
 | |
|        !png_gamma_significant(png_ptr, *c, sbits));
 | |
| }
 | |
| 
 | |
| #ifdef PNG_SIMPLIFIED_READ_SUPPORTED
 | |
| int
 | |
| png_need_gamma_correction(png_const_structrp png_ptr, png_fixed_point gamma,
 | |
|    int sRGB_output)
 | |
|    /* This is a hook for the simplified code; it just decides whether or not the
 | |
|     * given gamma (which defaults to that of the PNG data) is close enough to
 | |
|     * linear or sRGB not to require gamma correction.
 | |
|     */
 | |
| {
 | |
|    if (gamma == 0)
 | |
|       gamma = png_ptr->colorspace.gamma;
 | |
| 
 | |
|    if (gamma != 0 &&
 | |
|        (png_ptr->colorspace.flags &
 | |
|          (PNG_COLORSPACE_INVALID|PNG_COLORSPACE_HAVE_GAMMA)) ==
 | |
|             PNG_COLORSPACE_HAVE_GAMMA)
 | |
|    {
 | |
| 
 | |
|       if (sRGB_output && !png_muldiv(&gamma, gamma, PNG_GAMMA_sRGB, PNG_FP_1))
 | |
|          return 0; /* overflow, so no correction */
 | |
| 
 | |
|       return png_gamma_significant(png_ptr, gamma, (png_ptr->color_type &
 | |
|                PNG_COLOR_MASK_PALETTE) ? 8U : png_ptr->bit_depth);
 | |
|    }
 | |
| 
 | |
|    return 0; /* no info, no correction */
 | |
| }
 | |
| #endif /* SIMPLIFIED_READ */
 | |
| 
 | |
| #ifndef PNG_FLOATING_ARITHMETIC_SUPPORTED
 | |
| /* Fixed point gamma.
 | |
|  *
 | |
|  * The code to calculate the tables used below can be found in the shell script
 | |
|  * contrib/tools/intgamma.sh
 | |
|  *
 | |
|  * To calculate gamma this code implements fast log() and exp() calls using only
 | |
|  * fixed point arithmetic.  This code has sufficient precision for either 8-bit
 | |
|  * or 16-bit sample values.
 | |
|  *
 | |
|  * The tables used here were calculated using simple 'bc' programs, but C double
 | |
|  * precision floating point arithmetic would work fine.
 | |
|  *
 | |
|  * 8-bit log table
 | |
|  *   This is a table of -log(value/255)/log(2) for 'value' in the range 128 to
 | |
|  *   255, so it's the base 2 logarithm of a normalized 8-bit floating point
 | |
|  *   mantissa.  The numbers are 32-bit fractions.
 | |
|  */
 | |
| static const png_uint_32
 | |
| png_8bit_l2[128] =
 | |
| {
 | |
|    4270715492U, 4222494797U, 4174646467U, 4127164793U, 4080044201U, 4033279239U,
 | |
|    3986864580U, 3940795015U, 3895065449U, 3849670902U, 3804606499U, 3759867474U,
 | |
|    3715449162U, 3671346997U, 3627556511U, 3584073329U, 3540893168U, 3498011834U,
 | |
|    3455425220U, 3413129301U, 3371120137U, 3329393864U, 3287946700U, 3246774933U,
 | |
|    3205874930U, 3165243125U, 3124876025U, 3084770202U, 3044922296U, 3005329011U,
 | |
|    2965987113U, 2926893432U, 2888044853U, 2849438323U, 2811070844U, 2772939474U,
 | |
|    2735041326U, 2697373562U, 2659933400U, 2622718104U, 2585724991U, 2548951424U,
 | |
|    2512394810U, 2476052606U, 2439922311U, 2404001468U, 2368287663U, 2332778523U,
 | |
|    2297471715U, 2262364947U, 2227455964U, 2192742551U, 2158222529U, 2123893754U,
 | |
|    2089754119U, 2055801552U, 2022034013U, 1988449497U, 1955046031U, 1921821672U,
 | |
|    1888774511U, 1855902668U, 1823204291U, 1790677560U, 1758320682U, 1726131893U,
 | |
|    1694109454U, 1662251657U, 1630556815U, 1599023271U, 1567649391U, 1536433567U,
 | |
|    1505374214U, 1474469770U, 1443718700U, 1413119487U, 1382670639U, 1352370686U,
 | |
|    1322218179U, 1292211689U, 1262349810U, 1232631153U, 1203054352U, 1173618059U,
 | |
|    1144320946U, 1115161701U, 1086139034U, 1057251672U, 1028498358U, 999877854U,
 | |
|    971388940U, 943030410U, 914801076U, 886699767U, 858725327U, 830876614U,
 | |
|    803152505U, 775551890U, 748073672U, 720716771U, 693480120U, 666362667U,
 | |
|    639363374U, 612481215U, 585715177U, 559064263U, 532527486U, 506103872U,
 | |
|    479792461U, 453592303U, 427502463U, 401522014U, 375650043U, 349885648U,
 | |
|    324227938U, 298676034U, 273229066U, 247886176U, 222646516U, 197509248U,
 | |
|    172473545U, 147538590U, 122703574U, 97967701U, 73330182U, 48790236U,
 | |
|    24347096U, 0U
 | |
| 
 | |
| #if 0 /* NOT USED */
 | |
|    /* The following are the values for 16-bit tables - these work fine for the
 | |
|     * 8-bit conversions but produce very slightly larger errors in the 16-bit
 | |
|     * log (about 1.2 as opposed to 0.7 absolute error in the final value).  To
 | |
|     * use these all the shifts below must be adjusted appropriately.
 | |
|     */
 | |
|    65166, 64430, 63700, 62976, 62257, 61543, 60835, 60132, 59434, 58741, 58054,
 | |
|    57371, 56693, 56020, 55352, 54689, 54030, 53375, 52726, 52080, 51439, 50803,
 | |
|    50170, 49542, 48918, 48298, 47682, 47070, 46462, 45858, 45257, 44661, 44068,
 | |
|    43479, 42894, 42312, 41733, 41159, 40587, 40020, 39455, 38894, 38336, 37782,
 | |
|    37230, 36682, 36137, 35595, 35057, 34521, 33988, 33459, 32932, 32408, 31887,
 | |
|    31369, 30854, 30341, 29832, 29325, 28820, 28319, 27820, 27324, 26830, 26339,
 | |
|    25850, 25364, 24880, 24399, 23920, 23444, 22970, 22499, 22029, 21562, 21098,
 | |
|    20636, 20175, 19718, 19262, 18808, 18357, 17908, 17461, 17016, 16573, 16132,
 | |
|    15694, 15257, 14822, 14390, 13959, 13530, 13103, 12678, 12255, 11834, 11415,
 | |
|    10997, 10582, 10168, 9756, 9346, 8937, 8531, 8126, 7723, 7321, 6921, 6523,
 | |
|    6127, 5732, 5339, 4947, 4557, 4169, 3782, 3397, 3014, 2632, 2251, 1872, 1495,
 | |
|    1119, 744, 372
 | |
| #endif
 | |
| };
 | |
| 
 | |
| #if 0 /* UNUSED */
 | |
| static png_int_32
 | |
| png_log8bit(unsigned int x)
 | |
| {
 | |
|    png_uint_32 lg2 = 0U;
 | |
| 
 | |
|    /* Each time 'x' is multiplied by 2, 1 must be subtracted off the final log,
 | |
|     * because the log is actually negate that means adding 1.  The final
 | |
|     * returned value thus has the range 0 (for 255 input) to 7.994 (for 1
 | |
|     * input), return -1 for the overflow (log 0) case, - so the result is
 | |
|     * always at most 19 bits.
 | |
|     */
 | |
|    if ((x &= 0xffU) == 0U) /* 0 input, -inf output */
 | |
|       return -0xfffff;
 | |
| 
 | |
|    if ((x & 0xf0U) == 0U)
 | |
|       lg2  = 4U, x <<= 4;
 | |
| 
 | |
|    if ((x & 0xc0U) == 0U)
 | |
|       lg2 += 2U, x <<= 2;
 | |
| 
 | |
|    if ((x & 0x80U) == 0U)
 | |
|       lg2 += 1U, x <<= 1;
 | |
| 
 | |
|    /* result is at most 19 bits, so this cast is safe: */
 | |
|    return (png_int_32)((lg2 << 16) + ((png_8bit_l2[x-128U]+32768U)>>16));
 | |
| }
 | |
| #endif /* UNUSED */
 | |
| 
 | |
| /* The above gives exact (to 16 binary places) log2 values for 8-bit images,
 | |
|  * for 16-bit images we use the most significant 8 bits of the 16-bit value to
 | |
|  * get an approximation then multiply the approximation by a correction factor
 | |
|  * determined by the remaining up to 8 bits.  This requires an additional step
 | |
|  * in the 16-bit case.
 | |
|  *
 | |
|  * We want log2(value/65535), we have log2(v'/255), where:
 | |
|  *
 | |
|  *    value = v' * 256 + v''
 | |
|  *          = v' * f
 | |
|  *
 | |
|  * So f is value/v', which is equal to (256+v''/v') since v' is in the range 128
 | |
|  * to 255 and v'' is in the range 0 to 255 f will be in the range 256 to less
 | |
|  * than 258.  The final factor also needs to correct for the fact that our 8-bit
 | |
|  * value is scaled by 255, whereas the 16-bit values must be scaled by 65535.
 | |
|  *
 | |
|  * This gives a final formula using a calculated value 'x' which is value/v' and
 | |
|  * scaling by 65536 to match the above table:
 | |
|  *
 | |
|  *   log2(x/257) * 65536
 | |
|  *
 | |
|  * Since these numbers are so close to '1' we can use simple linear
 | |
|  * interpolation between the two end values 256/257 (result -368.61) and 258/257
 | |
|  * (result 367.179).  The values used below are scaled by a further 64 to give
 | |
|  * 16-bit precision in the interpolation:
 | |
|  *
 | |
|  * Start (256): -23591
 | |
|  * Zero  (257):      0
 | |
|  * End   (258):  23499
 | |
|  *
 | |
|  * In libpng 1.7.0 this is further generalized to return -log2(value/maxval) for
 | |
|  * any maxval up to 65535.  This is done by evaluating -log2(value/65535) first
 | |
|  * then adjusting for the required maxval:
 | |
|  *
 | |
|  *         ( value)        (value    65535)        (value)     ( 65535)
 | |
|  *    -log2(------) = -log2(----- x ------) = -log2(-----)-log2(------)
 | |
|  *         (maxval)        (65535   maxval)        (65535)     (maxval)
 | |
|  *
 | |
|  * The extra argument, 'factor', is (2^(16+12))*log2(65535/maxval) (a positive
 | |
|  * value less than 2^32) and this is *subtracted* from the intermediate
 | |
|  * calculation below.
 | |
|  */
 | |
| static png_int_32
 | |
| png_log(unsigned int x, png_uint_32 factor)
 | |
|    /* x: a value of up to 16 bits,
 | |
|     * factor: a 4.28 number which is subtracted from the log below
 | |
|     */
 | |
| {
 | |
|    png_uint_32 lg2 = 0U;
 | |
| 
 | |
|    /* As above, but now the input has 16 bits. */
 | |
|    if ((x &= 0xffffU) == 0U)
 | |
|       return -0xfffff;
 | |
| 
 | |
|    if ((x & 0xff00U) == 0U)
 | |
|       lg2  = 8U, x <<= 8;
 | |
| 
 | |
|    if ((x & 0xf000U) == 0U)
 | |
|       lg2 += 4U, x <<= 4;
 | |
| 
 | |
|    if ((x & 0xc000U) == 0U)
 | |
|       lg2 += 2U, x <<= 2;
 | |
| 
 | |
|    if ((x & 0x8000U) == 0U)
 | |
|       lg2 += 1U, x <<= 1;
 | |
| 
 | |
|    /* Calculate the base logarithm from the top 8 bits as a 28-bit fractional
 | |
|     * value.
 | |
|     */
 | |
|    lg2 <<= 28;
 | |
|    lg2 += (png_8bit_l2[(x>>8)-128U]+8U) >> 4;
 | |
| 
 | |
|    /* Now we need to interpolate the factor, this requires a division by the top
 | |
|     * 8 bits.  Do this with maximum precision.
 | |
|     */
 | |
|    {
 | |
|       png_uint_32 i = x;
 | |
| 
 | |
|       i = ((i << 16) + (i >> 9)) / (x>> 8);
 | |
| 
 | |
|       /* Since we divided by the top 8 bits of 'x' there will be a '1' at 1<<24,
 | |
|        * the value at 1<<16 (ignoring this) will be 0 or 1; this gives us
 | |
|        * exactly 16 bits to interpolate to get the low bits of the result.
 | |
|        * Round the answer.  Note that the end point values are scaled by 64 to
 | |
|        * retain overall precision and that 'lg2' is current scaled by an extra
 | |
|        * 12 bits, so adjust the overall scaling by 6-12.  Round at every step.
 | |
|        */
 | |
|       i -= 1U << 24;
 | |
| 
 | |
|       if (i <= 65536U) /* <= '257' */
 | |
|          lg2 += ((23591U * (65536U-i)) + (1U << (16+6-12-1))) >> (16+6-12);
 | |
| 
 | |
|       else
 | |
|          lg2 -= ((23499U * (i-65536U)) + (1U << (16+6-12-1))) >> (16+6-12);
 | |
|    }
 | |
| 
 | |
|    if (lg2 >= factor)
 | |
|       return (png_int_32)/*SAFE*/((lg2 - factor + 2048U) >> 12);
 | |
| 
 | |
|    else /* the result will be greater than 1.0, so negative: */
 | |
|       return -(png_int_32)/*SAFE*/((factor - lg2 + 2048U) >> 12);
 | |
| }
 | |
| 
 | |
| #if 0 /* UNUSED */
 | |
| static png_int_32
 | |
| png_log16bit(unsigned int x)
 | |
| {
 | |
|    return png_log(x, 0U);
 | |
| }
 | |
| #endif /* UNUSED */
 | |
| 
 | |
| /* libpng 1.7.0: generalization of png_log{8,16}bit to accept an n-bit input
 | |
|  * value.  We want to maintain 1% accuracy in linear light space.  This
 | |
|  * corresponds to, approximately, (1*g)% in a gamma encoded space where the
 | |
|  * gamma encoding is 'g' (in the PNG sense, e.g. 0.45455 for sRGB).  Apparently
 | |
|  * this requires unbounded accuracy as the gamma encoding value goes down and
 | |
|  * this is a problem for modern HDR data because it may require a high gamma to
 | |
|  * accurately encode image data over a wide dynamic range; the dynamic range of
 | |
|  * 16-bit linear data is only 655:1 if 1% accuracy is needed!
 | |
|  *
 | |
|  * However 16-bit gamma encoded data is still limited because PNG can only
 | |
|  * express gamma encoding.  (A log-to-base-1.01 encoding is unlimited; a 12-bit
 | |
|  * value, with 4094 steps, has a dynamic range of more than 1:10^17, which
 | |
|  * exceeds the human eye's range of 1:10^14.)
 | |
|  *
 | |
|  * Notice that sRGB uses a 1/2.4 encoding and CIELab uses a 1/3 encoding.  It is
 | |
|  * obvious that, if we assume a maximum D difference in the luminance of
 | |
|  * adjacent pixel values the dynamic range is given by the lowest pixel value
 | |
|  * which is D or less greater than its predecessor, so:
 | |
|  *
 | |
|  *   ( P ) (1)
 | |
|  *   (---)^(-) = D
 | |
|  *   (P-1) (g)
 | |
|  *
 | |
|  * and the maximum dynamic range that can be achieved using M+1 separate values,
 | |
|  * where M+1 is 2^N-1 for an N bit value, reserving the first value for 0, is:
 | |
|  *
 | |
|  *              (M) (1)
 | |
|  *   range(R) = (-)^(-)
 | |
|  *              (P) (g)
 | |
|  *
 | |
|  * So we can eliminate 'P' from the two equations:
 | |
|  *
 | |
|  *   P = (P-1) x (D^g)
 | |
|  *
 | |
|  *        D^g
 | |
|  *   P = -----
 | |
|  *       D^g-1
 | |
|  *
 | |
|  *       (M x (D^g-1)) (1)
 | |
|  *   R = (-----------)^(-)
 | |
|  *       (    D^g    ) (g)
 | |
|  *
 | |
|  *       (M x (D^g-1)) ^ (1/g)
 | |
|  *     = ---------------------
 | |
|  *                D
 | |
|  *
 | |
|  * Which is a function in two variables (R and g) for a given D (maximum delta
 | |
|  * between two adjacent pixel values) and M (number of pixel values, controlled
 | |
|  * by the channel bit depth).
 | |
|  *
 | |
|  * See contrib/tools/dynamic-range.c for code exploring this function.  This
 | |
|  * program will output the optimal gamma for a given number of bits and
 | |
|  * precision.
 | |
|  *
 | |
|  * The range of sensitivity of human vision is roughly as follows (this comes
 | |
|  * from the wikipedia article on scotopic vision):
 | |
|  *
 | |
|  *     scotopic: 10^-6 to 10^-3.5 cd/m^2
 | |
|  *     mesopic:  10^-3 to 10^0.5 cd/m^2
 | |
|  *     photopic: 10 to 10^8 cd/m^2
 | |
|  *
 | |
|  * Giving a total range of about 1:10^14.  The maximum precision at which this
 | |
|  * range can be achieved using 16-bit channels is about .15% using a gamma of
 | |
|  * 36, higher ranges are possible using higher gammas but precision is reduced.
 | |
|  * The range with 1% precision and 16-bit channels is 1:10^104, using a gamma of
 | |
|  * 240.
 | |
|  *
 | |
|  * In general the optimal gamma for n-bit channels (where 'n' is at least 7 and
 | |
|  * precision is .01 or less) is:
 | |
|  *
 | |
|  *                  2^n * precision
 | |
|  *          gamma = ---------------
 | |
|  *                       2.736
 | |
|  *
 | |
|  * Or: (24000 * precision) for 16-bit data.
 | |
|  *
 | |
|  * The net effect is that we can't rely on the encoding gamma being limited to
 | |
|  * values around 1/2.5!
 | |
|  */
 | |
| static png_int_32
 | |
| png_log_nbit(unsigned int x, unsigned int nbits)
 | |
| {
 | |
|    static const png_uint_32 factors[16] =
 | |
|    {
 | |
|       4294961387U, /* 1 bit */
 | |
|       3869501255U, /* 2 bit */
 | |
|       3541367788U, /* 3 bit */
 | |
|       3246213428U, /* 4 bit */
 | |
|       2965079441U, /* 5 bit */
 | |
|       2690447525U, /* 6 bit */
 | |
|       2418950626U, /* 7 bit */
 | |
|       2148993476U, /* 8 bit */
 | |
|       1879799410U, /* 9 bit */
 | |
|       1610985205U, /* 10 bit */
 | |
|       1342360514U, /* 11 bit */
 | |
|       1073830475U, /* 12 bit */
 | |
|        805347736U, /* 13 bit */
 | |
|        536888641U, /* 14 bit */
 | |
|        268441365U, /* 15 bit */
 | |
|                0U  /* 16 bit */
 | |
|    };
 | |
| 
 | |
|    return png_log(x, factors[nbits-1]);
 | |
| }
 | |
| 
 | |
| 
 | |
| /* The 'exp()' case must invert the above, taking a 20-bit fixed point
 | |
|  * logarithmic value and returning a 16 or 8-bit number as appropriate.  In
 | |
|  * each case only the low 16 bits are relevant - the fraction - since the
 | |
|  * integer bits (the top 4) simply determine a shift.
 | |
|  *
 | |
|  * The worst case is the 16-bit distinction between 65535 and 65534. This
 | |
|  * requires perhaps spurious accuracy in the decoding of the logarithm to
 | |
|  * distinguish log2(65535/65534.5) - 10^-5 or 17 bits.  There is little chance
 | |
|  * of needing this accuracy in practice.
 | |
|  *
 | |
|  * To deal with this the following exp() function works out the exponent of the
 | |
|  * frational part of the logarithm by using an accurate 32-bit value from the
 | |
|  * top four fractional bits then multiplying in the remaining bits.
 | |
|  */
 | |
| static const png_uint_32
 | |
| png_32bit_exp[16] =
 | |
| {
 | |
|    /* NOTE: the first entry is deliberately set to the maximum 32-bit value. */
 | |
|    4294967295U, 4112874773U, 3938502376U, 3771522796U, 3611622603U, 3458501653U,
 | |
|    3311872529U, 3171459999U, 3037000500U, 2908241642U, 2784941738U, 2666869345U,
 | |
|    2553802834U, 2445529972U, 2341847524U, 2242560872U
 | |
| };
 | |
| 
 | |
| /* Adjustment table; provided to explain the numbers in the code below. */
 | |
| #if 0 /* BC CODE */
 | |
| for (i=11;i>=0;--i){ print i, " ", (1 - e(-(2^i)/65536*l(2))) * 2^(32-i), "\n"}
 | |
|    11 44937.64284865548751208448
 | |
|    10 45180.98734845585101160448
 | |
|     9 45303.31936980687359311872
 | |
|     8 45364.65110595323018870784
 | |
|     7 45395.35850361789624614912
 | |
|     6 45410.72259715102037508096
 | |
|     5 45418.40724413220722311168
 | |
|     4 45422.25021786898173001728
 | |
|     3 45424.17186732298419044352
 | |
|     2 45425.13273269940811464704
 | |
|     1 45425.61317555035558641664
 | |
|     0 45425.85339951654943850496
 | |
| #endif
 | |
| 
 | |
| static png_uint_32
 | |
| png_exp(png_int_32 x)
 | |
|    /* Utility, the value 'x' must be in the range 0..0x1fffff */
 | |
| {
 | |
|    /* Obtain a 4-bit approximation */
 | |
|    png_uint_32 e = png_32bit_exp[(x >> 12) & 0xf];
 | |
| 
 | |
|    /* Incorporate the low 12 bits - these decrease the returned value by
 | |
|     * multiplying by a number less than 1 if the bit is set.  The multiplier
 | |
|     * is determined by the above table and the shift. Notice that the values
 | |
|     * converge on 45426 and this is used to allow linear interpolation of the
 | |
|     * low bits.
 | |
|     */
 | |
|    if (x & 0x800)
 | |
|       e -= (((e >> 16) * 44938U) +  16U) >> 5;
 | |
| 
 | |
|    if (x & 0x400)
 | |
|       e -= (((e >> 16) * 45181U) +  32U) >> 6;
 | |
| 
 | |
|    if (x & 0x200)
 | |
|       e -= (((e >> 16) * 45303U) +  64U) >> 7;
 | |
| 
 | |
|    if (x & 0x100)
 | |
|       e -= (((e >> 16) * 45365U) + 128U) >> 8;
 | |
| 
 | |
|    if (x & 0x080)
 | |
|       e -= (((e >> 16) * 45395U) + 256U) >> 9;
 | |
| 
 | |
|    if (x & 0x040)
 | |
|       e -= (((e >> 16) * 45410U) + 512U) >> 10;
 | |
| 
 | |
|    /* And handle the low 6 bits in a single block. */
 | |
|    e -= (((e >> 16) * 355U * (x & 0x3fU)) + 256U) >> 9;
 | |
| 
 | |
|    /* Handle the upper bits of x, note that this works for x up to 0x1fffff but
 | |
|     * fails for larger or negative x, where the shift (x >> 16) exceeds 31:
 | |
|     */
 | |
|    e >>= x >> 16;
 | |
|    return e;
 | |
| }
 | |
| 
 | |
| #if 0 /* UNUSED */
 | |
| static png_byte
 | |
| png_exp8bit(png_int_32 lg2)
 | |
| {
 | |
|    /* The input is a negative fixed point (16:16) logarithm with a useable range
 | |
|     * of [0.0..8.0).  Clamp the value so that the output of png_exp is in the
 | |
|     * range (254.5/255..0.5/255):
 | |
|     */
 | |
|    if (lg2 <= 185) /* -log2(254.5/255) */
 | |
|       return 255U;
 | |
| 
 | |
|    else if (lg2 > 589453) /* -log2(0.5/255) */
 | |
|       return 0U;
 | |
| 
 | |
|    else
 | |
|    {
 | |
|       /* Get a 32-bit value: */
 | |
|       png_uint_32 x = png_exp(lg2);
 | |
| 
 | |
|       /* Convert the 32-bit value to 0..255 by multiplying by 256-1. Note that
 | |
|        * the second, rounding, step can't overflow because of the first,
 | |
|        * subtraction, step.
 | |
|        */
 | |
|       x -= x >> 8;
 | |
|       return PNG_BYTE((x + 0x7fffffU) >> 24);
 | |
|    }
 | |
| }
 | |
| 
 | |
| static png_uint_16
 | |
| png_exp16bit(png_int_32 lg2)
 | |
| {
 | |
|    if (lg2 <= 0) /* -log2(65534.5/65535) */
 | |
|       return 65535U;
 | |
| 
 | |
|    else if (lg2 > 1114110) /* -log2(0.5/65535) */
 | |
|       return 0U;
 | |
| 
 | |
|    else
 | |
|    {
 | |
|       /* Get a 32-bit value: */
 | |
|       png_uint_32 x = png_exp(lg2);
 | |
| 
 | |
|       /* Convert the 32-bit value to 0..65535 by multiplying by 65536-1: */
 | |
|       x -= x >> 16;
 | |
|       return PNG_UINT_16((x + 32767U) >> 16);
 | |
|    }
 | |
| }
 | |
| #endif /* UNUSED */
 | |
| 
 | |
| static png_uint_32
 | |
| png_exp_nbit(png_int_32 lg2, unsigned int n)
 | |
| {
 | |
|    /* These pre-computed limits give the low value of lg2 at and below which
 | |
|     * 2^(-lg2/65536) * (2^n-1) gives (2^n-1) and the high value of lg2 above
 | |
|     * which 2(^-lg2/65536) * (2^n-1) gives 0:
 | |
|     */
 | |
|    static const png_int_32 limits[16][2] =
 | |
|    {
 | |
|       { 65535,   65535 }, /* bits =  1 */
 | |
|       { 17238,  169408 }, /* bits =  2 */
 | |
|       {  7006,  249518 }, /* bits =  3 */
 | |
|       {  3205,  321577 }, /* bits =  4 */
 | |
|       {  1537,  390214 }, /* bits =  5 */
 | |
|       {   753,  457263 }, /* bits =  6 */
 | |
|       {   372,  523546 }, /* bits =  7 */
 | |
|       {   185,  589453 }, /* bits =  8 */
 | |
|       {    92,  655175 }, /* bits =  9 */
 | |
|       {    46,  720803 }, /* bits = 10 */
 | |
|       {    23,  786385 }, /* bits = 11 */
 | |
|       {    11,  851944 }, /* bits = 12 */
 | |
|       {     5,  917492 }, /* bits = 13 */
 | |
|       {     2,  983034 }, /* bits = 14 */
 | |
|       {     1, 1048573 }, /* bits = 15 */
 | |
|       {     0, 1114110 }  /* bits = 16 */
 | |
|    };
 | |
| 
 | |
|    /* If 'max' is 2^n-1: */
 | |
|    if (lg2 <= limits[n-1][0]) /* -log2((max-.5)/max) */
 | |
|       return (1U << n)-1U;
 | |
| 
 | |
|    else if (lg2 > limits[n-1][1]) /* -log2(.5/max) */
 | |
|       return 0U;
 | |
| 
 | |
|    else /* 'n' will be at least 2 */
 | |
|    {
 | |
|       /* Get a 32-bit value: */
 | |
|       png_uint_32 x = png_exp(lg2);
 | |
| 
 | |
|       /* Convert the 32-bit value to 0..(2^n-1) by multiplying by 2^n-1: */
 | |
|       x -= x >> n;
 | |
|       return (x + ((1U<<(31U-n))-1U)) >> (32U-n);
 | |
|    }
 | |
| }
 | |
| #endif /* !FLOATING_ARITHMETIC */
 | |
| 
 | |
| #if 0 /* UNUSED */
 | |
| static png_byte
 | |
| png_gamma_8bit_correct(unsigned int value, png_fixed_point gamma_val)
 | |
| {
 | |
|    if (value == 0U)
 | |
|       return 0U;
 | |
| 
 | |
|    else if (value >= 255U)
 | |
|       return 255U;
 | |
| 
 | |
|    else
 | |
|    {
 | |
| #     ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED
 | |
|          /* 'value' is unsigned, ANSI-C90 requires the compiler to correctly
 | |
|           * convert this to a floating point value.  This includes values that
 | |
|           * would overflow if 'value' were to be converted to 'int'.
 | |
|           *
 | |
|           * Apparently GCC, however, does an intermediate conversion to (int)
 | |
|           * on some (ARM) but not all (x86) platforms, possibly because of
 | |
|           * hardware FP limitations.  (E.g. if the hardware conversion always
 | |
|           * assumes the integer register contains a signed value.)  This results
 | |
|           * in ANSI-C undefined behavior for large values.
 | |
|           *
 | |
|           * Other implementations on the same machine might actually be ANSI-C90
 | |
|           * conformant and therefore compile spurious extra code for the large
 | |
|           * values.
 | |
|           *
 | |
|           * We can be reasonably sure that an unsigned to float conversion
 | |
|           * won't be faster than an int to float one.  Therefore this code
 | |
|           * assumes responsibility for the undefined behavior, which it knows
 | |
|           * can't happen because of the check above.
 | |
|           *
 | |
|           * Note the argument to this routine is an (unsigned int) because, on
 | |
|           * 16-bit platforms, it is assigned a value which might be out of
 | |
|           * range for an (int); that would result in undefined behavior in the
 | |
|           * caller if the *argument* ('value') were to be declared (int).
 | |
|           */
 | |
|          double r = 255*pow((int)/*SAFE*/value/255.,gamma_val*.00001);
 | |
|          if (r < .5)
 | |
|             return 0U;
 | |
| 
 | |
|          else if (r >= 254.5)
 | |
|             return 255U;
 | |
| 
 | |
|          r = floor(r+.5);
 | |
|          return (png_byte)/*SAFE*/r;
 | |
| #     else
 | |
|          png_int_32 lg2 = png_log8bit(value);
 | |
|          png_int_32 res;
 | |
| 
 | |
|          /* Overflow in the muldiv means underflow in the calculation, this is
 | |
|           * OK (it happens for ridiculously high gamma).
 | |
|           */
 | |
|          if (!png_muldiv(&res, gamma_val, lg2, PNG_FP_1))
 | |
|             return 0U; /* underflow */
 | |
| 
 | |
|          return png_exp8bit(res);
 | |
| #     endif
 | |
|    }
 | |
| }
 | |
| #endif /* UNUSED */
 | |
| 
 | |
| /* libpng-1.7.0: this private function converts an n-bit input value to an
 | |
|  * m-bit output value.
 | |
|  */
 | |
| unsigned int
 | |
| png_gamma_nxmbit_correct(unsigned int value, png_fixed_point gamma_val,
 | |
|    unsigned int n/*input bits*/, unsigned int m/*output bits */)
 | |
| {
 | |
|    if (value == 0U)
 | |
|       return 0U;
 | |
| 
 | |
|    else
 | |
|    {
 | |
|       unsigned int min  = (1U<<n) - 1U;
 | |
|       unsigned int mout = (1U<<m) - 1U;
 | |
| 
 | |
|       if (value >= min)
 | |
|          return mout;
 | |
| 
 | |
|       else
 | |
|       {
 | |
| #        ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED
 | |
|             double r = value;
 | |
|             r /= min;
 | |
|             r = floor(mout * pow(r, gamma_val*.00001)+.5);
 | |
|             if (r < 1)
 | |
|                return 0U;
 | |
| 
 | |
|             else if (r >= mout)
 | |
|                return mout;
 | |
| 
 | |
|             return (unsigned int)/*SAFE*/r;
 | |
| #        else
 | |
|             png_int_32 lg2 = png_log_nbit(value, n);
 | |
|             png_int_32 res;
 | |
| 
 | |
|             if (!png_muldiv(&res, gamma_val, lg2, PNG_FP_1))
 | |
|                return 0U; /* underflow */
 | |
| 
 | |
|             return png_exp_nbit(res, m);
 | |
| #        endif
 | |
|       }
 | |
|    }
 | |
| }
 | |
| 
 | |
| #if 0 /*UNUSED*/
 | |
| static unsigned int
 | |
| png_gamma_sbit_correct(unsigned int value, png_fixed_point gamma_val,
 | |
|    unsigned int n/*input bits*/, unsigned int sbits,
 | |
|    unsigned int m/*output bits */)
 | |
|    /* As above but the number of significant bits in 'n' is passed in. */
 | |
| {
 | |
|    if (sbits < n)
 | |
|    {
 | |
|       value >>= (n-sbits);
 | |
|       n = sbits;
 | |
|    }
 | |
| 
 | |
|    return png_gamma_nxmbit_correct(value, gamma_val, n, m);
 | |
| }
 | |
| #endif /*UNUSED*/
 | |
| 
 | |
| static int
 | |
| push_gamma_expand(png_transformp *transform, png_transform_controlp tc,
 | |
|       int need_alpha)
 | |
|    /* Utility to push a transform to expand low-bit-depth gray and, where
 | |
|     * required, tRNS chunks.  The caller must return immediately if this
 | |
|     * returns true because the init of the new transform has been run in place
 | |
|     * of the caller's.
 | |
|     */
 | |
| {
 | |
| #  define png_ptr (tc->png_ptr)
 | |
|    unsigned int expand = 0;
 | |
| 
 | |
|    affirm(tc->init == PNG_TC_INIT_FINAL);
 | |
| 
 | |
|    if (tc->bit_depth < 8U) /* low bit gray: expand to 8 bits */
 | |
|       expand = PNG_EXPAND_LBD_GRAY;
 | |
| 
 | |
|    /* Gamma correction invalidates tRNS, so if it is being expanded and
 | |
|     * alpha is not being stripped expand it now.
 | |
|     */
 | |
|    if ((tc->format & PNG_FORMAT_FLAG_ALPHA) == 0 && !tc->palette &&
 | |
|        png_ptr->num_trans == 1 && (tc->invalid_info & PNG_INFO_tRNS) == 0)
 | |
|    {
 | |
|       if (need_alpha || (tc->expand_tRNS && !tc->strip_alpha))
 | |
|          expand |= PNG_EXPAND_tRNS;
 | |
| 
 | |
|       else
 | |
|          tc->invalid_info |= PNG_INFO_tRNS;
 | |
|    }
 | |
| 
 | |
|    if (expand == 0)
 | |
|       return 0; /* nothing needs to be done */
 | |
| 
 | |
|    {
 | |
|       png_transformp tr = png_push_transform(png_ptr, sizeof (png_expand),
 | |
|          png_init_expand, transform, NULL/*don't run init*/);
 | |
| 
 | |
|       debug(tr == *transform);
 | |
|       tr->args |= expand;
 | |
| 
 | |
|       /* This must be run immediately, because it just got inserted where this
 | |
|        * transform is; this is safe, the caller must return immediately.
 | |
|        */
 | |
|       png_init_expand(transform, tc);
 | |
|       affirm(tr->fn != NULL); /* because it should need to do something! */
 | |
|    }
 | |
| 
 | |
|    return 1;
 | |
| #  undef png_ptr
 | |
| }
 | |
| 
 | |
| /* Low bit depth gray gamma correction.  The 1-bit case is a no-op because 0 and
 | |
|  * 1 always map to 0 and 1.  The 2-bit case has the following possiblities:
 | |
|  *
 | |
|  *   bits/correction: g0 g1 g2 g3 g4 g5 g6
 | |
|  *    00      ->      00 00 00 00 00 00 00
 | |
|  *    01      ->      11 10 10 01 00 00 00
 | |
|  *    10      ->      11 11 10 10 10 01 00
 | |
|  *    11      ->      11 11 11 11 11 11 11
 | |
|  *
 | |
|  * Where the breakpoints are:
 | |
|  *
 | |
|  *    g0:          correction <=  16595 (1 - log(2.5/3))
 | |
|  *    g1:  16595 < correction <=  44966 (log(2.5/3)/log(2/3))
 | |
|  *    g2:  44966 < correction <=  63092 (1 - log(1.5/3))
 | |
|  *    g3:  63092 < correction <= 163092 (1 - log(.5/3))
 | |
|  *    g4: 163092 < correction <= 170951 (log(1.5/3)/log(2/3))
 | |
|  *    g5: 170951 < correction <= 441902 (log(.5/3)/log(2/3)
 | |
|  *    g6  441902 < correction
 | |
|  *
 | |
|  * This can be done by bit-hacking on the byte values (4 pixels), given that
 | |
|  * the correction is fixed (indeed, it can be done on whole 32-bit values!)
 | |
|  *
 | |
|  *    g0: B |= B>>1; B &= 0x55U; B |= B<<1;  * either bit set
 | |
|  *    g1: B ^= B>>1; B &= 0x55U; B += B;     * one bit set
 | |
|  *    g2: B &= (~B)>>1; B &= 0x55U; B += B;  * low bit set, high bit unset
 | |
|  *    g3: no-op
 | |
|  *    g4: B &= (~B)>>1; B &= 0x55U; B -= B;  * low bit set, high bit unset
 | |
|  *    g5: B ^= B>>1; B &= 0x55U; B -= B;     * one bit set
 | |
|  *    g6: B &= B>>1; B &= 0x55U; B |= B<<1;  * both bits set
 | |
|  */
 | |
| typedef struct
 | |
| {
 | |
|    png_transform   tr;
 | |
|    png_fixed_point correct;
 | |
|    png_fixed_point to_gamma;
 | |
|    png_uint_32     shifts;           /* 1 followed by up to 4 4-bit shifts */
 | |
|    png_uint_32     channel_scale[4]; /* up to 4 channel scale factors */
 | |
|    /* These factors are used:
 | |
|     *
 | |
|     *     (input >> (shifts & 0xFU) * channel_scale + SCALE_R) >> SCALE_S
 | |
|     *
 | |
|     * Where the rounding value, SCALE_R and the shift SCALE_S are dependent
 | |
|     * on the bit depth:
 | |
|     *
 | |
|     *    SCALE_S = 32 - bit_depth     range 16..31
 | |
|     *    SCALE_R = 1 << (SCALE_S-1)
 | |
|     */
 | |
|    unsigned int    to_bit_depth;
 | |
|    unsigned int    encode_alpha :1;
 | |
|    unsigned int    optimize_alpha :1;
 | |
| } png_transform_gamma;
 | |
| 
 | |
| static unsigned int
 | |
| init_gamma_sBIT(png_transform_gamma *tr, png_transform_controlp tc)
 | |
|    /* Returns true if sBIT processing is required, otherwise all relevant sBIT
 | |
|     * values match the from (tc) bit depth.
 | |
|     */
 | |
| {
 | |
|    /* The to_bit_depth and to_gamma fields are already set, but updated values
 | |
|     * are needed for sBIT and the shifts and channel_scale fields must be filled
 | |
|     * in correctly.  The do_gamma setting says whether gamma correction will be
 | |
|     * done, but the scale factors are filled in regardless.
 | |
|     *
 | |
|     * The general scaling equation is:
 | |
|     *
 | |
|     *    ((in >> shift) * factor + round) >> (32 - to_bit_depth)
 | |
|     *
 | |
|     * 'factor' is then the rounded value of:
 | |
|     *
 | |
|     *      out_max
 | |
|     *      ------- . (1 << (32-to_bit_depth))
 | |
|     *       in_max
 | |
|     */
 | |
| #  define png_ptr (tc->png_ptr)
 | |
|    const unsigned int to_bit_depth = tr->to_bit_depth;
 | |
|    const png_uint_32 numerator = ((1U<<to_bit_depth)-1U) << (32U-to_bit_depth);
 | |
|    /* in_max depends on the number of significant bits */
 | |
|    const unsigned int from_bit_depth = tc->bit_depth;
 | |
| 
 | |
|    /* The data in the gamma transform is stored in the order of the channels in
 | |
|     * the input row, which is the PNG order.  It may be reversed below.
 | |
|     */
 | |
|    png_uint_32p channel_scale = tr->channel_scale;
 | |
|    png_uint_32 shifts = 0U;
 | |
|    unsigned int count = 0U;
 | |
|    unsigned int need_sBIT = 0U;
 | |
| 
 | |
|    if (tc->format & PNG_FORMAT_FLAG_COLOR)
 | |
|    {
 | |
|       const unsigned int sBIT = tc->sBIT_R;
 | |
| 
 | |
|       if (sBIT < from_bit_depth)
 | |
|          need_sBIT = 1U;
 | |
| 
 | |
|       debug(sBIT > 0U && sBIT <= from_bit_depth);
 | |
|       shifts |= (from_bit_depth - sBIT) << count;
 | |
|       count += 4U;
 | |
|       /* round the scale: */
 | |
|       *channel_scale++ = (numerator + (1U<<(sBIT-1U))) / ((1U << sBIT)-1U);
 | |
|    }
 | |
| 
 | |
|    {
 | |
|       const unsigned int sBIT = tc->sBIT_G;
 | |
| 
 | |
|       if (sBIT < from_bit_depth)
 | |
|          need_sBIT = 1U;
 | |
| 
 | |
|       debug(sBIT > 0U && sBIT <= from_bit_depth);
 | |
|       shifts |= (from_bit_depth - sBIT) << count;
 | |
|       count += 4U;
 | |
|       *channel_scale++ = (numerator + (1U<<(sBIT-1U))) / ((1U << sBIT)-1U);
 | |
|    }
 | |
| 
 | |
|    if (tc->format & PNG_FORMAT_FLAG_COLOR)
 | |
|    {
 | |
|       const unsigned int sBIT = tc->sBIT_B;
 | |
| 
 | |
|       if (sBIT < from_bit_depth)
 | |
|          need_sBIT = 1U;
 | |
| 
 | |
|       debug(sBIT > 0U && sBIT <= from_bit_depth);
 | |
|       shifts |= (from_bit_depth - sBIT) << count;
 | |
|       count += 4U;
 | |
|       /* round the scale: */
 | |
|       *channel_scale++ = (numerator + (1U<<(sBIT-1U))) / ((1U << sBIT)-1U);
 | |
|    }
 | |
| 
 | |
|    if (tc->format & PNG_FORMAT_FLAG_ALPHA)
 | |
|    {
 | |
|       const unsigned int sBIT = tc->sBIT_A;
 | |
| 
 | |
|       if (sBIT < from_bit_depth)
 | |
|          need_sBIT = 1U;
 | |
| 
 | |
|       debug(sBIT > 0U && sBIT <= from_bit_depth);
 | |
|       shifts |= (from_bit_depth - sBIT) << count;
 | |
|       count += 4U;
 | |
|       /* round the scale: */
 | |
|       *channel_scale++ = (numerator + (1U<<(sBIT-1U))) / ((1U << sBIT)-1U);
 | |
|    }
 | |
| 
 | |
|    tr->shifts = shifts | (1U << count);
 | |
| 
 | |
|    return need_sBIT;
 | |
| #  undef png_ptr
 | |
| }
 | |
| 
 | |
| static void
 | |
| reverse_gamma_sBIT(png_transform_gamma *tr)
 | |
| {
 | |
|    /* This is called for the 'down' gamma implementations, they read the shifts
 | |
|     * and the channel scales in reverse, so:
 | |
|     */
 | |
|    png_uint_32 shifts = tr->shifts;
 | |
|    png_uint_32 scales[4U];
 | |
|    unsigned int count = 0U;
 | |
| 
 | |
|    tr->shifts = 1U;
 | |
| 
 | |
|    while (shifts != 1U)
 | |
|    {
 | |
|       scales[3U-count] = tr->channel_scale[count];
 | |
|       ++count;
 | |
|       tr->shifts <<= 4;
 | |
|       tr->shifts |= shifts & 0xFU;
 | |
|       shifts >>= 4;
 | |
|    }
 | |
| 
 | |
|    memcpy(tr->channel_scale, scales+(4U-count), count * sizeof (png_uint_32));
 | |
| }
 | |
| 
 | |
| static void
 | |
| png_do_gamma8_up(png_transformp *transform, png_transform_controlp tc)
 | |
| {
 | |
| #  define png_ptr (tc->png_ptr)
 | |
|    png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp);
 | |
|    png_const_bytep ep = sp + PNG_TC_ROWBYTES(*tc);
 | |
|    png_bytep dp = png_voidcast(png_bytep, tc->dp);
 | |
|    png_transform_gamma *tr =
 | |
|       png_transform_cast(png_transform_gamma, *transform);
 | |
|    const png_fixed_point correct = tr->correct;
 | |
|    const unsigned int bit_depth = tr->to_bit_depth;
 | |
|    const png_uint_32 shifts = tr->shifts;
 | |
| 
 | |
|    affirm(tc->bit_depth == 8U);
 | |
|    affirm(tr->shifts != 0U/*uninitialized*/);
 | |
|    debug((shifts & 0x8888U) == 0U); /* all shifts 7 or less */
 | |
|    debug(!tr->encode_alpha && !tr->optimize_alpha); /* only set for 16 bits */
 | |
| 
 | |
|    tc->sp = dp;
 | |
|    tc->bit_depth = bit_depth;
 | |
|    tc->gamma = tr->to_gamma;
 | |
| 
 | |
|    /* Handle the <8 bit output case differently because there can be no alpha
 | |
|     * channel.
 | |
|     */
 | |
|    if (bit_depth < 8U)
 | |
|    {
 | |
|       const unsigned int shift = shifts & 0xFU;
 | |
|       unsigned int bits = 8U;
 | |
|       unsigned int ob = 0U;
 | |
| 
 | |
|       debug((shifts >> 4) == 1U && shift < 8U);
 | |
|       affirm(PNG_TC_CHANNELS(*tc) == 1);
 | |
| 
 | |
|       do
 | |
|       {
 | |
|          const unsigned int inb = png_gamma_nxmbit_correct(
 | |
|             *sp++ >> shift, correct, 8U-shift, bit_depth);
 | |
|          bits -= bit_depth;
 | |
|          ob = ob | (inb << bits);
 | |
|          if (bits == 0U)
 | |
|             bits = 8U, *dp++ = PNG_BYTE(ob), ob = 0U;
 | |
|       }
 | |
|       while (sp < ep);
 | |
| 
 | |
|       if (bits < 8U)
 | |
|          *dp++ = PNG_BYTE(ob);
 | |
|    }
 | |
| 
 | |
|    else /* 8-bit --> 8-bit */
 | |
|    {
 | |
|       png_uint_32 alpha_scale;
 | |
|       const unsigned int channels = PNG_TC_CHANNELS(*tc);
 | |
|       unsigned int channel, alpha;
 | |
| 
 | |
|       debug(bit_depth == 8U && (shifts >> (4*channels)) == 1U);
 | |
| 
 | |
|       /* The alpha channel is always last, so if present checking against the
 | |
|        * top bits of 'channels' works because of the 1U shibboleth at the end.
 | |
|        */
 | |
|       if ((tc->format & PNG_FORMAT_FLAG_ALPHA) == 0)
 | |
|          alpha_scale = alpha = 0U;
 | |
| 
 | |
|       else
 | |
|       {
 | |
|          alpha = shifts >> (4U*(channels-1U));
 | |
|          alpha_scale = tr->channel_scale[channels-1U];
 | |
|       }
 | |
| 
 | |
|       channel = 1U;
 | |
| 
 | |
|       do
 | |
|       {
 | |
|          unsigned int inb = *sp++, shift;
 | |
| 
 | |
|          if (channel == 1U)
 | |
|             channel = shifts;
 | |
| 
 | |
|          shift = channel & 0xFU;
 | |
|          inb >>= shift;
 | |
| 
 | |
|          /* The alpha channel is not gamma encoded but it may need some
 | |
|           * appropriate scaling.
 | |
|           */
 | |
|          if (channel == alpha)
 | |
|             inb = (inb * alpha_scale + 0x800000U) >> 24;
 | |
| 
 | |
|          else
 | |
|             inb = png_gamma_nxmbit_correct(inb, correct, 8U-shift, 8U);
 | |
| 
 | |
|          channel >>= 4; /* for the next channel, or the shibboleth */
 | |
|          *dp++ = PNG_BYTE(inb);
 | |
|       }
 | |
|       while (sp < ep);
 | |
| 
 | |
|       debug(channel == 1U);
 | |
|    }
 | |
| #  undef png_ptr
 | |
| }
 | |
| 
 | |
| static void
 | |
| png_do_gamma16_up(png_transformp *transform, png_transform_controlp tc)
 | |
| {
 | |
| #  define png_ptr (tc->png_ptr)
 | |
|    png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp);
 | |
|    png_const_bytep ep = sp + PNG_TC_ROWBYTES(*tc) - 1U/*safety*/;
 | |
|    png_bytep dp = png_voidcast(png_bytep, tc->dp);
 | |
|    png_transform_gamma *tr =
 | |
|       png_transform_cast(png_transform_gamma, *transform);
 | |
|    const png_fixed_point correct = tr->correct;
 | |
|    const unsigned int bit_depth = tr->to_bit_depth;
 | |
|    const png_uint_32 shifts = tr->shifts;
 | |
| 
 | |
|    affirm(tc->bit_depth == 16U);
 | |
|    affirm(tr->shifts != 0U/*uninitialized*/);
 | |
|    debug(!tr->optimize_alpha);
 | |
| 
 | |
|    /* This is exactly the same as above but the input has 16 bits per component,
 | |
|     * not 8.
 | |
|     */
 | |
|    tc->sp = dp;
 | |
|    tc->bit_depth = bit_depth;
 | |
|    tc->gamma = tr->to_gamma;
 | |
| 
 | |
|    /* Handle the <8 bit output case differently, the input cannot be color (at
 | |
|     * present) and, if there is an alpha channel, then it is for the
 | |
|     * low-bit-depth gray input case and we expect the alpha to be transparent.
 | |
|     */
 | |
|    if (bit_depth < 8U)
 | |
|    {
 | |
|       const unsigned int shift = shifts & 0xFU;
 | |
|       unsigned int bits = 8U;
 | |
|       unsigned int ob = 0U;
 | |
| 
 | |
|       affirm((tc->format & PNG_FORMAT_FLAG_COLOR) == 0U);
 | |
| 
 | |
|       if ((tc->format & PNG_FORMAT_FLAG_ALPHA) == 0U)
 | |
|       {
 | |
|          debug((shifts >> 4) == 1U && shift < 16U);
 | |
|          debug(!tr->encode_alpha && !tr->optimize_alpha);
 | |
| 
 | |
|          do
 | |
|          {
 | |
|             unsigned int inb = *sp++ << 8; /* high bits first */
 | |
|             inb = png_gamma_nxmbit_correct(
 | |
|                (inb + *sp++) >> shift, correct, 16U-shift, bit_depth);
 | |
| 
 | |
|             bits -= bit_depth;
 | |
|             ob = ob | (inb << bits);
 | |
|             if (bits == 0U)
 | |
|                bits = 8U, *dp++ = PNG_BYTE(ob), ob = 0U;
 | |
|          }
 | |
|          while (sp < ep);
 | |
| 
 | |
|          UNTESTED
 | |
|       }
 | |
| 
 | |
|       else /* low bit GA intermediate format */
 | |
|       {
 | |
|          debug((shifts >> 8) == 1U && shift < 16U);
 | |
|          debug(!tr->encode_alpha && !tr->optimize_alpha);
 | |
|          debug(tc->transparent_alpha);
 | |
| 
 | |
|          /* Gray is first then the alpha component, the alpha component is just
 | |
|           * mapped to 0 or 1.
 | |
|           */
 | |
|          do
 | |
|          {
 | |
|             unsigned int gray = *sp++ << 8; /* high bits first */
 | |
|             unsigned int alpha;
 | |
|             gray += *sp++;
 | |
| 
 | |
|             alpha = (*sp++ << 8);
 | |
|             alpha += *sp++;
 | |
| 
 | |
|             if (alpha == 0U)
 | |
|                gray = 0U; /* will be replaced later */
 | |
| 
 | |
|             else
 | |
|             {
 | |
|                gray = png_gamma_nxmbit_correct(gray >> shift, correct,
 | |
|                      16U-shift, bit_depth);
 | |
|                debug(alpha == 65535U);
 | |
|                alpha = (1U << bit_depth)-1U;
 | |
|             }
 | |
| 
 | |
|             bits -= bit_depth;
 | |
|             ob = ob | (gray << bits);
 | |
|             bits -= bit_depth;
 | |
|             ob = ob | (alpha << bits);
 | |
| 
 | |
|             if (bits == 0U)
 | |
|                bits = 8U, *dp++ = PNG_BYTE(ob), ob = 0U;
 | |
|          }
 | |
|          while (sp < ep-2U);
 | |
|       }
 | |
| 
 | |
|       if (bits < 8U)
 | |
|          *dp++ = PNG_BYTE(ob);
 | |
| 
 | |
|       debug(sp == ep+1U);
 | |
|    }
 | |
| 
 | |
|    else
 | |
|    {
 | |
|       png_uint_32 alpha_scale;
 | |
|       const unsigned int channels = PNG_TC_CHANNELS(*tc);
 | |
|       unsigned int channel, alpha;
 | |
| 
 | |
|       debug((bit_depth == 8U || bit_depth == 16U) &&
 | |
|             (shifts >> (4*channels)) == 1U);
 | |
| 
 | |
|       /* Note that 'encode_alpha' turns on gamma encoding of the alpha
 | |
|        * channel (and this is a really weird operation!)
 | |
|        */
 | |
|       if ((tc->format & PNG_FORMAT_FLAG_ALPHA) == 0 || tr->encode_alpha)
 | |
|          alpha_scale = alpha = 0U;
 | |
| 
 | |
|       else
 | |
|       {
 | |
|          alpha = shifts >> (4U*(channels-1U));
 | |
|          alpha_scale = tr->channel_scale[channels-1U];
 | |
|       }
 | |
| 
 | |
|       channel = 1U;
 | |
| 
 | |
|       if (bit_depth == 16U)
 | |
|       {
 | |
|          do
 | |
|          {
 | |
|             unsigned int inb = *sp++ << 8, shift;
 | |
|             inb += *sp++;
 | |
| 
 | |
|             if (channel == 1U)
 | |
|                channel = shifts;
 | |
| 
 | |
|             shift = channel & 0xFU;
 | |
|             inb >>= shift;
 | |
| 
 | |
|             /* The 16-16bit scaling factor equation may be off-by-1 but this
 | |
|              * hardly matters for alpha or for gamma operations.
 | |
|              */
 | |
|             if (channel == alpha)
 | |
|                inb = (inb * alpha_scale + 0x8000U) >> 16;
 | |
| 
 | |
|             else
 | |
|                inb = png_gamma_nxmbit_correct(inb, correct, 16U-shift, 16U);
 | |
| 
 | |
|             channel >>= 4; /* for the next channel, or the shibboleth */
 | |
|             *dp++ = PNG_BYTE(inb >> 8);
 | |
|             *dp++ = PNG_BYTE(inb);
 | |
|          }
 | |
|          while (sp < ep);
 | |
| 
 | |
|          debug(channel == 1U && sp == ep+1U);
 | |
|       }
 | |
| 
 | |
|       else /* bit_depth == 8U */
 | |
|       {
 | |
|          do
 | |
|          {
 | |
|             unsigned int inb = *sp++ << 8, shift;
 | |
|             inb += *sp++;
 | |
| 
 | |
|             if (channel == 1U)
 | |
|                channel = shifts;
 | |
| 
 | |
|             shift = channel & 0xFU;
 | |
|             inb >>= shift;
 | |
| 
 | |
|             if (channel == alpha)
 | |
|                inb = (inb * alpha_scale + 0x800000U) >> 24;
 | |
| 
 | |
|             else
 | |
|                inb = png_gamma_nxmbit_correct(inb, correct, 16U-shift, 8U);
 | |
| 
 | |
|             channel >>= 4; /* for the next channel, or the shibboleth */
 | |
|             *dp++ = PNG_BYTE(inb);
 | |
|          }
 | |
|          while (sp < ep);
 | |
| 
 | |
|          debug(channel == 1U && sp == ep+1U);
 | |
|       }
 | |
|    }
 | |
| #  undef png_ptr
 | |
| }
 | |
| 
 | |
| #ifdef PNG_READ_ALPHA_MODE_SUPPORTED
 | |
| static void
 | |
| png_do_gamma16_up_optimize(png_transformp *transform, png_transform_controlp tc)
 | |
|    /* As above, but the alpha channel is 'optimized' */
 | |
| {
 | |
| #  define png_ptr (tc->png_ptr)
 | |
|    png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp);
 | |
|    png_const_bytep ep = sp + PNG_TC_ROWBYTES(*tc);
 | |
|    png_bytep dp = png_voidcast(png_bytep, tc->dp);
 | |
|    png_transform_gamma *tr =
 | |
|       png_transform_cast(png_transform_gamma, *transform);
 | |
|    const png_fixed_point correct = tr->correct;
 | |
| 
 | |
|    /* The input always as 16 bits, the output 8 or 16.  There is always an alpha
 | |
|     * channel and it is converted to the 'optimized' form, where pixels with
 | |
|     * alpha not 0.0 or 1.0 are left in linear form (not gamma corrected.)  Where
 | |
|     * bit depth convertion is required it is from 16-bits to 8-bits and the
 | |
|     * DIV257 macro can be used.
 | |
|     *
 | |
|     * The following affirms and NOT_REACHED cases are consequences of the way
 | |
|     * the background (compose) code works:
 | |
|     */
 | |
|    affirm(tr->optimize_alpha && !tr->encode_alpha && tc->bit_depth == 16U);
 | |
| 
 | |
|    /* TODO: split this into separate functions */
 | |
|    switch (tr->to_bit_depth)
 | |
|    {
 | |
|       case 8U: /* 16-bit --> 8-bit */
 | |
|          tc->sp = dp;
 | |
|          tc->bit_depth = 8U;
 | |
|          tc->gamma = tr->to_gamma;
 | |
| 
 | |
|          switch (PNG_TC_CHANNELS(*tc))
 | |
|          {
 | |
|             case 2:/* GA */
 | |
|                debug(tr->shifts == 0x100U);
 | |
|                ep -= 3U; /*SAFETY*/
 | |
| 
 | |
|                do
 | |
|                {
 | |
|                   png_uint_32 alpha = PNG_DIV257((sp[2] << 8) + sp[3]);
 | |
| 
 | |
|                   switch (alpha)
 | |
|                   {
 | |
|                      case 0U:
 | |
|                         dp[1] = dp[0] = 0U;
 | |
|                         break;
 | |
| 
 | |
|                      default: /* optimized case: linear color data */
 | |
|                         dp[0] = png_check_byte(png_ptr,
 | |
|                               PNG_DIV257((sp[0] << 8) + sp[1]));
 | |
|                         dp[1] = PNG_BYTE(alpha);
 | |
|                         break;
 | |
| 
 | |
|                      case 255U: /* opaque pixels are encoded */
 | |
|                         dp[0] = PNG_BYTE(png_gamma_nxmbit_correct(
 | |
|                            (sp[0] << 8) + sp[1], correct, 16U, 8U));
 | |
|                         dp[1] = 255U;
 | |
|                         break;
 | |
|                   }
 | |
| 
 | |
|                   sp += 4U;
 | |
|                   dp += 2U;
 | |
|                }
 | |
|                while (sp < ep);
 | |
| 
 | |
|                debug(sp == ep+3U);
 | |
|                break;
 | |
| 
 | |
|             case 4:/* RGBA */
 | |
|                debug(tr->shifts == 0x10000U);
 | |
|                ep -= 7U; /*SAFETY*/
 | |
| 
 | |
|                do
 | |
|                {
 | |
|                   png_uint_32 alpha = PNG_DIV257((sp[6] << 8) + sp[7]);
 | |
| 
 | |
|                   switch (alpha)
 | |
|                   {
 | |
|                      case 0U:
 | |
|                         memset(dp, 0U, 4U);
 | |
|                         break;
 | |
| 
 | |
|                      default: /* optimized case: linear color data */
 | |
|                         dp[0] = PNG_BYTE(PNG_DIV257((sp[0] << 8) + sp[1]));
 | |
|                         dp[1] = PNG_BYTE(PNG_DIV257((sp[2] << 8) + sp[3]));
 | |
|                         dp[2] = PNG_BYTE(PNG_DIV257((sp[4] << 8) + sp[5]));
 | |
|                         dp[3] = PNG_BYTE(alpha);
 | |
|                         break;
 | |
| 
 | |
|                      case 255U: /* opaque pixels are encoded */
 | |
|                         dp[0] = PNG_BYTE(png_gamma_nxmbit_correct(
 | |
|                            (sp[0] << 8) + sp[1], correct, 16U, 8U));
 | |
|                         dp[1] = PNG_BYTE(png_gamma_nxmbit_correct(
 | |
|                            (sp[2] << 8) + sp[3], correct, 16U, 8U));
 | |
|                         dp[2] = PNG_BYTE(png_gamma_nxmbit_correct(
 | |
|                            (sp[4] << 8) + sp[5], correct, 16U, 8U));
 | |
|                         dp[3] = 255U;
 | |
|                         break;
 | |
|                   }
 | |
| 
 | |
|                   sp += 8U;
 | |
|                   dp += 4U;
 | |
|                }
 | |
|                while (sp < ep);
 | |
| 
 | |
|                debug(sp == ep+7U);
 | |
|                break;
 | |
| 
 | |
|             default:
 | |
|                NOT_REACHED;
 | |
|                break;
 | |
|          }
 | |
|          break;
 | |
| 
 | |
|       case 16: /* 16-bit to 16-bit */
 | |
|          tc->sp = dp;
 | |
|          tc->bit_depth = 16U;
 | |
|          tc->gamma = tr->to_gamma;
 | |
| 
 | |
|          switch (PNG_TC_CHANNELS(*tc))
 | |
|          {
 | |
|             case 2:/* GA */
 | |
|                debug(tr->shifts == 0x100U);
 | |
|                ep -= 3U; /*SAFETY*/
 | |
| 
 | |
|                do
 | |
|                {
 | |
|                   unsigned int alpha = (sp[2] << 8) + sp[3];
 | |
| 
 | |
|                   switch (alpha)
 | |
|                   {
 | |
|                      case 0U:
 | |
|                         memset(dp, 0U, 4U);
 | |
|                         break;
 | |
| 
 | |
|                      default: /* optimized case: linear color data */
 | |
|                         if (dp != sp)
 | |
|                         {
 | |
|                            memcpy(dp, sp, 4U);
 | |
|                            UNTESTED
 | |
|                         }
 | |
|                         break;
 | |
| 
 | |
|                      case 65535U: /* opaque pixels are encoded */
 | |
|                         {
 | |
|                            unsigned int gray = png_gamma_nxmbit_correct(
 | |
|                               (sp[0] << 8) + sp[1], correct, 16U, 16U);
 | |
|                            dp[0] = PNG_BYTE(gray >> 8);
 | |
|                            dp[1] = PNG_BYTE(gray);
 | |
|                         }
 | |
|                         dp[3] = dp[2] = 255U;
 | |
|                         break;
 | |
|                   }
 | |
| 
 | |
|                   sp += 4U;
 | |
|                   dp += 4U;
 | |
|                }
 | |
|                while (sp < ep);
 | |
| 
 | |
|                debug(sp == ep+3U);
 | |
|                break;
 | |
| 
 | |
|             case 4:/* RGBA */
 | |
|                debug(tr->shifts == 0x10000U);
 | |
|                ep -= 7U; /*SAFETY*/
 | |
| 
 | |
|                do
 | |
|                {
 | |
|                   unsigned int alpha = (sp[6] << 8) + sp[7];
 | |
| 
 | |
|                   switch (alpha)
 | |
|                   {
 | |
|                      case 0U:
 | |
|                         memset(dp, 0U, 8U);
 | |
|                         break;
 | |
| 
 | |
|                      default: /* optimized case: linear color data */
 | |
|                         if (dp != sp)
 | |
|                         {
 | |
|                            memcpy(dp, sp, 8U);
 | |
|                            UNTESTED
 | |
|                         }
 | |
|                         break;
 | |
| 
 | |
|                      case 65535U: /* opaque pixels are encoded */
 | |
|                         {
 | |
|                            unsigned int c = png_gamma_nxmbit_correct(
 | |
|                               (sp[0] << 8) + sp[1], correct, 16U, 16U);
 | |
|                            dp[0] = PNG_BYTE(c >> 8);
 | |
|                            dp[1] = PNG_BYTE(c);
 | |
| 
 | |
|                            c = png_gamma_nxmbit_correct(
 | |
|                               (sp[2] << 8) + sp[3], correct, 16U, 16U);
 | |
|                            dp[2] = PNG_BYTE(c >> 8);
 | |
|                            dp[3] = PNG_BYTE(c);
 | |
| 
 | |
|                            c = png_gamma_nxmbit_correct(
 | |
|                               (sp[4] << 8) + sp[5], correct, 16U, 16U);
 | |
|                            dp[4] = PNG_BYTE(c >> 8);
 | |
|                            dp[5] = PNG_BYTE(c);
 | |
|                         }
 | |
|                         dp[7] = dp[6] = 255U;
 | |
|                         break;
 | |
|                   }
 | |
| 
 | |
|                   sp += 8U;
 | |
|                   dp += 8U;
 | |
|                }
 | |
|                while (sp < ep);
 | |
| 
 | |
|                debug(sp == ep+7U);
 | |
|                break;
 | |
| 
 | |
|             default:
 | |
|                NOT_REACHED;
 | |
|                break;
 | |
|          }
 | |
|          break;
 | |
| 
 | |
|       default:
 | |
|          NOT_REACHED;
 | |
|          break;
 | |
|    }
 | |
| #  undef png_ptr
 | |
| }
 | |
| #endif /* READ_ALPHA_MODE */
 | |
| 
 | |
| static void
 | |
| png_do_scale16_up(png_transformp *transform, png_transform_controlp tc)
 | |
| {
 | |
| #  define png_ptr (tc->png_ptr)
 | |
|    png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp);
 | |
|    png_const_bytep ep = sp + PNG_TC_ROWBYTES(*tc);
 | |
|    png_bytep dp = png_voidcast(png_bytep, tc->dp);
 | |
|    png_transform_gamma *tr =
 | |
|       png_transform_cast(png_transform_gamma, *transform);
 | |
|    const unsigned int bit_depth = tr->to_bit_depth;
 | |
| 
 | |
|    affirm(tc->bit_depth == 16U && bit_depth < 8U);
 | |
|    affirm(tr->shifts != 0U/*uninitialized*/);
 | |
| 
 | |
|    /* This is exactly the same as above but without the gamma correction and
 | |
|     * without the 8-bit target support.  The code handles one or two channels,
 | |
|     * but the result is not a PNG format unless the number of channels is just
 | |
|     * 1 (grayscale).
 | |
|     *
 | |
|     * For multi-channel low bit depth the channels are packed into bytes using
 | |
|     * the standard PNG big-endian packing.
 | |
|     */
 | |
|    affirm((tc->format & PNG_FORMAT_FLAG_COLOR) == 0);
 | |
|    /* The alpha shift is actually ignored; at present we only get here with an
 | |
|     * alpha channel if it is to be removed for transparent alpha processing.
 | |
|     */
 | |
|    debug(tc->format & PNG_FORMAT_FLAG_ALPHA ?
 | |
|          (tr->shifts >> 8) == 1U : (tr->shifts >> 4) == 1U);
 | |
|    debug(tc->transparent_alpha);
 | |
| 
 | |
|    tc->sp = dp;
 | |
|    /* This is a pure scaling operation so sBIT is not invalidated or altered. */
 | |
|    tc->bit_depth = bit_depth;
 | |
| 
 | |
|    /* TODO: maybe do this properly and use the alpha shift, but only the top bit
 | |
|     * matters.
 | |
|     */
 | |
|    {
 | |
|       const unsigned int shift = tr->shifts & 0xFU;
 | |
|       const png_uint_32 factor = tr->channel_scale[0];
 | |
|       const png_uint_32 round = 1U << (31U-bit_depth);
 | |
|       unsigned int bits = 8U;
 | |
|       unsigned int ob = 0U;
 | |
| 
 | |
|       do
 | |
|       {
 | |
|          png_uint_32 inb = *sp++ << 8; /* high bits first */
 | |
|          inb += *sp++;
 | |
| 
 | |
|          inb = ((inb >> shift) * factor + round) >> (32U-bit_depth);
 | |
|          bits -= bit_depth;
 | |
|          ob = ob | (inb << bits);
 | |
|          if (bits == 0U)
 | |
|             bits = 8U, *dp++ = PNG_BYTE(ob), ob = 0U;
 | |
|       }
 | |
|       while (sp < ep);
 | |
| 
 | |
|       if (bits < 8U)
 | |
|          *dp++ = PNG_BYTE(ob);
 | |
|    }
 | |
| #  undef png_ptr
 | |
| }
 | |
| 
 | |
| static void
 | |
| png_do_gamma8_down(png_transformp *transform, png_transform_controlp tc)
 | |
| {
 | |
| #  define png_ptr (tc->png_ptr)
 | |
|    png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp);
 | |
|    png_bytep dp = png_voidcast(png_bytep, tc->dp);
 | |
|    png_const_bytep ep = dp + 1U/*safety*/;
 | |
|    png_transform_gamma *tr =
 | |
|       png_transform_cast(png_transform_gamma, *transform);
 | |
|    const png_fixed_point correct = tr->correct;
 | |
|    const png_uint_32 shifts = tr->shifts;
 | |
| 
 | |
|    affirm(tc->bit_depth == 8U && tr->to_bit_depth == 16U);
 | |
|    affirm(tr->shifts != 0U/*uninitialized*/);
 | |
|    debug((shifts & 0x8888U) == 0U); /* all shifts 7 or less */
 | |
|    debug(!tr->encode_alpha && !tr->optimize_alpha); /* only set for 16 bits */
 | |
| 
 | |
|    sp += PNG_TC_ROWBYTES(*tc);
 | |
|    tc->sp = dp;
 | |
|    tc->bit_depth = tr->to_bit_depth;
 | |
|    tc->gamma = tr->to_gamma;
 | |
|    dp += PNG_TC_ROWBYTES(*tc);
 | |
| 
 | |
|    {
 | |
|       png_uint_32 alpha_scale;
 | |
|       unsigned int channel, alpha;
 | |
| 
 | |
|       debug((shifts >> (4*PNG_TC_CHANNELS(*tc))) == 1U);
 | |
| 
 | |
|       /* We are going down so alpha, if present, is first.  Notice that the init
 | |
|        * routine has to reverse both 'shifts' and 'channel_scale' for the _down
 | |
|        * cases.
 | |
|        */
 | |
|       if ((tc->format & PNG_FORMAT_FLAG_ALPHA) == 0)
 | |
|          alpha_scale = alpha = 0U;
 | |
| 
 | |
|       else
 | |
|       {
 | |
|          alpha = shifts;
 | |
|          alpha_scale = tr->channel_scale[0U];
 | |
|       }
 | |
| 
 | |
|       channel = 1U;
 | |
| 
 | |
|       do /* 8-bit --> 16-bit */
 | |
|       {
 | |
|          unsigned int inb = *--sp, shift;
 | |
| 
 | |
|          if (channel == 1U)
 | |
|             channel = shifts;
 | |
| 
 | |
|          shift = channel & 0xFU;
 | |
|          inb >>= shift;
 | |
| 
 | |
|          if (channel == alpha) /* unencoded alpha, must scale */
 | |
|             inb = (inb * alpha_scale + 0x8000U) >> 16;
 | |
| 
 | |
|          else
 | |
|             inb = png_gamma_nxmbit_correct(inb, correct, 8U-shift, 16U);
 | |
| 
 | |
|          channel >>= 4;
 | |
| 
 | |
|          *--dp = PNG_BYTE(inb);
 | |
|          *--dp = PNG_BYTE(inb >> 8);
 | |
|       }
 | |
|       while (dp > ep);
 | |
| 
 | |
|       debug(channel == 1U && dp == ep-1U);
 | |
|    }
 | |
| #  undef png_ptr
 | |
| }
 | |
| 
 | |
| static void
 | |
| png_do_expand8_down(png_transformp *transform, png_transform_controlp tc)
 | |
| {
 | |
| #  define png_ptr (tc->png_ptr)
 | |
|    png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp);
 | |
|    png_bytep dp = png_voidcast(png_bytep, tc->dp);
 | |
|    png_const_bytep ep = dp + 1U/*safety*/;
 | |
|    png_transform_gamma *tr =
 | |
|       png_transform_cast(png_transform_gamma, *transform);
 | |
|    const png_uint_32 shifts = tr->shifts;
 | |
| 
 | |
|    affirm(tc->bit_depth == 8U && tr->to_bit_depth == 16U);
 | |
|    affirm(tr->shifts != 0U/*uninitialized*/);
 | |
| 
 | |
|    sp += PNG_TC_ROWBYTES(*tc);
 | |
|    tc->sp = dp;
 | |
|    tc->bit_depth = 16U;
 | |
|    dp += PNG_TC_ROWBYTES(*tc);
 | |
| 
 | |
|    {
 | |
|       png_uint_32 channel = 1U;
 | |
|       png_const_uint_32p scale = 0U;
 | |
| 
 | |
|       do /* 8-bit -> 16-bit */
 | |
|       {
 | |
|          unsigned int inb = *--sp, shift;
 | |
| 
 | |
|          if (channel == 1U)
 | |
|             channel = shifts, scale = tr->channel_scale;
 | |
| 
 | |
|          shift = channel & 0xFU;
 | |
|          channel >>= 4;
 | |
|          inb >>= shift;
 | |
|          inb = (inb * *scale++ + 0x8000U) >> 16;
 | |
|          /* dp starts beyond the end: */
 | |
|          *--dp = PNG_BYTE(inb);
 | |
|          *--dp = PNG_BYTE(inb >> 8);
 | |
|       }
 | |
|       while (dp > ep);
 | |
| 
 | |
|       debug(channel == 1U && dp == ep-1U);
 | |
|    }
 | |
| #  undef png_ptr
 | |
| }
 | |
| 
 | |
| static void
 | |
| png_do_expand8_down_fast(png_transformp *transform, png_transform_controlp tc)
 | |
|    /* Optimized version of the above for when the sBIT settings are all a full 8
 | |
|     * bits (the normal case).
 | |
|     */
 | |
| {
 | |
| #  define png_ptr (tc->png_ptr)
 | |
|    png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp);
 | |
|    png_bytep dp = png_voidcast(png_bytep, tc->dp);
 | |
|    png_const_bytep ep = dp + 1U/*safety*/;
 | |
|    png_transform_gamma *tr =
 | |
|       png_transform_cast(png_transform_gamma, *transform);
 | |
| 
 | |
|    affirm(tc->bit_depth == 8U && tr->to_bit_depth == 16U);
 | |
|    affirm(tr->shifts != 0U/*uninitialized*/);
 | |
| 
 | |
|    sp += PNG_TC_ROWBYTES(*tc);
 | |
|    tc->sp = dp;
 | |
|    tc->bit_depth = 16U;
 | |
|    dp += PNG_TC_ROWBYTES(*tc);
 | |
| 
 | |
|    do
 | |
|       dp -= 2, dp[0] = dp[1] = *--sp;
 | |
|    while (dp > ep);
 | |
| 
 | |
|    debug(dp == ep-1U);
 | |
| #  undef png_ptr
 | |
| }
 | |
| 
 | |
| static void
 | |
| png_init_gamma_uncached(png_transformp *transform, png_transform_controlp tc)
 | |
| {
 | |
| #  define png_ptr (tc->png_ptr)
 | |
|    png_transform_gamma *tr =
 | |
|       png_transform_cast(png_transform_gamma, *transform);
 | |
| 
 | |
|    debug(tc->init == PNG_TC_INIT_FINAL);
 | |
| 
 | |
|    /* Set this first; the result says if the sBIT data is significant, but it is
 | |
|     * ignored here.
 | |
|     */
 | |
|    (void)init_gamma_sBIT(tr, tc);
 | |
| 
 | |
|    /* If png_set_alpha_mode is called but no background processing needs to be
 | |
|     * done (because there is no alpha channel or tRNS) we get to here with
 | |
|     * potentially spurious alpha mode flags.
 | |
|     */
 | |
|    if (!(tc->format & PNG_FORMAT_FLAG_ALPHA))
 | |
|       tr->encode_alpha = tr->optimize_alpha = 0U;
 | |
| 
 | |
|    /* Use separate functions for the two input depths but not for the five
 | |
|     * possible output depths and four channel counts.
 | |
|     */
 | |
|    if (tc->bit_depth == 8U)
 | |
|    {
 | |
|       if (tr->to_bit_depth <= 8U)
 | |
|          tr->tr.fn = png_do_gamma8_up;
 | |
| 
 | |
|       else
 | |
|       {
 | |
|          debug(tr->to_bit_depth == 16U);
 | |
|          reverse_gamma_sBIT(tr);
 | |
|          tr->tr.fn = png_do_gamma8_down;
 | |
|       }
 | |
|    }
 | |
| 
 | |
|    else
 | |
|    {
 | |
|       affirm(tc->bit_depth == 16U);
 | |
| #     ifdef PNG_READ_ALPHA_MODE_SUPPORTED
 | |
|          if (!tr->optimize_alpha)
 | |
|             tr->tr.fn = png_do_gamma16_up;
 | |
|          else
 | |
|             tr->tr.fn = png_do_gamma16_up_optimize;
 | |
| #     else /* !READ_ALPHA_MODE */
 | |
|          tr->tr.fn = png_do_gamma16_up;
 | |
| #     endif /* !READ_ALPHA_MODE */
 | |
|    }
 | |
| 
 | |
|    /* Since the 'do' routines always perform gamma correction they will always
 | |
|     * expand the significant bits to the full output bit depth.
 | |
|     */
 | |
|    tc->invalid_info |= PNG_INFO_sBIT;
 | |
|    tc->bit_depth = tr->to_bit_depth;
 | |
|    tc->sBIT_R = tc->sBIT_G = tc->sBIT_B =
 | |
|       png_check_byte(png_ptr, tc->bit_depth);
 | |
|    if (tr->encode_alpha)
 | |
|       tc->sBIT_A = tc->sBIT_G;
 | |
|    tc->gamma = tr->to_gamma;
 | |
| #  undef png_ptr
 | |
| }
 | |
| 
 | |
| #ifdef PNG_READ_sBIT_SUPPORTED
 | |
| static unsigned int
 | |
| tc_sBIT(png_const_transform_controlp tc)
 | |
|    /* Determine the maximum number of significant bits in the row at this point.
 | |
|     * This uses the png_struct::sig_bit field if it has not been invalidated,
 | |
|     * otherwise it just returns the current bit depth.
 | |
|     */
 | |
| {
 | |
|    const png_structrp png_ptr = tc->png_ptr;
 | |
|    unsigned int bit_depth = tc->bit_depth;
 | |
| 
 | |
|    if ((tc->invalid_info & PNG_INFO_sBIT) == 0U)
 | |
|    {
 | |
|       /* Normally the bit depth will not have been changed from the original PNG
 | |
|        * depth, but it currently is changed by the grayscale expand to 8 bits,
 | |
|        * an operation which doesn't invalidate sBIT.
 | |
|        */
 | |
|       unsigned int sBIT;
 | |
| 
 | |
|       if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) != 0U)
 | |
|       {
 | |
|          /* Must use the largest of the sBIT depths, except that unset values
 | |
|           * take priority.
 | |
|           */
 | |
|          sBIT = png_ptr->sig_bit.red && png_ptr->sig_bit.green &&
 | |
|             png_ptr->sig_bit.blue;
 | |
| 
 | |
|          if (sBIT != 0U)
 | |
|          {
 | |
|             sBIT = png_ptr->sig_bit.red;
 | |
| 
 | |
|             if (png_ptr->sig_bit.green > sBIT)
 | |
|                sBIT = png_ptr->sig_bit.green;
 | |
|             if (png_ptr->sig_bit.blue > sBIT)
 | |
|                sBIT = png_ptr->sig_bit.blue;
 | |
|          }
 | |
|       }
 | |
| 
 | |
|       else
 | |
|          sBIT = png_ptr->sig_bit.gray;
 | |
| 
 | |
|       if (sBIT > 0U && sBIT < bit_depth)
 | |
|          bit_depth = sBIT;
 | |
|    }
 | |
| 
 | |
|    return bit_depth;
 | |
| }
 | |
| #else /* !READ_sBIT */
 | |
| #  define tc_sBIT(tc) ((tc)->bit_depth)
 | |
| #endif /* READ_sBIT */
 | |
| 
 | |
| static void
 | |
| png_init_gamma(png_transformp *transform, png_transform_controlp tc)
 | |
| {
 | |
|    const png_structrp png_ptr = tc->png_ptr;
 | |
|    png_transform_gamma *tr =
 | |
|       png_transform_cast(png_transform_gamma, *transform);
 | |
| 
 | |
|    if (tc->init == PNG_TC_INIT_FORMAT)
 | |
|    {
 | |
|       /* This should only happen for the final encode gamma transform, which
 | |
|        * never initializes the target bit depth (see png_set_gamma and
 | |
|        * png_set_alpha_mode).  The affirm is required here; in we can't continue
 | |
|        * safely if the bit depth has been set somehow.
 | |
|        */
 | |
|       debug(tr->tr.order == PNG_TR_GAMMA_ENCODE);
 | |
|       affirm(tr->to_gamma > 0 && tr->to_bit_depth == 0U);
 | |
| 
 | |
|       /* At this point the output gamma should not have been set yet: */
 | |
|       debug(png_ptr->row_gamma == 0);
 | |
| 
 | |
|       /* The following must be true; png_set_gamma and png_set_alpha_mode set
 | |
|        * (or default) the PNG gamma and other routines that insert a gamma
 | |
|        * transform must only do in PNG_TC_INIT_FINAL:
 | |
|        */
 | |
|       debug(tc->gamma > 0);
 | |
| 
 | |
|       /* At this point the data gamma must be updated so that we get the correct
 | |
|        * png_struct::row_gamma at the end of the init:
 | |
|        */
 | |
|       tc->gamma = tr->to_gamma;
 | |
| 
 | |
|       /* For safety invalidate the sBIT information too; we don't know yet
 | |
|        * whether a gamma transform will be required but if it is the sBIT
 | |
|        * information becomes invalid.
 | |
|        */
 | |
|       tc->invalid_info |= PNG_INFO_sBIT;
 | |
|    }
 | |
| 
 | |
|    else /* PNG_TC_INIT_FINAL */
 | |
|    {
 | |
|       /* It is very bad if we get here when processing a row: */
 | |
|       affirm(tc->init == PNG_TC_INIT_FINAL && png_ptr->row_bit_depth > 0);
 | |
| 
 | |
|       /* There are three cases:
 | |
|        *
 | |
|        * 1) Gamma correction is required, output bit depth may need to be
 | |
|        *    defaulted.
 | |
|        * 2) Gamma correction is not required but a bit depth change is
 | |
|        *    necessary.
 | |
|        * 3) Neither is required; the transform can be eliminated.
 | |
|        *
 | |
|        * First default the bit depth if it is not already set.  Note that if the
 | |
|        * output is a palette then 'row_bit_depth' refers to the palette size and
 | |
|        * 8U must be used here.  tc->palette is irrelevant; it only tells us that
 | |
|        * the data came from a palette.
 | |
|        */
 | |
|       if (tr->to_bit_depth == 0)
 | |
|       {
 | |
|          if ((png_ptr->row_format & PNG_FORMAT_FLAG_COLORMAP) != 0U)
 | |
|             tr->to_bit_depth = 8U;
 | |
| 
 | |
|          else
 | |
|             tr->to_bit_depth = png_ptr->row_bit_depth;
 | |
|       }
 | |
| 
 | |
|       /* (1); is gamma correction required?  If tc->gamma is 0 at this point it
 | |
|        * is not, but then the png_struct::row_gamma should be 0 too.
 | |
|        */
 | |
|       implies(tc->gamma == 0, png_ptr->row_gamma == 0);
 | |
|       implies(tr->to_gamma == 0, tc->gamma == 0);
 | |
| 
 | |
|       if (!png_gamma_equal(png_ptr, tc->gamma, tr->to_gamma, &tr->correct,
 | |
|                            tc_sBIT(tc)))
 | |
|       {
 | |
|          /* First make sure the input doesn't have a tRNS chunk which needs to
 | |
|           * be expanded now; if it does push_gamma_expand will push an
 | |
|           * appropriate transform *before* this one and we need to return
 | |
|           * immediately (the caller will call back to this function).
 | |
|           */
 | |
|          if (push_gamma_expand(transform, tc, 0/*need alpha*/))
 | |
|          {
 | |
|             affirm(tc->bit_depth >= 8U &&
 | |
|                    (tc->invalid_info & PNG_INFO_tRNS) != 0U &&
 | |
|                    *transform != &tr->tr);
 | |
|             return;
 | |
|          }
 | |
| 
 | |
|          debug(*transform == &tr->tr && tc->bit_depth >= 8U);
 | |
| 
 | |
|          /* The format is now 8 or 16-bit G, GA, RGB or RGBA and gamma
 | |
|           * correction is required.
 | |
|           */
 | |
|          png_init_gamma_uncached(transform, tc);
 | |
|          /* TODO: implement caching for the !tc->caching cases! */
 | |
|          return;
 | |
|       }
 | |
| 
 | |
|       /* The cases where the two gamma values are close enough to be considered
 | |
|        * equal.  The code lies about the gamma; this prevents apps and the
 | |
|        * simplified API getting into loops or bad conditions because the gamma
 | |
|        * was not set to the expected value.
 | |
|        *
 | |
|        * Note that png_transform_control::gamma is only set here if both the
 | |
|        * input and output gamma values are known, otherwise the transform
 | |
|        * introduces a spurious know gamma value.
 | |
|        */
 | |
|       if (tr->to_gamma > 0 && tc->gamma > 0)
 | |
|          tc->gamma = tr->to_gamma;
 | |
| 
 | |
|       if (tr->to_bit_depth > tc->bit_depth)
 | |
|       {
 | |
|          /* This is either the to-linear operation, in which case the expected
 | |
|           * bit depth is 16U, or it is the final encode in the case where an
 | |
|           * 'expand' operation was also specified.
 | |
|           *
 | |
|           * We don't care about the PNG_TR_GAMMA_ENCODE case because we know
 | |
|           * that there has to be an expand operation further down the pipeline.
 | |
|           */
 | |
|          if (tr->tr.order < PNG_TR_GAMMA_ENCODE)
 | |
|          {
 | |
|             affirm(tr->to_bit_depth == 16U);
 | |
| 
 | |
|             if (push_gamma_expand(transform, tc, 0/*need alpha*/))
 | |
|             {
 | |
|                affirm(tc->bit_depth == 8U &&
 | |
|                       (tc->invalid_info & PNG_INFO_tRNS) != 0U &&
 | |
|                       *transform != &tr->tr);
 | |
|                return;
 | |
|             }
 | |
| 
 | |
|             debug(*transform == &tr->tr);
 | |
|             affirm(tc->bit_depth == 8U); /* if 16U we would not be here! */
 | |
| 
 | |
|             /* not using byte_ops here, but if there is no sBIT required
 | |
|              * (normally the case) the fast code can be used:
 | |
|              */
 | |
|             if (init_gamma_sBIT(tr, tc))
 | |
|                tr->tr.fn = png_do_expand8_down;
 | |
| 
 | |
|             else
 | |
|                tr->tr.fn = png_do_expand8_down_fast;
 | |
| 
 | |
|             tc->bit_depth = 16U;
 | |
|          }
 | |
| 
 | |
|          else /* PNG_TR_GAMMA_ENCODE: nothing need be done */
 | |
|             tr->tr.fn = NULL;
 | |
|       }
 | |
| 
 | |
|       else if (tr->to_bit_depth < tc->bit_depth)
 | |
|       {
 | |
|          /* No gamma correction but bit depth *reduction* is required.  Expect
 | |
|           * the 'from' bit depth to always be 16, otherwise this transform
 | |
|           * should not have been pushed.  Also expect this to be the gamma
 | |
|           * 'encode' operation at the end of the arithmetic.
 | |
|           */
 | |
|          affirm(tc->bit_depth == 16U && tr->tr.order == PNG_TR_GAMMA_ENCODE);
 | |
| 
 | |
|          /* If the target bit depth is 8-bit delay the operation and use the
 | |
|           * standard 16-8-bit scale code.  For low bit depth do it now.
 | |
|           */
 | |
|          if (tr->to_bit_depth == 8U)
 | |
|          {
 | |
|             png_set_scale_16(png_ptr);
 | |
|             tr->tr.fn = NULL;
 | |
|          }
 | |
| 
 | |
|          else /* low bit depth */
 | |
|          {
 | |
|             (void)init_gamma_sBIT(tr, tc);
 | |
|             tr->tr.fn = png_do_scale16_up;
 | |
|             tc->bit_depth = tr->to_bit_depth;
 | |
|          }
 | |
|       }
 | |
| 
 | |
|       else /* gamma !significant and nothing to do */
 | |
|          tr->tr.fn = NULL;
 | |
|    }
 | |
| }
 | |
| 
 | |
| static png_fixed_point
 | |
| translate_gamma_flags(png_const_structrp png_ptr, png_fixed_point gamma,
 | |
|    int is_screen)
 | |
|    /* If 'is_screen' is set this returns the inverse of the supplied value; i.e.
 | |
|     * this routine always returns an encoding value.
 | |
|     */
 | |
| {
 | |
|    /* Check for flag values.  The main reason for having the old Mac value as a
 | |
|     * flag is that it is pretty near impossible to work out what the correct
 | |
|     * value is from Apple documentation - a working Mac system is needed to
 | |
|     * discover the value!
 | |
|     */
 | |
|    switch (gamma)
 | |
|    {
 | |
|       case PNG_DEFAULT_sRGB:
 | |
|       case PNG_GAMMA_sRGB:
 | |
|       case PNG_FP_1/PNG_GAMMA_sRGB: /* stupid case: -100000 */
 | |
|          gamma = PNG_GAMMA_sRGB_INVERSE;
 | |
|          break;
 | |
| 
 | |
|       case PNG_GAMMA_MAC_18:
 | |
|       case PNG_FP_1/PNG_GAMMA_MAC_18: /* stupid case: -50000 */
 | |
|          gamma = PNG_GAMMA_MAC_INVERSE;
 | |
|          break;
 | |
| 
 | |
|       default:
 | |
|          if (is_screen)
 | |
|          {
 | |
|             /* Check for a ridiculously low value; this will result in an
 | |
|              * overflow
 | |
|              * in the reciprocal calculation.
 | |
|              */
 | |
|             if (gamma < 5)
 | |
|             {
 | |
|                png_app_error(png_ptr, "invalid screen gamma (too low)");
 | |
|                gamma = 0;
 | |
|             }
 | |
| 
 | |
|             else if (gamma != PNG_FP_1) /* optimize linear */
 | |
|                gamma = png_reciprocal(gamma);
 | |
|          }
 | |
| 
 | |
|          else if (gamma <= 0)
 | |
|          {
 | |
|             png_app_error(png_ptr, "invalid file gamma (too low)");
 | |
|             gamma = 0;
 | |
|          }
 | |
|          break;
 | |
|    }
 | |
| 
 | |
|    return gamma;
 | |
| }
 | |
| 
 | |
| static png_transform_gamma *
 | |
| add_gamma_transform(png_structrp png_ptr, unsigned int order,
 | |
|    png_fixed_point gamma, unsigned int bit_depth, int force)
 | |
| {
 | |
|    /* Add a png_transform_gamma transform at the given position; this is a
 | |
|     * utility which just adds the transform and (unconditionally) overwrites the
 | |
|     * to_gamma field.  gamma must be valid.  If 'force' is true the gamma value
 | |
|     * in an existing transform will be overwritten, otherwise this is just a
 | |
|     * default value.
 | |
|     */
 | |
|    png_transform_gamma *tr = png_transform_cast(png_transform_gamma,
 | |
|       png_add_transform(png_ptr, sizeof (png_transform_gamma), png_init_gamma,
 | |
|          order));
 | |
| 
 | |
|    if (force || tr->to_gamma == 0)
 | |
|       tr->to_gamma = gamma;
 | |
| 
 | |
|    tr->to_bit_depth = bit_depth;
 | |
| 
 | |
|    return tr;
 | |
| }
 | |
| 
 | |
| void PNGFAPI
 | |
| png_set_gamma_fixed(png_structrp png_ptr, png_fixed_point scrn_gamma,
 | |
|    png_fixed_point file_gamma)
 | |
| {
 | |
|    png_debug(1, "in png_set_gamma_fixed");
 | |
| 
 | |
|    /* Validate the passed in file gamma value: */
 | |
|    file_gamma = translate_gamma_flags(png_ptr, file_gamma, 0/*file*/);
 | |
| 
 | |
|    /* The returned value may be 0, this results in a png_app_error above which
 | |
|     * may be ignored; if that happens simply ignore the setting.
 | |
|     */
 | |
|    if (file_gamma > 0)
 | |
|    {
 | |
|       /* Set the colorspace gamma value unconditionally - this overrides the
 | |
|        * value in the PNG file if a gAMA chunk was present.  png_set_alpha_mode
 | |
|        * provides a different, easier, way to default the file gamma.
 | |
|        */
 | |
|       png_ptr->colorspace.gamma = file_gamma;
 | |
|       if (png_ptr->colorspace.flags & PNG_COLORSPACE_INVALID)
 | |
|          png_ptr->colorspace.flags = PNG_COLORSPACE_HAVE_GAMMA;
 | |
|       else
 | |
|          png_ptr->colorspace.flags |= PNG_COLORSPACE_HAVE_GAMMA;
 | |
|    }
 | |
| 
 | |
|    /* Do the same thing with the screen gamma; check it and handle it if valid.
 | |
|     * This adds/sets the encoding of the final gamma transform in the chain.
 | |
|     * png_set_alpha_mode does the same thing.
 | |
|     */
 | |
|    scrn_gamma = translate_gamma_flags(png_ptr, scrn_gamma, 1/*screen*/);
 | |
| 
 | |
|    if (scrn_gamma > 0)
 | |
|       (void)add_gamma_transform(png_ptr, PNG_TR_GAMMA_ENCODE, scrn_gamma,
 | |
|             0/*bit depth*/, 1/*force to_gamma to scrn_gamma*/);
 | |
| }
 | |
| 
 | |
| #ifdef PNG_FLOATING_POINT_SUPPORTED
 | |
| static png_fixed_point
 | |
| convert_gamma_value(png_structrp png_ptr, double output_gamma)
 | |
| {
 | |
|    /* The following silently ignores cases where fixed point (times 100,000)
 | |
|     * gamma values are passed to the floating point API.  This is safe and it
 | |
|     * means the fixed point constants work just fine with the floating point
 | |
|     * API.  The alternative would just lead to undetected errors and spurious
 | |
|     * bug reports.  Negative values fail inside the _fixed API unless they
 | |
|     * correspond to the flag values.
 | |
|     */
 | |
|    if (output_gamma < 0 || output_gamma > 128)
 | |
|       output_gamma *= .00001;
 | |
| 
 | |
|    return png_fixed(png_ptr, output_gamma, "gamma value");
 | |
| }
 | |
| 
 | |
| void PNGAPI
 | |
| png_set_gamma(png_structrp png_ptr, double scrn_gamma, double file_gamma)
 | |
| {
 | |
|    png_set_gamma_fixed(png_ptr, convert_gamma_value(png_ptr, scrn_gamma),
 | |
|       convert_gamma_value(png_ptr, file_gamma));
 | |
| }
 | |
| #endif /* FLOATING_POINT */
 | |
| #endif /* READ_GAMMA */
 | |
| 
 | |
| #ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED
 | |
| static void
 | |
| png_do_rtog_48(png_transformp *transform, png_transform_controlp tc)
 | |
| {
 | |
| #  define png_ptr (tc->png_ptr)
 | |
|    const png_uint_32 r = (*transform)->args >> 16;
 | |
|    const png_uint_32 g = (*transform)->args & 0xFFFFU;
 | |
|    const png_uint_32 b = 65536U - r - g;
 | |
| 
 | |
|    png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp);
 | |
|    const png_const_bytep ep = sp + PNG_TC_ROWBYTES(*tc) - 6U;
 | |
|    png_bytep dp = png_voidcast(png_bytep, tc->dp);
 | |
| 
 | |
|    debug(tc->bit_depth == 16U && tc->format == PNG_FORMAT_FLAG_COLOR &&
 | |
|          (tc->gamma == 0U || !png_gamma_significant(png_ptr, tc->gamma, 16U)));
 | |
| 
 | |
|    tc->sp = dp;
 | |
|    tc->format &= PNG_BIC_MASK(PNG_FORMAT_FLAG_COLOR);
 | |
| 
 | |
|    while (sp <= ep)
 | |
|    {
 | |
|       png_uint_32 gray = (((sp[0] << 8) + sp[1]) * r +
 | |
|          ((sp[2] << 8) + sp[3]) * g +
 | |
|          ((sp[4] << 8) + sp[5]) * b + 32767U) >> 16;
 | |
| 
 | |
|       debug(gray < 65536U);
 | |
|       *dp++ = PNG_BYTE(gray >> 8);
 | |
|       *dp++ = PNG_BYTE(gray);
 | |
|       sp += 6U;
 | |
|    }
 | |
| #  undef png_ptr
 | |
| }
 | |
| 
 | |
| static void
 | |
| png_do_rtog_64(png_transformp *transform, png_transform_controlp tc)
 | |
| {
 | |
| #  define png_ptr (tc->png_ptr)
 | |
|    const png_uint_32 r = (*transform)->args >> 16;
 | |
|    const png_uint_32 g = (*transform)->args & 0xFFFFU;
 | |
|    const png_uint_32 b = 65536U - r - g;
 | |
| 
 | |
|    png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp);
 | |
|    const png_const_bytep ep = sp + PNG_TC_ROWBYTES(*tc) - 8U;
 | |
|    png_bytep dp = png_voidcast(png_bytep, tc->dp);
 | |
| 
 | |
|    debug(tc->bit_depth == 16U &&
 | |
|          tc->format == PNG_FORMAT_FLAG_COLOR+PNG_FORMAT_FLAG_ALPHA &&
 | |
|          (tc->gamma == 0U || !png_gamma_significant(png_ptr, tc->gamma, 16U)));
 | |
| 
 | |
|    tc->sp = dp;
 | |
|    tc->format &= PNG_BIC_MASK(PNG_FORMAT_FLAG_COLOR);
 | |
| 
 | |
|    while (sp <= ep)
 | |
|    {
 | |
|       png_uint_32 gray = (((sp[0] << 8) + sp[1]) * r +
 | |
|          ((sp[2] << 8) + sp[3]) * g +
 | |
|          ((sp[4] << 8) + sp[5]) * b + 32767U) >> 16;
 | |
| 
 | |
|       debug(gray < 65536U);
 | |
|       *dp++ = PNG_BYTE(gray >> 8);
 | |
|       *dp++ = PNG_BYTE(gray);
 | |
|       sp += 6U;
 | |
|       *dp++ = *sp++; /* alpha */
 | |
|       *dp++ = *sp++;
 | |
|    }
 | |
| #  undef png_ptr
 | |
| }
 | |
| 
 | |
| static void
 | |
| png_init_rgb_to_gray_arithmetic(png_transformp *transform,
 | |
|    png_transform_controlp tc)
 | |
| {
 | |
| #  define png_ptr (tc->png_ptr)
 | |
|    /* This only gets used in the final init stage: */
 | |
|    debug(tc->init == PNG_TC_INIT_FINAL && tc->bit_depth == 16U &&
 | |
|          (tc->format & PNG_BIC_MASK(PNG_FORMAT_FLAG_ALPHA)) ==
 | |
|             PNG_FORMAT_FLAG_COLOR);
 | |
| 
 | |
|    (*transform)->fn = (tc->format & PNG_FORMAT_FLAG_ALPHA) ? png_do_rtog_64 :
 | |
|       png_do_rtog_48;
 | |
| 
 | |
|    tc->format &= PNG_BIC_MASK(PNG_FORMAT_FLAG_COLOR);
 | |
|    tc->invalid_info |= PNG_INFO_sBIT;
 | |
|    tc->sBIT_R = tc->sBIT_G = tc->sBIT_B = tc->sBIT_A =
 | |
|       png_check_byte(png_ptr, tc->bit_depth);
 | |
| #  undef png_ptr
 | |
| }
 | |
| 
 | |
| typedef struct
 | |
| {
 | |
|    png_transform tr;
 | |
|    png_fixed_point red_coefficient;
 | |
|    png_fixed_point green_coefficient;
 | |
|    unsigned int    coefficients_set   :1;
 | |
|    unsigned int    error_action       :2;
 | |
| }  png_transform_rgb_to_gray;
 | |
| 
 | |
| static void
 | |
| png_update_rgb_status(png_structrp png_ptr, png_transformp *transform)
 | |
| {
 | |
|    png_transform_rgb_to_gray *tr = png_transform_cast(png_transform_rgb_to_gray,
 | |
|       *transform);
 | |
| 
 | |
|    png_ptr->rgb_to_gray_status = 1U;
 | |
|    tr->tr.fn = NULL; /* one warning/error only */
 | |
| 
 | |
|    switch (tr->error_action)
 | |
|    {
 | |
|       case PNG_ERROR_ACTION_WARN:
 | |
|          png_warning(png_ptr, "RGB to gray found nongray pixel");
 | |
|          break;
 | |
| 
 | |
|       case PNG_ERROR_ACTION_ERROR:
 | |
|          png_error(png_ptr, "RGB to gray found nongray pixel");
 | |
|          break;
 | |
| 
 | |
|       default:
 | |
|          break;
 | |
|    }
 | |
| }
 | |
| 
 | |
| static void
 | |
| png_do_rgb_check24(png_transformp *transform, png_transform_controlp tc)
 | |
| {
 | |
| #  define png_ptr (tc->png_ptr)
 | |
|    /* Sets 'rgb_to_gray' status if a pixel is found where the red green and blue
 | |
|     * channels are not equal.
 | |
|     */
 | |
|    png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp);
 | |
|    const png_const_bytep ep = sp + PNG_TC_ROWBYTES(*tc) - 3U;
 | |
| 
 | |
|    debug(tc->bit_depth == 8U && tc->format == PNG_FORMAT_FLAG_COLOR);
 | |
| 
 | |
|    while (sp <= ep)
 | |
|    {
 | |
|       if ((sp[0] ^ sp[1]) | (sp[2] ^ sp[1]))
 | |
|       {
 | |
|          png_update_rgb_status(png_ptr, transform);
 | |
|          break;
 | |
|       }
 | |
| 
 | |
|       sp += 3U;
 | |
|    }
 | |
| #  undef png_ptr
 | |
| }
 | |
| 
 | |
| static void
 | |
| png_do_rgb_check32(png_transformp *transform, png_transform_controlp tc)
 | |
| {
 | |
| #  define png_ptr (tc->png_ptr)
 | |
|    /* Sets 'rgb_to_gray' status if a pixel is found where the red green and blue
 | |
|     * channels are not equal and alpha is not zero.
 | |
|     */
 | |
|    png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp);
 | |
|    const png_const_bytep ep = sp + PNG_TC_ROWBYTES(*tc) - 4U;
 | |
| 
 | |
|    debug(tc->bit_depth == 8U &&
 | |
|          tc->format == PNG_FORMAT_FLAG_COLOR+PNG_FORMAT_FLAG_ALPHA);
 | |
| 
 | |
|    while (sp <= ep)
 | |
|    {
 | |
|       if (((sp[0] ^ sp[1]) | (sp[2] ^ sp[1])) && sp[3] != 0)
 | |
|       {
 | |
|          png_update_rgb_status(png_ptr, transform);
 | |
|          break;
 | |
|       }
 | |
| 
 | |
|       sp += 4U;
 | |
|    }
 | |
| #  undef png_ptr
 | |
| }
 | |
| 
 | |
| static void
 | |
| png_do_rgb_check48(png_transformp *transform, png_transform_controlp tc)
 | |
| {
 | |
| #  define png_ptr (tc->png_ptr)
 | |
|    /* Sets 'rgb_to_gray' status if a pixel is found where the red green and blue
 | |
|     * channels are not equal.
 | |
|     */
 | |
|    png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp);
 | |
|    const png_const_bytep ep = sp + PNG_TC_ROWBYTES(*tc) - 6U;
 | |
| 
 | |
|    debug(tc->bit_depth == 16U && tc->format == PNG_FORMAT_FLAG_COLOR);
 | |
| 
 | |
|    while (sp <= ep)
 | |
|    {
 | |
|       if ((sp[0] ^ sp[2]) | (sp[4] ^ sp[2]) |
 | |
|           (sp[1] ^ sp[3]) | (sp[5] ^ sp[3]))
 | |
|       {
 | |
|          png_update_rgb_status(png_ptr, transform);
 | |
|          break;
 | |
|       }
 | |
| 
 | |
|       sp += 6U;
 | |
|    }
 | |
| #  undef png_ptr
 | |
| }
 | |
| 
 | |
| static void
 | |
| png_do_rgb_check64(png_transformp *transform, png_transform_controlp tc)
 | |
| {
 | |
| #  define png_ptr (tc->png_ptr)
 | |
|    /* Sets 'rgb_to_gray' status if a pixel is found where the red green and blue
 | |
|     * channels are not equal and alpha is not zero.
 | |
|     */
 | |
|    png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp);
 | |
|    const png_const_bytep ep = sp + PNG_TC_ROWBYTES(*tc) - 8U;
 | |
| 
 | |
|    debug(tc->bit_depth == 16U &&
 | |
|          tc->format == PNG_FORMAT_FLAG_COLOR+PNG_FORMAT_FLAG_ALPHA);
 | |
| 
 | |
|    while (sp <= ep)
 | |
|    {
 | |
|       if (((sp[0] ^ sp[2]) | (sp[4] ^ sp[2]) |
 | |
|           (sp[1] ^ sp[3]) | (sp[5] ^ sp[3])) &&
 | |
|           (sp[6] | sp[7]) != 0)
 | |
|       {
 | |
|          png_update_rgb_status(png_ptr, transform);
 | |
|          break;
 | |
|       }
 | |
| 
 | |
|       sp += 8U;
 | |
|    }
 | |
| #  undef png_ptr
 | |
| }
 | |
| 
 | |
| static void
 | |
| png_init_rgb_to_gray(png_transformp *transform, png_transform_controlp tc)
 | |
| {
 | |
|    png_structrp png_ptr = tc->png_ptr;
 | |
| 
 | |
|    /* Basic checks: if there is no color in the format this transform is not
 | |
|     * applicable.
 | |
|     */
 | |
|    if ((tc->format & PNG_FORMAT_FLAG_COLOR) != 0)
 | |
|    {
 | |
|       png_transform_rgb_to_gray *tr = png_transform_cast(
 | |
|          png_transform_rgb_to_gray, *transform);
 | |
| 
 | |
|       /* no colormap allowed: */
 | |
|       affirm(tc->init && !(tc->format & PNG_FORMAT_FLAG_COLORMAP));
 | |
|       /* no extra flags yet: */
 | |
|       debug(!(tc->format &
 | |
|                PNG_BIC_MASK(PNG_FORMAT_FLAG_COLOR+PNG_FORMAT_FLAG_ALPHA)));
 | |
|       /* at present no non-palette caching: */
 | |
|       implies(tc->caching, tc->palette);
 | |
| 
 | |
|       if (tc->init == PNG_TC_INIT_FORMAT)
 | |
|       {
 | |
|          /* The convertion should just remove the 'COLOR' flag and do nothing
 | |
|           * else, but if a tRNS chunk is present this would invalidate it.
 | |
|           * Handle this by expanding it now.
 | |
|           */
 | |
|          if ((tc->format & PNG_FORMAT_FLAG_ALPHA) == 0 && !tc->palette &&
 | |
|              png_ptr->num_trans == 1 && !(tc->invalid_info & PNG_INFO_tRNS))
 | |
|          {
 | |
|             /* Only if expand was requested and not cancelled: */
 | |
|             if (tc->expand_tRNS && !tc->strip_alpha)
 | |
|                tc->format |= PNG_FORMAT_FLAG_ALPHA;
 | |
| 
 | |
|             tc->invalid_info |= PNG_INFO_tRNS; /* prevent expansion later */
 | |
|          }
 | |
| 
 | |
|          tc->format &= PNG_BIC_MASK(PNG_FORMAT_FLAG_COLOR);
 | |
|       }
 | |
| 
 | |
|       else /* PNG_TC_INIT_FINAL */
 | |
|       {
 | |
|          unsigned int index;   /* channel to select (invalid) */
 | |
|          png_byte sBIT_color;  /* sBIT of that channel if valid */
 | |
|          png_fixed_point r, g; /* Coefficients in range 0..65536 */
 | |
| 
 | |
|          /* Push a tRNS transform if required.  Because this is a push the
 | |
|           * transform the init needs to be run now.  This needs to go in
 | |
|           * before the check on r==g==b because a color key might be used.
 | |
|           */
 | |
|          if ((tc->format & PNG_FORMAT_FLAG_ALPHA) == 0 && !tc->palette &&
 | |
|              png_ptr->num_trans == 1 && !(tc->invalid_info & PNG_INFO_tRNS))
 | |
|          {
 | |
|             if (tc->expand_tRNS && !tc->strip_alpha)
 | |
|             {
 | |
|                png_transformp tr_expand = png_push_transform(png_ptr,
 | |
|                   sizeof (png_expand), png_init_expand, transform, NULL);
 | |
| 
 | |
|                debug(*transform == tr_expand);
 | |
|                tr_expand->args |= PNG_EXPAND_tRNS;
 | |
|                png_init_expand(transform, tc);
 | |
|                /* Check for the infinite loop possibility: */
 | |
|                affirm((tc->invalid_info & PNG_INFO_tRNS) != 0);
 | |
|                return;
 | |
|             }
 | |
| 
 | |
|             else
 | |
|                tc->invalid_info |= PNG_INFO_tRNS;
 | |
|          }
 | |
| 
 | |
|          {
 | |
|             png_fixed_point red, green;
 | |
| 
 | |
|             if (tr->coefficients_set)
 | |
|             {
 | |
|                red = tr->red_coefficient;
 | |
|                green = tr->green_coefficient;
 | |
|             }
 | |
| 
 | |
| #           ifdef PNG_COLORSPACE_SUPPORTED
 | |
|                else if ((png_ptr->colorspace.flags &
 | |
|                          (PNG_COLORSPACE_HAVE_ENDPOINTS+PNG_COLORSPACE_INVALID))
 | |
|                          == PNG_COLORSPACE_HAVE_ENDPOINTS)
 | |
|                {
 | |
|                   red = png_ptr->colorspace.end_points_XYZ.red_Y;
 | |
|                   green = png_ptr->colorspace.end_points_XYZ.green_Y;
 | |
|                }
 | |
| #           endif
 | |
| 
 | |
|             else /* no colorspace support, assume sRGB */
 | |
|             {
 | |
|                /* From IEC 61966-2-1:1999, the reverse transformation from sRGB
 | |
|                 * RGB values to XYZ D65 values (not CIEXYZ!).  These are not
 | |
|                 * exact inverses of the forward transformation; they only have
 | |
|                 * four (decimal) digits of precision.
 | |
|                 *
 | |
|                 * API CHANGE: in 1.7.0 the sRGB values from the official IEC
 | |
|                 * specification are used, previously libpng used values from
 | |
|                 * Charles Poynton's ColorFAQ of 1998-01-04.  The original page
 | |
|                 * is gone, however up to date information can be found below:
 | |
|                 *
 | |
|                 *    http://www.poynton.com/ColorFAQ.html
 | |
|                 *
 | |
|                 * At the time of reading (20150628) this web site quotes the
 | |
|                 * same values as below and cites ITU Rec 709 as the source.
 | |
|                 */
 | |
|                red = 21260;
 | |
|                green = 71520;
 | |
|             }
 | |
| 
 | |
|             /* Prior to 1.7 this calculation was done with 15-bit precision,
 | |
|              * this is because the code was written pre-muldiv and tried to
 | |
|              * work round the problems caused by the signs in integer
 | |
|              * calculations.
 | |
|              */
 | |
|             (void)png_muldiv(&r, red, 65536, PNG_FP_1);
 | |
|             (void)png_muldiv(&g, green, 65536, PNG_FP_1);
 | |
|          }
 | |
| 
 | |
|          /* If the convertion can be deduced to select a single channel do so.
 | |
|           * If the error action is set to error just copy the red channel, if
 | |
|           * the coefficients select just one channel use that.
 | |
|           */
 | |
|          if (tr->error_action == PNG_ERROR_ACTION_ERROR || r >= 65536)
 | |
|             index = 0U, sBIT_color = tc->sBIT_R; /* select red */
 | |
| 
 | |
|          else if (g >= 65536)
 | |
|             index = 1U, sBIT_color = tc->sBIT_G; /* select green */
 | |
| 
 | |
|          else if (r + g == 0)
 | |
|             index = 2U, sBIT_color = tc->sBIT_B; /* select blue */
 | |
| 
 | |
|          else
 | |
|             index = 3U, sBIT_color = 0U/*UNUSED*/;
 | |
| 
 | |
|          if (index == 3U)
 | |
|          {
 | |
|             /* Arithmetic will have to be done.  For this we need linear 16-bit
 | |
|              * data which must then be converted back to the required bit depth,
 | |
|              * png_init_gamma handles this.  It may push other expand operations
 | |
|              * (it shouldn't but it can), so give it some space.
 | |
|              *
 | |
|              * The gamma must be restored to the original value, 0U for the bit
 | |
|              * depth means use the output bit depth.
 | |
|              */
 | |
|             (void)add_gamma_transform(png_ptr, PNG_TR_GAMMA_ENCODE, tc->gamma,
 | |
|                0U/*bit depth*/, 0/*default*/);
 | |
| 
 | |
|             /* If png_init_gamma is called with tc->gamma 0 it does the right
 | |
|              * thing in PNG_TC_INIT_FINAL; it just does any required bit depth
 | |
|              * adjustment.
 | |
|              */
 | |
|             (void)add_gamma_transform(png_ptr, tr->tr.order + 0x10U, PNG_FP_1,
 | |
|                16U, 1/*force: doesn't matter*/);
 | |
| 
 | |
|             {
 | |
|                /* This init routine will update the sBIT information
 | |
|                 * appropriately.
 | |
|                 */
 | |
|                png_transformp tr_rtog = png_add_transform(png_ptr, 0/*size*/,
 | |
|                   png_init_rgb_to_gray_arithmetic, tr->tr.order + 0x20U);
 | |
| 
 | |
|                /* r and g are known to be in the range 0..65535, so pack them
 | |
|                 * into the 'args' argument of a new transform.
 | |
|                 */
 | |
|                tr_rtog->args = (((png_uint_32)r) << 16) + g;
 | |
|             }
 | |
|          }
 | |
| 
 | |
|          else /* index < 3 */
 | |
|          {
 | |
|             /* TODO: does this need to select the correct sBIT value too? */
 | |
|             png_add_rgb_to_gray_byte_ops(png_ptr, tc, index,
 | |
|                tr->tr.order + 0x10U);
 | |
|             tc->sBIT_G = sBIT_color;
 | |
|          }
 | |
| 
 | |
|          /* Prior to 1.7 libpng would always check for r!=g!=b.  In 1.7 an extra
 | |
|           * error_action setting is added to prevent this overhead.
 | |
|           */
 | |
|          if (tr->error_action)
 | |
|             tr->tr.fn = tc->bit_depth == 8 ?
 | |
|                ((tc->format & PNG_FORMAT_FLAG_ALPHA) ?
 | |
|                 png_do_rgb_check32 : png_do_rgb_check24) :
 | |
|                ((tc->format & PNG_FORMAT_FLAG_ALPHA) ?
 | |
|                 png_do_rgb_check64 : png_do_rgb_check48);
 | |
| 
 | |
|          else
 | |
|             tr->tr.fn = NULL; /* PNG_ERROR_ACTION_NO_CHECK */
 | |
|       }
 | |
|    }
 | |
| 
 | |
|    else /* not color: transform not applicable */
 | |
|       (*transform)->fn = NULL;
 | |
| }
 | |
| 
 | |
| void PNGFAPI
 | |
| png_set_rgb_to_gray_fixed(png_structrp png_ptr, int error_action,
 | |
|     png_fixed_point red, png_fixed_point green)
 | |
|    /* API CHANGE: in 1.7 calling this on a palette PNG no longer causes the
 | |
|     * palette to be expanded (unless explicitly requested), rather it converts
 | |
|     * the palette to grayscale.
 | |
|     */
 | |
| {
 | |
|    /* The coefficients must be reasonable, the error handling is to warn (pre
 | |
|     * 1.7) or app error (1.7) and drop back to the cHRM definition of Y.  The
 | |
|     * drop back is done in the init routine if relevant flag is unset.  Passing
 | |
|     * negative values causes this default to be used without a warning.
 | |
|     */
 | |
|    int pset = 0;
 | |
| 
 | |
|    if (red >= 0 && green >= 0)
 | |
|    {
 | |
|       if (red <= PNG_FP_1 && green <= PNG_FP_1 && red + green <= PNG_FP_1)
 | |
|          pset = 1;
 | |
| 
 | |
|       else /* overflow */
 | |
|          png_app_error(png_ptr, "rgb_to_gray coefficients too large (ignored)");
 | |
|    }
 | |
| 
 | |
|    {
 | |
|       png_transform_rgb_to_gray *tr =
 | |
|          png_transform_cast(png_transform_rgb_to_gray,
 | |
|             png_add_transform(png_ptr, sizeof (png_transform_rgb_to_gray),
 | |
|                png_init_rgb_to_gray, PNG_TR_RGB_TO_GRAY));
 | |
| 
 | |
|       tr->error_action = 0x3U & error_action;
 | |
| 
 | |
|       if (red < 0 || green < 0) /* use cHRM default */
 | |
|          tr->coefficients_set = 0U;
 | |
| 
 | |
|       else if (pset) /* else bad coefficients which get ignored */
 | |
|       {
 | |
|          tr->coefficients_set = 1U;
 | |
|          tr->red_coefficient = red;
 | |
|          tr->green_coefficient = green;
 | |
|       }
 | |
|    }
 | |
| }
 | |
| 
 | |
| #ifdef PNG_FLOATING_POINT_SUPPORTED
 | |
| /* Convert a RGB image to a grayscale of the same width.  This allows us,
 | |
|  * for example, to convert a 24 bpp RGB image into an 8 bpp grayscale image.
 | |
|  */
 | |
| 
 | |
| void PNGAPI
 | |
| png_set_rgb_to_gray(png_structrp png_ptr, int error_action, double red,
 | |
|    double green)
 | |
| {
 | |
|    png_set_rgb_to_gray_fixed(png_ptr, error_action,
 | |
|       png_fixed(png_ptr, red, "rgb to gray red coefficient"),
 | |
|       png_fixed(png_ptr, green, "rgb to gray green coefficient"));
 | |
| }
 | |
| #endif /* FLOATING POINT */
 | |
| #endif /* RGB_TO_GRAY */
 | |
| 
 | |
| #ifdef PNG_READ_BACKGROUND_SUPPORTED
 | |
| typedef struct
 | |
| {
 | |
|    png_transform     tr;
 | |
|    struct
 | |
|    {
 | |
|       png_color_16      background;
 | |
|       unsigned int      need_expand :1; /* Background matches format of PNG */
 | |
|       unsigned int      rgb_to_gray :1; /* RGB-to-gray transform found */
 | |
|       unsigned int      compose_background   :1; /* png_set_background */
 | |
|       unsigned int      associate_alpha      :1;
 | |
|       unsigned int      encode_alpha         :1;
 | |
|       unsigned int      optimize_alpha       :1;
 | |
|       unsigned int      background_is_gray   :1; /* Background color is gray */
 | |
|       unsigned int      background_bit_depth :5; /* bit depth, 1..16 */
 | |
|       unsigned int      ntrans               :3; /* 1..6 bytes */
 | |
|       png_byte          transparent_pixel[6];
 | |
|       png_byte          background_pixel[6];
 | |
|       png_fixed_point   background_gamma;
 | |
|    }  st; /* to allow the whole state to be copied reliably */
 | |
| }  png_transform_background;
 | |
| 
 | |
| static void
 | |
| resolve_background_color(png_transform_background *tr,
 | |
|    png_transform_controlp tc)
 | |
| {
 | |
|    png_const_structp png_ptr = tc->png_ptr;
 | |
| 
 | |
|    /* Deduce the bit depth and color information for the background, the
 | |
|     * special case is when need_expand is set and the PNG has palette format,
 | |
|     * then (and only then) the background value is a palette index.
 | |
|     */
 | |
|    if (tr->st.need_expand && tc->palette)
 | |
|    {
 | |
|       unsigned int i = tr->st.background.index;
 | |
|       png_byte r, g, b;
 | |
| 
 | |
|       if (i >= png_ptr->num_palette)
 | |
|       {
 | |
|          png_app_error(png_ptr, "background index out of range");
 | |
|          tr->tr.fn = NULL;
 | |
|          return;
 | |
|       }
 | |
| 
 | |
|       tr->st.background_bit_depth = 8U;
 | |
|       r = png_ptr->palette[i].red;
 | |
|       g = png_ptr->palette[i].green;
 | |
|       b = png_ptr->palette[i].blue;
 | |
| 
 | |
|       if (r == g && g == b)
 | |
|       {
 | |
|          tr->st.background_is_gray = 1U;
 | |
|          tr->st.background.gray = g;
 | |
|          UNTESTED
 | |
|       }
 | |
| 
 | |
|       else
 | |
|       {
 | |
|          tr->st.background_is_gray = 0U;
 | |
|          tr->st.background.red = r;
 | |
|          tr->st.background.green = g;
 | |
|          tr->st.background.blue = b;
 | |
|          UNTESTED
 | |
|       }
 | |
|    }
 | |
| 
 | |
|    else /* background is not a palette index */
 | |
|    {
 | |
|       int use_rgb;
 | |
|       png_uint_16 mask;
 | |
| 
 | |
|       /* First work out the bit depth and whether or not to use the RGB
 | |
|        * fields of the background.
 | |
|        */
 | |
|       if (tr->st.need_expand)
 | |
|       {
 | |
|          affirm(!(tc->format & PNG_FORMAT_FLAG_COLORMAP));
 | |
|          tr->st.background_bit_depth =
 | |
|             png_check_bits(png_ptr, png_ptr->bit_depth, 5U);
 | |
|          use_rgb = (png_ptr->color_type & PNG_COLOR_MASK_COLOR) != 0;
 | |
|       }
 | |
| 
 | |
|       else /* screen format background */
 | |
|       {
 | |
|          /* If the final output is in palette format assume the background
 | |
|           * is in a matching format.  This covers two cases, an original
 | |
|           * COLORMAP PNG  and png_set_quantize.
 | |
|           */
 | |
|          if ((png_ptr->row_format & PNG_FORMAT_FLAG_COLORMAP) != 0)
 | |
|             tr->st.background_bit_depth = 8U;
 | |
| 
 | |
|          else
 | |
|             tr->st.background_bit_depth =
 | |
|                png_check_bits(png_ptr, png_ptr->row_bit_depth, 5U);
 | |
| 
 | |
|          use_rgb = (png_ptr->row_format & PNG_FORMAT_FLAG_COLOR) != 0;
 | |
|       }
 | |
| 
 | |
|       /* The PNG spec says to use the low bits of the values, so we mask out
 | |
|        * the high bits here (at present no warning is produced if they are
 | |
|        * set.)
 | |
|        */
 | |
|       mask = png_check_u16(png_ptr, (1U << tr->st.background_bit_depth)-1U);
 | |
| 
 | |
|       if (use_rgb)
 | |
|       {
 | |
|          png_uint_16 r, g, b;
 | |
| 
 | |
|          r = tr->st.background.red & mask;
 | |
|          g = tr->st.background.green & mask;
 | |
|          b = tr->st.background.blue & mask;
 | |
| 
 | |
|          if (r == g && g == b)
 | |
|          {
 | |
|             tr->st.background_is_gray = 1U;
 | |
|             tr->st.background.gray = g;
 | |
|          }
 | |
| 
 | |
|          else
 | |
|          {
 | |
|             tr->st.background_is_gray = 0U;
 | |
|             tr->st.background.red = r;
 | |
|             tr->st.background.green = g;
 | |
|             tr->st.background.blue = b;
 | |
|          }
 | |
|       }
 | |
| 
 | |
|       else /* gray */
 | |
|       {
 | |
|          tr->st.background_is_gray = 1U;
 | |
|          tr->st.background.gray = tr->st.background.gray & mask;
 | |
|       }
 | |
|    }
 | |
| }
 | |
| 
 | |
| static void
 | |
| gamma_correct_background_component(png_const_structrp png_ptr, png_uint_16p cp,
 | |
|    unsigned int bdc, png_fixed_point correction, unsigned int bdout)
 | |
|    /* Utility function for gamma_correct_background. */
 | |
| {
 | |
|    unsigned int c = *cp;
 | |
| 
 | |
|    /* 0.0 and 1.0 are unchanged (and common): */
 | |
|    if (c > 0U && c < (1U<<bdc)-1U)
 | |
|    {
 | |
|       if (correction != 0)
 | |
|          c = png_check_bits(png_ptr,
 | |
|             png_gamma_nxmbit_correct(c, correction, bdc, bdout), bdout);
 | |
| 
 | |
|       else if (bdc != bdout)
 | |
|       {
 | |
|          /* Scale the value from bdc to bdout bits. */
 | |
|          png_int_32 i;
 | |
|          affirm(png_muldiv(&i, c, (1U<<bdout)-1U, (1U<<bdc)-1U));
 | |
|          c = png_check_bits(png_ptr, i, bdout);
 | |
|       }
 | |
|    }
 | |
| 
 | |
|    else if (c != 0U)
 | |
|       c = (1U << bdout) - 1U;
 | |
| 
 | |
|    *cp = PNG_UINT_16(c);
 | |
|    PNG_UNUSED(png_ptr) /* if checking disabled */
 | |
| }
 | |
| 
 | |
| static void
 | |
| gamma_correct_background(png_transform_background *tr,
 | |
|    png_const_transform_controlp tc)
 | |
| {
 | |
| #  define png_ptr (tc->png_ptr)
 | |
|    png_fixed_point correction = tc->gamma;
 | |
|    const unsigned int bdback = tr->st.background_bit_depth;
 | |
|    const unsigned int bdrow = tc->bit_depth;
 | |
| 
 | |
|    /* This is harmless if it fails but it will damage the output pixels - they
 | |
|     * won't have the requested color depth accuracy where the background is
 | |
|     * used.
 | |
|     */
 | |
|    debug(bdback <= bdrow);
 | |
|    debug(tr->st.background_is_gray || (bdrow >= 8U && bdback >= 8U));
 | |
| 
 | |
|    /* The background is assumed to be full precision; there is no sBIT
 | |
|     * information for it.  The convertion converts from the current depth and
 | |
|     * gamma of the background to that in the transform control.  It uses the
 | |
|     * full 16-bit precision when considering the gamma values even though this
 | |
|     * is probably spurious.
 | |
|     */
 | |
|    if (correction != 0 && (tr->st.background_gamma == 0 ||
 | |
|        png_gamma_equal(png_ptr, tr->st.background_gamma, correction,
 | |
|           &correction, 16U)))
 | |
|       correction = 0; /* no correction! */
 | |
| 
 | |
|    if (tr->st.background_is_gray)
 | |
|       gamma_correct_background_component(png_ptr, &tr->st.background.gray,
 | |
|             bdback, correction, bdrow);
 | |
| 
 | |
|    else
 | |
|    {
 | |
|       gamma_correct_background_component(png_ptr, &tr->st.background.red,
 | |
|             bdback, correction, bdrow);
 | |
|       gamma_correct_background_component(png_ptr, &tr->st.background.green,
 | |
|             bdback, correction, bdrow);
 | |
|       gamma_correct_background_component(png_ptr, &tr->st.background.blue,
 | |
|             bdback, correction, bdrow);
 | |
|    }
 | |
| 
 | |
|    /* Regardless of whether there was a correction set the background gamma: */
 | |
|    tr->st.background_gamma = tc->gamma;
 | |
|    tr->st.background_bit_depth = png_check_bits(png_ptr, bdrow, 5U);
 | |
| #  undef png_ptr
 | |
| }
 | |
| 
 | |
| static void
 | |
| fill_background_pixel(png_transform_background *tr, png_transform_controlp tc)
 | |
| {
 | |
| #  define png_ptr (tc->png_ptr)
 | |
|    /* Fill in 'background_pixel' if the appropriate sequence of bytes for the
 | |
|     * format given in the transform control.
 | |
|     */
 | |
|    unsigned int bdtc = tc->bit_depth;
 | |
| 
 | |
|    /* If necessary adjust the background pixel to the current row format (it is
 | |
|     * important to do this as late as possible to avoid spurious
 | |
|     * interconvertions).
 | |
|     */
 | |
|    gamma_correct_background(tr, tc);
 | |
| 
 | |
|    if (tr->st.background_is_gray)
 | |
|    {
 | |
|       unsigned int g = tr->st.background.gray;
 | |
| 
 | |
|       /* 'g' now has enough bits for the destination, note that in the case of
 | |
|        * low bit depth gray this causes the pixel to be replicated through the
 | |
|        * written byte.  Fill all six bytes with the replicated background:
 | |
|        */
 | |
|       while (bdtc < 8U)
 | |
|       {
 | |
|          g &= (1U << bdtc) - 1U; /* use only the low bits */
 | |
|          g |= g << bdtc;
 | |
|          bdtc <<= 1;
 | |
|       }
 | |
| 
 | |
|       memset(tr->st.background_pixel, PNG_BYTE(g), 6U);
 | |
|       if (bdtc == 16U)
 | |
|          tr->st.background_pixel[0] = tr->st.background_pixel[2] =
 | |
|             tr->st.background_pixel[4] = PNG_BYTE(g >> 8);
 | |
|       /* Must not include the alpha channel here: */
 | |
|       tr->st.ntrans = png_check_bits(png_ptr,
 | |
|          ((tc->format & PNG_FORMAT_FLAG_COLOR)+1U) << (bdtc == 16U), 3U);
 | |
|    }
 | |
| 
 | |
|    else
 | |
|    {
 | |
|       unsigned int r = tr->st.background.red;
 | |
|       unsigned int g = tr->st.background.green;
 | |
|       unsigned int b = tr->st.background.blue;
 | |
| 
 | |
|       debug((tc->format & PNG_FORMAT_FLAG_COLOR) != 0);
 | |
| 
 | |
|       switch (bdtc)
 | |
|       {
 | |
|          case 8U:
 | |
|             tr->st.background_pixel[0] = PNG_BYTE(r);
 | |
|             tr->st.background_pixel[1] = PNG_BYTE(g);
 | |
|             tr->st.background_pixel[2] = PNG_BYTE(b);
 | |
|             tr->st.ntrans = 3U;
 | |
|             break;
 | |
| 
 | |
|          case 16U:
 | |
|             tr->st.background_pixel[0] = PNG_BYTE(r>>8);
 | |
|             tr->st.background_pixel[1] = PNG_BYTE(r);
 | |
|             tr->st.background_pixel[2] = PNG_BYTE(g>>8);
 | |
|             tr->st.background_pixel[3] = PNG_BYTE(g);
 | |
|             tr->st.background_pixel[4] = PNG_BYTE(b>>8);
 | |
|             tr->st.background_pixel[5] = PNG_BYTE(b);
 | |
|             tr->st.ntrans = 6U;
 | |
|             break;
 | |
| 
 | |
|          default:
 | |
|             NOT_REACHED;
 | |
|       }
 | |
|    }
 | |
| #  undef png_ptr
 | |
| }
 | |
| 
 | |
| /* Look for colors matching the trans_color in png_ptr and replace them.  This
 | |
|  * must handle all the non-alpha formats.
 | |
|  */
 | |
| static void
 | |
| png_do_replace_tRNS_multi(png_transformp *transform, png_transform_controlp tc)
 | |
| {
 | |
| #  define png_ptr (tc->png_ptr)
 | |
|    png_transform_background *tr =
 | |
|       png_transform_cast(png_transform_background, *transform);
 | |
|    png_bytep dp = png_voidcast(png_bytep, tc->dp);
 | |
|    const unsigned int cbytes = tr->st.ntrans;
 | |
|    png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp);
 | |
|    const png_const_bytep ep = sp + PNG_TC_ROWBYTES(*tc) - cbytes/*safety*/;
 | |
|    const int copy = dp != sp;
 | |
| 
 | |
|    /* We expect opaque and transparent pixels to be interleaved but with long
 | |
|     * sequences of each.
 | |
|     */
 | |
|    debug(!(tc->format & PNG_FORMAT_FLAG_ALPHA) &&
 | |
|          PNG_TC_PIXEL_DEPTH(*tc) == cbytes << 3);
 | |
|    tc->invalid_info |= PNG_INFO_tRNS;
 | |
|    tc->sp = dp;
 | |
| 
 | |
|    /* Look for pixels that match the transparent value, copying opaque ones as
 | |
|     * required.
 | |
|     */
 | |
|    do
 | |
|    {
 | |
|       const png_const_bytep opaque_start = sp;
 | |
|       size_t cb;
 | |
| 
 | |
|       /* Find a transparent pixel, or the end: */
 | |
|       do
 | |
|       {
 | |
|          if (memcmp(sp, tr->st.transparent_pixel, cbytes) == 0) /*transparent*/
 | |
|             break;
 | |
|          sp += cbytes;
 | |
|       }
 | |
|       while (sp <= ep);
 | |
| 
 | |
|       cb = sp - opaque_start;
 | |
| 
 | |
|       /* Copy any opaque pixels: */
 | |
|       if (cb > 0)
 | |
|       {
 | |
|          if (copy)
 | |
|             memcpy(dp, opaque_start, cb);
 | |
|          dp += cb;
 | |
|       }
 | |
| 
 | |
|       /* Set transparent pixels to the background (this has to be done one-by
 | |
|        * one; the case where all the bytes in the background are equal is not
 | |
|        * optimized.)
 | |
|        */
 | |
|       if (sp <= ep) do
 | |
|       {
 | |
|          memcpy(dp, tr->st.background_pixel, cbytes);
 | |
|          sp += cbytes;
 | |
|          dp += cbytes;
 | |
|       }
 | |
|       while (sp <= ep && memcmp(sp, tr->st.transparent_pixel, cbytes) == 0);
 | |
|    } while (sp <= ep);
 | |
| 
 | |
|    debug(sp == ep+cbytes);
 | |
| #  undef png_ptr
 | |
| }
 | |
| 
 | |
| static void
 | |
| png_do_replace_tRNS_8(png_transformp *transform, png_transform_controlp tc)
 | |
|    /* The single byte version: 8-bit gray */
 | |
| {
 | |
| #  define png_ptr (tc->png_ptr)
 | |
|    png_transform_background *tr =
 | |
|       png_transform_cast(png_transform_background, *transform);
 | |
|    png_bytep dp = png_voidcast(png_bytep, tc->dp);
 | |
|    png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp);
 | |
|    png_alloc_size_t row_bytes = tc->width;
 | |
|    const int copy = dp != sp;
 | |
|    const int transparent_pixel = tr->st.transparent_pixel[0];
 | |
|    const int background_pixel = tr->st.background_pixel[0];
 | |
| 
 | |
|    /* We expect opaque and transparent pixels to be interleaved but with long
 | |
|     * sequences of each.
 | |
|     */
 | |
|    debug(!(tc->format & PNG_FORMAT_FLAG_ALPHA) &&
 | |
|          PNG_TC_PIXEL_DEPTH(*tc) == 8 && tr->st.ntrans == 1);
 | |
|    tc->invalid_info |= PNG_INFO_tRNS;
 | |
|    tc->sp = dp;
 | |
| 
 | |
|    /* Now search for a byte that matches the transparent pixel. */
 | |
|    do
 | |
|    {
 | |
|       const png_const_bytep tp = png_voidcast(png_const_bytep,
 | |
|          memchr(sp, transparent_pixel, row_bytes));
 | |
|       png_alloc_size_t cb;
 | |
| 
 | |
|       if (tp == NULL) /* all remaining pixels are opaque */
 | |
|       {
 | |
|          if (copy)
 | |
|             memcpy(dp, sp, row_bytes);
 | |
|          return;
 | |
|       }
 | |
| 
 | |
|       cb = tp - sp;
 | |
|       if (cb > 0) /* some opaque pixels found */
 | |
|       {
 | |
|          if (copy)
 | |
|             memcpy(dp, sp, cb);
 | |
|          sp = tp;
 | |
|          dp += cb;
 | |
|          debug(row_bytes > cb);
 | |
|          row_bytes -= cb;
 | |
|       }
 | |
| 
 | |
|       /* Now count the transparent pixels, this could use strspn but for the
 | |
|        * moment does not.
 | |
|        */
 | |
|       debug(row_bytes > 0);
 | |
|       ++sp; /* next to check, may be beyond the last */
 | |
|       while (--row_bytes > 0 && *sp == transparent_pixel) ++sp;
 | |
| 
 | |
|       cb = sp - tp;
 | |
|       memset(dp, background_pixel, cb);
 | |
|       dp += cb;
 | |
|    } while (row_bytes > 0);
 | |
|    UNTESTED
 | |
| #  undef png_ptr
 | |
| }
 | |
| 
 | |
| static void
 | |
| png_do_set_row(png_transformp *transform, png_transform_controlp tc)
 | |
|    /* This is a no-op transform that both invalidates INFO from args and sets
 | |
|     * the entire row to the byte given in the top bits.
 | |
|     */
 | |
| {
 | |
|    png_bytep dp = png_voidcast(png_bytep, tc->dp);
 | |
| 
 | |
|    tc->sp = dp;
 | |
|    memset(dp, (*transform)->args >> 24, PNG_TC_ROWBYTES(*tc));
 | |
| }
 | |
| 
 | |
| static void
 | |
| png_do_replace_tRNS_lbd(png_transformp *transform, png_transform_controlp tc)
 | |
| {
 | |
|    /* This is the 2 or 4 bit depth grayscale case; the 1 bit case is handled by
 | |
|     * the two routines above and the 8-bit and 16-bit cases by the two before
 | |
|     * that.
 | |
|     *
 | |
|     * The transform contains pixel values that have been expanded to one byte,
 | |
|     * the code needs to match the tRNS pixel and substitute the background one
 | |
|     * in each byte.
 | |
|     */
 | |
| #  define png_ptr (tc->png_ptr)
 | |
|    png_transform_background *tr =
 | |
|       png_transform_cast(png_transform_background, *transform);
 | |
|    png_bytep dp = png_voidcast(png_bytep, tc->dp);
 | |
|    png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp);
 | |
|    png_const_bytep ep = sp + PNG_TC_ROWBYTES(*tc);
 | |
|    const unsigned int copy = sp != dp;
 | |
|    const png_byte transparent_pixel = tr->st.transparent_pixel[0];
 | |
|    const png_byte background_pixel = tr->st.background_pixel[0];
 | |
| 
 | |
|    /* We expect opaque and transparent pixels to be interleaved but with long
 | |
|     * sequences of each.
 | |
|     */
 | |
|    debug(!(tc->format & PNG_FORMAT_FLAG_ALPHA) &&
 | |
|          PNG_TC_PIXEL_DEPTH(*tc) < 8 && tr->st.ntrans == 1);
 | |
|    tc->sp = dp;
 | |
| 
 | |
|    /* Now search for a byte that contains the transparent pixel
 | |
|     *
 | |
|     * NOTE: this is the "strlen" algorithm, I first saw a variant implemented in
 | |
|     * Acorn RISC iX (strlen) around 1991, almost certainly derived from a
 | |
|     * suggestion by Alan Mycroft dating from April 27, 1987 (Mycroft was one of
 | |
|     * the authors of the 'Norcroft' compiler used for RISC iX, and well known to
 | |
|     * the RISC iX implementors.) See, e.g.:
 | |
|     *
 | |
|     *    http://bits.stephan-brumme.com/null.html.
 | |
|     *
 | |
|     * The exact form used here is the one reported by Brumme; I haven't been
 | |
|     * able to find the original Mycroft posting, it was probably on comp.arch.
 | |
|     *
 | |
|     * The 4-bit and 2-bit versions (probably slower in the 4-bit case than the
 | |
|     * do-it-by-pixel version, but definately faster once 32-bit handling is
 | |
|     * implemented):
 | |
|     *
 | |
|     *    4 bit: (byte - 0x11) & ~byte & 0x88
 | |
|     *    2 bit: (byte - 0x55) & ~byte & 0xcc
 | |
|     *
 | |
|     * The generalizations to 32 bits (8 and 16 pixels per step) should be
 | |
|     * obvious.
 | |
|     *
 | |
|     * This algorithm reads pixels within a byte beyond the end of the row and,
 | |
|     * potentially, changes the non-existent pixels.  This is harmless and not
 | |
|     * a security risk.
 | |
|     */
 | |
|    if (tc->bit_depth == 4U)
 | |
|    {
 | |
|       /* For the moment the algorithm isn't used; there are only two pixels in
 | |
|        * each byte so it is likely to be quicker to check as below:
 | |
|        */
 | |
|       do
 | |
|       {
 | |
|          const png_byte b = *sp++;
 | |
|          const unsigned int m = b ^ transparent_pixel;
 | |
| 
 | |
|          if (m == 0U) /* both transparent */
 | |
|             *dp = background_pixel;
 | |
| 
 | |
|          else if ((m & 0xF0U) == 0U) /* first transparent */
 | |
|             *dp = PNG_BYTE((background_pixel & 0xF0U) | (b & 0x0FU));
 | |
| 
 | |
|          else if ((m & 0x0FU) == 0U) /* second transparent */
 | |
|             *dp = PNG_BYTE((background_pixel & 0x0FU) | (b & 0xF0U));
 | |
| 
 | |
|          else if (copy) /* neither transparent */
 | |
|             *dp = b;
 | |
| 
 | |
|          ++dp;
 | |
|       } while (sp < ep);
 | |
|    }
 | |
| 
 | |
|    else
 | |
|    {
 | |
|       affirm(tc->bit_depth == 2U);
 | |
| 
 | |
|       do
 | |
|       {
 | |
|          const png_byte b = *sp++;
 | |
|          const unsigned int m = b ^ transparent_pixel;
 | |
| 
 | |
|          if (m == 0U) /* transparent */
 | |
|             *dp = background_pixel;
 | |
| 
 | |
|          else if (0xAAU & ((m - 0x55U) & ~m))
 | |
|          {
 | |
|             /* One or more pixels transparent */
 | |
|             const unsigned int mask =
 | |
|                (m & 0xC0U ? 0xC0U : 0U) |
 | |
|                (m & 0x30U ? 0x30U : 0U) |
 | |
|                (m & 0x0CU ? 0x0CU : 0U) |
 | |
|                (m & 0x03U ? 0x03U : 0U);
 | |
| 
 | |
|             *dp = PNG_BYTE((b & mask) | (background_pixel & ~mask));
 | |
|          }
 | |
| 
 | |
|          else if (copy) /* no transparent pixels */
 | |
|             *dp = b;
 | |
| 
 | |
|          ++dp;
 | |
|       } while (sp < ep);
 | |
|    }
 | |
| 
 | |
| #  undef png_ptr
 | |
| }
 | |
| 
 | |
| static void
 | |
| png_do_background_with_transparent_GA8(png_transformp *transform,
 | |
|    png_transform_controlp tc)
 | |
| {
 | |
| #  define png_ptr (tc->png_ptr)
 | |
|    png_transform_background *tr =
 | |
|       png_transform_cast(png_transform_background, *transform);
 | |
|    png_bytep dp = png_voidcast(png_bytep, tc->dp);
 | |
|    png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp);
 | |
|    const png_const_bytep ep = sp + PNG_TC_ROWBYTES(*tc) - 1U/*safety*/;
 | |
|    const png_byte background_pixel = tr->st.background_pixel[0];
 | |
| 
 | |
|    /* Because this is an alpha format and we are removing the alpha channel we
 | |
|     * can copy up.
 | |
|     */
 | |
|    debug(tc->bit_depth == 8U && tc->format == PNG_FORMAT_GA &&
 | |
|          tr->st.ntrans == 1U);
 | |
|    tc->format &= PNG_BIC_MASK(PNG_FORMAT_FLAG_ALPHA);
 | |
|    tc->sp = dp;
 | |
| 
 | |
|    /* Look for pixels that have alpha 0; all others should have alpha 1.0,
 | |
|     * however they are simply treated as opaque regardless.
 | |
|     */
 | |
|    do
 | |
|    {
 | |
|       *dp++ = (sp[1] == 0U) ? background_pixel : sp[0];
 | |
|       sp += 2U;
 | |
|    } while (sp < ep);
 | |
| 
 | |
|    debug(sp == ep+1U);
 | |
| #  undef png_ptr
 | |
| }
 | |
| 
 | |
| static void
 | |
| png_do_background_with_transparent_GA16(png_transformp *transform,
 | |
|    png_transform_controlp tc)
 | |
| {
 | |
| #  define png_ptr (tc->png_ptr)
 | |
|    png_transform_background *tr =
 | |
|       png_transform_cast(png_transform_background, *transform);
 | |
|    png_bytep dp = png_voidcast(png_bytep, tc->dp);
 | |
|    png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp);
 | |
|    const png_const_bytep ep = sp + PNG_TC_ROWBYTES(*tc) - 3U/*safety*/;
 | |
| 
 | |
|    debug(tc->bit_depth == 16U && tc->format == PNG_FORMAT_GA &&
 | |
|          tr->st.ntrans == 2U);
 | |
|    tc->format &= PNG_BIC_MASK(PNG_FORMAT_FLAG_ALPHA);
 | |
|    tc->sp = dp;
 | |
| 
 | |
|    do
 | |
|    {
 | |
|       if (sp[2] == 0U && sp[3] == 0U) /* transparent */
 | |
|          dp[0] = tr->st.background_pixel[0], dp[1] = tr->st.background_pixel[1];
 | |
| 
 | |
|       else
 | |
|          dp[0] = sp[0], dp[1] = sp[1];
 | |
| 
 | |
|       dp += 2U;
 | |
|       sp += 4U;
 | |
|    } while (sp < ep);
 | |
| 
 | |
|    debug(sp == ep+3U);
 | |
| #  undef png_ptr
 | |
| }
 | |
| 
 | |
| static void
 | |
| png_do_background_with_transparent_GAlbd(png_transformp *transform,
 | |
|    png_transform_controlp tc)
 | |
|    /* This is the low-bit-depth gray case, the input is 1, 2 or 4-bit per
 | |
|     * channel gray-alpha.
 | |
|     */
 | |
| {
 | |
| #  define png_ptr (tc->png_ptr)
 | |
|    png_transform_background *tr =
 | |
|       png_transform_cast(png_transform_background, *transform);
 | |
|    png_bytep dp = png_voidcast(png_bytep, tc->dp);
 | |
|    png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp);
 | |
|    const png_const_bytep ep = sp + PNG_TC_ROWBYTES(*tc);
 | |
|    const unsigned int bit_depth = tc->bit_depth;
 | |
|    const unsigned int mask = (1U << bit_depth) - 1U;
 | |
|    const unsigned int back = tr->st.background_pixel[0] & mask;
 | |
|    unsigned int opos, ob, inb;
 | |
| 
 | |
|    debug(bit_depth < 8U && tc->format == PNG_FORMAT_GA && tr->st.ntrans == 1U);
 | |
|    tc->format &= PNG_BIC_MASK(PNG_FORMAT_FLAG_ALPHA);
 | |
|    tc->sp = dp;
 | |
| 
 | |
|    ob = 0U;   /* output byte */
 | |
|    opos = 0U; /* bit index of previous output pixel (counts down) */
 | |
|    inb = 0U;  /* quiet a GCC 4.8.5 warning */
 | |
| 
 | |
|    for (;;)
 | |
|    {
 | |
|       /* The output is half the size of the input, so we need a new input byte
 | |
|        * for every 4 bits of output:
 | |
|        */
 | |
|       if (opos == 0U || opos == 4U)
 | |
|       {
 | |
|          if (sp >= ep)
 | |
|             break;
 | |
| 
 | |
|          inb = *sp++;
 | |
|       }
 | |
| 
 | |
|       /* Move to the next *output* pixel, this wraps when bits is 0U: */
 | |
|       opos = (opos - bit_depth) & 0x7U;
 | |
| 
 | |
|       /* Extract the whole input pixel to the low bits of a temporary: */
 | |
|       {
 | |
|          unsigned int pixel = inb >> ((opos*2U) & 0x7U);
 | |
| 
 | |
|          /* The alpha channel is second, check for a value of 0: */
 | |
|          if ((pixel & mask)/* A component*/ == 0U)
 | |
|             pixel = back;
 | |
| 
 | |
|          else
 | |
|          {
 | |
|             debug((pixel & mask) == mask);
 | |
|             pixel = (pixel >> bit_depth) & mask; /* G component */
 | |
|          }
 | |
| 
 | |
|          ob |= pixel << opos;
 | |
|       }
 | |
| 
 | |
|       if (opos == 0U)
 | |
|          *dp++ = PNG_BYTE(ob), ob = 0U;
 | |
|    }
 | |
| 
 | |
|    if (opos != 0U)
 | |
|       *dp++ = PNG_BYTE(ob);
 | |
| 
 | |
|    debug(sp == ep);
 | |
| #  undef png_ptr
 | |
| }
 | |
| 
 | |
| static void
 | |
| png_do_background_with_transparent_RGBA8(png_transformp *transform,
 | |
|    png_transform_controlp tc)
 | |
| {
 | |
| #  define png_ptr (tc->png_ptr)
 | |
|    png_transform_background *tr =
 | |
|       png_transform_cast(png_transform_background, *transform);
 | |
|    png_bytep dp = png_voidcast(png_bytep, tc->dp);
 | |
|    png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp);
 | |
|    const png_const_bytep ep = sp + PNG_TC_ROWBYTES(*tc) - 3U/*safety*/;
 | |
| 
 | |
|    debug(tc->bit_depth == 8U && tc->format == PNG_FORMAT_RGBA &&
 | |
|          tr->st.ntrans == 3U);
 | |
|    tc->format &= PNG_BIC_MASK(PNG_FORMAT_FLAG_ALPHA);
 | |
|    tc->sp = dp;
 | |
| 
 | |
|    do
 | |
|    {
 | |
|       if (sp[3] == 0U) /* transparent */
 | |
|          memcpy(dp, tr->st.background_pixel, 3U);
 | |
| 
 | |
|       else
 | |
|          memmove(dp, sp, 3U);
 | |
| 
 | |
|       dp += 3U;
 | |
|       sp += 4U;
 | |
|    } while (sp < ep);
 | |
| 
 | |
|    debug(sp == ep+3U);
 | |
| #  undef png_ptr
 | |
| }
 | |
| 
 | |
| static void
 | |
| png_do_background_with_transparent_RGBA16(png_transformp *transform,
 | |
|    png_transform_controlp tc)
 | |
| {
 | |
| #  define png_ptr (tc->png_ptr)
 | |
|    png_transform_background *tr =
 | |
|       png_transform_cast(png_transform_background, *transform);
 | |
|    png_bytep dp = png_voidcast(png_bytep, tc->dp);
 | |
|    png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp);
 | |
|    const png_const_bytep ep = sp + PNG_TC_ROWBYTES(*tc) - 7U/*safety*/;
 | |
| 
 | |
|    debug(tc->bit_depth == 16U && tc->format == PNG_FORMAT_RGBA &&
 | |
|          tr->st.ntrans == 6U);
 | |
|    tc->format &= PNG_BIC_MASK(PNG_FORMAT_FLAG_ALPHA);
 | |
|    tc->sp = dp;
 | |
| 
 | |
|    do
 | |
|    {
 | |
|       if (sp[6] == 0U && sp[7] == 0U) /* transparent */
 | |
|          memcpy(dp, tr->st.background_pixel, 6U);
 | |
| 
 | |
|       else
 | |
|          memmove(dp, sp, 6U);
 | |
| 
 | |
|       dp += 6U;
 | |
|       sp += 8U;
 | |
|    } while (sp < ep);
 | |
| 
 | |
|    debug(sp == ep+7U);
 | |
| #  undef png_ptr
 | |
| }
 | |
| 
 | |
| static void
 | |
| png_init_background_transparent(png_transformp *transform,
 | |
|    png_transform_controlp tc)
 | |
|    /* Select the correct version of the above routines. */
 | |
| {
 | |
| #  define png_ptr (tc->png_ptr)
 | |
|    png_transform_background *tr =
 | |
|       png_transform_cast(png_transform_background, *transform);
 | |
| 
 | |
|    debug(tc->init == PNG_TC_INIT_FINAL /* never called in 'FORMAT' */ &&
 | |
|          (tc->format & PNG_FORMAT_FLAG_ALPHA) != 0);
 | |
| 
 | |
|    /* Now we know the format on which processing will happen so it is possible
 | |
|     * to generate the correct fill pixel value to use.
 | |
|     */
 | |
|    fill_background_pixel(tr, tc);
 | |
|    tc->format &= PNG_BIC_MASK(PNG_FORMAT_FLAG_ALPHA);
 | |
|    tc->invalid_info |= PNG_INFO_sBIT;
 | |
|    tc->sBIT_R = tc->sBIT_G = tc->sBIT_B = tc->sBIT_A =
 | |
|       png_check_byte(png_ptr, tc->bit_depth);
 | |
| 
 | |
|    if (!(tc->format & PNG_FORMAT_FLAG_COLOR))
 | |
|    {
 | |
|       if (tc->bit_depth == 8U)
 | |
|          tr->tr.fn = png_do_background_with_transparent_GA8;
 | |
| 
 | |
|       else if (tc->bit_depth == 16U)
 | |
|          tr->tr.fn = png_do_background_with_transparent_GA16;
 | |
| 
 | |
|       else /* low-bit-depth gray with alpha (not a PNG format!) */
 | |
|          tr->tr.fn = png_do_background_with_transparent_GAlbd;
 | |
|    }
 | |
| 
 | |
|    else /* color */
 | |
|    {
 | |
|       if (tc->bit_depth == 8U)
 | |
|          tr->tr.fn = png_do_background_with_transparent_RGBA8;
 | |
| 
 | |
|       else
 | |
|       {
 | |
|          debug(tc->bit_depth == 16U);
 | |
|          tr->tr.fn = png_do_background_with_transparent_RGBA16;
 | |
|       }
 | |
|    }
 | |
| #  undef png_ptr
 | |
| }
 | |
| 
 | |
| /* The calculated values below have the range 0..65535*65535, the output has the
 | |
|  * range 0..65535, so divide by 65535.  Two approaches are given here, one
 | |
|  * modifies the value in place, the other uses a more complex expression.  With
 | |
|  * gcc on an AMD64 system the in-place approach is very slightly faster.
 | |
|  *
 | |
|  * The two expressions are slightly different in what they calculate but both
 | |
|  * give the exact answer (verified by exhaustive testing.)
 | |
|  *
 | |
|  * The macro must be given a png_uint_32 variable (lvalue), normally an auto
 | |
|  * variable.
 | |
|  */
 | |
| #ifndef PNG_COMPOSE_DIV_65535
 | |
| #  ifdef PNG_COMPOSE_DIV_EXPRESSION_SUPPORTED
 | |
| #     define PNG_COMPOSE_DIV_65535(v)\
 | |
|          (v = ((v + (v>>16) + (v>>31) + 32768U) >> 16))
 | |
| #  else
 | |
| #     define PNG_COMPOSE_DIV_65535(v)\
 | |
|          (v += v >> 16, v += v >> 31, v += 32768U, v >>= 16)
 | |
| #  endif
 | |
| #endif
 | |
| 
 | |
| static void
 | |
| png_do_background_alpha_GA(png_transformp *transform, png_transform_controlp tc)
 | |
| {
 | |
| #  define png_ptr (tc->png_ptr)
 | |
|    png_transform_background *tr =
 | |
|       png_transform_cast(png_transform_background, *transform);
 | |
|    png_bytep dp = png_voidcast(png_bytep, tc->dp);
 | |
|    png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp);
 | |
|    const png_const_bytep ep = sp + PNG_TC_ROWBYTES(*tc) - 3U/*safety*/;
 | |
|    const unsigned int background = tr->st.background.gray;
 | |
|    const int copy = (sp != dp);
 | |
|    const int compose = tr->st.compose_background;
 | |
| 
 | |
|    affirm(tc->bit_depth == 16U && tc->format == PNG_FORMAT_GA &&
 | |
|          tr->st.background_bit_depth == 16U);
 | |
| 
 | |
|    /* If gamma transforms are eliminated this might fail: */
 | |
|    debug(tr->st.background_gamma == tc->gamma ||
 | |
|          tr->st.background_gamma == 0 ||
 | |
|          tc->sBIT_G == 1);
 | |
| 
 | |
|    tc->sp = tc->dp; /* nothing else changes */
 | |
| 
 | |
|    do
 | |
|    {
 | |
|       const png_uint_32 alpha = (sp[2] << 8) + sp[3];
 | |
| 
 | |
|       switch (alpha)
 | |
|       {
 | |
|          case 0U: /* transparent */
 | |
|             memset(dp, 0U, 4U);
 | |
|             break;
 | |
| 
 | |
|          default:
 | |
|             {
 | |
|                png_uint_32 v = ((sp[0] << 8) + sp[1]) * alpha +
 | |
|                   background * (65535U - alpha);
 | |
| 
 | |
|                PNG_COMPOSE_DIV_65535(v);
 | |
|                debug(v <= 65535U);
 | |
|                dp[0] = PNG_BYTE(v >> 8);
 | |
|                dp[1] = PNG_BYTE(v);
 | |
|             }
 | |
| 
 | |
|             if (compose)
 | |
|                dp[3] = dp[2] = 0xFFU; /* alpha; set to 1.0 */
 | |
| 
 | |
|             else if (copy)
 | |
|             {
 | |
|                dp[2] = PNG_BYTE(alpha >> 8);
 | |
|                dp[3] = PNG_BYTE(alpha);
 | |
|             }
 | |
|             break;
 | |
| 
 | |
|          case 65535U: /* opaque */
 | |
|             if (copy)
 | |
|                memcpy(dp, sp, 4U);
 | |
|             break;
 | |
|       }
 | |
| 
 | |
|       sp += 4U;
 | |
|       dp += 4U;
 | |
|    }
 | |
|    while (sp < ep);
 | |
| 
 | |
|    debug(sp == ep+3U);
 | |
| #  undef png_ptr
 | |
| }
 | |
| 
 | |
| static void
 | |
| png_do_background_alpha_RGBA(png_transformp *transform,
 | |
|    png_transform_controlp tc)
 | |
| {
 | |
| #  define png_ptr (tc->png_ptr)
 | |
|    png_transform_background *tr =
 | |
|       png_transform_cast(png_transform_background, *transform);
 | |
|    png_bytep dp = png_voidcast(png_bytep, tc->dp);
 | |
|    png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp);
 | |
|    const png_const_bytep ep = sp + PNG_TC_ROWBYTES(*tc) - 7U/*safety*/;
 | |
|    const unsigned int bred = tr->st.background.red;
 | |
|    const unsigned int bgreen = tr->st.background.green;
 | |
|    const unsigned int bblue = tr->st.background.blue;
 | |
|    const int copy = (sp != dp);
 | |
|    const int compose = tr->st.compose_background;
 | |
| 
 | |
|    affirm(tc->bit_depth == 16U && tc->format == PNG_FORMAT_RGBA &&
 | |
|          tr->st.background_bit_depth == 16U);
 | |
| 
 | |
|    debug(tr->st.background_gamma == tc->gamma ||
 | |
|          tr->st.background_gamma == 0 ||
 | |
|          (tc->sBIT_R == 1 && tc->sBIT_G == 1 && tc->sBIT_B == 1));
 | |
| 
 | |
|    tc->sp = tc->dp; /* nothing else changes */
 | |
| 
 | |
|    do
 | |
|    {
 | |
|       const png_uint_32 alpha = (sp[6] << 8) + sp[7];
 | |
| 
 | |
|       switch (alpha)
 | |
|       {
 | |
|          case 0U: /* transparent */
 | |
|             memset(dp, 0U, 8U);
 | |
|             break;
 | |
| 
 | |
|          default:
 | |
|             {
 | |
|                const png_uint_32 balpha = (65535U - alpha);
 | |
|                png_uint_32 r = ((sp[0] << 8) + sp[1]) * alpha + bred * balpha;
 | |
|                png_uint_32 g = ((sp[2] << 8) + sp[3]) * alpha + bgreen * balpha;
 | |
|                png_uint_32 b = ((sp[4] << 8) + sp[5]) * alpha + bblue * balpha;
 | |
| 
 | |
|                PNG_COMPOSE_DIV_65535(r);
 | |
|                PNG_COMPOSE_DIV_65535(g);
 | |
|                PNG_COMPOSE_DIV_65535(b);
 | |
|                debug(r <= 65535U && g <= 65535U && b <= 65535U);
 | |
|                dp[0] = PNG_BYTE(r >> 8);
 | |
|                dp[1] = PNG_BYTE(r);
 | |
|                dp[2] = PNG_BYTE(g >> 8);
 | |
|                dp[3] = PNG_BYTE(g);
 | |
|                dp[4] = PNG_BYTE(b >> 8);
 | |
|                dp[5] = PNG_BYTE(b);
 | |
|             }
 | |
| 
 | |
|             if (compose)
 | |
|                dp[7] = dp[6] = 0xFFU;
 | |
| 
 | |
|             else if (copy)
 | |
|             {
 | |
|                dp[6] = PNG_BYTE(alpha >> 8);
 | |
|                dp[7] = PNG_BYTE(alpha);
 | |
|             }
 | |
|             break;
 | |
| 
 | |
|          case 65535U: /* opaque */
 | |
|             if (copy)
 | |
|                memcpy(dp, sp, 8U);
 | |
|             break;
 | |
|       }
 | |
| 
 | |
|       sp += 8U;
 | |
|       dp += 8U;
 | |
|    }
 | |
|    while (sp < ep);
 | |
| 
 | |
|    debug(sp == ep+7U);
 | |
| #  undef png_ptr
 | |
| }
 | |
| 
 | |
| static void
 | |
| png_init_background_alpha_end(png_transformp *transform,
 | |
|    png_transform_controlp tc)
 | |
|    /* This is just the last part of png_init_background_alpha (below) */
 | |
| {
 | |
| #  define png_ptr (tc->png_ptr)
 | |
|    png_transform_background *tr =
 | |
|       png_transform_cast(png_transform_background, *transform);
 | |
| 
 | |
|    debug(tc->init == PNG_TC_INIT_FINAL);
 | |
| 
 | |
|    /* Repeat the tests at the end of png_init_background_alpha: */
 | |
|    affirm(tc->bit_depth == 16U && (tc->format & PNG_FORMAT_FLAG_ALPHA) != 0);
 | |
|    debug(tc->gamma == 0 ||
 | |
|          !png_gamma_significant(png_ptr, tc->gamma, tc_sBIT(tc)));
 | |
| 
 | |
|    /* tr->st.background_is_gray was filled in by resolve_background_color and
 | |
|     * records if either the background was a gray value or it was a color
 | |
|     * value with all the channels equal.
 | |
|     */
 | |
|    if (!tr->st.background_is_gray && !(tc->format & PNG_FORMAT_FLAG_COLOR))
 | |
|    {
 | |
| #     ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED
 | |
|          /* Color background with gray data: this happens when there is a
 | |
|           * gray to RGB transform in the pipeline but it hasn't happened
 | |
|           * yet.  Unfortunately it has to happen now to be able to do the
 | |
|           * compose against the colored background.
 | |
|           */
 | |
|          png_push_gray_to_rgb_byte_ops(transform, tc);
 | |
|          affirm((tc->format & PNG_FORMAT_FLAG_COLOR) != 0);
 | |
|          return;
 | |
| #     else /* !GRAY_TO_RGB */
 | |
|          impossible("gray to RGB"); /* how can this happen? */
 | |
| #     endif /* !GRAY_TO_RGB */
 | |
|    }
 | |
| 
 | |
|    /* The transform happens in two parts, a part to do the arithmetic on
 | |
|     * pixels where it is required followed by a part to replace transparent
 | |
|     * pixels.  These two parts require different versions of the background
 | |
|     * pixel.  Set up the second part first.
 | |
|     *
 | |
|     * This only happens with background composition, otherwise the
 | |
|     * transparent pixels are already 0 and nothing needs to be done.
 | |
|     */
 | |
|    if (tr->st.compose_background)
 | |
|    {
 | |
|       /* The transparent pixel handling happens *after* the data has been
 | |
|        * re-encoded to the output gamma:
 | |
|        */
 | |
|       png_transform_background *tr_alpha =
 | |
|          png_transform_cast(png_transform_background,
 | |
|             png_add_transform(png_ptr, sizeof (png_transform_background),
 | |
|                png_init_background_transparent, PNG_TR_GAMMA_ENCODE+0xF0U));
 | |
| 
 | |
|       /* Copy the current state into the new png_transform_background: */
 | |
|       tr_alpha->st = tr->st;
 | |
|       tr_alpha->tr.args = tr->tr.args;
 | |
|    }
 | |
| 
 | |
|    /* Now it is possible to overwrite tr->st.background with the linear version.
 | |
|     */
 | |
|    gamma_correct_background(tr, tc);
 | |
| 
 | |
|    /* sBIT informationmust also be invalidated here, because a gamma
 | |
|     * transform may run before the transparent pixel handling.
 | |
|     */
 | |
|    tc->invalid_info |= PNG_INFO_sBIT;
 | |
|    tc->sBIT_R = tc->sBIT_G = tc->sBIT_B = tc->sBIT_A =
 | |
|       png_check_byte(png_ptr, tc->bit_depth);
 | |
| 
 | |
|    /* And select an appropriate function; there are only two choices: */
 | |
|    switch (tc->format)
 | |
|    {
 | |
|       case PNG_FORMAT_GA:
 | |
|          /* If the background format is color this indicates that there is a
 | |
|           * gray to RGB transform missing and we need it to happen before
 | |
|           * this point!
 | |
|           */
 | |
|          affirm(tr->st.background_is_gray);
 | |
|          tr->tr.fn = png_do_background_alpha_GA;
 | |
|          break;
 | |
| 
 | |
|       case PNG_FORMAT_RGBA:
 | |
|          if (tr->st.background_is_gray)
 | |
|             tr->st.background.blue = tr->st.background.green =
 | |
|                tr->st.background.red = tr->st.background.gray;
 | |
|          tr->tr.fn = png_do_background_alpha_RGBA;
 | |
|          break;
 | |
| 
 | |
|       default:
 | |
|          NOT_REACHED;
 | |
|    }
 | |
| #  undef png_ptr
 | |
| }
 | |
| 
 | |
| static void
 | |
| png_init_background_alpha(png_transformp *transform, png_transform_controlp tc)
 | |
|    /* This is used when alpha composition is required because the alpha channel
 | |
|     * may contain values that are between 0 and 1.  Because doing alpha
 | |
|     * composition requires linear arithmetic the data is converted to 16-bit
 | |
|     * linear, however this means that the background pixel gets converted too
 | |
|     * and, for 16-bit output, this tends to smash the value.  Consequently the
 | |
|     * algorithm used here is to skip those pixels and use the 'transparent
 | |
|     * alpha' routines to replace them after the gamma correction step.
 | |
|     */
 | |
| {
 | |
| #  define png_ptr (tc->png_ptr)
 | |
|    png_transform_background *tr =
 | |
|       png_transform_cast(png_transform_background, *transform);
 | |
| 
 | |
|    debug(tc->init == PNG_TC_INIT_FINAL);
 | |
|    /* png_init_background ensures this is true: */
 | |
|    debug((tc->format & PNG_FORMAT_FLAG_ALPHA) != 0);
 | |
| 
 | |
|    /* Always push gamma transforms; don't try to optimize the case when they
 | |
|     * aren't needed because that would be an attempt to duplicate the tests in
 | |
|     * png_init_gamma and it might now work reliably.
 | |
|     *
 | |
|     * Need to push the to-linear transform *before* this transform and add gamma
 | |
|     * correction afterward to get back to the screen format.  Do the afterward
 | |
|     * bit first to avoid complexity over *transform:
 | |
|     */
 | |
|    {
 | |
|       png_transform_gamma *tr_end = add_gamma_transform(png_ptr,
 | |
|          PNG_TR_GAMMA_ENCODE, tc->gamma, 0U/*bit depth*/, 0/*default*/);
 | |
| 
 | |
|       /* Encoding the alpha channel happens in the last step, so this needs to
 | |
|        * be set here.  Notice that in C++ terms we are very friendly with
 | |
|        * png_transform_gamma.
 | |
|        */
 | |
|       tr_end->encode_alpha = tr->st.encode_alpha;
 | |
|       tr_end->optimize_alpha = tr->st.optimize_alpha;
 | |
|    }
 | |
| 
 | |
|    {
 | |
|       /* Now add tr_gamma before this transform, expect it to go in at
 | |
|        * *transform or the whole thing won't work:
 | |
|        */
 | |
|       png_transform_gamma *tr_gamma = png_transform_cast(png_transform_gamma,
 | |
|          png_push_transform(png_ptr, sizeof (png_transform_gamma),
 | |
|             png_init_gamma, transform, NULL/*don't run init*/));
 | |
| 
 | |
|       /* This must happen before we run png_gamma_init: */
 | |
|       tr_gamma->to_gamma = PNG_FP_1;
 | |
|       tr_gamma->to_bit_depth = 16U;
 | |
| 
 | |
|       /* Now run the this transform; it was pushed before this one, so it gets
 | |
|        * to do its init first and this function must return as the caller will
 | |
|        * immediately call here again.
 | |
|        */
 | |
|       debug(*transform == &tr_gamma->tr);
 | |
|       png_init_gamma(transform, tc);
 | |
|       affirm(tc->bit_depth == 16U &&
 | |
|              (tc->format & PNG_FORMAT_FLAG_ALPHA) != 0);
 | |
|       /* This is only a 'debug' because it needs to replicate the test in
 | |
|        * png_init_gamma and that is easy to get wrong (a harmless mistake).
 | |
|        */
 | |
|       debug(tc->gamma == 0 ||
 | |
|             !png_gamma_significant(png_ptr, tc->gamma, tc_sBIT(tc)));
 | |
|    }
 | |
| 
 | |
|    /* A transform was pushed, so this transform init will be run again: */
 | |
|    tr->tr.fn = png_init_background_alpha_end;
 | |
| #  undef png_ptr
 | |
| }
 | |
| 
 | |
| /* Handle alpha and tRNS via a background color */
 | |
| static void
 | |
| png_init_background(png_transformp *transform, png_transform_controlp tc)
 | |
| {
 | |
|    /* This init function is called right at the start, this means it can get at
 | |
|     * the tRNS values if appropriate.  If not the RGB to gray transform comes
 | |
|     * next followed by PNG_TR_COMPOSE_ALPHA, which actually does the non-tRNS
 | |
|     * work.
 | |
|     */
 | |
|    png_structp png_ptr = tc->png_ptr;
 | |
|    png_transform_background *tr =
 | |
|       png_transform_cast(png_transform_background, *transform);
 | |
| 
 | |
|    if (tc->init == PNG_TC_INIT_FORMAT)
 | |
|    {
 | |
|       /* Background composition removes the alpha channel, so the other
 | |
|        * operations become irrelevant:
 | |
|        */
 | |
|       if (tr->st.compose_background)
 | |
|          tr->st.associate_alpha = tr->st.encode_alpha = tr->st.optimize_alpha =
 | |
|             0U;
 | |
| 
 | |
|       else if (!tr->st.associate_alpha)
 | |
|       {
 | |
|          /* There is nothing to do, delete the whole transform. */
 | |
|          tr->tr.fn = NULL;
 | |
|          return;
 | |
|       }
 | |
| 
 | |
|       /* Else alpha association ('pre-multiplication') which is achieved by
 | |
|        * composing on a 0 background.  The background color will be black (all
 | |
|        * zeros) and the background gamma will be zero.
 | |
|        */
 | |
| 
 | |
|       /* Because we are in PNG_TC_INIT_FORMAT no other transforms will have been
 | |
|        * inserted between this one and an rgb-to-gray transform, so we can find
 | |
|        * out if rgb-to-gray has been requested:
 | |
|        */
 | |
|       tr->st.rgb_to_gray = tr->tr.next != NULL &&
 | |
|          tr->tr.next->order == PNG_TR_RGB_TO_GRAY;
 | |
| 
 | |
|       if ((tc->format & PNG_FORMAT_FLAG_ALPHA) != 0)
 | |
|       {
 | |
|          /* Associated alpha does not strip the alpha channel! */
 | |
|          if (tr->st.compose_background)
 | |
|             tc->format &= PNG_BIC_MASK(PNG_FORMAT_FLAG_ALPHA);
 | |
|       }
 | |
| 
 | |
|       else if (!tc->palette &&
 | |
|          png_ptr->num_trans == 1 && !(tc->invalid_info & PNG_INFO_tRNS))
 | |
|       {
 | |
|          /* tRNS will be expanded, or handled */
 | |
|          tc->invalid_info |= PNG_INFO_tRNS;
 | |
|          if (!tr->st.compose_background)
 | |
|          {
 | |
|             tc->format |= PNG_FORMAT_FLAG_ALPHA;
 | |
|             /* And in this case, only, because we are adding an alpha channel we
 | |
|              * need to have a channel depth of at least 8:
 | |
|              */
 | |
|             if (tc->bit_depth < 8U)
 | |
|                tc->bit_depth = 8U;
 | |
|          }
 | |
|       }
 | |
| 
 | |
|       else /* no transparent pixels to change */
 | |
|          tr->tr.fn = NULL;
 | |
|    }
 | |
| 
 | |
|    else /* PNG_TC_INIT_FINAL */
 | |
|    {
 | |
|       png_fixed_point correction;
 | |
| 
 | |
|       debug(tc->init == PNG_TC_INIT_FINAL &&
 | |
|             ((tc->format & PNG_FORMAT_FLAG_ALPHA) != 0 ||
 | |
|              (!tc->palette && png_ptr->num_trans == 1 &&
 | |
|               !(tc->invalid_info & PNG_INFO_tRNS))));
 | |
| 
 | |
|       /* The screen gamma is known, so the background gamma can be found, note
 | |
|        * that both the gamma values used below will be 0 if no gamma information
 | |
|        * was in the PNG and no gamma information has been provided by
 | |
|        * png_set_gamma or png_set_alpha_mode.
 | |
|        */
 | |
|       switch (tr->st.background_gamma)
 | |
|       {
 | |
|          case PNG_BACKGROUND_GAMMA_FILE:
 | |
|             /* png_init_transform_control has already found the file gamma,
 | |
|              * and because this is the first arithmetic transformation
 | |
|              * nothing has changed it.
 | |
|              */
 | |
|             tr->st.background_gamma = tc->gamma;
 | |
|             break;
 | |
| 
 | |
|          case PNG_BACKGROUND_GAMMA_SCREEN:
 | |
|             tr->st.background_gamma = png_ptr->row_gamma;
 | |
|             break;
 | |
| 
 | |
|          default:
 | |
|             /* already set */
 | |
|             break;
 | |
|       }
 | |
| 
 | |
|       /* Work out what the background color is, this only depends on 'tc' for
 | |
|        * palette information, so it can be done now before we know the actual
 | |
|        * bit_depth/format that will be required:
 | |
|        */
 | |
|       resolve_background_color(tr, tc);
 | |
| 
 | |
|       /* Is this format compatible with the current row data?  If it is then it
 | |
|        * is possible to avoid the arithmetic if no alpha processing is required.
 | |
|        * This is a useful optimization because PNG files with just transparent
 | |
|        * pixels and no alpha are common.
 | |
|        *
 | |
|        * NOTE: if an RGB-to-gray transform is present this is fine so long as
 | |
|        * the background is gray, otherwise (non-gray background) there is a
 | |
|        * following gray-to-RGB transform and the now gray image must be
 | |
|        * composited on a color background.
 | |
|        */
 | |
|       if (tr->st.compose_background /* alpha channel stripped */ &&
 | |
|           (tr->st.background_is_gray ||
 | |
|            ((tc->format & PNG_FORMAT_FLAG_COLOR) != 0 && !tr->st.rgb_to_gray))
 | |
|             /* color compatible */ &&
 | |
|           tc->bit_depth >= tr->st.background_bit_depth
 | |
|             /* bit depth compatible */ &&
 | |
|           (tc->transparent_alpha ||
 | |
|            (!tc->palette && png_ptr->num_trans == 1 &&
 | |
|             !(tc->invalid_info & PNG_INFO_tRNS)))
 | |
|             /* no alpha processing */ &&
 | |
|           png_gamma_equal(png_ptr, tc->gamma, png_ptr->row_gamma, &correction,
 | |
|              tc->bit_depth) /* gamma compatible (so no gamma processing) */)
 | |
|       {
 | |
|          /* How the operation gets performed depends on whether the current data
 | |
|           * has an alpha channel or not.
 | |
|           */
 | |
|          if ((tc->format & PNG_FORMAT_FLAG_ALPHA) != 0)
 | |
|          {
 | |
|             affirm(tc->transparent_alpha);
 | |
|             /* This init routine does the sBIT handling: */
 | |
|             png_init_background_transparent(transform, tc);
 | |
|          }
 | |
| 
 | |
|          else if (!tc->palette && png_ptr->num_trans == 1 &&
 | |
|             !(tc->invalid_info & PNG_INFO_tRNS))
 | |
|          {
 | |
|             /* The background pixel needs to be filled in now; no more init
 | |
|              * routines are called in this case.  It is important to delay this
 | |
|              * as late as possible because it needs to know the actual tc format
 | |
|              * that must be used.
 | |
|              */
 | |
|             fill_background_pixel(tr, tc);
 | |
| 
 | |
|             debug(!(png_ptr->color_type & PNG_COLOR_MASK_PALETTE));
 | |
| 
 | |
|             /* The pixel depth should not have been changed yet: */
 | |
|             debug(PNG_PIXEL_DEPTH(*png_ptr) == PNG_TC_PIXEL_DEPTH(*tc));
 | |
| 
 | |
|             /* The transparent_pixel value needs to be filled in. */
 | |
|             affirm(tr->st.ntrans ==
 | |
|                fill_transparent_pixel(png_ptr, tr->st.transparent_pixel));
 | |
| 
 | |
|             /* The whole operation is a no-op if the transparent pixel and the
 | |
|              * background pixel match, even in the associated alpha case where
 | |
|              * both will be 0 throughout.
 | |
|              *
 | |
|              * NOTE: for palette images this test happens in the caching
 | |
|              * operation, so the answer is still correct.
 | |
|              *
 | |
|              * NOTE: for low bit depth gray both 'transparent_pixel' and
 | |
|              * 'background_pixel' have been expanded to fill a byte, so this
 | |
|              * works.
 | |
|              */
 | |
|             if (memcmp(tr->st.transparent_pixel, tr->st.background_pixel,
 | |
|                      tr->st.ntrans) == 0)
 | |
|                tr->tr.fn = NULL;
 | |
| 
 | |
|             /* Then the processing function depends on the pixel size: */
 | |
|             else if (tr->st.ntrans > 1U)
 | |
|                tr->tr.fn = png_do_replace_tRNS_multi;
 | |
| 
 | |
|             else if (tc->bit_depth == 8U)
 | |
|                tr->tr.fn = png_do_replace_tRNS_8;
 | |
| 
 | |
|             else if (tc->bit_depth == 1U)
 | |
|             {
 | |
|                /* This is the silly case: the replacement pixel does not match
 | |
|                 * the transparent pixel (handled above) so either all the '0'
 | |
|                 * bits are replaced by '1' or all the '1' bits are replaced by
 | |
|                 * '0':
 | |
|                 */
 | |
|                png_uint_32 args = tr->st.background_pixel[0];
 | |
| 
 | |
|                args <<= 24;
 | |
|                args |= PNG_INFO_tRNS | PNG_INFO_sRGB;
 | |
|                tr->tr.args = args;
 | |
|                tr->tr.fn = png_do_set_row;
 | |
|             }
 | |
| 
 | |
|             else
 | |
|                tr->tr.fn = png_do_replace_tRNS_lbd;
 | |
| 
 | |
|             tc->invalid_info |= PNG_INFO_tRNS | PNG_INFO_sBIT;
 | |
|             tc->sBIT_R = tc->sBIT_G = tc->sBIT_B = tc->sBIT_A =
 | |
|                png_check_byte(png_ptr, tc->bit_depth);
 | |
|          }
 | |
| 
 | |
|          else
 | |
|          {
 | |
|             /* Nothing to do; should have been eliminated before! */
 | |
|             tr->tr.fn = NULL;
 | |
|             NOT_REACHED;
 | |
|          }
 | |
|       }
 | |
| 
 | |
|       else /* alpha, or maybe gamma, processing required */
 | |
|       {
 | |
|          /* Alpha case, add an appropriate transform; this has to be done
 | |
|           * *after* the RGB-to-gray case so move the transform info there:
 | |
|           */
 | |
|          png_transform_background *tr_alpha =
 | |
|             png_transform_cast(png_transform_background,
 | |
|                png_add_transform(png_ptr, sizeof (png_transform_background),
 | |
|                   png_init_background_alpha, PNG_TR_COMPOSE_ALPHA));
 | |
| 
 | |
|          /* Copy the current state into the new png_transform_background: */
 | |
|          tr_alpha->st = tr->st;
 | |
|          tr_alpha->tr.args = tr->tr.args;
 | |
| 
 | |
|          /* The rest of the init occurs later; this transform is no longer
 | |
|           * needed.
 | |
|           */
 | |
|          tr->tr.fn = NULL;
 | |
| 
 | |
|          /* Ensure that png_init_background_alpha gets an alpha channel, this
 | |
|           * needs to happen here because otherwise intervening transforms can
 | |
|           * invalidate tRNS.
 | |
|           */
 | |
|          tc->expand_tRNS = 1U;
 | |
|          if (tr->st.compose_background)
 | |
|             tc->strip_alpha = 0U;
 | |
| 
 | |
|          /* And push the expand: */
 | |
|          (void)push_gamma_expand(transform, tc, 1/*need alpha*/);
 | |
| 
 | |
|          /* Regardless of whether anything got pushed the following should now
 | |
|           * be true:
 | |
|           */
 | |
|          affirm((tc->format & PNG_FORMAT_FLAG_ALPHA) != 0 &&
 | |
|                 tc->bit_depth >= 8U);
 | |
|       }
 | |
|    }
 | |
| }
 | |
| 
 | |
| void PNGFAPI
 | |
| png_set_background_fixed(png_structrp png_ptr,
 | |
|     png_const_color_16p background_color, int background_gamma_code,
 | |
|     int need_expand, png_fixed_point background_gamma)
 | |
| {
 | |
|    if (png_ptr != NULL)
 | |
|    {
 | |
|       if (background_color != NULL)
 | |
|       {
 | |
|          png_transform_background *tr =
 | |
|             png_transform_cast(png_transform_background,
 | |
|                png_add_transform(png_ptr, sizeof (png_transform_background),
 | |
|                   png_init_background, PNG_TR_COMPOSE));
 | |
| 
 | |
|          /* This silently overwrites the information if png_set_background is
 | |
|           * called more than once.
 | |
|           */
 | |
|          tr->st.background = *background_color;
 | |
|          tr->st.need_expand = need_expand != 0;
 | |
|          tr->st.compose_background = 1U; /* png_set_background called */
 | |
|          switch (background_gamma_code)
 | |
|          {
 | |
|             case PNG_BACKGROUND_GAMMA_SCREEN:
 | |
|             case PNG_BACKGROUND_GAMMA_FILE:
 | |
|                tr->st.background_gamma = background_gamma_code;
 | |
|                break;
 | |
| 
 | |
|             case PNG_BACKGROUND_GAMMA_UNIQUE:
 | |
|                if (background_gamma >= 16 && background_gamma <= 625000000)
 | |
|                {
 | |
|                   tr->st.background_gamma = background_gamma;
 | |
|                   break;
 | |
|                }
 | |
| 
 | |
|                png_app_error(png_ptr, "gamma value out of range");
 | |
|                /* FALL THROUGH */
 | |
|             default:
 | |
|                png_app_error(png_ptr, "invalid gamma information");
 | |
|                tr->st.background_gamma = (need_expand ?
 | |
|                   PNG_BACKGROUND_GAMMA_FILE : PNG_BACKGROUND_GAMMA_SCREEN);
 | |
|                break;
 | |
|          }
 | |
|       }
 | |
| 
 | |
|       else
 | |
|          png_app_error(png_ptr, "missing background color");
 | |
|    }
 | |
| }
 | |
| 
 | |
| #  ifdef PNG_FLOATING_POINT_SUPPORTED
 | |
| void PNGAPI
 | |
| png_set_background(png_structrp png_ptr,
 | |
|     png_const_color_16p background_color, int background_gamma_code,
 | |
|     int need_expand, double background_gamma)
 | |
| {
 | |
|    png_set_background_fixed(png_ptr, background_color, background_gamma_code,
 | |
|       need_expand, png_fixed(png_ptr, background_gamma, "png_set_background"));
 | |
| }
 | |
| #  endif  /* FLOATING_POINT */
 | |
| #endif /* READ_BACKGROUND */
 | |
| 
 | |
| #ifdef PNG_READ_ALPHA_MODE_SUPPORTED
 | |
| void PNGFAPI
 | |
| png_set_alpha_mode_fixed(png_structrp png_ptr, int mode,
 | |
|    png_fixed_point output_gamma)
 | |
| {
 | |
|    if (png_ptr != NULL)
 | |
|    {
 | |
|       /* Check the passed in output_gamma value; it must be valid and it must be
 | |
|        * converted to the reciprocal for use below:
 | |
|        */
 | |
|       output_gamma = translate_gamma_flags(png_ptr, output_gamma, 1/*screen*/);
 | |
| 
 | |
|       if (output_gamma > 0) /* Else an app_error has been signalled. */
 | |
|       {
 | |
|          /* Only set the colorspace gamma if it has not already been set (this
 | |
|           * has the side effect that the gamma in a second call to
 | |
|           * png_set_alpha_mode will be ignored.)
 | |
|           */
 | |
|          if ((png_ptr->colorspace.flags &
 | |
|               (PNG_COLORSPACE_INVALID | PNG_COLORSPACE_HAVE_GAMMA)) !=
 | |
|               PNG_COLORSPACE_HAVE_GAMMA)
 | |
|          {
 | |
|             /* The default file gamma is the output gamma encoding: */
 | |
|             png_ptr->colorspace.gamma = output_gamma;
 | |
|             if (png_ptr->colorspace.flags & PNG_COLORSPACE_INVALID)
 | |
|                png_ptr->colorspace.flags = PNG_COLORSPACE_HAVE_GAMMA;
 | |
|             else
 | |
|                png_ptr->colorspace.flags |= PNG_COLORSPACE_HAVE_GAMMA;
 | |
|          }
 | |
| 
 | |
|          /* Always set the output gamma, note that it may be changed to PNG_FP_1
 | |
|           * for the associated alpha support.  This means that the last call to
 | |
|           * png_set_gamma[_fixed] or png_set_alpha_mode sets the output gamma,
 | |
|           * which is probably what is expected.
 | |
|           */
 | |
|          {
 | |
|             png_transform_gamma *tr_gamma = add_gamma_transform(png_ptr,
 | |
|                PNG_TR_GAMMA_ENCODE,
 | |
|                mode == PNG_ALPHA_ASSOCIATED ? PNG_FP_1 : output_gamma, 0U,
 | |
|                1/*force*/);
 | |
| 
 | |
|             /* Get a background transform and set the appropriate fields.
 | |
|              *
 | |
|              * png_set_background removes the alpha channel so it effectively
 | |
|              * disbles png_set_alpha_mode however png_set_alpha_mode is still
 | |
|              * useful to set a default gamma value.
 | |
|              */
 | |
|             png_transform_background *tr =
 | |
|                png_transform_cast(png_transform_background,
 | |
|                   png_add_transform(png_ptr, sizeof (png_transform_background),
 | |
|                      png_init_background, PNG_TR_COMPOSE));
 | |
| 
 | |
|             /* There are really 8 possibilities here, composed of any
 | |
|              * combination of:
 | |
|              *
 | |
|              *    premultiply the color channels
 | |
|              *    do not encode non-opaque pixels (leave as linear)
 | |
|              *    encode the alpha as well as the color channels
 | |
|              *
 | |
|              * The differences disappear if the input/output ('screen') gamma is
 | |
|              * 1.0,  because then the encoding is a no-op and there is only the
 | |
|              * choice of premultiplying the color channels or not.
 | |
|              */
 | |
|             switch (mode)
 | |
|             {
 | |
|                case PNG_ALPHA_PNG:        /* default: png standard */
 | |
|                   /* No compose, but it may be set by png_set_background!  This
 | |
|                    * is the only mode that doesn't interfere with what
 | |
|                    * png_set_background does.
 | |
|                    */
 | |
|                   tr->st.associate_alpha = 0U;
 | |
|                   tr_gamma->encode_alpha = tr->st.encode_alpha = 0U;
 | |
|                   tr_gamma->optimize_alpha = tr->st.optimize_alpha = 0U;
 | |
|                   break;
 | |
| 
 | |
|                case PNG_ALPHA_ASSOCIATED: /* color channels premultiplied */
 | |
|                   tr->st.associate_alpha = 1U;
 | |
|                   tr_gamma->encode_alpha = tr->st.encode_alpha = 0U;
 | |
|                   tr_gamma->optimize_alpha = tr->st.optimize_alpha = 0U;
 | |
|                   break;
 | |
| 
 | |
|                case PNG_ALPHA_OPTIMIZED:
 | |
|                   /* associated with opaque pixels having the given gamma and
 | |
|                    * non-opaque pixels being linear.
 | |
|                    */
 | |
|                   tr->st.associate_alpha = 1U;
 | |
|                   tr_gamma->encode_alpha = tr->st.encode_alpha = 0U;
 | |
|                   tr_gamma->optimize_alpha = tr->st.optimize_alpha = 1U;
 | |
|                   /* output_gamma records the encoding of opaque pixels! */
 | |
|                   break;
 | |
| 
 | |
|                case PNG_ALPHA_BROKEN:
 | |
|                   /* associated+non-linear+alpha encoded */
 | |
|                   tr->st.associate_alpha = 1U;
 | |
|                   tr_gamma->encode_alpha = tr->st.encode_alpha = 1U;
 | |
|                   tr_gamma->optimize_alpha = tr->st.optimize_alpha = 0U;
 | |
|                   break;
 | |
| 
 | |
|                default:
 | |
|                   png_app_error(png_ptr, "invalid alpha mode");
 | |
|                   /* A return at this point is safe; if a background transform
 | |
|                    * was created the init routine will remove it because
 | |
|                    * nothing is set.
 | |
|                    */
 | |
|                   break;
 | |
|             } /* alpha mode switch */
 | |
|          } /* add gamma and background transforms */
 | |
|       } /* valid output gamma */
 | |
|    } /* png_ptr != NULL */
 | |
| }
 | |
| 
 | |
| #ifdef PNG_FLOATING_POINT_SUPPORTED
 | |
| void PNGAPI
 | |
| png_set_alpha_mode(png_structrp png_ptr, int mode, double output_gamma)
 | |
| {
 | |
|    png_set_alpha_mode_fixed(png_ptr, mode, convert_gamma_value(png_ptr,
 | |
|       output_gamma));
 | |
| }
 | |
| #endif /* FLOATING_POINT */
 | |
| #endif /* READ_ALPHA_MODE */
 | |
| 
 | |
| #ifdef PNG_READ_TRANSFORMS_SUPPORTED
 | |
| typedef struct
 | |
| {
 | |
|    png_transform         tr;
 | |
|    png_transform_control tc;
 | |
|    union
 | |
|    {
 | |
|       png_uint_32        u32[1]; /* ensure alignment */
 | |
|       png_uint_16        u16[1];
 | |
|       png_byte           b8[1];
 | |
|    }  cache;
 | |
| }  png_transform_cache;
 | |
| 
 | |
| #define png_transform_cache_size(size)\
 | |
|    (offsetof(png_transform_cache, cache)+(size))
 | |
| #define png_transform_cache_cast(pointer,size)\
 | |
|    png_voidcast(png_transform_cache*,\
 | |
|       png_transform_cast_check(png_ptr, PNG_SRC_LINE, (pointer),\
 | |
|          png_transform_cache_size(size)))
 | |
|    /* This is like png_transform_cast except that 'size' is the size of the
 | |
|     * cache part in the above structure and the type returned is always
 | |
|     * 'png_transform_cache*'.
 | |
|     */
 | |
| 
 | |
| /* Functions to handle the cache operation.  These don't do any initialization;
 | |
|  * that happens below when PNG_TC_INIT_FINAL is being run on the whole list.
 | |
|  * These functions are only implemented for read so the transform control
 | |
|  * source and destination are always aligned.
 | |
|  *
 | |
|  * First some utility functions:
 | |
|  */
 | |
| static void
 | |
| png_transform_control_cp(png_transform_controlp tcDest,
 | |
|    png_const_transform_controlp tcSrc)
 | |
| {
 | |
|    /* Copy tcSrc over tcDest without overwriting the information specific to the
 | |
|     * row being transformed.
 | |
|     */
 | |
|    png_structp     png_ptr = tcDest->png_ptr;
 | |
|    png_const_voidp sp      = tcDest->sp;
 | |
|    png_voidp       dp      = tcDest->dp;
 | |
|    png_uint_32     width   = tcDest->width;
 | |
|    unsigned int    init    = tcDest->init;
 | |
| 
 | |
|    *tcDest = *tcSrc;
 | |
| 
 | |
|    tcDest->png_ptr = png_ptr;
 | |
|    tcDest->sp      = sp;
 | |
|    tcDest->dp      = dp;
 | |
|    tcDest->width   = width;
 | |
|    tcDest->init    = png_check_bits(tcDest->png_ptr, init, 2);
 | |
| }
 | |
| 
 | |
| #if !PNG_RELEASE_BUILD
 | |
| static int
 | |
| png_transform_control_eq(png_const_transform_controlp tc1,
 | |
|    png_const_transform_controlp tc2)
 | |
| {
 | |
|    /* Say if *tc1 == *tc2, ignoring differences in uncopied fields and 'cost':
 | |
|     */
 | |
|    return
 | |
| #     ifdef PNG_READ_GAMMA_SUPPORTED
 | |
|          tc1->gamma == tc2->gamma &&
 | |
| #     endif
 | |
|       tc1->format == tc2->format &&
 | |
|       tc1->range == tc2->range &&
 | |
|       tc1->bit_depth == tc2->bit_depth &&
 | |
|       tc1->caching == tc2->caching &&
 | |
|       tc1->palette == tc2->palette;
 | |
|       /* invalid_info, cost, interchannel and channel_add are only set during
 | |
|        * init, so don't do the compare.
 | |
|        */
 | |
| }
 | |
| #endif /* !RELEASE_BUILD */
 | |
| 
 | |
| /* Now the routines that actually perform the transform.  There are two basic
 | |
|  * cases:
 | |
|  *
 | |
|  * 1) A cached transform that does not change the pixel size and where the pixel
 | |
|  *    size 8 bits or less.  This can be done by a 256-entry single byte lookup
 | |
|  *    table, regardless of the bit depth.  Two versions of the code exist, one
 | |
|  *    which just transforms the row, the other which transforms and records the
 | |
|  *    maximum pixel depth.
 | |
|  *
 | |
|  * 2) A cached transform that increases pixel depth.  The destination pixel
 | |
|  *    depth will always be a multiple of 8 bits, the source pixel will be less
 | |
|  *    than or equal to 8 bits and will be in the PNG native (big endian) layout.
 | |
|  */
 | |
| #define png_ptr (tc->png_ptr) /* Used in all functions below */
 | |
| /* (1): single-byte cached transforms: */
 | |
| static void
 | |
| do_transform_cache_byte(png_transformp *trIn, png_transform_controlp tc)
 | |
| {
 | |
|    png_transform_cache *tr = png_transform_cache_cast(*trIn, 256U);
 | |
| 
 | |
|    /* Copy the bytes through the 256-byte LUT: */
 | |
|    png_bytep dp = png_voidcast(png_bytep, tc->dp);
 | |
|    png_const_bytep ep = dp + PNG_TC_ROWBYTES(*tc);
 | |
|    png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp);
 | |
| 
 | |
|    tc->sp = dp;
 | |
| 
 | |
|    do
 | |
|       *dp++ = tr->cache.b8[*sp++];
 | |
|    while (dp < ep);
 | |
| 
 | |
|    png_transform_control_cp(tc, &tr->tc);
 | |
| }
 | |
| 
 | |
| /* (2) A cached transform that increases pixel depth.
 | |
|  *
 | |
|  * There are six output depth possibilites, all a whole number of bytes:
 | |
|  *
 | |
|  *    1 byte,   8 bits: palette or grayscale
 | |
|  *    2 bytes, 16 bits: 16-bit grayscale or 8-bit gray+alpa
 | |
|  *    3 bytes, 24 bits: 8-bit RGB
 | |
|  *    4 bytes, 32 bits: 16-bit gray+alpha or 8-bit RGBA
 | |
|  *    6 bytes, 48 bits: 16-bit RGB
 | |
|  *    8 bytes, 64 bits: 16-bit RGBA
 | |
|  *
 | |
|  * The input must be 1, 2, 4 or 8-bit gray or palette.  The first 1-byte case is
 | |
|  * handled for 8-bit gray/palette above, so there are 22 possibilities.  The
 | |
|  * function names below are:
 | |
|  *
 | |
|  *    do_transform_cache_<input-bits>_<output-bits>
 | |
|  */
 | |
| #define transform_cache_size(ipd,opd) ((((1U << (ipd)) * (opd))+7U) >> 3)
 | |
| static void
 | |
| do_transform_cache_(png_transformp *trIn, png_transform_controlp tc,
 | |
|    unsigned int ipd, unsigned int opd)
 | |
|    /* This is the implementation for unknown ipd, opd, below it is called with
 | |
|     * fixed values.  The purpose of this is to allow the compiler/system builder
 | |
|     * to decide how to optimize for size vs space vs speed.  Note that this
 | |
|     * implementation, while it would work for 8 bit ipd, is not used in that
 | |
|     * case.
 | |
|     */
 | |
| {
 | |
|    png_transform_cache *tr =
 | |
|       png_transform_cache_cast(*trIn, transform_cache_size(ipd, opd));
 | |
| 
 | |
|    png_bytep dp = png_voidcast(png_bytep, tc->dp);
 | |
|    png_const_bytep ep = dp;
 | |
|    png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp);
 | |
|    unsigned int s, shift, mask;
 | |
| 
 | |
|    sp += PNG_TC_ROWBYTES(*tc); /* One byte beyond the end */
 | |
| 
 | |
|    png_transform_control_cp(tc, &tr->tc);
 | |
|    dp += PNG_TC_ROWBYTES(*tc);
 | |
| 
 | |
|    shift = 7U & -(tc->width * ipd);
 | |
|       /* MSB: shift right required to get last pixel */
 | |
|    mask = (1U << ipd) - 1U;
 | |
|       /* Mask to extract a single pixel from the low bits of a byte */
 | |
|    opd >>= 3;
 | |
|       /* Output pixel size in bytes */
 | |
|    s = *--sp;
 | |
|       /* The first byte; the last byte of the input row */
 | |
| 
 | |
|    for (;;)
 | |
|    {
 | |
|       png_const_bytep opixel = (((s >> shift) & mask)+1U) * opd + tr->cache.b8;
 | |
|          /* Points to the byte after last byte of the output value */
 | |
|       unsigned int i;
 | |
| 
 | |
|       for (i=0; i<opd; ++i)
 | |
|          *--dp = *--opixel;
 | |
| 
 | |
|       if (dp <= ep)
 | |
|          break;
 | |
| 
 | |
|       shift += ipd; /* To find shift for *previous* pixel */
 | |
| 
 | |
|       if (shift == 8U)
 | |
|          s = *--sp, shift = 0U/*right-most pixel*/;
 | |
|    }
 | |
| 
 | |
|    debug(dp == ep && shift == 8U-ipd && sp == tc->sp);
 | |
|    tc->sp = ep; /* start of row, safe even if the above fails */
 | |
| }
 | |
| 
 | |
| #define do_transform_cache(ipd,opd)\
 | |
| static void \
 | |
| do_transform_cache_##ipd##_##opd(png_transformp *tr, png_transform_controlp tc)\
 | |
| {\
 | |
|    do_transform_cache_(tr, tc, ipd, opd);\
 | |
| }
 | |
| 
 | |
| #define TCLOW(opd)\
 | |
| do_transform_cache(1,opd)\
 | |
| do_transform_cache(2,opd)\
 | |
| do_transform_cache(4,opd)
 | |
| 
 | |
| TCLOW(8)
 | |
| TCLOW(16)
 | |
| TCLOW(24)
 | |
| TCLOW(32)
 | |
| TCLOW(48)
 | |
| TCLOW(64)
 | |
| 
 | |
| #undef TCLOW
 | |
| #undef do_transform_cache
 | |
| 
 | |
| static void
 | |
| do_transform_cache_8_(png_transformp *trIn, png_transform_controlp tc,
 | |
|    unsigned int opd)
 | |
|    /* This is the 8-bit input implementation. */
 | |
| {
 | |
|    png_transform_cache *tr =
 | |
|       png_transform_cache_cast(*trIn, transform_cache_size(8, opd));
 | |
| 
 | |
|    png_bytep dp = png_voidcast(png_bytep, tc->dp);
 | |
|    png_const_bytep ep = dp;
 | |
|    png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp);
 | |
| 
 | |
|    sp += PNG_TC_ROWBYTES(*tc); /* One byte beyond the end */
 | |
| 
 | |
|    png_transform_control_cp(tc, &tr->tc);
 | |
|    dp += PNG_TC_ROWBYTES(*tc);
 | |
| 
 | |
|    opd >>= 3; /* Output pixel size in bytes */
 | |
|    do
 | |
|    {
 | |
|       png_const_bytep opixel = (*--sp + 1U) * opd + tr->cache.b8;
 | |
|          /* Points to the byte after last byte of the output value */
 | |
|       unsigned int i;
 | |
| 
 | |
|       for (i=0; i<opd; ++i)
 | |
|          *--dp = *--opixel;
 | |
|    }
 | |
|    while (dp > ep);
 | |
| 
 | |
|    debug(dp == ep && sp == tc->sp);
 | |
|    tc->sp = ep; /* start of row, safe even if the above fails */
 | |
| }
 | |
| 
 | |
| #define do_transform_cache(opd)\
 | |
| static void \
 | |
| do_transform_cache_8_##opd(png_transformp *tr, png_transform_controlp tc)\
 | |
| {\
 | |
|    do_transform_cache_8_(tr, tc, opd);\
 | |
| }
 | |
| 
 | |
| /* The 8-bit to 8-bit case uses the byte transform code */
 | |
| do_transform_cache(16)
 | |
| do_transform_cache(24)
 | |
| do_transform_cache(32)
 | |
| do_transform_cache(48)
 | |
| do_transform_cache(64)
 | |
| 
 | |
| #undef do_transform_cache
 | |
| 
 | |
| #define do_transform_cache(ipd,opd) do_transform_cache_##ipd##_##opd
 | |
| 
 | |
| #undef png_ptr
 | |
| 
 | |
| typedef struct
 | |
| {
 | |
|    png_transformp *start;
 | |
|       /* This is a pointer to the pointer to the start of the list being cached,
 | |
|        * i.e. *start is the first transform in the list.
 | |
|        */
 | |
|    png_transform_control tstart;
 | |
|       /* This is the transform control at the start; i.e. before (*start)->fn is
 | |
|        * called.  Note that for palette data it will contain the original
 | |
|        * palette format/bit-depth, not that passed to (*start)->fn which will
 | |
|        * represent the palette.
 | |
|        */
 | |
|    png_transformp *end;
 | |
|    png_transform_control tend;
 | |
|       /* The same data from the end of the run to be cached, i.e. after the
 | |
|        * function of the transform which *contains* '*end' (end points to
 | |
|        * tr->next).
 | |
|        */
 | |
| }  png_cache_params, *png_cache_paramsp;
 | |
| 
 | |
| static void
 | |
| init_caching(png_structp png_ptr, png_cache_paramsp cp)
 | |
|    /* Given an already initialized cp->tend turn on caching if appropriate. */
 | |
| {
 | |
|    /* Handle the colormap case, where a cache is always required: */
 | |
|    if (cp->tend.format & PNG_FORMAT_FLAG_COLORMAP)
 | |
|    {
 | |
|       /* This turns starts the palette caching with the next transform: */
 | |
|       cp->tend.palette = cp->tend.caching = 1U;
 | |
|       cp->tend.transparent_alpha = png_ptr->transparent_palette;
 | |
|       cp->tend.format = PNG_FORMAT_FLAG_COLOR;
 | |
| #     ifdef PNG_READ_tRNS_SUPPORTED
 | |
|          if (png_ptr->num_trans > 0 && !(cp->tend.invalid_info & PNG_INFO_tRNS))
 | |
|          {
 | |
|             cp->tend.format |= PNG_FORMAT_FLAG_ALPHA;
 | |
|          }
 | |
| #     endif /* READ_tRNS */
 | |
|       cp->tend.bit_depth = 8U;
 | |
|    }
 | |
| 
 | |
|    else if (PNG_TC_PIXEL_DEPTH(cp->tend) <= 8)
 | |
|    {
 | |
|       /* Cacheable pixel transforms; the pixel is less than 8 bits in size so
 | |
|        * the cache makes sense.
 | |
|        *
 | |
|        * TODO: check the cost estimate and the image size to avoid expensive
 | |
|        * caches of very small images.
 | |
|        */
 | |
|       cp->tend.caching = 1U;
 | |
|    }
 | |
| 
 | |
|    /* TODO: handle handle 8-bit GA/RGB/RGBA */
 | |
| }
 | |
| 
 | |
| static void
 | |
| add_cache_transform(png_structp png_ptr, unsigned int order,
 | |
|    png_transform_fn fn, png_cache_paramsp cp,
 | |
|    png_const_bytep cache, unsigned int size)
 | |
|    /* Add a transform from the input format cp->tstart to the output format
 | |
|     * stored in cp->tend.
 | |
|     */
 | |
| {
 | |
|    affirm(size <= 2048U); /* 256 8-byte pixels at most */
 | |
|    {
 | |
|       png_transform_cache *tr = png_transform_cache_cast(
 | |
|          png_add_transform(png_ptr, png_transform_cache_size(size), fn, order),
 | |
|             size);
 | |
| 
 | |
|       /* This must have replaced the transform in *cp->start: */
 | |
|       affirm(&tr->tr == *cp->start);
 | |
| 
 | |
|       /* Fill in the respective members: */
 | |
|       tr->tc = cp->tend;
 | |
|       memcpy(tr->cache.b8, cache, size);
 | |
| 
 | |
|       /* Skip this transform, because the calling routine has already executed
 | |
|        * the cache (it could be executed again, just to verify that it works;
 | |
|        * cp->tstart should be correct.)
 | |
|        */
 | |
|       cp->start = &tr->tr.next;
 | |
|    }
 | |
| }
 | |
| 
 | |
| static unsigned int
 | |
| setup_palette_cache(png_structp png_ptr, png_byte cache[8*256])
 | |
|    /* This returns the number of entries in the cache; the width */
 | |
| {
 | |
|    const unsigned int num_palette = png_ptr->num_palette;
 | |
| #  ifdef PNG_READ_tRNS_SUPPORTED
 | |
|       unsigned int num_trans = png_ptr->num_trans;
 | |
| #  endif /* READ_tRNS */
 | |
|    const png_colorp  palette = png_ptr->palette;
 | |
|    png_bytep p;
 | |
|    unsigned int i;
 | |
| #  ifdef PNG_READ_tRNS_SUPPORTED
 | |
|       const png_bytep trans_alpha = png_ptr->trans_alpha;
 | |
| #  endif /* READ_tRNS */
 | |
| 
 | |
|    for (i=0, p=cache; i<num_palette; ++i)
 | |
|    {
 | |
|       *p++ = palette[i].red;
 | |
|       *p++ = palette[i].green;
 | |
|       *p++ = palette[i].blue;
 | |
| #     ifdef PNG_READ_tRNS_SUPPORTED
 | |
|          if (num_trans > 0)
 | |
|          {
 | |
|             if (i < num_trans)
 | |
|                *p++ = trans_alpha[i];
 | |
| 
 | |
|             else
 | |
|                *p++ = 0xFFU;
 | |
|          }
 | |
| #     endif /* READ_tRNS */
 | |
|    }
 | |
| 
 | |
|    return num_palette;
 | |
| }
 | |
| 
 | |
| static void
 | |
| png_remove_PLTE_and_tRNS(png_structrp png_ptr)
 | |
| {
 | |
|    if (png_ptr->palette != NULL)
 | |
|       png_free(png_ptr, png_ptr->palette);
 | |
| 
 | |
|    png_ptr->palette = NULL;
 | |
|    png_ptr->num_palette = 0;
 | |
| 
 | |
| #  ifdef PNG_READ_tRNS_SUPPORTED
 | |
|       if (png_ptr->trans_alpha != NULL)
 | |
|          png_free(png_ptr, png_ptr->trans_alpha);
 | |
| 
 | |
|       png_ptr->trans_alpha = NULL;
 | |
|       png_ptr->num_trans = 0;
 | |
| #  endif /* READ_tRNS */
 | |
| }
 | |
| 
 | |
| static void
 | |
| update_palette(png_structp png_ptr, png_cache_paramsp cp,
 | |
|    unsigned int max_depth)
 | |
| {
 | |
|    union
 | |
|    {
 | |
|       png_uint_32 u32[1];
 | |
|       png_uint_16 u16[1];    /* For alignment */
 | |
|       png_byte    b8[8*256]; /* For 16-bit RGBA intermediate */
 | |
|    }  cache;
 | |
| 
 | |
|    /* The caller only calls this function if the initial transform control had
 | |
|     * the palette flag set, implying that the original 'format' was a COLORMAP
 | |
|     * one.  Also this can only happen (at present) when starting the transform
 | |
|     * list, so:
 | |
|     */
 | |
|    affirm((cp->tstart.format & PNG_FORMAT_FLAG_COLORMAP) != 0); /* required */
 | |
|    debug(cp->start == &png_ptr->transform_list); /* should be harmless */
 | |
| 
 | |
|    /* Run the whole of the given list on the palette data.  PNG_TC_INIT_FINAL
 | |
|     * has already been run; this is a full run (with init == 0).
 | |
|     */
 | |
|    {
 | |
|       unsigned int check_depth;
 | |
|       only_deb(png_transform_control orig = cp->tend;)
 | |
| 
 | |
|       cp->tend = cp->tstart;
 | |
|       init_caching(png_ptr, cp);
 | |
|       /* And set up tend to actually work out the palette: */
 | |
|       cp->tend.init = 0U;
 | |
|       cp->tend.width = setup_palette_cache(png_ptr, cache.b8);
 | |
|       cp->tend.sp = cache.b8;
 | |
|       cp->tend.dp = cache.b8;
 | |
| 
 | |
|       check_depth =
 | |
|          png_run_this_transform_list_forwards(&cp->tend, cp->start, *cp->end);
 | |
| 
 | |
|       /* If we get here these two things must be true or there are been some
 | |
|        * buggy difference of opinion between the INIT code and the actual run:
 | |
|        */
 | |
|       affirm(check_depth == max_depth && cp->tend.palette);
 | |
| 
 | |
|       /* This should match the passed in final format obtained before, this
 | |
|        * debug statement detects discrepancies between the init code and the
 | |
|        * run code:
 | |
|        */
 | |
|       debug(png_transform_control_eq(&cp->tend, &orig));
 | |
| 
 | |
|       /* Also, expect the palette to still be valid: */
 | |
|       debug((cp->tend.invalid_info & PNG_INFO_PLTE) == 0);
 | |
|    }
 | |
| 
 | |
|    /* The result must be compatible with a PNG palette with respect to bit
 | |
|     * depth; specifically the expand-16 transform has no effect on palette data.
 | |
|     *
 | |
|     * The colormap setting must not have been re-introduced here either; there
 | |
|     * may be some quantize interactions here, neither can unexpected flags be
 | |
|     * handled; just COLOR and ALPHA.
 | |
|     */
 | |
|    affirm(cp->tend.bit_depth == 8 &&
 | |
|           (cp->tend.format & PNG_FORMAT_FLAG_COLORMAP) == 0);
 | |
| 
 | |
|    /* Remove all the transforms between start(inclusive) and end(exclusive);
 | |
|     * they have been processed.  The effect they had on the transform control
 | |
|     * is irrelevant because the caller re-instates the settings from tstart.
 | |
|     */
 | |
|    {
 | |
|       png_transformp list = *cp->start; /* list to free */
 | |
| 
 | |
|       *cp->start = *cp->end; /* part of list not to be freed */
 | |
|       *cp->end = NULL; /* terminate the list to be freed */
 | |
|       cp->end = cp->start; /* else cp->end points to the end of the list! */
 | |
| 
 | |
|       png_transform_free(png_ptr, &list);
 | |
|    }
 | |
| 
 | |
|    /* Adjust the PNG palette and, if required, the tRNS entries.  Note that
 | |
|     * if the transforms stripped the alpha channel from the palette num_trans
 | |
|     * will get set to 0 here.
 | |
|     *
 | |
|     * This is the point where the gamma gets frozen too.  The alternative
 | |
|     * design is to pass palette, tRNS and gamma up the transform chain, but
 | |
|     * that doesn't work because the palette change would, apparently, have to
 | |
|     * be repeated on each row.  This seems simpler at the cost of a little
 | |
|     * obscurity; the answer to the question, "Where does the palette get
 | |
|     * updated?", is "Here!"
 | |
|     *
 | |
|     * API CHANGE: (fix): previously the init code would silently overwrite
 | |
|     * the palette information shared with png_info, breaking the API for
 | |
|     * png_read_update_info, which doesn't update the info if it isn't called,
 | |
|     * by changing the palette and maybe tRNS when the first row was read!
 | |
|     *
 | |
|     * NOTE: PNG_FORMAT_FLAG_RANGE is lost at this point, even if the palette
 | |
|     * entries were shifted or inverted.  This could be fixed, but it would
 | |
|     * complicate the libpng API to expose the information.
 | |
|     */
 | |
|    /* Write the transformed palette: */
 | |
|    {
 | |
|       png_colorp palette = png_voidcast(png_colorp, png_calloc(png_ptr,
 | |
|                sizeof (png_color[PNG_MAX_PALETTE_LENGTH])));
 | |
|       png_const_bytep p;
 | |
|       const int is_color = (cp->tend.format & PNG_FORMAT_FLAG_COLOR) != 0;
 | |
|       unsigned int i;
 | |
| #     ifdef PNG_READ_tRNS_SUPPORTED
 | |
|          unsigned int num_trans = 0;
 | |
|          const int do_trans = (cp->tend.format & PNG_FORMAT_FLAG_ALPHA) != 0;
 | |
|          png_byte trans_alpha[PNG_MAX_PALETTE_LENGTH];
 | |
| #     endif /* READ_tRNS */
 | |
| 
 | |
|       memset(palette, 0xFFU, sizeof (png_color[PNG_MAX_PALETTE_LENGTH]));
 | |
|       png_free(png_ptr, png_ptr->palette);
 | |
|       png_ptr->palette = palette;
 | |
| 
 | |
|       for (i=0, p=cache.b8; i<cp->tend.width; ++i)
 | |
|       {
 | |
|          if (is_color)
 | |
|          {
 | |
|             palette[i].red = *p++;
 | |
|             palette[i].green = *p++;
 | |
|             palette[i].blue = *p++;
 | |
|          }
 | |
| 
 | |
|          else
 | |
|             palette[i].blue = palette[i].green = palette[i].red = *p++;
 | |
| 
 | |
| #        ifdef PNG_READ_tRNS_SUPPORTED
 | |
|             if (do_trans)
 | |
|             {
 | |
|                png_byte a = *p++;
 | |
|                trans_alpha[i] = a;
 | |
| 
 | |
|                /* Strip opaque entries from the end: */
 | |
|                if (a < 0xFFU)
 | |
|                   num_trans = i+1;
 | |
|             }
 | |
| #        endif /* READ_tRNS */
 | |
|       }
 | |
| 
 | |
|       png_ptr->num_palette = png_check_bits(png_ptr, cp->tend.width, 9);
 | |
| 
 | |
| #     ifdef PNG_READ_tRNS_SUPPORTED
 | |
|          if (num_trans > 0)
 | |
|          {
 | |
|             png_bytep tRNS = png_voidcast(png_bytep, png_malloc(png_ptr,
 | |
|                      PNG_MAX_PALETTE_LENGTH));
 | |
| 
 | |
|             memset(tRNS, 0xFFU, PNG_MAX_PALETTE_LENGTH);
 | |
| 
 | |
|             if (png_ptr->trans_alpha != NULL)
 | |
|                png_free(png_ptr, png_ptr->trans_alpha);
 | |
| 
 | |
|             png_ptr->trans_alpha = tRNS;
 | |
| 
 | |
|             memcpy(tRNS, trans_alpha, num_trans);
 | |
|             png_ptr->num_trans = png_check_bits(png_ptr, num_trans, 9);
 | |
|          }
 | |
| #     endif /* READ_tRNS */
 | |
|    }
 | |
| 
 | |
|    /* NOTE: the caller sets cp->start to cp->end and cp->tend to cp->tstart,
 | |
|     * this causes processing to continue with the palette format and the
 | |
|     * first unprocessed transform.  The reset of the transform control loses the
 | |
|     * gamma information as well, of course, as any information about the palette
 | |
|     * and tRNS changes (such as the RANGE flags).
 | |
|     */
 | |
| }
 | |
| 
 | |
| /* These structure and the save/restore routines that follow it exist to save
 | |
|  * data from a png_transform_control that is specific to the sample encoding of
 | |
|  * the PNG data, rather than the row format itself.
 | |
|  */
 | |
| typedef struct
 | |
| {
 | |
| #  ifdef PNG_READ_GAMMA_SUPPORTED
 | |
|       png_fixed_point gamma;
 | |
| #  endif
 | |
|    png_byte           sBIT_R;
 | |
|    png_byte           sBIT_G;
 | |
|    png_byte           sBIT_B;
 | |
|    png_byte           sBIT_A;       /* Signnificant bits in the row channels. */
 | |
|    unsigned int       invalid_info; /* PNG_INFO_* for invalidated chunks */
 | |
| } png_tc_channel_data;
 | |
| 
 | |
| static void
 | |
| save_cp_channel_data(png_tc_channel_data *save, png_const_transform_controlp tc)
 | |
| {
 | |
| #  ifdef PNG_READ_GAMMA_SUPPORTED
 | |
|       save->gamma = tc->gamma;
 | |
| #  endif /* READ_GAMMA */
 | |
| 
 | |
|    /* The sBIT information and the list of invalidated chunks must also be
 | |
|     * preserved:
 | |
|     */
 | |
|    save->sBIT_R = tc->sBIT_R;
 | |
|    save->sBIT_G = tc->sBIT_G;
 | |
|    save->sBIT_B = tc->sBIT_B;
 | |
|    save->sBIT_A = tc->sBIT_A;
 | |
|    save->invalid_info = tc->invalid_info;
 | |
| }
 | |
| 
 | |
| static void
 | |
| restore_cp_channel_data(png_transform_controlp tc,
 | |
|       const png_tc_channel_data *save)
 | |
|    /* Reverse the above */
 | |
| {
 | |
| #  ifdef PNG_READ_GAMMA_SUPPORTED
 | |
|       tc->gamma = save->gamma;
 | |
| #  endif /* READ_GAMMA */
 | |
| 
 | |
|    tc->sBIT_R = save->sBIT_R;
 | |
|    tc->sBIT_G = save->sBIT_G;
 | |
|    tc->sBIT_B = save->sBIT_B;
 | |
|    tc->sBIT_A = save->sBIT_A;
 | |
|    tc->invalid_info = save->invalid_info;
 | |
| }
 | |
| 
 | |
| static void
 | |
| make_cache(png_structp png_ptr, png_cache_paramsp cp, unsigned int max_depth)
 | |
| {
 | |
|    /* At present the cache is just a byte lookup table.  We need the original
 | |
|     * pixel depth to work out how big the working buffer needs to be.
 | |
|     */
 | |
|    const unsigned int ipd = PNG_TC_PIXEL_DEPTH(cp->tstart);
 | |
|    const unsigned int opd = PNG_TC_PIXEL_DEPTH(cp->tend);
 | |
|    unsigned int order; /* records position of start transform */
 | |
|    unsigned int width; /* width of cache in pixels */
 | |
|    png_tc_channel_data save; /* Record of the final channel info */
 | |
|    union
 | |
|    {
 | |
|       png_uint_32 u32[1];
 | |
|       png_uint_16 u16[1];    /* For alignment */
 | |
|       png_byte    b8[8*256]; /* For 16-bit RGBA */
 | |
|    }  cache;
 | |
| 
 | |
|    debug(cp->tend.init == PNG_TC_INIT_FINAL);
 | |
|    affirm(opd <= 64 && max_depth <= 64); /* or the cache is not big enough */
 | |
|    affirm(ipd == opd || (opd & 0x7U) == 0);
 | |
| 
 | |
|    if ((cp->tstart.format & PNG_FORMAT_FLAG_COLORMAP) != 0)
 | |
|       width = setup_palette_cache(png_ptr, cache.b8);
 | |
| 
 | |
|    else switch (ipd)
 | |
|    {
 | |
|       /* The input to the cache is the full range of possible pixel values: */
 | |
|       case 1:
 | |
|          /* 2 1-bit pixels, MSB first */
 | |
|          cache.b8[0] = 0x40U;
 | |
|          width = 2;
 | |
|          break;
 | |
| 
 | |
|       case 2:
 | |
|          /* 4 2-bit pixels, MSB first */
 | |
|          cache.b8[0] = 0x1BU;
 | |
|          width = 4;
 | |
|          break;
 | |
| 
 | |
|       case 4:
 | |
|          /* 16 4-bit pixels, MSB first */
 | |
|          cache.b8[0] = 0x01U;
 | |
|          cache.b8[1] = 0x23U;
 | |
|          cache.b8[2] = 0x45U;
 | |
|          cache.b8[3] = 0x67U;
 | |
|          cache.b8[4] = 0x89U;
 | |
|          cache.b8[5] = 0xABU;
 | |
|          cache.b8[6] = 0xCDU;
 | |
|          cache.b8[7] = 0xEFU;
 | |
|          width = 16;
 | |
|          break;
 | |
| 
 | |
|       case 8:
 | |
|          /* 256 8-bit pixels */
 | |
|          {
 | |
|             unsigned int i;
 | |
| 
 | |
|             for (i=0; i<256; ++i)
 | |
|                cache.b8[i] = PNG_BYTE(i);
 | |
|          }
 | |
|          width = 256;
 | |
|          break;
 | |
| 
 | |
|       default:
 | |
|          impossible("cache input bit depth");
 | |
|    }
 | |
| 
 | |
|    /* Reset the transform control to run the transforms on this data, but save
 | |
|     * the channel info because the row processing functions do not always
 | |
|     * write it.
 | |
|     */
 | |
|    save_cp_channel_data(&save, &cp->tend);
 | |
|    cp->tend = cp->tstart;
 | |
|    init_caching(png_ptr, cp);
 | |
|    /* And set tend to work out the result of transforming each possible pixel
 | |
|     * value:
 | |
|     */
 | |
|    cp->tend.init = 0U;
 | |
|    cp->tend.width = width;
 | |
|    cp->tend.sp = cache.b8;
 | |
|    cp->tend.dp = cache.b8;
 | |
| 
 | |
|    {
 | |
|       unsigned int check_depth =
 | |
|          png_run_this_transform_list_forwards(&cp->tend, cp->start, *cp->end);
 | |
| 
 | |
|       /* This must not change: */
 | |
|       affirm(PNG_TC_PIXEL_DEPTH(cp->tend) == opd && check_depth == max_depth);
 | |
|    }
 | |
| 
 | |
|    /* Restore the potentially lost channel data. */
 | |
|    restore_cp_channel_data(&cp->tend, &save);
 | |
| 
 | |
|    /* This is all the information required to cache the set of transforms
 | |
|     * between 'start' and 'end'.  We take the transformed pixels and make a
 | |
|     * cache transform of them.  The cache transform skips the work, transforms
 | |
|     * the row, and sets the tranform_control to (a copy of) cp->tend.
 | |
|     *
 | |
|     * Remove all the transforms between start(inclusive) and end(exclusive);
 | |
|     * they have been processed.  The effect they had on the transform control
 | |
|     * is irrelevant because the caller re-instates the settings from tstart.
 | |
|     */
 | |
|    {
 | |
|       png_transformp list = *cp->start; /* list to free */
 | |
| 
 | |
|       *cp->start = *cp->end; /* part of list not to be freed */
 | |
|       *cp->end = NULL; /* terminate the list to be freed */
 | |
|       cp->end = NULL; /* reset below */
 | |
| 
 | |
|       order = list->order; /* used below when adding the cache transform */
 | |
|       png_transform_free(png_ptr, &list);
 | |
|    }
 | |
| 
 | |
|    /* Make the required cache, as enumerated above there are 22 possibilities,
 | |
|     * this selects between them, fixes up the cache for the 'byte' cases (where
 | |
|     * multiple pixels can be handled byte-by-byte) and selects the correct
 | |
|     * transform function.
 | |
|     */
 | |
|    if (ipd == opd)
 | |
|    {
 | |
|       /* We already know that ipd is <= 8 bits, so we can expand this case to
 | |
|        * the byte transform.  The complexity is that for ipd < 8 bits we only
 | |
|        * have information for individual pixel values and these may be
 | |
|        * pixel-swapped within the byte.
 | |
|        */
 | |
|       if (ipd < 8)
 | |
|       {
 | |
|          const int lsb = (cp->tend.format & PNG_FORMAT_FLAG_SWAPPED) != 0;
 | |
|          unsigned int ishift, b;
 | |
|          png_byte bcache[256];
 | |
| 
 | |
|          switch (ipd)
 | |
|          {
 | |
|             case 1: ishift = 3U; break;
 | |
|             case 2: ishift = 2U; break;
 | |
|             case 4: ishift = 1U; break;
 | |
|             default: impossible("ipd");
 | |
|          }
 | |
| 
 | |
|          /* Work out the right answer for each byte of pixels: */
 | |
|          for (b=0U; b<256U; ++b)
 | |
|          {
 | |
|             unsigned int o = 0U; /* output byte */
 | |
|             unsigned int p = 8U; /* right shift to find input pixel */
 | |
| 
 | |
|             do
 | |
|             {
 | |
|                unsigned int q = ((1U<<ipd)-1U) & (b >> (p-=ipd));
 | |
|                   /* The input pixel.  For a palette this value might be outside
 | |
|                    * the range of palette indices, in which case simply insert
 | |
|                    * '0':
 | |
|                    */
 | |
|                if (q < width)
 | |
|                {
 | |
|                   unsigned int r = cache.b8[q >> ishift];
 | |
|                   r >>= ((lsb ? q : ~q) & ((1U<<ishift)-1U)) << (3U-ishift);
 | |
|                   r &= ((1U<<ipd)-1U);
 | |
|                   o |= r << (lsb ? (8U-ipd)-p : p);
 | |
|                }
 | |
| 
 | |
|                else
 | |
|                {
 | |
|                   UNTESTED
 | |
|                }
 | |
|             }
 | |
|             while (p != 0U);
 | |
| 
 | |
|             bcache[b] = png_check_byte(png_ptr, o);
 | |
|          }
 | |
| 
 | |
|          /* This is a byte transform, with the optional check-for-invalid-index
 | |
|           * functionality.
 | |
|           */
 | |
|          add_cache_transform(png_ptr, order, do_transform_cache_byte, cp,
 | |
|             bcache, 256U);
 | |
|       }
 | |
| 
 | |
|       else /* ipd == 8 */
 | |
|          add_cache_transform(png_ptr, order, do_transform_cache_byte, cp,
 | |
|             cache.b8, 256U);
 | |
|    }
 | |
| 
 | |
|    else
 | |
|    {
 | |
|       /* opd is a whole number of bytes, ipd is 1, 2, 4 or 8 and not equal to
 | |
|        * opd.
 | |
|        */
 | |
|       png_transform_fn fn;
 | |
| 
 | |
| #     define C(ipd,opd) ((ipd) + 8*(opd))
 | |
|       switch (C(ipd,opd))
 | |
|       {
 | |
| #        define CASE(ipd,opd)\
 | |
|             case C(ipd,opd): fn = do_transform_cache(ipd,opd); break
 | |
| 
 | |
|             CASE(1,8);
 | |
|             CASE(2,8);
 | |
|             CASE(4,8);
 | |
|             /* No 8,8 */
 | |
| 
 | |
| #        define CASES(opd)\
 | |
|             CASE(1,opd);\
 | |
|             CASE(2,opd);\
 | |
|             CASE(4,opd);\
 | |
|             CASE(8,opd)
 | |
| 
 | |
|             CASES(16);
 | |
|             CASES(24);
 | |
|             CASES(32);
 | |
|             CASES(48);
 | |
|             CASES(64);
 | |
| #        undef CASES
 | |
| #        undef CASE
 | |
| 
 | |
|          default:
 | |
|             impossible("cache bit depths");
 | |
|       }
 | |
| #     undef C
 | |
| 
 | |
|       /* In the event that the cache is not the full width implied by ipd zero
 | |
|        * the remaining bytes for security; otherwise they get copied into the
 | |
|        * cache transform and might get used.  (Specifically if there is an
 | |
|        * out-of-range palette index they do get used!)
 | |
|        */
 | |
|       {
 | |
|          unsigned int size = transform_cache_size(ipd, opd);
 | |
|          png_alloc_size_t cachebytes = PNG_TC_ROWBYTES(cp->tend);
 | |
| 
 | |
|          affirm(cachebytes <= sizeof cache.b8);
 | |
| 
 | |
|          if (cachebytes < size)
 | |
|             memset(cache.b8+cachebytes, 0, size - cachebytes);
 | |
| 
 | |
|          add_cache_transform(png_ptr, order, fn, cp, cache.b8, size);
 | |
|       }
 | |
|    }
 | |
| 
 | |
|    /* Because a transform was inserted cp->end needs to be set to the new
 | |
|     * pointer to the original end.  add_cache_transform sets cp->start to this,
 | |
|     * so:
 | |
|     */
 | |
|    cp->end = cp->start;
 | |
| 
 | |
|    /* This invalidates the palette if that is what was cached because the
 | |
|     * palette and, if present, tRNS chunk did not get updated above.
 | |
|     */
 | |
|    if (cp->tstart.palette)
 | |
|       png_remove_PLTE_and_tRNS(png_ptr);
 | |
| }
 | |
| 
 | |
| static void restore_cp(png_cache_paramsp cp)
 | |
| {
 | |
|    /* A utility to restore cp->tstart by copying it into cp->tend.  This is used
 | |
|     * both in the palette case when restoring the transform control for the
 | |
|     * indexed data and in the case where no transforms were cached.  It
 | |
|     * preserves the color-channel-specific data from cp->tend because in either
 | |
|     * case it is possible for this data to be modified without preserving any
 | |
|     * transforms, e.g. if only the gamma is changed but no gamma transform is
 | |
|     * retained because the change was not significant.
 | |
|     */
 | |
|    png_tc_channel_data save;
 | |
| 
 | |
|    save_cp_channel_data(&save, &cp->tend);
 | |
|    cp->tend = cp->tstart;
 | |
|    restore_cp_channel_data(&cp->tend, &save);
 | |
| }
 | |
| 
 | |
| static void
 | |
| handle_cache(png_structp png_ptr, png_cache_paramsp cp, unsigned int max_depth)
 | |
| {
 | |
|    /* There is nothing to do if there are no transforms between 'start' and
 | |
|     * 'end':
 | |
|     */
 | |
|    if (cp->start != cp->end)
 | |
|    {
 | |
|       only_deb(png_transformp tr_check = *cp->end;)
 | |
| 
 | |
|       /* libpng doesn't currently implement any pixel size of more than 64 bits
 | |
|        * so:
 | |
|        */
 | |
|       affirm(max_depth <= 64);
 | |
| 
 | |
|       if (cp->tend.palette)
 | |
|       {
 | |
|          /* The transforms being cached apply to the palette, the following
 | |
|           * transforms will apply to the original index data and the transformed
 | |
|           * data must be used to update the palette:
 | |
|           */
 | |
|          if (cp->tend.init == PNG_TC_INIT_FINAL)
 | |
|             update_palette(png_ptr, cp, max_depth);
 | |
| 
 | |
|          cp->start = cp->end;
 | |
|          restore_cp(cp); /* reset to palette data */
 | |
|       }
 | |
| 
 | |
|       else
 | |
|       {
 | |
|          /* Continue with the transform control in cp.tend; even if there was
 | |
|           * palette data in cp.tstart it has been expanded.
 | |
|           */
 | |
|          if (cp->tend.init == PNG_TC_INIT_FINAL)
 | |
|             make_cache(png_ptr, cp, max_depth);
 | |
| 
 | |
|          cp->tstart = cp->tend; /* keep current context */
 | |
|       }
 | |
| 
 | |
|       debug(tr_check == *cp->end);
 | |
|    }
 | |
| 
 | |
|    else /* no transforms cached */
 | |
|       restore_cp(cp); /* removes any palette caching info */
 | |
| }
 | |
| 
 | |
| #ifdef PNG_READ_tRNS_SUPPORTED
 | |
| static void
 | |
| check_tRNS_for_alpha(png_structrp png_ptr)
 | |
| {
 | |
|    unsigned int num_trans = png_ptr->num_trans;
 | |
| 
 | |
|    debug(png_ptr->color_type == PNG_COLOR_TYPE_PALETTE);
 | |
| 
 | |
|    while (num_trans > 0)
 | |
|    {
 | |
|       {
 | |
|          const png_byte trans = png_ptr->trans_alpha[--num_trans];
 | |
| 
 | |
|          if (trans == 0xFFU)
 | |
|             continue;
 | |
| 
 | |
|          if (trans > 0U)
 | |
|             return; /* Palette has at least one entry >0, <0xff */
 | |
|       }
 | |
| 
 | |
|       /* There is some point to the tRNS chunk; it has a non-opaque entry, this
 | |
|        * code could truncate it but there is no obvious performance advantage to
 | |
|        * doing this.
 | |
|        */
 | |
|       while (num_trans > 0)
 | |
|       {
 | |
|          const png_byte trans = png_ptr->trans_alpha[--num_trans];
 | |
| 
 | |
|          if (trans > 0U && trans < 0xFFU)
 | |
|             return;
 | |
|       }
 | |
| 
 | |
|       /* Here if the above did not find an entry >0 && <0xFFU but did find a
 | |
|        * transparent entry (0u).  Record this.
 | |
|        */
 | |
|       png_ptr->transparent_palette = 1U;
 | |
|       return;
 | |
|    }
 | |
| 
 | |
|    /* All entries opaque; remove the tRNS data: */
 | |
|    png_ptr->num_trans = 0U;
 | |
| }
 | |
| #endif /* READ_tRNS */
 | |
| 
 | |
| unsigned int /* PRIVATE */
 | |
| png_read_init_transform_mech(png_structp png_ptr, png_transform_controlp tc)
 | |
|    /* This is called once for each init stage (PNG_TC_INIT_FORMAT and
 | |
|     * PNG_TC_INIT_FINAL) to run the transform list forwards, returning the
 | |
|     * maximum depth required to process the row.  It handles caching of the
 | |
|     * transforms and the processing of the palette for color-mapped PNG data.
 | |
|     */
 | |
| {
 | |
|    png_transformp *list = &png_ptr->transform_list;
 | |
|    unsigned int max_depth;
 | |
|    png_cache_params cp;
 | |
| 
 | |
|    /* PNG color-mapped data must be handled here so that the palette is updated
 | |
|     * correctly.  png_set_palette_to_rgb causes the palette flag to be removed
 | |
|     * from the transform control but does no other change.  png_set_quantize
 | |
|     * causes 8-bit RGB, RGBA or palette data to be converted into palette
 | |
|     * indices, setting the palette flag.
 | |
|     */
 | |
| #  ifdef PNG_READ_tRNS_SUPPORTED
 | |
|       /* This happens once at the start to find out if the tRNS chunk consisted
 | |
|        * entirely of opaque (255) and/or transparent (0) entries.
 | |
|        */
 | |
|       if (tc->init == PNG_TC_INIT_FORMAT &&
 | |
|           png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
 | |
|          check_tRNS_for_alpha(png_ptr);
 | |
| #  endif /* READ_tRNS */
 | |
|    cp.end = cp.start = list;
 | |
|    cp.tend = cp.tstart = *tc;
 | |
|    init_caching(png_ptr, &cp);
 | |
|    max_depth = PNG_TC_PIXEL_DEPTH(cp.tend);
 | |
| 
 | |
|    while (*cp.end != NULL)
 | |
|    {
 | |
|       png_transformp tr = *cp.end;
 | |
| 
 | |
|       /* The user transform cannot be cached. */
 | |
|       if (tr->order >= PNG_TR_USER)
 | |
|          break;
 | |
| 
 | |
|       /* If the 'palette' flag is set and the next transform has order
 | |
|        * PNG_TR_ENCODING or later cache the results so far and continue with the
 | |
|        * original palette data (cp.tstart).
 | |
|        */
 | |
|       if (cp.tend.palette && tr->order >= PNG_TR_ENCODING)
 | |
|       {
 | |
|          handle_cache(png_ptr, &cp, max_depth);
 | |
| 
 | |
|          /* The cache handling function must maintain cp.end; */
 | |
|          affirm(tr == *cp.end);
 | |
|          max_depth = PNG_TC_PIXEL_DEPTH(cp.tend);
 | |
|       }
 | |
| 
 | |
|       /* Now run the transform list entry: */
 | |
|       if (tr->fn != NULL)
 | |
|       {
 | |
|          tr->fn(cp.end, &cp.tend);
 | |
|          tr = *cp.end; /* in case something was inserted */
 | |
|       }
 | |
| 
 | |
|       if (tr->fn == NULL) /* delete this transform */
 | |
|          png_remove_transform(png_ptr, cp.end);
 | |
| 
 | |
|       else
 | |
|       {
 | |
|          /* Handle the initialization of the maximum pixel depth. */
 | |
|          unsigned int tc_depth = PNG_TC_PIXEL_DEPTH(cp.tend);
 | |
| 
 | |
|          if (tc_depth > max_depth)
 | |
|             max_depth = tc_depth;
 | |
| 
 | |
|          /* Advance to the next transform. */
 | |
|          cp.end = &tr->next;
 | |
|       }
 | |
|    }
 | |
| 
 | |
|    /* At the end if still caching record the cache information (this is common;
 | |
|     * this is generally the case for an expanded palette.)
 | |
|     */
 | |
|    if (cp.tend.caching)
 | |
|    {
 | |
|       png_transformp tr = *cp.end;
 | |
|       handle_cache(png_ptr, &cp, max_depth);
 | |
|       affirm(tr == *cp.end);
 | |
|       max_depth = PNG_TC_PIXEL_DEPTH(cp.tend);
 | |
|    }
 | |
| 
 | |
|    /* At the end run the init on the user transform: */
 | |
|    if (*cp.end != NULL)
 | |
|    {
 | |
|       png_transformp tr = *cp.end;
 | |
|       affirm(tr->order == PNG_TR_USER);
 | |
|       if (tr->fn != NULL)
 | |
|          tr->fn(cp.end, &cp.tend);
 | |
|       /* This cannot insert anything, so: */
 | |
|       affirm(tr == *cp.end && tr->next == NULL);
 | |
| 
 | |
|       if (tr->fn == NULL) /* delete this transform */
 | |
|          png_remove_transform(png_ptr, cp.end);
 | |
| 
 | |
|       else
 | |
|       {
 | |
|          unsigned int tc_depth = PNG_TC_PIXEL_DEPTH(cp.tend);
 | |
| 
 | |
|          if (tc_depth > max_depth)
 | |
|             max_depth = tc_depth;
 | |
|       }
 | |
|    }
 | |
| 
 | |
|    /* And write the input transform control: */
 | |
|    *tc = cp.tend;
 | |
| 
 | |
|    return max_depth;
 | |
| }
 | |
| 
 | |
| /* Modify the info structure to reflect the transformations.  The
 | |
|  * info should be updated so a PNG file could be written with it,
 | |
|  * assuming the transformations result in valid PNG data.
 | |
|  */
 | |
| void /* PRIVATE */
 | |
| png_read_transform_info(png_structrp png_ptr, png_inforp info_ptr)
 | |
| {
 | |
|    png_debug(1, "in png_read_transform_info");
 | |
| 
 | |
|    /* WARNING: this is very basic at present.  It just updates the format
 | |
|     * information.  It should update the palette (and will eventually) as well
 | |
|     * as invalidating chunks that the transforms break.
 | |
|     */
 | |
| #  ifdef PNG_TRANSFORM_MECH_SUPPORTED
 | |
|       info_ptr->format = png_ptr->row_format;
 | |
|       info_ptr->bit_depth = png_ptr->row_bit_depth;
 | |
| #     ifdef PNG_READ_GAMMA_SUPPORTED
 | |
|          /* If an info struct is used with a different png_ptr in a call to
 | |
|           * png_set_gAMA then the png_struct information won't be updated, this
 | |
|           * doesn't matter on write, but don't zap the value in the info on read
 | |
|           * unless it is known:
 | |
|           *
 | |
|           * TODO: review this whole mess.
 | |
|           */
 | |
|          if (png_ptr->row_gamma > 0)
 | |
|             info_ptr->colorspace.gamma = png_ptr->row_gamma;
 | |
| #     endif
 | |
| 
 | |
|       /* Invalidate chunks marked as invalid: */
 | |
| #     ifdef PNG_READ_TRANSFORMS_SUPPORTED
 | |
|          info_ptr->valid &= ~png_ptr->invalid_info;
 | |
| 
 | |
|          /* If the palette or tRNS chunk was changed copy them over to the info
 | |
|           * structure; this may actually re-validate the PLTE or tRNS chunks,
 | |
|           * but only if png_ptr has a new version, otherwise the invalid_info
 | |
|           * settings from above can still invalidate the chunk.
 | |
|           */
 | |
|          if (png_ptr->palette != info_ptr->palette)
 | |
|          {
 | |
|             png_free_data(png_ptr, info_ptr, PNG_FREE_PLTE, 0);
 | |
|             info_ptr->palette = png_ptr->palette;
 | |
|             info_ptr->num_palette = png_ptr->num_palette;
 | |
|             if (info_ptr->palette != NULL && info_ptr->num_palette > 0)
 | |
|                info_ptr->valid |= PNG_INFO_PLTE;
 | |
| 
 | |
| #           ifdef PNG_READ_tRNS
 | |
|                /* ONLY do this if the palette was changed above because, in
 | |
|                 * fact, the tRNS data is not shared (yes, this is inconsistent,
 | |
|                 * perhaps fix it?)
 | |
|                 */
 | |
|                if ((info_ptr->format & PNG_FORMAT_FLAG_COLORMAP) != 0 &&
 | |
|                    png_ptr->trans_alpha != info_ptr->trans_alpha)
 | |
|                {
 | |
|                   png_free_data(png_ptr, info_ptr, PNG_FREE_TRNS, 0);
 | |
|                   /* NOTE: it is shared now! */
 | |
|                   info_ptr->trans_alpha = png_ptr->trans_alpha;
 | |
|                   info_ptr->num_trans = png_ptr->num_trans;
 | |
|                   if (info_ptr->trans_alpha != NULL && info_ptr->num_trans > 0)
 | |
|                      info_ptr->valid |= PNG_INFO_tRNS;
 | |
|                }
 | |
| #           endif /* READ_tRNS */
 | |
|          }
 | |
| #     endif /* READ_TRANSFORMS */
 | |
| #  else /* !TRANSFORM_MECH */
 | |
|       PNG_UNUSED(png_ptr)
 | |
|       PNG_UNUSED(info_ptr)
 | |
| #  endif /* !TRANSFORM_MECH */
 | |
| }
 | |
| #endif /* READ_TRANSFORMS */
 | 
