Alien-FreeImage

 view release on metacpan or  search on metacpan

src/Source/LibPNG/pngread.c  view on Meta::CPAN

            if (control != NULL)
            {
               memset(control, 0, (sizeof *control));

               control->png_ptr = png_ptr;
               control->info_ptr = info_ptr;
               control->for_write = 0;

               image->opaque = control;
               return 1;
            }

            /* Error clean up */
            png_destroy_info_struct(png_ptr, &info_ptr);
         }

         png_destroy_read_struct(&png_ptr, NULL, NULL);
      }

      return png_image_error(image, "png_image_read: out of memory");
   }

   return png_image_error(image, "png_image_read: opaque pointer not NULL");
}

/* Utility to find the base format of a PNG file from a png_struct. */
static png_uint_32
png_image_format(png_structrp png_ptr)
{
   png_uint_32 format = 0;

   if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) != 0)
      format |= PNG_FORMAT_FLAG_COLOR;

   if ((png_ptr->color_type & PNG_COLOR_MASK_ALPHA) != 0)
      format |= PNG_FORMAT_FLAG_ALPHA;

   /* Use png_ptr here, not info_ptr, because by examination png_handle_tRNS
    * sets the png_struct fields; that's all we are interested in here.  The
    * precise interaction with an app call to png_set_tRNS and PNG file reading
    * is unclear.
    */
   else if (png_ptr->num_trans > 0)
      format |= PNG_FORMAT_FLAG_ALPHA;

   if (png_ptr->bit_depth == 16)
      format |= PNG_FORMAT_FLAG_LINEAR;

   if ((png_ptr->color_type & PNG_COLOR_MASK_PALETTE) != 0)
      format |= PNG_FORMAT_FLAG_COLORMAP;

   return format;
}

/* Is the given gamma significantly different from sRGB?  The test is the same
 * one used in pngrtran.c when deciding whether to do gamma correction.  The
 * arithmetic optimizes the division by using the fact that the inverse of the
 * file sRGB gamma is 2.2
 */
static int
png_gamma_not_sRGB(png_fixed_point g)
{
   if (g < PNG_FP_1)
   {
      /* An uninitialized gamma is assumed to be sRGB for the simplified API. */
      if (g == 0)
         return 0;

      return png_gamma_significant((g * 11 + 2)/5 /* i.e. *2.2, rounded */);
   }

   return 1;
}

/* Do the main body of a 'png_image_begin_read' function; read the PNG file
 * header and fill in all the information.  This is executed in a safe context,
 * unlike the init routine above.
 */
static int
png_image_read_header(png_voidp argument)
{
   png_imagep image = png_voidcast(png_imagep, argument);
   png_structrp png_ptr = image->opaque->png_ptr;
   png_inforp info_ptr = image->opaque->info_ptr;

   png_set_benign_errors(png_ptr, 1/*warn*/);
   png_read_info(png_ptr, info_ptr);

   /* Do this the fast way; just read directly out of png_struct. */
   image->width = png_ptr->width;
   image->height = png_ptr->height;

   {
      png_uint_32 format = png_image_format(png_ptr);

      image->format = format;

#ifdef PNG_COLORSPACE_SUPPORTED
      /* Does the colorspace match sRGB?  If there is no color endpoint
       * (colorant) information assume yes, otherwise require the
       * 'ENDPOINTS_MATCHP_sRGB' colorspace flag to have been set.  If the
       * colorspace has been determined to be invalid ignore it.
       */
      if ((format & PNG_FORMAT_FLAG_COLOR) != 0 && ((png_ptr->colorspace.flags
         & (PNG_COLORSPACE_HAVE_ENDPOINTS|PNG_COLORSPACE_ENDPOINTS_MATCH_sRGB|
            PNG_COLORSPACE_INVALID)) == PNG_COLORSPACE_HAVE_ENDPOINTS))
         image->flags |= PNG_IMAGE_FLAG_COLORSPACE_NOT_sRGB;
#endif
   }

   /* We need the maximum number of entries regardless of the format the
    * application sets here.
    */
   {
      png_uint_32 cmap_entries;

      switch (png_ptr->color_type)
      {
         case PNG_COLOR_TYPE_GRAY:
            cmap_entries = 1U << png_ptr->bit_depth;
            break;

src/Source/LibPNG/pngread.c  view on Meta::CPAN

   /* Prepare the reader to ignore all recognized chunks whose data will not
    * be used, i.e., all chunks recognized by libpng except for those
    * involved in basic image reading:
    *
    *    IHDR, PLTE, IDAT, IEND
    *
    * Or image data handling:
    *
    *    tRNS, bKGD, gAMA, cHRM, sRGB, [iCCP] and sBIT.
    *
    * This provides a small performance improvement and eliminates any
    * potential vulnerability to security problems in the unused chunks.
    *
    * At present the iCCP chunk data isn't used, so iCCP chunk can be ignored
    * too.  This allows the simplified API to be compiled without iCCP support,
    * however if the support is there the chunk is still checked to detect
    * errors (which are unfortunately quite common.)
    */
   {
         static PNG_CONST png_byte chunks_to_process[] = {
            98,  75,  71,  68, '\0',  /* bKGD */
            99,  72,  82,  77, '\0',  /* cHRM */
           103,  65,  77,  65, '\0',  /* gAMA */
#        ifdef PNG_READ_iCCP_SUPPORTED
           105,  67,  67,  80, '\0',  /* iCCP */
#        endif
           115,  66,  73,  84, '\0',  /* sBIT */
           115,  82,  71,  66, '\0',  /* sRGB */
           };

       /* Ignore unknown chunks and all other chunks except for the
        * IHDR, PLTE, tRNS, IDAT, and IEND chunks.
        */
       png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_NEVER,
         NULL, -1);

       /* But do not ignore image data handling chunks */
       png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_AS_DEFAULT,
         chunks_to_process, (int)/*SAFE*/(sizeof chunks_to_process)/5);
    }
}

#  define PNG_SKIP_CHUNKS(p) png_image_skip_unused_chunks(p)
#else
#  define PNG_SKIP_CHUNKS(p) ((void)0)
#endif /* HANDLE_AS_UNKNOWN */

/* The following macro gives the exact rounded answer for all values in the
 * range 0..255 (it actually divides by 51.2, but the rounding still generates
 * the correct numbers 0..5
 */
#define PNG_DIV51(v8) (((v8) * 5 + 130) >> 8)

/* Utility functions to make particular color-maps */
static void
set_file_encoding(png_image_read_control *display)
{
   png_fixed_point g = display->image->opaque->png_ptr->colorspace.gamma;
   if (png_gamma_significant(g) != 0)
   {
      if (png_gamma_not_sRGB(g) != 0)
      {
         display->file_encoding = P_FILE;
         display->gamma_to_linear = png_reciprocal(g);
      }

      else
         display->file_encoding = P_sRGB;
   }

   else
      display->file_encoding = P_LINEAR8;
}

static unsigned int
decode_gamma(png_image_read_control *display, png_uint_32 value, int encoding)
{
   if (encoding == P_FILE) /* double check */
      encoding = display->file_encoding;

   if (encoding == P_NOTSET) /* must be the file encoding */
   {
      set_file_encoding(display);
      encoding = display->file_encoding;
   }

   switch (encoding)
   {
      case P_FILE:
         value = png_gamma_16bit_correct(value*257, display->gamma_to_linear);
         break;

      case P_sRGB:
         value = png_sRGB_table[value];
         break;

      case P_LINEAR:
         break;

      case P_LINEAR8:
         value *= 257;
         break;

      default:
         png_error(display->image->opaque->png_ptr,
            "unexpected encoding (internal error)");
         break;
   }

   return value;
}

static png_uint_32
png_colormap_compose(png_image_read_control *display,
   png_uint_32 foreground, int foreground_encoding, png_uint_32 alpha,
   png_uint_32 background, int encoding)
{
   /* The file value is composed on the background, the background has the given
    * encoding and so does the result, the file is encoded with P_FILE and the
    * file and alpha are 8-bit values.  The (output) encoding will always be
    * P_LINEAR or P_sRGB.

src/Source/LibPNG/pngread.c  view on Meta::CPAN


      case PNG_COLOR_TYPE_RGB:
      case PNG_COLOR_TYPE_RGB_ALPHA:
         /* Exclude the case where the output is gray; we can always handle this
          * with the cases above.
          */
         if ((output_format & PNG_FORMAT_FLAG_COLOR) == 0)
         {
            /* The color-map will be grayscale, so we may as well convert the
             * input RGB values to a simple grayscale and use the grayscale
             * code above.
             *
             * NOTE: calling this apparently damages the recognition of the
             * transparent color in background color handling; call
             * png_set_tRNS_to_alpha before png_set_background_fixed.
             */
            png_set_rgb_to_gray_fixed(png_ptr, PNG_ERROR_ACTION_NONE, -1,
               -1);
            data_encoding = P_sRGB;

            /* The output will now be one or two 8-bit gray or gray+alpha
             * channels.  The more complex case arises when the input has alpha.
             */
            if ((png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA ||
               png_ptr->num_trans > 0) &&
               (output_format & PNG_FORMAT_FLAG_ALPHA) != 0)
            {
               /* Both input and output have an alpha channel, so no background
                * processing is required; just map the GA bytes to the right
                * color-map entry.
                */
               expand_tRNS = 1;

               if (PNG_GA_COLORMAP_ENTRIES > image->colormap_entries)
                  png_error(png_ptr, "rgb[ga] color-map: too few entries");

               cmap_entries = make_ga_colormap(display);
               background_index = PNG_CMAP_GA_BACKGROUND;
               output_processing = PNG_CMAP_GA;
            }

            else
            {
               /* Either the input or the output has no alpha channel, so there
                * will be no non-opaque pixels in the color-map; it will just be
                * grayscale.
                */
               if (PNG_GRAY_COLORMAP_ENTRIES > image->colormap_entries)
                  png_error(png_ptr, "rgb[gray] color-map: too few entries");

               /* Ideally this code would use libpng to do the gamma correction,
                * but if an input alpha channel is to be removed we will hit the
                * libpng bug in gamma+compose+rgb-to-gray (the double gamma
                * correction bug).  Fix this by dropping the gamma correction in
                * this case and doing it in the palette; this will result in
                * duplicate palette entries, but that's better than the
                * alternative of double gamma correction.
                */
               if ((png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA ||
                  png_ptr->num_trans > 0) &&
                  png_gamma_not_sRGB(png_ptr->colorspace.gamma) != 0)
               {
                  cmap_entries = make_gray_file_colormap(display);
                  data_encoding = P_FILE;
               }

               else
                  cmap_entries = make_gray_colormap(display);

               /* But if the input has alpha or transparency it must be removed
                */
               if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA ||
                  png_ptr->num_trans > 0)
               {
                  png_color_16 c;
                  png_uint_32 gray = back_g;

                  /* We need to ensure that the application background exists in
                   * the colormap and that completely transparent pixels map to
                   * it.  Achieve this simply by ensuring that the entry
                   * selected for the background really is the background color.
                   */
                  if (data_encoding == P_FILE) /* from the fixup above */
                  {
                     /* The app supplied a gray which is in output_encoding, we
                      * need to convert it to a value of the input (P_FILE)
                      * encoding then set this palette entry to the required
                      * output encoding.
                      */
                     if (output_encoding == P_sRGB)
                        gray = png_sRGB_table[gray]; /* now P_LINEAR */

                     gray = PNG_DIV257(png_gamma_16bit_correct(gray,
                        png_ptr->colorspace.gamma)); /* now P_FILE */

                     /* And make sure the corresponding palette entry contains
                      * exactly the required sRGB value.
                      */
                     png_create_colormap_entry(display, gray, back_g, back_g,
                        back_g, 0/*unused*/, output_encoding);
                  }

                  else if (output_encoding == P_LINEAR)
                  {
                     gray = PNG_sRGB_FROM_LINEAR(gray * 255);

                     /* And make sure the corresponding palette entry matches.
                      */
                     png_create_colormap_entry(display, gray, back_g, back_g,
                        back_g, 0/*unused*/, P_LINEAR);
                  }

                  /* The background passed to libpng, however, must be the
                   * output (normally sRGB) value.
                   */
                  c.index = 0; /*unused*/
                  c.gray = c.red = c.green = c.blue = (png_uint_16)gray;

                  /* NOTE: the following is apparently a bug in libpng. Without
                   * it the transparent color recognition in
                   * png_set_background_fixed seems to go wrong.



( run in 0.492 second using v1.01-cache-2.11-cpan-941387dca55 )