⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pngrtran.c

📁 一套图像处理程序,支持三种图像文件格式,我调试过了,很好用
💻 C
📖 第 1 页 / 共 5 页
字号:

/* pngrtran.c - transforms the data in a row for png readers

   libpng 1.0 beta 3 - version 0.89
   For conditions of distribution and use, see copyright notice in png.h
   Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
   May 25, 1996
   */

#define PNG_INTERNAL
#include "png.h"

#if defined(PNG_READ_BACKGROUND_SUPPORTED)
/* handle alpha and tRNS via a background color */
void
png_set_background(png_structp png_ptr,
   png_color_16p background_color, int background_gamma_code,
   int need_expand, double background_gamma)
{
   png_ptr->transformations |= PNG_BACKGROUND;
   png_memcpy(&(png_ptr->background), background_color,
      sizeof(png_color_16));
   png_ptr->background_gamma = (float)background_gamma;
   png_ptr->background_gamma_type = (png_byte)(background_gamma_code);
   png_ptr->transformations |= (need_expand ? PNG_BACKGROUND_EXPAND : 0);
}
#endif

#if defined(PNG_READ_16_TO_8_SUPPORTED)
/* strip 16 bit depth files to 8 bit depth */
void
png_set_strip_16(png_structp png_ptr)
{
   png_ptr->transformations |= PNG_16_TO_8;
}
#endif

#if defined(PNG_READ_DITHER_SUPPORTED)
/* 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
   is greater then the maximum number, the palette will be
   modified to fit in the maximum number */


typedef struct png_dsort_struct
{
   struct png_dsort_struct FAR * next;
   png_byte left;
   png_byte right;
} png_dsort;
typedef png_dsort FAR *       png_dsortp;
typedef png_dsort FAR * FAR * png_dsortpp;

void
png_set_dither(png_structp png_ptr, png_colorp palette,
   int num_palette, int maximum_colors, png_uint_16p histogram,
   int full_dither)
{
   png_ptr->transformations |= PNG_DITHER;

   if (!full_dither)
   {
      int i;

      png_ptr->dither_index = (png_bytep)png_large_malloc(png_ptr,
         num_palette * sizeof (png_byte));
      for (i = 0; i < num_palette; i++)
         png_ptr->dither_index[i] = (png_byte)i;
   }

   if (num_palette > maximum_colors)
   {
      if (histogram)
      {
         /* this is easy enough, just throw out the least used colors.
            perhaps not the best solution, but good enough */

         int i;
         png_bytep sort;

         /* initialize an array to sort colors */
         sort = (png_bytep)png_large_malloc(png_ptr, num_palette * sizeof (png_byte));

         /* initialize the sort array */
         for (i = 0; i < num_palette; i++)
            sort[i] = (png_byte)i;

         /* 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[sort[j]] < histogram[sort[j + 1]])
               {
                  png_byte t;

                  t = sort[j];
                  sort[j] = sort[j + 1];
                  sort[j + 1] = t;
                  done = 0;
               }
            }
            if (done)
               break;
         }

         /* swap the palette around, and set up a table, if necessary */
         if (full_dither)
         {
            int j;

            /* put all the useful colors within the max, but don't
               move the others */
            j = num_palette;
            for (i = 0; i < maximum_colors; i++)
            {
               if (sort[i] >= maximum_colors)
               {
                  do
                     j--;
                  while (sort[j] >= maximum_colors);
                  palette[i] = palette[j];
               }
            }
         }
         else
         {
            int j;

            /* move all the used colors inside the max limit, and
               develop a translation table */
            j = num_palette;
            for (i = 0; i < maximum_colors; i++)
            {
               /* only move the colors we need to */
               if (sort[i] >= maximum_colors)
               {
                  png_color tmp_color;

                  do
                     j--;
                  while (sort[j] >= maximum_colors);

                  tmp_color = palette[j];
                  palette[j] = palette[i];
                  palette[i] = tmp_color;
                  /* indicate where the color went */
                  png_ptr->dither_index[j] = (png_byte)i;
                  png_ptr->dither_index[i] = (png_byte)j;
               }
            }
            /* find closest color for those colors we are not
               using */
            for (i = 0; i < num_palette; i++)
            {
               if (png_ptr->dither_index[i] >= maximum_colors)
               {
                  int min_d, j, min_j, index;

                  /* find the closest color to one we threw out */
                  index = png_ptr->dither_index[i];
                  min_d = PNG_COLOR_DIST(palette[index],
                        palette[0]);
                  min_j = 0;
                  for (j = 1; j < maximum_colors; j++)
                  {
                     int d;

                     d = PNG_COLOR_DIST(palette[index],
                        palette[j]);

                     if (d < min_d)
                     {
                        min_d = d;
                        min_j = j;
                     }
                  }
                  /* point to closest color */
                  png_ptr->dither_index[i] = (png_byte)min_j;
               }
            }
         }
         png_large_free(png_ptr, sort);
      }
      else
      {
         /* 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).
            */
         int i;
         int max_d;
         int num_new_palette;
         png_dsortpp hash;
         png_bytep index_to_palette;
            /* where the original index currently is in the palette */
         png_bytep palette_to_index;
            /* which original index points to this palette color */

         /* initialize palette index arrays */
         index_to_palette = (png_bytep)png_large_malloc(png_ptr,
            num_palette * sizeof (png_byte));
         palette_to_index = (png_bytep)png_large_malloc(png_ptr,
            num_palette * sizeof (png_byte));

         /* initialize the sort array */
         for (i = 0; i < num_palette; i++)
         {
            index_to_palette[i] = (png_byte)i;
            palette_to_index[i] = (png_byte)i;
         }

         hash = (png_dsortpp)png_large_malloc(png_ptr, 769 * sizeof (png_dsortp));
         for (i = 0; i < 769; i++)
            hash[i] = (png_dsortp)0;
/*         png_memset(hash, 0, 769 * sizeof (png_dsortp)); */

         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)
         {
            for (i = 0; i < num_new_palette - 1; i++)
            {
               int j;

               for (j = i + 1; j < num_new_palette; j++)
               {
                  int d;

                  d = PNG_COLOR_DIST(palette[i], palette[j]);

                  if (d <= max_d)
                  {
                     png_dsortp t;

                     t = png_large_malloc(png_ptr, sizeof (png_dsort));
                     t->next = hash[d];
                     t->left = (png_byte)i;
                     t->right = (png_byte)j;
                     hash[d] = t;
                  }
               }
            }

            for (i = 0; i <= max_d; i++)
            {
               if (hash[i])
               {
                  png_dsortp p;

                  for (p = hash[i]; p; 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 & 1)
                        {
                           j = p->left;
                           next_j = p->right;
                        }
                        else
                        {
                           j = p->right;
                           next_j = p->left;
                        }

                        num_new_palette--;
                        palette[index_to_palette[j]] =
                           palette[num_new_palette];
                        if (!full_dither)
                        {
                           int k;

                           for (k = 0; k < num_palette; k++)
                           {
                              if (png_ptr->dither_index[k] ==
                                 index_to_palette[j])
                                 png_ptr->dither_index[k] =
                                    index_to_palette[next_j];
                              if (png_ptr->dither_index[k] ==
                                 num_new_palette)
                                 png_ptr->dither_index[k] =
                                    index_to_palette[j];
                           }
                        }

                        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_byte)num_new_palette;
                        palette_to_index[num_new_palette] = (png_byte)j;
                     }
                     if (num_new_palette <= maximum_colors)
                        break;
                  }
                  if (num_new_palette <= maximum_colors)
                     break;
               }
            }

            for (i = 0; i < 769; i++)
            {
               if (hash[i])
               {
                  png_dsortp p;

                  p = hash[i];
                  while (p)
                  {
                     png_dsortp t;

                     t = p->next;
                     png_large_free(png_ptr, p);
                     p = t;
                  }
               }
               hash[i] = 0;
            }
            max_d += 96;
         }
         png_large_free(png_ptr, hash);
         png_large_free(png_ptr, palette_to_index);
         png_large_free(png_ptr, index_to_palette);
      }
      num_palette = maximum_colors;
   }
   if (!(png_ptr->palette))
   {
      png_ptr->palette = palette;
   }
   png_ptr->num_palette = (png_uint_16)num_palette;

   if (full_dither)
   {
      int i;
      int total_bits, num_red, num_green, num_blue;
      png_uint_32 num_entries;
      png_bytep distance;

      total_bits = PNG_DITHER_RED_BITS + PNG_DITHER_GREEN_BITS +
         PNG_DITHER_BLUE_BITS;

      num_red = (1 << PNG_DITHER_RED_BITS);
      num_green = (1 << PNG_DITHER_GREEN_BITS);
      num_blue = (1 << PNG_DITHER_BLUE_BITS);
      num_entries = ((png_uint_32)1 << total_bits);

      png_ptr->palette_lookup = (png_bytep )png_large_malloc(png_ptr,
         (png_size_t)num_entries * sizeof (png_byte));

      png_memset(png_ptr->palette_lookup, 0, (png_size_t)num_entries * sizeof (png_byte));

      distance = (png_bytep )png_large_malloc(png_ptr,
         (png_size_t)num_entries * sizeof (png_byte));

      png_memset(distance, 0xff, (png_size_t)num_entries * sizeof (png_byte));

      for (i = 0; i < num_palette; i++)
      {
         int r, g, b, ir, ig, ib;

         r = (palette[i].red >> (8 - PNG_DITHER_RED_BITS));

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -