mirror of
				https://git.code.sf.net/p/libpng/code.git
				synced 2025-07-10 18:04:09 +02:00 
			
		
		
		
	pngvalid fixes and backward compat
This fix is to the PNG_MAX_GAMMA_8 handling and png_set_rgb_to_gray, which had bugs which were likely to expose end cases of rgb-to-gray conversion errors. This might explain some of the machine math dependencies we are seeing (*might*). Signed-off-by: John Bowler <jbowler@acm.org>
This commit is contained in:
		
							parent
							
								
									b0076faf1f
								
							
						
					
					
						commit
						8d93ec2eca
					
				@ -532,7 +532,8 @@ sample(png_const_bytep row, png_byte colour_type, png_byte bit_depth,
 | 
			
		||||
 */
 | 
			
		||||
static void
 | 
			
		||||
pixel_copy(png_bytep toBuffer, png_uint_32 toIndex,
 | 
			
		||||
   png_const_bytep fromBuffer, png_uint_32 fromIndex, unsigned int pixelSize)
 | 
			
		||||
   png_const_bytep fromBuffer, png_uint_32 fromIndex, unsigned int pixelSize,
 | 
			
		||||
   int littleendian)
 | 
			
		||||
{
 | 
			
		||||
   /* Assume we can multiply by 'size' without overflow because we are
 | 
			
		||||
    * just working in a single buffer.
 | 
			
		||||
@ -542,15 +543,25 @@ pixel_copy(png_bytep toBuffer, png_uint_32 toIndex,
 | 
			
		||||
   if (pixelSize < 8) /* Sub-byte */
 | 
			
		||||
   {
 | 
			
		||||
      /* Mask to select the location of the copied pixel: */
 | 
			
		||||
      unsigned int destMask = ((1U<<pixelSize)-1) << (8-pixelSize-(toIndex&7));
 | 
			
		||||
      unsigned int destMask = ((1U<<pixelSize)-1) <<
 | 
			
		||||
         (littleendian ? toIndex&7 : 8-pixelSize-(toIndex&7));
 | 
			
		||||
      /* The following read the entire pixels and clears the extra: */
 | 
			
		||||
      unsigned int destByte = toBuffer[toIndex >> 3] & ~destMask;
 | 
			
		||||
      unsigned int sourceByte = fromBuffer[fromIndex >> 3];
 | 
			
		||||
 | 
			
		||||
      /* Don't rely on << or >> supporting '0' here, just in case: */
 | 
			
		||||
      fromIndex &= 7;
 | 
			
		||||
      if (fromIndex > 0) sourceByte <<= fromIndex;
 | 
			
		||||
      if ((toIndex & 7) > 0) sourceByte >>= toIndex & 7;
 | 
			
		||||
      if (littleendian)
 | 
			
		||||
      {
 | 
			
		||||
         if (fromIndex > 0) sourceByte >>= fromIndex;
 | 
			
		||||
         if ((toIndex & 7) > 0) sourceByte <<= toIndex & 7;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      else
 | 
			
		||||
      {
 | 
			
		||||
         if (fromIndex > 0) sourceByte <<= fromIndex;
 | 
			
		||||
         if ((toIndex & 7) > 0) sourceByte >>= toIndex & 7;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      toBuffer[toIndex >> 3] = (png_byte)(destByte | (sourceByte & destMask));
 | 
			
		||||
   }
 | 
			
		||||
@ -563,7 +574,8 @@ pixel_copy(png_bytep toBuffer, png_uint_32 toIndex,
 | 
			
		||||
 * bytes at the end.
 | 
			
		||||
 */
 | 
			
		||||
static void
 | 
			
		||||
row_copy(png_bytep toBuffer, png_const_bytep fromBuffer, unsigned int bitWidth)
 | 
			
		||||
row_copy(png_bytep toBuffer, png_const_bytep fromBuffer, unsigned int bitWidth,
 | 
			
		||||
      int littleendian)
 | 
			
		||||
{
 | 
			
		||||
   memcpy(toBuffer, fromBuffer, bitWidth >> 3);
 | 
			
		||||
 | 
			
		||||
@ -573,10 +585,10 @@ row_copy(png_bytep toBuffer, png_const_bytep fromBuffer, unsigned int bitWidth)
 | 
			
		||||
 | 
			
		||||
      toBuffer += bitWidth >> 3;
 | 
			
		||||
      fromBuffer += bitWidth >> 3;
 | 
			
		||||
      /* The remaining bits are in the top of the byte, the mask is the bits to
 | 
			
		||||
       * retain.
 | 
			
		||||
       */
 | 
			
		||||
      mask = 0xff >> (bitWidth & 7);
 | 
			
		||||
      if (littleendian)
 | 
			
		||||
         mask = 0xff << (bitWidth & 7);
 | 
			
		||||
      else
 | 
			
		||||
         mask = 0xff >> (bitWidth & 7);
 | 
			
		||||
      *toBuffer = (png_byte)((*toBuffer & mask) | (*fromBuffer & ~mask));
 | 
			
		||||
   }
 | 
			
		||||
}
 | 
			
		||||
@ -3587,7 +3599,7 @@ check_interlace_type(int const interlace_type)
 | 
			
		||||
 */
 | 
			
		||||
static void
 | 
			
		||||
interlace_row(png_bytep buffer, png_const_bytep imageRow,
 | 
			
		||||
   unsigned int pixel_size, png_uint_32 w, int pass)
 | 
			
		||||
   unsigned int pixel_size, png_uint_32 w, int pass, int littleendian)
 | 
			
		||||
{
 | 
			
		||||
   png_uint_32 xin, xout, xstep;
 | 
			
		||||
 | 
			
		||||
@ -3603,7 +3615,7 @@ interlace_row(png_bytep buffer, png_const_bytep imageRow,
 | 
			
		||||
 | 
			
		||||
   for (xout=0; xin<w; xin+=xstep)
 | 
			
		||||
   {
 | 
			
		||||
      pixel_copy(buffer, xout, imageRow, xin, pixel_size);
 | 
			
		||||
      pixel_copy(buffer, xout, imageRow, xin, pixel_size, littleendian);
 | 
			
		||||
      ++xout;
 | 
			
		||||
   }
 | 
			
		||||
}
 | 
			
		||||
@ -3611,7 +3623,7 @@ interlace_row(png_bytep buffer, png_const_bytep imageRow,
 | 
			
		||||
#ifdef PNG_READ_SUPPORTED
 | 
			
		||||
static void
 | 
			
		||||
deinterlace_row(png_bytep buffer, png_const_bytep row,
 | 
			
		||||
   unsigned int pixel_size, png_uint_32 w, int pass)
 | 
			
		||||
   unsigned int pixel_size, png_uint_32 w, int pass, int littleendian)
 | 
			
		||||
{
 | 
			
		||||
   /* The inverse of the above, 'row' is part of row 'y' of the output image,
 | 
			
		||||
    * in 'buffer'.  The image is 'w' wide and this is pass 'pass', distribute
 | 
			
		||||
@ -3625,7 +3637,7 @@ deinterlace_row(png_bytep buffer, png_const_bytep row,
 | 
			
		||||
 | 
			
		||||
   for (xin=0; xout<w; xout+=xstep)
 | 
			
		||||
   {
 | 
			
		||||
      pixel_copy(buffer, xout, row, xin, pixel_size);
 | 
			
		||||
      pixel_copy(buffer, xout, row, xin, pixel_size, littleendian);
 | 
			
		||||
      ++xin;
 | 
			
		||||
   }
 | 
			
		||||
}
 | 
			
		||||
@ -3748,7 +3760,8 @@ make_transform_image(png_store* const ps, png_byte const colour_type,
 | 
			
		||||
                     if (PNG_ROW_IN_INTERLACE_PASS(y, pass) &&
 | 
			
		||||
                         PNG_PASS_COLS(w, pass) > 0)
 | 
			
		||||
                        interlace_row(buffer, buffer,
 | 
			
		||||
                              bit_size(pp, colour_type, bit_depth), w, pass);
 | 
			
		||||
                              bit_size(pp, colour_type, bit_depth), w, pass,
 | 
			
		||||
                              0/*data always bigendian*/);
 | 
			
		||||
                     else
 | 
			
		||||
                        continue;
 | 
			
		||||
                  }
 | 
			
		||||
@ -3980,7 +3993,8 @@ make_size_image(png_store* const ps, png_byte const colour_type,
 | 
			
		||||
                      * set unset things to 0).
 | 
			
		||||
                      */
 | 
			
		||||
                     memset(tempRow, 0xff, sizeof tempRow);
 | 
			
		||||
                     interlace_row(tempRow, row, pixel_size, w, pass);
 | 
			
		||||
                     interlace_row(tempRow, row, pixel_size, w, pass,
 | 
			
		||||
                           0/*data always bigendian*/);
 | 
			
		||||
                     row = tempRow;
 | 
			
		||||
                  }
 | 
			
		||||
                  else
 | 
			
		||||
@ -4273,7 +4287,8 @@ make_error(png_store* const ps, png_byte const colour_type,
 | 
			
		||||
                     if (PNG_ROW_IN_INTERLACE_PASS(y, pass) &&
 | 
			
		||||
                         PNG_PASS_COLS(w, pass) > 0)
 | 
			
		||||
                        interlace_row(buffer, buffer,
 | 
			
		||||
                              bit_size(pp, colour_type, bit_depth), w, pass);
 | 
			
		||||
                              bit_size(pp, colour_type, bit_depth), w, pass,
 | 
			
		||||
                              0/*data always bigendian*/);
 | 
			
		||||
                     else
 | 
			
		||||
                        continue;
 | 
			
		||||
                  }
 | 
			
		||||
@ -4473,6 +4488,7 @@ typedef struct standard_display
 | 
			
		||||
   png_uint_32 bit_width;      /* Width of output row in bits */
 | 
			
		||||
   size_t      cbRow;          /* Bytes in a row of the output image */
 | 
			
		||||
   int         do_interlace;   /* Do interlacing internally */
 | 
			
		||||
   int         littleendian;   /* App (row) data is little endian */
 | 
			
		||||
   int         is_transparent; /* Transparency information was present. */
 | 
			
		||||
   int         has_tRNS;       /* color type GRAY or RGB with a tRNS chunk. */
 | 
			
		||||
   int         speed;          /* Doing a speed test */
 | 
			
		||||
@ -4515,6 +4531,7 @@ standard_display_init(standard_display *dp, png_store* ps, png_uint_32 id,
 | 
			
		||||
   dp->bit_width = 0;
 | 
			
		||||
   dp->cbRow = 0;
 | 
			
		||||
   dp->do_interlace = do_interlace;
 | 
			
		||||
   dp->littleendian = 0;
 | 
			
		||||
   dp->is_transparent = 0;
 | 
			
		||||
   dp->speed = ps->speed;
 | 
			
		||||
   dp->use_update_info = use_update_info;
 | 
			
		||||
@ -4970,9 +4987,10 @@ progressive_row(png_structp ppIn, png_bytep new_row, png_uint_32 y, int pass)
 | 
			
		||||
#endif /* READ_INTERLACING */
 | 
			
		||||
      {
 | 
			
		||||
         if (dp->interlace_type == PNG_INTERLACE_ADAM7)
 | 
			
		||||
            deinterlace_row(row, new_row, dp->pixel_size, dp->w, pass);
 | 
			
		||||
            deinterlace_row(row, new_row, dp->pixel_size, dp->w, pass,
 | 
			
		||||
                  dp->littleendian);
 | 
			
		||||
         else
 | 
			
		||||
            row_copy(row, new_row, dp->pixel_size * dp->w);
 | 
			
		||||
            row_copy(row, new_row, dp->pixel_size * dp->w, dp->littleendian);
 | 
			
		||||
      }
 | 
			
		||||
#ifdef PNG_READ_INTERLACING_SUPPORTED
 | 
			
		||||
      else
 | 
			
		||||
@ -5030,11 +5048,11 @@ sequential_row(standard_display *dp, png_structp pp, png_infop pi,
 | 
			
		||||
 | 
			
		||||
               if (iImage >= 0)
 | 
			
		||||
                  deinterlace_row(store_image_row(ps, pp, iImage, y), row,
 | 
			
		||||
                     dp->pixel_size, dp->w, pass);
 | 
			
		||||
                     dp->pixel_size, dp->w, pass, dp->littleendian);
 | 
			
		||||
 | 
			
		||||
               if (iDisplay >= 0)
 | 
			
		||||
                  deinterlace_row(store_image_row(ps, pp, iDisplay, y), display,
 | 
			
		||||
                     dp->pixel_size, dp->w, pass);
 | 
			
		||||
                     dp->pixel_size, dp->w, pass, dp->littleendian);
 | 
			
		||||
            }
 | 
			
		||||
         }
 | 
			
		||||
         else
 | 
			
		||||
@ -5871,6 +5889,7 @@ typedef struct transform_display
 | 
			
		||||
   /* Parameters */
 | 
			
		||||
   png_modifier*              pm;
 | 
			
		||||
   const image_transform* transform_list;
 | 
			
		||||
   unsigned int max_gamma_8;
 | 
			
		||||
 | 
			
		||||
   /* Local variables */
 | 
			
		||||
   png_byte output_colour_type;
 | 
			
		||||
@ -6053,6 +6072,7 @@ transform_display_init(transform_display *dp, png_modifier *pm, png_uint_32 id,
 | 
			
		||||
   /* Parameter fields */
 | 
			
		||||
   dp->pm = pm;
 | 
			
		||||
   dp->transform_list = transform_list;
 | 
			
		||||
   dp->max_gamma_8 = 16;
 | 
			
		||||
 | 
			
		||||
   /* Local variable fields */
 | 
			
		||||
   dp->output_colour_type = 255; /* invalid */
 | 
			
		||||
@ -6916,6 +6936,10 @@ image_transform_png_set_scale_16_set(const image_transform *this,
 | 
			
		||||
    transform_display *that, png_structp pp, png_infop pi)
 | 
			
		||||
{
 | 
			
		||||
   png_set_scale_16(pp);
 | 
			
		||||
#  if PNG_LIBPNG_VER < 10700
 | 
			
		||||
      /* libpng will limit the gamma table size: */
 | 
			
		||||
      that->max_gamma_8 = PNG_MAX_GAMMA_8;
 | 
			
		||||
#  endif
 | 
			
		||||
   this->next->set(this->next, that, pp, pi);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -6960,6 +6984,10 @@ image_transform_png_set_strip_16_set(const image_transform *this,
 | 
			
		||||
    transform_display *that, png_structp pp, png_infop pi)
 | 
			
		||||
{
 | 
			
		||||
   png_set_strip_16(pp);
 | 
			
		||||
#  if PNG_LIBPNG_VER < 10700
 | 
			
		||||
      /* libpng will limit the gamma table size: */
 | 
			
		||||
      that->max_gamma_8 = PNG_MAX_GAMMA_8;
 | 
			
		||||
#  endif
 | 
			
		||||
   this->next->set(this->next, that, pp, pi);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -7226,14 +7254,15 @@ image_transform_png_set_rgb_to_gray_ini(const image_transform *this,
 | 
			
		||||
          *  conversion adds another +/-2 in the 16-bit case and
 | 
			
		||||
          *  +/-(1<<(15-PNG_MAX_GAMMA_8)) in the 8-bit case.
 | 
			
		||||
          */
 | 
			
		||||
#        if PNG_LIBPNG_VER < 10700
 | 
			
		||||
            if (that->this.bit_depth < 16)
 | 
			
		||||
               that->max_gamma_8 = PNG_MAX_GAMMA_8;
 | 
			
		||||
#        endif
 | 
			
		||||
         that->pm->limit += pow(
 | 
			
		||||
#           if PNG_MAX_GAMMA_8 < 14
 | 
			
		||||
               (that->this.bit_depth == 16 ? 8. :
 | 
			
		||||
                  6. + (1<<(15-PNG_MAX_GAMMA_8)))
 | 
			
		||||
#           else
 | 
			
		||||
               8.
 | 
			
		||||
#           endif
 | 
			
		||||
               /65535, data.gamma);
 | 
			
		||||
            (that->this.bit_depth == 16 || that->max_gamma_8 > 14 ?
 | 
			
		||||
               8. :
 | 
			
		||||
               6. + (1<<(15-that->max_gamma_8))
 | 
			
		||||
            )/65535, data.gamma);
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      else
 | 
			
		||||
@ -7418,9 +7447,12 @@ image_transform_png_set_rgb_to_gray_mod(const image_transform *this,
 | 
			
		||||
         const unsigned int sample_depth = that->sample_depth;
 | 
			
		||||
         const unsigned int calc_depth = (pm->assume_16_bit_calculations ? 16 :
 | 
			
		||||
            sample_depth);
 | 
			
		||||
         const unsigned int gamma_depth = (sample_depth == 16 ?
 | 
			
		||||
            PNG_MAX_GAMMA_8 :
 | 
			
		||||
            (pm->assume_16_bit_calculations ? PNG_MAX_GAMMA_8 : sample_depth));
 | 
			
		||||
         const unsigned int gamma_depth =
 | 
			
		||||
            (sample_depth == 16 ?
 | 
			
		||||
               display->max_gamma_8 :
 | 
			
		||||
               (pm->assume_16_bit_calculations ?
 | 
			
		||||
                  display->max_gamma_8 :
 | 
			
		||||
                  sample_depth));
 | 
			
		||||
         int isgray;
 | 
			
		||||
         double r, g, b;
 | 
			
		||||
         double rlo, rhi, glo, ghi, blo, bhi, graylo, grayhi;
 | 
			
		||||
@ -7457,7 +7489,7 @@ image_transform_png_set_rgb_to_gray_mod(const image_transform *this,
 | 
			
		||||
         b = blo = bhi = that->bluef;
 | 
			
		||||
         blo -= that->bluee;
 | 
			
		||||
         blo = DD(blo, calc_depth, 1/*round*/);
 | 
			
		||||
         bhi += that->greene;
 | 
			
		||||
         bhi += that->bluee;
 | 
			
		||||
         bhi = DU(bhi, calc_depth, 1/*round*/);
 | 
			
		||||
 | 
			
		||||
         isgray = r==g && g==b;
 | 
			
		||||
@ -7639,7 +7671,7 @@ image_transform_png_set_rgb_to_gray_mod(const image_transform *this,
 | 
			
		||||
            const png_modifier *pm = display->pm;
 | 
			
		||||
            double in_qe = (that->sample_depth > 8 ? .5/65535 : .5/255);
 | 
			
		||||
            double out_qe = (that->sample_depth > 8 ? .5/65535 :
 | 
			
		||||
               (pm->assume_16_bit_calculations ? .5/(1<<PNG_MAX_GAMMA_8) :
 | 
			
		||||
               (pm->assume_16_bit_calculations ? .5/(1<<display->max_gamma_8) :
 | 
			
		||||
               .5/255));
 | 
			
		||||
            double rhi, ghi, bhi, grayhi;
 | 
			
		||||
            double g1 = 1/data.gamma;
 | 
			
		||||
@ -8287,6 +8319,7 @@ image_transform_png_set_packswap_set(const image_transform *this,
 | 
			
		||||
    transform_display *that, png_structp pp, png_infop pi)
 | 
			
		||||
{
 | 
			
		||||
   png_set_packswap(pp);
 | 
			
		||||
   that->this.littleendian = 1;
 | 
			
		||||
   this->next->set(this->next, that, pp, pi);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -8769,7 +8802,7 @@ gamma_info_imp(gamma_display *dp, png_structp pp, png_infop pi)
 | 
			
		||||
   /* If requested strip 16 to 8 bits - this is handled automagically below
 | 
			
		||||
    * because the output bit depth is read from the library.  Note that there
 | 
			
		||||
    * are interactions with sBIT but, internally, libpng makes sbit at most
 | 
			
		||||
    * PNG_MAX_GAMMA_8 when doing the following.
 | 
			
		||||
    * PNG_MAX_GAMMA_8 prior to 1.7 when doing the following.
 | 
			
		||||
    */
 | 
			
		||||
   if (dp->scale16)
 | 
			
		||||
#     ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED
 | 
			
		||||
@ -10210,7 +10243,11 @@ static void perform_gamma_scale16_tests(png_modifier *pm)
 | 
			
		||||
#  ifndef PNG_MAX_GAMMA_8
 | 
			
		||||
#     define PNG_MAX_GAMMA_8 11
 | 
			
		||||
#  endif
 | 
			
		||||
#  define SBIT_16_TO_8 PNG_MAX_GAMMA_8
 | 
			
		||||
#  if defined PNG_MAX_GAMMA_8 || PNG_LIBPNG_VER < 10700
 | 
			
		||||
#     define SBIT_16_TO_8 PNG_MAX_GAMMA_8
 | 
			
		||||
#  else
 | 
			
		||||
#     define SBIT_16_TO_8 16
 | 
			
		||||
#  endif
 | 
			
		||||
   /* Include the alpha cases here. Note that sbit matches the internal value
 | 
			
		||||
    * used by the library - otherwise we will get spurious errors from the
 | 
			
		||||
    * internal sbit style approximation.
 | 
			
		||||
@ -11223,7 +11260,11 @@ int main(int argc, char **argv)
 | 
			
		||||
   pm.maxout16 = .499;  /* Error in *encoded* value */
 | 
			
		||||
   pm.maxabs16 = .00005;/* 1/20000 */
 | 
			
		||||
   pm.maxcalc16 =1./65535;/* +/-1 in 16 bits for compose errors */
 | 
			
		||||
   pm.maxcalcG = 1./((1<<PNG_MAX_GAMMA_8)-1);
 | 
			
		||||
#  if PNG_LIBPNG_VER < 10700
 | 
			
		||||
      pm.maxcalcG = 1./((1<<PNG_MAX_GAMMA_8)-1);
 | 
			
		||||
#  else
 | 
			
		||||
      pm.maxcalcG = 1./((1<<16)-1);
 | 
			
		||||
#  endif
 | 
			
		||||
 | 
			
		||||
   /* NOTE: this is a reasonable perceptual limit. We assume that humans can
 | 
			
		||||
    * perceive light level differences of 1% over a 100:1 range, so we need to
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user