#include "pngpriv.h"
#ifdef PNG_ARM_NEON_IMPLEMENTATION
# if PNG_ARM_NEON_IMPLEMENTATION == 1
#define PNG_ARM_NEON_INTRINSICS_AVAILABLE
# if defined(_MSC_VER) && !defined(__clang__) && defined(_M_ARM64)
# include <arm64_neon.h>
# else
# include <arm_neon.h>
# endif
# endif
#endif
#ifdef PNG_READ_SUPPORTED
void PNGAPI
png_set_crc_action(png_structrp png_ptr, int crit_action, int ancil_action)
{ … }
#ifdef PNG_READ_TRANSFORMS_SUPPORTED
static int
png_rtran_ok(png_structrp png_ptr, int need_IHDR)
{ … }
#endif
#ifdef PNG_READ_BACKGROUND_SUPPORTED
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)
{ … }
# 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)
{ … }
# endif
#endif
#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED
void PNGAPI
png_set_scale_16(png_structrp png_ptr)
{ … }
#endif
#ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED
void PNGAPI
png_set_strip_16(png_structrp png_ptr)
{ … }
#endif
#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED
void PNGAPI
png_set_strip_alpha(png_structrp png_ptr)
{ … }
#endif
#if defined(PNG_READ_ALPHA_MODE_SUPPORTED) || defined(PNG_READ_GAMMA_SUPPORTED)
static png_fixed_point
translate_gamma_flags(png_structrp png_ptr, png_fixed_point output_gamma,
int is_screen)
{ … }
# ifdef PNG_FLOATING_POINT_SUPPORTED
static png_fixed_point
convert_gamma_value(png_structrp png_ptr, double output_gamma)
{ … }
# endif
#endif
#ifdef PNG_READ_ALPHA_MODE_SUPPORTED
void PNGFAPI
png_set_alpha_mode_fixed(png_structrp png_ptr, int mode,
png_fixed_point output_gamma)
{ … }
# ifdef PNG_FLOATING_POINT_SUPPORTED
void PNGAPI
png_set_alpha_mode(png_structrp png_ptr, int mode, double output_gamma)
{ … }
# endif
#endif
#ifdef PNG_READ_QUANTIZE_SUPPORTED
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;
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_rtran_ok(png_ptr, 0) == 0)
return;
png_ptr->transformations |= PNG_QUANTIZE;
if (full_quantize == 0)
{
int i;
png_ptr->quantize_index = (png_bytep)png_malloc(png_ptr,
(png_alloc_size_t)num_palette);
for (i = 0; i < num_palette; i++)
png_ptr->quantize_index[i] = (png_byte)i;
}
if (num_palette > maximum_colors)
{
if (histogram != NULL)
{
int i;
png_ptr->quantize_sort = (png_bytep)png_malloc(png_ptr,
(png_alloc_size_t)num_palette);
for (i = 0; i < num_palette; i++)
png_ptr->quantize_sort[i] = (png_byte)i;
for (i = num_palette - 1; i >= maximum_colors; i--)
{
int done;
int j;
done = 1;
for (j = 0; j < i; j++)
{
if (histogram[png_ptr->quantize_sort[j]]
< histogram[png_ptr->quantize_sort[j + 1]])
{
png_byte t;
t = png_ptr->quantize_sort[j];
png_ptr->quantize_sort[j] = png_ptr->quantize_sort[j + 1];
png_ptr->quantize_sort[j + 1] = t;
done = 0;
}
}
if (done != 0)
break;
}
if (full_quantize != 0)
{
int j = num_palette;
for (i = 0; i < maximum_colors; i++)
{
if ((int)png_ptr->quantize_sort[i] >= maximum_colors)
{
do
j--;
while ((int)png_ptr->quantize_sort[j] >= maximum_colors);
palette[i] = palette[j];
}
}
}
else
{
int j = num_palette;
for (i = 0; i < maximum_colors; i++)
{
if ((int)png_ptr->quantize_sort[i] >= maximum_colors)
{
png_color tmp_color;
do
j--;
while ((int)png_ptr->quantize_sort[j] >= maximum_colors);
tmp_color = palette[j];
palette[j] = palette[i];
palette[i] = tmp_color;
png_ptr->quantize_index[j] = (png_byte)i;
png_ptr->quantize_index[i] = (png_byte)j;
}
}
for (i = 0; i < num_palette; i++)
{
if ((int)png_ptr->quantize_index[i] >= maximum_colors)
{
int min_d, k, min_k, d_index;
d_index = png_ptr->quantize_index[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;
}
}
png_ptr->quantize_index[i] = (png_byte)min_k;
}
}
}
png_free(png_ptr, png_ptr->quantize_sort);
png_ptr->quantize_sort = NULL;
}
else
{
int i;
int max_d;
int num_new_palette;
png_dsortp t;
png_dsortpp hash;
t = NULL;
png_ptr->index_to_palette = (png_bytep)png_malloc(png_ptr,
(png_alloc_size_t)num_palette);
png_ptr->palette_to_index = (png_bytep)png_malloc(png_ptr,
(png_alloc_size_t)num_palette);
for (i = 0; i < num_palette; i++)
{
png_ptr->index_to_palette[i] = (png_byte)i;
png_ptr->palette_to_index[i] = (png_byte)i;
}
hash = (png_dsortpp)png_calloc(png_ptr, (png_alloc_size_t)(769 *
(sizeof (png_dsortp))));
num_new_palette = num_palette;
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)
{
t = (png_dsortp)png_malloc_warn(png_ptr,
(png_alloc_size_t)(sizeof (png_dsort)));
if (t == NULL)
break;
t->next = hash[d];
t->left = (png_byte)i;
t->right = (png_byte)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; p = p->next)
{
if ((int)png_ptr->index_to_palette[p->left]
< num_new_palette &&
(int)png_ptr->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--;
palette[png_ptr->index_to_palette[j]]
= palette[num_new_palette];
if (full_quantize == 0)
{
int k;
for (k = 0; k < num_palette; k++)
{
if (png_ptr->quantize_index[k] ==
png_ptr->index_to_palette[j])
png_ptr->quantize_index[k] =
png_ptr->index_to_palette[next_j];
if ((int)png_ptr->quantize_index[k] ==
num_new_palette)
png_ptr->quantize_index[k] =
png_ptr->index_to_palette[j];
}
}
png_ptr->index_to_palette[png_ptr->palette_to_index
[num_new_palette]] = png_ptr->index_to_palette[j];
png_ptr->palette_to_index[png_ptr->index_to_palette[j]]
= png_ptr->palette_to_index[num_new_palette];
png_ptr->index_to_palette[j] =
(png_byte)num_new_palette;
png_ptr->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] != NULL)
{
png_dsortp p = hash[i];
while (p)
{
t = p->next;
png_free(png_ptr, p);
p = t;
}
}
hash[i] = 0;
}
max_d += 96;
}
png_free(png_ptr, hash);
png_free(png_ptr, png_ptr->palette_to_index);
png_free(png_ptr, png_ptr->index_to_palette);
png_ptr->palette_to_index = NULL;
png_ptr->index_to_palette = NULL;
}
num_palette = maximum_colors;
}
if (png_ptr->palette == NULL)
{
png_ptr->palette = palette;
}
png_ptr->num_palette = (png_uint_16)num_palette;
if (full_quantize != 0)
{
int i;
png_bytep distance;
int total_bits = PNG_QUANTIZE_RED_BITS + PNG_QUANTIZE_GREEN_BITS +
PNG_QUANTIZE_BLUE_BITS;
int num_red = (1 << PNG_QUANTIZE_RED_BITS);
int num_green = (1 << PNG_QUANTIZE_GREEN_BITS);
int num_blue = (1 << PNG_QUANTIZE_BLUE_BITS);
size_t num_entries = ((size_t)1 << total_bits);
png_ptr->palette_lookup = (png_bytep)png_calloc(png_ptr,
(png_alloc_size_t)(num_entries));
distance = (png_bytep)png_malloc(png_ptr, (png_alloc_size_t)num_entries);
memset(distance, 0xff, num_entries);
for (i = 0; i < num_palette; i++)
{
int ir, ig, ib;
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 < num_red; ir++)
{
int dr = ((ir > r) ? ir - r : r - ir);
int index_r = (ir << (PNG_QUANTIZE_BLUE_BITS +
PNG_QUANTIZE_GREEN_BITS));
for (ig = 0; ig < num_green; ig++)
{
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 < num_blue; ib++)
{
int d_index = index_g | ib;
int db = ((ib > b) ? ib - b : b - ib);
int dmax = ((dm > db) ? dm : db);
int d = dmax + dt + db;
if (d < (int)distance[d_index])
{
distance[d_index] = (png_byte)d;
png_ptr->palette_lookup[d_index] = (png_byte)i;
}
}
}
}
}
png_free(png_ptr, distance);
}
}
#endif
#ifdef PNG_READ_GAMMA_SUPPORTED
void PNGFAPI
png_set_gamma_fixed(png_structrp png_ptr, png_fixed_point scrn_gamma,
png_fixed_point file_gamma)
{ … }
# ifdef PNG_FLOATING_POINT_SUPPORTED
void PNGAPI
png_set_gamma(png_structrp png_ptr, double scrn_gamma, double file_gamma)
{ … }
# endif
#endif
#ifdef PNG_READ_EXPAND_SUPPORTED
void PNGAPI
png_set_expand(png_structrp png_ptr)
{ … }
void PNGAPI
png_set_palette_to_rgb(png_structrp png_ptr)
{ … }
void PNGAPI
png_set_expand_gray_1_2_4_to_8(png_structrp png_ptr)
{ … }
void PNGAPI
png_set_tRNS_to_alpha(png_structrp png_ptr)
{ … }
#endif
#ifdef PNG_READ_EXPAND_16_SUPPORTED
void PNGAPI
png_set_expand_16(png_structrp png_ptr)
{ … }
#endif
#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED
void PNGAPI
png_set_gray_to_rgb(png_structrp png_ptr)
{ … }
#endif
#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED
void PNGFAPI
png_set_rgb_to_gray_fixed(png_structrp png_ptr, int error_action,
png_fixed_point red, png_fixed_point green)
{ … }
#ifdef PNG_FLOATING_POINT_SUPPORTED
void PNGAPI
png_set_rgb_to_gray(png_structrp png_ptr, int error_action, double red,
double green)
{ … }
#endif
#endif
#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \
defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
void PNGAPI
png_set_read_user_transform_fn(png_structrp png_ptr, png_user_transform_ptr
read_user_transform_fn)
{ … }
#endif
#ifdef PNG_READ_TRANSFORMS_SUPPORTED
#ifdef PNG_READ_GAMMA_SUPPORTED
static int
png_gamma_threshold(png_fixed_point screen_gamma, png_fixed_point file_gamma)
{ … }
#endif
static void
png_init_palette_transformations(png_structrp png_ptr)
{ … }
static void
png_init_rgb_transformations(png_structrp png_ptr)
{ … }
void
png_init_read_transformations(png_structrp png_ptr)
{ … }
void
png_read_transform_info(png_structrp png_ptr, png_inforp info_ptr)
{ … }
#ifdef PNG_READ_PACK_SUPPORTED
static void
png_do_unpack(png_row_infop row_info, png_bytep row)
{ … }
#endif
#ifdef PNG_READ_SHIFT_SUPPORTED
static void
png_do_unshift(png_row_infop row_info, png_bytep row,
png_const_color_8p sig_bits)
{ … }
#endif
#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED
static void
png_do_scale_16_to_8(png_row_infop row_info, png_bytep row)
{ … }
#endif
#ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED
static void
png_do_chop(png_row_infop row_info, png_bytep row)
{ … }
#endif
#ifdef PNG_READ_SWAP_ALPHA_SUPPORTED
static void
png_do_read_swap_alpha(png_row_infop row_info, png_bytep row)
{ … }
#endif
#ifdef PNG_READ_INVERT_ALPHA_SUPPORTED
static void
png_do_read_invert_alpha(png_row_infop row_info, png_bytep row)
{
png_uint_32 row_width;
png_debug(1, "in png_do_read_invert_alpha");
row_width = row_info->width;
if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
{
if (row_info->bit_depth == 8)
{
png_bytep sp = row + row_info->rowbytes;
png_bytep dp = sp;
png_uint_32 i;
for (i = 0; i < row_width; i++)
{
*(--dp) = (png_byte)(255 - *(--sp));
sp-=3;
dp=sp;
}
}
#ifdef PNG_READ_16BIT_SUPPORTED
else
{
png_bytep sp = row + row_info->rowbytes;
png_bytep dp = sp;
png_uint_32 i;
for (i = 0; i < row_width; i++)
{
*(--dp) = (png_byte)(255 - *(--sp));
*(--dp) = (png_byte)(255 - *(--sp));
sp-=6;
dp=sp;
}
}
#endif
}
else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
{
if (row_info->bit_depth == 8)
{
png_bytep sp = row + row_info->rowbytes;
png_bytep dp = sp;
png_uint_32 i;
for (i = 0; i < row_width; i++)
{
*(--dp) = (png_byte)(255 - *(--sp));
*(--dp) = *(--sp);
}
}
#ifdef PNG_READ_16BIT_SUPPORTED
else
{
png_bytep sp = row + row_info->rowbytes;
png_bytep dp = sp;
png_uint_32 i;
for (i = 0; i < row_width; i++)
{
*(--dp) = (png_byte)(255 - *(--sp));
*(--dp) = (png_byte)(255 - *(--sp));
sp-=2;
dp=sp;
}
}
#endif
}
}
#endif
#ifdef PNG_READ_FILLER_SUPPORTED
static void
png_do_read_filler(png_row_infop row_info, png_bytep row,
png_uint_32 filler, png_uint_32 flags)
{ … }
#endif
#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED
static void
png_do_gray_to_rgb(png_row_infop row_info, png_bytep row)
{ … }
#endif
#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED
static int
png_do_rgb_to_gray(png_structrp png_ptr, png_row_infop row_info, png_bytep row)
{ … }
#endif
#if defined(PNG_READ_BACKGROUND_SUPPORTED) ||\
defined(PNG_READ_ALPHA_MODE_SUPPORTED)
static void
png_do_compose(png_row_infop row_info, png_bytep row, png_structrp png_ptr)
{ … }
#endif
#ifdef PNG_READ_GAMMA_SUPPORTED
static void
png_do_gamma(png_row_infop row_info, png_bytep row, png_structrp png_ptr)
{ … }
#endif
#ifdef PNG_READ_ALPHA_MODE_SUPPORTED
static void
png_do_encode_alpha(png_row_infop row_info, png_bytep row, png_structrp png_ptr)
{ … }
#endif
#ifdef PNG_READ_EXPAND_SUPPORTED
static void
png_do_expand_palette(png_structrp png_ptr, png_row_infop row_info,
png_bytep row, png_const_colorp palette, png_const_bytep trans_alpha,
int num_trans)
{ … }
static void
png_do_expand(png_row_infop row_info, png_bytep row,
png_const_color_16p trans_color)
{ … }
#endif
#ifdef PNG_READ_EXPAND_16_SUPPORTED
static void
png_do_expand_16(png_row_infop row_info, png_bytep row)
{ … }
#endif
#ifdef PNG_READ_QUANTIZE_SUPPORTED
static void
png_do_quantize(png_row_infop row_info, png_bytep row,
png_const_bytep palette_lookup, png_const_bytep quantize_lookup)
{
png_bytep sp, dp;
png_uint_32 i;
png_uint_32 row_width=row_info->width;
png_debug(1, "in png_do_quantize");
if (row_info->bit_depth == 8)
{
if (row_info->color_type == PNG_COLOR_TYPE_RGB && palette_lookup)
{
int r, g, b, p;
sp = row;
dp = row;
for (i = 0; i < row_width; i++)
{
r = *sp++;
g = *sp++;
b = *sp++;
p = (((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));
*dp++ = palette_lookup[p];
}
row_info->color_type = PNG_COLOR_TYPE_PALETTE;
row_info->channels = 1;
row_info->pixel_depth = row_info->bit_depth;
row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width);
}
else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA &&
palette_lookup != NULL)
{
int r, g, b, p;
sp = row;
dp = row;
for (i = 0; i < row_width; i++)
{
r = *sp++;
g = *sp++;
b = *sp++;
sp++;
p = (((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));
*dp++ = palette_lookup[p];
}
row_info->color_type = PNG_COLOR_TYPE_PALETTE;
row_info->channels = 1;
row_info->pixel_depth = row_info->bit_depth;
row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width);
}
else if (row_info->color_type == PNG_COLOR_TYPE_PALETTE &&
quantize_lookup)
{
sp = row;
for (i = 0; i < row_width; i++, sp++)
{
*sp = quantize_lookup[*sp];
}
}
}
}
#endif
void
png_do_read_transformations(png_structrp png_ptr, png_row_infop row_info)
{ … }
#endif
#endif