📄 pngrtran.c
字号:
/* 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 + -