libpng/pngrtran.c

3566 lines
116 KiB
C
Raw Normal View History

1995-07-20 03:43:20 -04:00
1997-05-16 03:46:07 -04:00
/* pngrtran.c - transforms the data in a row for PNG readers
1998-01-01 08:13:13 -05:00
*
1998-05-21 10:27:50 -04:00
* 1.0.1d
1998-01-01 08:13:13 -05:00
* For conditions of distribution and use, see copyright notice in png.h
* Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
* Copyright (c) 1996, 1997 Andreas Dilger
1998-01-07 21:54:20 -05:00
* Copyright (c) 1998, Glenn Randers-Pehrson
1998-05-21 10:27:50 -04:00
* May 21, 1998
1998-01-01 08:13:13 -05:00
*
* This file contains functions optionally called by an application
* in order to tell libpng how to handle data when reading a PNG.
1998-05-21 10:27:50 -04:00
* Transformations that are used in both reading and writing are
1998-01-01 08:13:13 -05:00
* in pngtrans.c.
*/
1995-07-20 03:43:20 -04:00
#define PNG_INTERNAL
#include "png.h"
1998-01-01 08:13:13 -05:00
/* Set the action on getting a CRC error for an ancillary or critical chunk. */
void
png_set_crc_action(png_structp png_ptr, int crit_action, int ancil_action)
{
png_debug(1, "in png_set_crc_action\n");
/* Tell libpng how we react to CRC errors in critical chunks */
switch (crit_action)
{
case PNG_CRC_NO_CHANGE: /* leave setting as is */
break;
case PNG_CRC_WARN_USE: /* warn/use data */
png_ptr->flags &= ~PNG_FLAG_CRC_CRITICAL_MASK;
png_ptr->flags |= PNG_FLAG_CRC_CRITICAL_USE;
break;
case PNG_CRC_QUIET_USE: /* quiet/use data */
png_ptr->flags &= ~PNG_FLAG_CRC_CRITICAL_MASK;
png_ptr->flags |= PNG_FLAG_CRC_CRITICAL_USE |
PNG_FLAG_CRC_CRITICAL_IGNORE;
break;
case PNG_CRC_WARN_DISCARD: /* not a valid action for critical data */
png_warning(png_ptr, "Can't discard critical data on CRC error.");
case PNG_CRC_ERROR_QUIT: /* error/quit */
case PNG_CRC_DEFAULT:
default:
png_ptr->flags &= ~PNG_FLAG_CRC_CRITICAL_MASK;
break;
}
switch (ancil_action)
{
case PNG_CRC_NO_CHANGE: /* leave setting as is */
break;
case PNG_CRC_WARN_USE: /* warn/use data */
png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK;
png_ptr->flags |= PNG_FLAG_CRC_ANCILLARY_USE;
break;
case PNG_CRC_QUIET_USE: /* quiet/use data */
png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK;
png_ptr->flags |= PNG_FLAG_CRC_ANCILLARY_USE |
PNG_FLAG_CRC_ANCILLARY_NOWARN;
break;
case PNG_CRC_ERROR_QUIT: /* error/quit */
png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK;
png_ptr->flags |= PNG_FLAG_CRC_ANCILLARY_NOWARN;
break;
case PNG_CRC_WARN_DISCARD: /* warn/discard data */
case PNG_CRC_DEFAULT:
default:
png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK;
break;
}
}
1995-09-26 06:22:39 -04:00
#if defined(PNG_READ_BACKGROUND_SUPPORTED)
1995-07-20 03:43:20 -04:00
/* handle alpha and tRNS via a background color */
void
1995-12-19 04:22:19 -05:00
png_set_background(png_structp png_ptr,
png_color_16p background_color, int background_gamma_code,
1995-09-26 06:22:39 -04:00
int need_expand, double background_gamma)
1995-07-20 03:43:20 -04:00
{
1997-05-16 03:46:07 -04:00
png_debug(1, "in png_set_background\n");
1997-01-17 02:34:35 -05:00
if (background_gamma_code == PNG_BACKGROUND_GAMMA_UNKNOWN)
{
png_warning(png_ptr, "Application must supply a known background gamma");
return;
}
1995-07-20 03:43:20 -04:00
png_ptr->transformations |= PNG_BACKGROUND;
1998-05-02 13:52:25 -04:00
png_memcpy(&(png_ptr->background), background_color, sizeof(png_color_16));
1995-09-26 06:22:39 -04:00
png_ptr->background_gamma = (float)background_gamma;
1996-01-26 02:38:47 -05:00
png_ptr->background_gamma_type = (png_byte)(background_gamma_code);
1996-06-05 16:50:50 -04:00
png_ptr->transformations |= (need_expand ? PNG_BACKGROUND_EXPAND : 0);
1998-05-02 13:52:25 -04:00
/* Note: if need_expand is set and color_type is either RGB or RGB_ALPHA
* (in which case need_expand is superfluous anyway), the background color
* might actually be gray yet not be flagged as such. This is not a problem
* for the current code, which uses PNG_FLAG_BACKGROUND_IS_GRAY only to
* decide when to do the png_do_gray_to_rgb() transformation.
*/
if ((need_expand && !(png_ptr->color_type & PNG_COLOR_MASK_COLOR)) ||
(!need_expand && background_color->red == background_color->green &&
background_color->red == background_color->blue))
png_ptr->flags |= PNG_FLAG_BACKGROUND_IS_GRAY;
1995-07-20 03:43:20 -04:00
}
1995-09-26 06:22:39 -04:00
#endif
1995-07-20 03:43:20 -04:00
1995-09-26 06:22:39 -04:00
#if defined(PNG_READ_16_TO_8_SUPPORTED)
1995-07-20 03:43:20 -04:00
/* strip 16 bit depth files to 8 bit depth */
void
1995-12-19 04:22:19 -05:00
png_set_strip_16(png_structp png_ptr)
1995-07-20 03:43:20 -04:00
{
1997-05-16 03:46:07 -04:00
png_debug(1, "in png_set_strip_16\n");
1995-07-20 03:43:20 -04:00
png_ptr->transformations |= PNG_16_TO_8;
}
1995-09-26 06:22:39 -04:00
#endif
1995-07-20 03:43:20 -04:00
1997-05-16 03:46:07 -04:00
#if defined(PNG_READ_STRIP_ALPHA_SUPPORTED)
void
png_set_strip_alpha(png_structp png_ptr)
{
png_debug(1, "in png_set_strip_alpha\n");
png_ptr->transformations |= PNG_STRIP_ALPHA;
}
#endif
1995-09-26 06:22:39 -04:00
#if defined(PNG_READ_DITHER_SUPPORTED)
1997-05-16 03:46:07 -04:00
/* Dither file to 8 bit. Supply a palette, the current number
1998-01-01 08:13:13 -05:00
* of elements in the palette, the maximum number of elements
* allowed, and a histogram if possible. If the current number
* of colors is greater then the maximum number, the palette will be
* modified to fit in the maximum number. "full_dither" indicates
* whether we need a dithering cube set up for RGB images, or if we
* simply are reducing the number of colors in a paletted image.
*/
1995-12-19 04:22:19 -05:00
typedef struct png_dsort_struct
1995-07-20 03:43:20 -04:00
{
1995-12-19 04:22:19 -05:00
struct png_dsort_struct FAR * next;
1995-07-20 03:43:20 -04:00
png_byte left;
png_byte right;
1995-12-19 04:22:19 -05:00
} png_dsort;
typedef png_dsort FAR * png_dsortp;
typedef png_dsort FAR * FAR * png_dsortpp;
1995-07-20 03:43:20 -04:00
void
1995-12-19 04:22:19 -05:00
png_set_dither(png_structp png_ptr, png_colorp palette,
int num_palette, int maximum_colors, png_uint_16p histogram,
1995-07-20 03:43:20 -04:00
int full_dither)
{
1997-05-16 03:46:07 -04:00
png_debug(1, "in png_set_dither\n");
1995-07-20 03:43:20 -04:00
png_ptr->transformations |= PNG_DITHER;
1996-01-26 02:38:47 -05:00
if (!full_dither)
1995-07-20 03:43:20 -04:00
{
int i;
1997-01-17 02:34:35 -05:00
png_ptr->dither_index = (png_bytep)png_malloc(png_ptr,
1998-02-07 11:20:57 -05:00
(png_uint_32)(num_palette * sizeof (png_byte)));
1995-07-20 03:43:20 -04:00
for (i = 0; i < num_palette; i++)
1996-01-26 02:38:47 -05:00
png_ptr->dither_index[i] = (png_byte)i;
1995-07-20 03:43:20 -04:00
}
if (num_palette > maximum_colors)
{
1997-05-16 03:46:07 -04:00
if (histogram != NULL)
1995-07-20 03:43:20 -04:00
{
1997-05-16 03:46:07 -04:00
/* This is easy enough, just throw out the least used colors.
Perhaps not the best solution, but good enough. */
1995-07-20 03:43:20 -04:00
int i;
1996-01-26 02:38:47 -05:00
png_bytep sort;
1995-07-20 03:43:20 -04:00
/* initialize an array to sort colors */
1998-02-07 11:20:57 -05:00
sort = (png_bytep)png_malloc(png_ptr, (png_uint_32)(num_palette
* sizeof (png_byte)));
1995-07-20 03:43:20 -04:00
/* initialize the sort array */
for (i = 0; i < num_palette; i++)
1996-01-26 02:38:47 -05:00
sort[i] = (png_byte)i;
1995-07-20 03:43:20 -04:00
1997-05-16 03:46:07 -04:00
/* Find the least used palette entries by starting a
1995-07-20 03:43:20 -04:00
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 */
1996-01-26 02:38:47 -05:00
int j;
1995-07-20 03:43:20 -04:00
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)
{
1998-05-21 10:27:50 -04:00
int j = num_palette;
1995-07-20 03:43:20 -04:00
/* put all the useful colors within the max, but don't
move the others */
1998-05-21 10:27:50 -04:00
for (i = 0; i < maximum_colors; i++)
1995-07-20 03:43:20 -04:00
{
1998-02-07 11:20:57 -05:00
if ((int)sort[i] >= maximum_colors)
1995-07-20 03:43:20 -04:00
{
do
j--;
1998-02-07 11:20:57 -05:00
while ((int)sort[j] >= maximum_colors);
1995-07-20 03:43:20 -04:00
palette[i] = palette[j];
}
1996-01-26 02:38:47 -05:00
}
1995-07-20 03:43:20 -04:00
}
else
{
1998-05-21 10:27:50 -04:00
int j = num_palette;
1995-07-20 03:43:20 -04:00
1996-01-26 02:38:47 -05:00
/* move all the used colors inside the max limit, and
1995-07-20 03:43:20 -04:00
develop a translation table */
1998-05-21 10:27:50 -04:00
for (i = 0; i < maximum_colors; i++)
1995-07-20 03:43:20 -04:00
{
/* only move the colors we need to */
1998-02-07 11:20:57 -05:00
if ((int)sort[i] >= maximum_colors)
1995-07-20 03:43:20 -04:00
{
png_color tmp_color;
do
j--;
1998-02-07 11:20:57 -05:00
while ((int)sort[j] >= maximum_colors);
1995-07-20 03:43:20 -04:00
tmp_color = palette[j];
palette[j] = palette[i];
palette[i] = tmp_color;
/* indicate where the color went */
1996-01-26 02:38:47 -05:00
png_ptr->dither_index[j] = (png_byte)i;
png_ptr->dither_index[i] = (png_byte)j;
1995-07-20 03:43:20 -04:00
}
}
1997-05-16 03:46:07 -04:00
/* find closest color for those colors we are not using */
1995-07-20 03:43:20 -04:00
for (i = 0; i < num_palette; i++)
{
1998-02-07 11:20:57 -05:00
if ((int)png_ptr->dither_index[i] >= maximum_colors)
1995-07-20 03:43:20 -04:00
{
1997-05-16 03:46:07 -04:00
int min_d, k, min_k, d_index;
1995-07-20 03:43:20 -04:00
1996-01-26 02:38:47 -05:00
/* find the closest color to one we threw out */
1997-05-16 03:46:07 -04:00
d_index = png_ptr->dither_index[i];
min_d = PNG_COLOR_DIST(palette[d_index], palette[0]);
for (k = 1, min_k = 0; k < maximum_colors; k++)
1995-07-20 03:43:20 -04:00
{
int d;
1997-05-16 03:46:07 -04:00
d = PNG_COLOR_DIST(palette[d_index], palette[k]);
1995-07-20 03:43:20 -04:00
if (d < min_d)
{
min_d = d;
1997-05-16 03:46:07 -04:00
min_k = k;
1995-07-20 03:43:20 -04:00
}
}
1996-01-26 02:38:47 -05:00
/* point to closest color */
1997-05-16 03:46:07 -04:00
png_ptr->dither_index[i] = (png_byte)min_k;
1995-07-20 03:43:20 -04:00
}
}
}
1997-01-17 02:34:35 -05:00
png_free(png_ptr, sort);
1995-07-20 03:43:20 -04:00
}
else
{
1997-05-16 03:46:07 -04:00
/* This is much harder to do simply (and quickly). Perhaps
1995-07-20 03:43:20 -04:00
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).
1997-05-16 03:46:07 -04:00
[I don't understand this at all, so if someone wants to
work on improving it, be my guest - AED]
1995-07-20 03:43:20 -04:00
*/
int i;
int max_d;
int num_new_palette;
1996-01-26 02:38:47 -05:00
png_dsortpp hash;
png_bytep index_to_palette;
1995-07-20 03:43:20 -04:00
/* where the original index currently is in the palette */
1995-12-19 04:22:19 -05:00
png_bytep palette_to_index;
1995-07-20 03:43:20 -04:00
/* which original index points to this palette color */
/* initialize palette index arrays */
1997-01-17 02:34:35 -05:00
index_to_palette = (png_bytep)png_malloc(png_ptr,
1998-02-07 11:20:57 -05:00
(png_uint_32)(num_palette * sizeof (png_byte)));
1997-01-17 02:34:35 -05:00
palette_to_index = (png_bytep)png_malloc(png_ptr,
1998-02-07 11:20:57 -05:00
(png_uint_32)(num_palette * sizeof (png_byte)));
1995-07-20 03:43:20 -04:00
/* initialize the sort array */
for (i = 0; i < num_palette; i++)
{
1996-01-26 02:38:47 -05:00
index_to_palette[i] = (png_byte)i;
palette_to_index[i] = (png_byte)i;
1995-07-20 03:43:20 -04:00
}
1998-02-07 11:20:57 -05:00
hash = (png_dsortpp)png_malloc(png_ptr, (png_uint_32)(769 *
sizeof (png_dsortp)));
1995-07-20 03:43:20 -04:00
for (i = 0; i < 769; i++)
1997-05-16 03:46:07 -04:00
hash[i] = NULL;
1995-12-19 04:22:19 -05:00
/* png_memset(hash, 0, 769 * sizeof (png_dsortp)); */
1995-07-20 03:43:20 -04:00
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;
1996-01-26 02:38:47 -05:00
while (num_new_palette > maximum_colors)
1995-07-20 03:43:20 -04:00
{
for (i = 0; i < num_new_palette - 1; i++)
{
int j;
for (j = i + 1; j < num_new_palette; j++)
{
int d;
1996-01-26 02:38:47 -05:00
d = PNG_COLOR_DIST(palette[i], palette[j]);
1995-07-20 03:43:20 -04:00
if (d <= max_d)
{
1995-12-19 04:22:19 -05:00
png_dsortp t;
1995-07-20 03:43:20 -04:00
1998-02-07 11:20:57 -05:00
t = (png_dsortp)png_malloc(png_ptr, (png_uint_32)(sizeof
(png_dsort)));
1995-07-20 03:43:20 -04:00
t->next = hash[d];
1996-01-26 02:38:47 -05:00
t->left = (png_byte)i;
t->right = (png_byte)j;
1995-07-20 03:43:20 -04:00
hash[d] = t;
}
}
}
for (i = 0; i <= max_d; i++)
{
1997-05-16 03:46:07 -04:00
if (hash[i] != NULL)
1995-07-20 03:43:20 -04:00
{
1995-12-19 04:22:19 -05:00
png_dsortp p;
1995-07-20 03:43:20 -04:00
for (p = hash[i]; p; p = p->next)
{
1998-02-07 11:20:57 -05:00
if ((int)index_to_palette[p->left] < num_new_palette &&
(int)index_to_palette[p->right] < num_new_palette)
1995-07-20 03:43:20 -04:00
{
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--;
1997-05-16 03:46:07 -04:00
palette[index_to_palette[j]] = palette[num_new_palette];
1995-07-20 03:43:20 -04:00
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];
1998-02-07 11:20:57 -05:00
if ((int)png_ptr->dither_index[k] ==
1995-07-20 03:43:20 -04:00
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];
1996-01-26 02:38:47 -05:00
index_to_palette[j] = (png_byte)num_new_palette;
palette_to_index[num_new_palette] = (png_byte)j;
1995-07-20 03:43:20 -04:00
}
if (num_new_palette <= maximum_colors)
break;
}
if (num_new_palette <= maximum_colors)
break;
}
}
for (i = 0; i < 769; i++)
{
1997-05-16 03:46:07 -04:00
if (hash[i] != NULL)
1995-07-20 03:43:20 -04:00
{
1998-05-02 13:52:25 -04:00
png_dsortp p = hash[i];
1995-07-20 03:43:20 -04:00
while (p)
{
1996-01-26 02:38:47 -05:00
png_dsortp t;
1995-07-20 03:43:20 -04:00
t = p->next;
1997-01-17 02:34:35 -05:00
png_free(png_ptr, p);
1995-07-20 03:43:20 -04:00
p = t;
}
}
hash[i] = 0;
}
max_d += 96;
}
1997-01-17 02:34:35 -05:00
png_free(png_ptr, hash);
png_free(png_ptr, palette_to_index);
png_free(png_ptr, index_to_palette);
1995-07-20 03:43:20 -04:00
}
num_palette = maximum_colors;
}
1997-05-16 03:46:07 -04:00
if (png_ptr->palette == NULL)
1996-01-26 02:38:47 -05:00
{
1995-07-20 03:43:20 -04:00
png_ptr->palette = palette;
}
1996-01-26 02:38:47 -05:00
png_ptr->num_palette = (png_uint_16)num_palette;
1995-07-20 03:43:20 -04:00
if (full_dither)
{
int i;
1995-12-19 04:22:19 -05:00
png_bytep distance;
1998-05-02 13:52:25 -04:00
int total_bits = PNG_DITHER_RED_BITS + PNG_DITHER_GREEN_BITS +
1996-01-26 02:38:47 -05:00
PNG_DITHER_BLUE_BITS;
1998-05-02 13:52:25 -04:00
int num_red = (1 << PNG_DITHER_RED_BITS);
int num_green = (1 << PNG_DITHER_GREEN_BITS);
int num_blue = (1 << PNG_DITHER_BLUE_BITS);
png_size_t num_entries = ((png_size_t)1 << total_bits);
1995-07-20 03:43:20 -04:00
1997-01-17 02:34:35 -05:00
png_ptr->palette_lookup = (png_bytep )png_malloc(png_ptr,
1998-02-07 11:20:57 -05:00
(png_uint_32)(num_entries * sizeof (png_byte)));
1995-07-20 03:43:20 -04:00
1997-05-16 03:46:07 -04:00
png_memset(png_ptr->palette_lookup, 0, num_entries * sizeof (png_byte));
1995-07-20 03:43:20 -04:00
1998-02-07 11:20:57 -05:00
distance = (png_bytep)png_malloc(png_ptr, (png_uint_32)(num_entries *
sizeof(png_byte)));
1995-07-20 03:43:20 -04:00
1997-05-16 03:46:07 -04:00
png_memset(distance, 0xff, num_entries * sizeof(png_byte));
1995-07-20 03:43:20 -04:00
for (i = 0; i < num_palette; i++)
{
1998-05-02 13:52:25 -04:00
int ir, ig, ib;
int r = (palette[i].red >> (8 - PNG_DITHER_RED_BITS));
int g = (palette[i].green >> (8 - PNG_DITHER_GREEN_BITS));
int b = (palette[i].blue >> (8 - PNG_DITHER_BLUE_BITS));
1995-07-20 03:43:20 -04:00
for (ir = 0; ir < num_red; ir++)
{
1998-05-02 13:52:25 -04:00
int dr = abs(ir - r);
int index_r = (ir << (PNG_DITHER_BLUE_BITS + PNG_DITHER_GREEN_BITS));
1995-07-20 03:43:20 -04:00
for (ig = 0; ig < num_green; ig++)
1996-01-26 02:38:47 -05:00
{
1998-05-02 13:52:25 -04:00
int dg = abs(ig - g);
int dt = dr + dg;
int dm = ((dr > dg) ? dr : dg);
int index_g = index_r | (ig << PNG_DITHER_BLUE_BITS);
1995-07-20 03:43:20 -04:00
for (ib = 0; ib < num_blue; ib++)
1996-01-26 02:38:47 -05:00
{
1998-05-02 13:52:25 -04:00
int d_index = index_g | ib;
int db = abs(ib - b);
int dmax = ((dm > db) ? dm : db);
int d = dmax + dt + db;
1995-07-20 03:43:20 -04:00
1998-02-07 11:20:57 -05:00
if (d < (int)distance[d_index])
1995-07-20 03:43:20 -04:00
{
1997-05-16 03:46:07 -04:00
distance[d_index] = (png_byte)d;
png_ptr->palette_lookup[d_index] = (png_byte)i;
1995-07-20 03:43:20 -04:00
}
}
}
}
}
1997-01-17 02:34:35 -05:00
png_free(png_ptr, distance);
1995-07-20 03:43:20 -04:00
}
}
1995-09-26 06:22:39 -04:00
#endif
1995-07-20 03:43:20 -04:00
1995-09-26 06:22:39 -04:00
#if defined(PNG_READ_GAMMA_SUPPORTED)
1997-01-17 02:34:35 -05:00
/* Transform the image from the file_gamma to the screen_gamma. We
1998-01-01 08:13:13 -05:00
* only do transformations on images where the file_gamma and screen_gamma
* are not close reciprocals, otherwise it slows things down slightly, and
* also needlessly introduces small errors.
*/
1995-07-20 03:43:20 -04:00
void
1998-01-16 23:06:18 -05:00
png_set_gamma(png_structp png_ptr, double scrn_gamma, double file_gamma)
1995-07-20 03:43:20 -04:00
{
1997-05-16 03:46:07 -04:00
png_debug(1, "in png_set_gamma\n");
1998-01-16 23:06:18 -05:00
if (fabs(scrn_gamma * file_gamma - 1.0) > PNG_GAMMA_THRESHOLD)
1997-01-17 02:34:35 -05:00
png_ptr->transformations |= PNG_GAMMA;
1995-09-26 06:22:39 -04:00
png_ptr->gamma = (float)file_gamma;
1998-01-16 23:06:18 -05:00
png_ptr->screen_gamma = (float)scrn_gamma;
1995-07-20 03:43:20 -04:00
}
1995-09-26 06:22:39 -04:00
#endif
1995-07-20 03:43:20 -04:00
1995-09-26 06:22:39 -04:00
#if defined(PNG_READ_EXPAND_SUPPORTED)
1997-01-17 02:34:35 -05:00
/* Expand paletted images to rgb, expand grayscale images of
1998-01-01 08:13:13 -05:00
* less then 8 bit depth to 8 bit depth, and expand tRNS chunks
* to alpha channels.
*/
1995-07-20 03:43:20 -04:00
void
1995-12-19 04:22:19 -05:00
png_set_expand(png_structp png_ptr)
1995-07-20 03:43:20 -04:00
{
1997-05-16 03:46:07 -04:00
png_debug(1, "in png_set_expand\n");
1995-07-20 03:43:20 -04:00
png_ptr->transformations |= PNG_EXPAND;
}
1995-09-26 06:22:39 -04:00
#endif
1995-07-20 03:43:20 -04:00
1995-09-26 06:22:39 -04:00
#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
1995-07-20 03:43:20 -04:00
void
1995-12-19 04:22:19 -05:00
png_set_gray_to_rgb(png_structp png_ptr)
1995-07-20 03:43:20 -04:00
{
1997-05-16 03:46:07 -04:00
png_debug(1, "in png_set_gray_to_rgb\n");
1995-07-20 03:43:20 -04:00
png_ptr->transformations |= PNG_GRAY_TO_RGB;
}
1995-09-26 06:22:39 -04:00
#endif
1995-07-20 03:43:20 -04:00
1997-01-17 02:34:35 -05:00
#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
/* Convert a RGB image to a grayscale of the given width. This would
1998-01-01 08:13:13 -05:00
* allow us, for example, to convert a 24 bpp RGB image into an 8 or
* 16 bpp grayscale image. (Not yet implemented.)
*/
1997-01-17 02:34:35 -05:00
void
png_set_rgb_to_gray(png_structp png_ptr, int gray_bits)
{
1997-05-16 03:46:07 -04:00
png_debug(1, "in png_set_rgb_to_gray\n");
1997-01-17 02:34:35 -05:00
png_ptr->transformations |= PNG_RGB_TO_GRAY;
/* Need to do something with gray_bits here. */
1998-01-16 23:06:18 -05:00
png_warning(png_ptr, "RGB to GRAY transformation is not yet implemented.");
1997-01-17 02:34:35 -05:00
}
#endif
1998-03-07 07:06:55 -05:00
#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
void
png_set_read_user_transform_fn(png_structp png_ptr, png_user_transform_ptr
read_user_transform_fn)
{
png_debug(1, "in png_set_read_user_transform_fn\n");
png_ptr->transformations |= PNG_USER_TRANSFORM;
png_ptr->read_user_transform_fn = read_user_transform_fn;
}
#endif
1997-05-16 03:46:07 -04:00
/* Initialize everything needed for the read. This includes modifying
1998-01-01 08:13:13 -05:00
* the palette.
*/
1995-07-20 03:43:20 -04:00
void
1995-12-19 04:22:19 -05:00
png_init_read_transformations(png_structp png_ptr)
1995-07-20 03:43:20 -04:00
{
1998-05-21 10:27:50 -04:00
png_debug(1, "in png_init_read_transformations\n");
1998-05-09 11:02:29 -04:00
#if defined(PNG_USELESS_TESTS_SUPPORTED)
1998-05-21 10:27:50 -04:00
if(png_ptr != NULL)
#endif
{
#if defined(PNG_READ_BACKGROUND_SUPPORTED) || defined(PNG_READ_SHIFT_SUPPORTED) \
|| defined(PNG_READ_GAMMA_SUPPORTED)
int color_type = png_ptr->color_type;
1998-05-09 11:02:29 -04:00
#endif
1995-07-20 03:43:20 -04:00
1996-06-05 16:50:50 -04:00
#if defined(PNG_READ_EXPAND_SUPPORTED) && defined(PNG_READ_BACKGROUND_SUPPORTED)
if (png_ptr->transformations & PNG_BACKGROUND_EXPAND)
1995-07-20 03:43:20 -04:00
{
1998-05-02 13:52:25 -04:00
if (!(color_type & PNG_COLOR_MASK_COLOR)) /* i.e., GRAY or GRAY_ALPHA */
1995-07-20 03:43:20 -04:00
{
1996-06-05 16:50:50 -04:00
/* expand background chunk. */
1995-07-20 03:43:20 -04:00
switch (png_ptr->bit_depth)
{
case 1:
1996-06-05 16:50:50 -04:00
png_ptr->background.gray *= (png_uint_16)0xff;
png_ptr->background.red = png_ptr->background.green =
png_ptr->background.blue = png_ptr->background.gray;
1995-07-20 03:43:20 -04:00
break;
case 2:
1996-06-05 16:50:50 -04:00
png_ptr->background.gray *= (png_uint_16)0x55;
png_ptr->background.red = png_ptr->background.green =
png_ptr->background.blue = png_ptr->background.gray;
1995-07-20 03:43:20 -04:00
break;
case 4:
1996-06-05 16:50:50 -04:00
png_ptr->background.gray *= (png_uint_16)0x11;
png_ptr->background.red = png_ptr->background.green =
png_ptr->background.blue = png_ptr->background.gray;
break;
case 8:
case 16:
png_ptr->background.red = png_ptr->background.green =
png_ptr->background.blue = png_ptr->background.gray;
1995-07-20 03:43:20 -04:00
break;
}
}
1996-06-05 16:50:50 -04:00
else if (color_type == PNG_COLOR_TYPE_PALETTE)
1995-07-20 03:43:20 -04:00
{
1996-06-05 16:50:50 -04:00
png_ptr->background.red =
1995-07-20 03:43:20 -04:00
png_ptr->palette[png_ptr->background.index].red;
png_ptr->background.green =
png_ptr->palette[png_ptr->background.index].green;
1996-06-05 16:50:50 -04:00
png_ptr->background.blue =
1995-07-20 03:43:20 -04:00
png_ptr->palette[png_ptr->background.index].blue;
1998-01-16 23:06:18 -05:00
#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED)
if (png_ptr->transformations & PNG_INVERT_ALPHA)
{
#if defined(PNG_READ_EXPAND_SUPPORTED)
1998-03-10 00:02:06 -05:00
if (!(png_ptr->transformations & PNG_EXPAND))
1998-01-16 23:06:18 -05:00
#endif
{
/* invert the alpha channel (in tRNS) unless the pixels are
going to be expanded, in which case leave it for later */
1998-04-21 16:03:57 -04:00
int i,istop;
istop=(int)png_ptr->num_trans;
for (i=0; i<istop; i++)
1998-01-16 23:06:18 -05:00
png_ptr->trans[i] = 255 - png_ptr->trans[i];
}
}
#endif
1995-07-20 03:43:20 -04:00
}
}
1995-09-26 06:22:39 -04:00
#endif
1995-07-20 03:43:20 -04:00
1995-09-26 06:22:39 -04:00
#if defined(PNG_READ_BACKGROUND_SUPPORTED)
1995-07-20 03:43:20 -04:00
png_ptr->background_1 = png_ptr->background;
1995-09-26 06:22:39 -04:00
#endif
#if defined(PNG_READ_GAMMA_SUPPORTED)
1995-07-20 03:43:20 -04:00
if (png_ptr->transformations & PNG_GAMMA)
{
png_build_gamma_table(png_ptr);
1995-09-26 06:22:39 -04:00
#if defined(PNG_READ_BACKGROUND_SUPPORTED)
1996-06-05 16:50:50 -04:00
if (png_ptr->transformations & PNG_BACKGROUND)
1995-07-20 03:43:20 -04:00
{
1996-06-05 16:50:50 -04:00
if (color_type == PNG_COLOR_TYPE_PALETTE)
{
png_color back, back_1;
1998-05-02 13:52:25 -04:00
png_colorp palette = png_ptr->palette;
int num_palette = png_ptr->num_palette;
int i;
1996-06-05 16:50:50 -04:00
1997-05-16 03:46:07 -04:00
if (png_ptr->background_gamma_type == PNG_BACKGROUND_GAMMA_FILE)
{
back.red = png_ptr->gamma_table[png_ptr->background.red];
back.green = png_ptr->gamma_table[png_ptr->background.green];
back.blue = png_ptr->gamma_table[png_ptr->background.blue];
back_1.red = png_ptr->gamma_to_1[png_ptr->background.red];
back_1.green = png_ptr->gamma_to_1[png_ptr->background.green];
back_1.blue = png_ptr->gamma_to_1[png_ptr->background.blue];
}
else
{
1998-03-10 00:02:06 -05:00
double g, gs;
1997-05-16 03:46:07 -04:00
1998-03-10 00:02:06 -05:00
switch (png_ptr->background_gamma_type)
{
case PNG_BACKGROUND_GAMMA_SCREEN:
g = (png_ptr->screen_gamma);
gs = 1.0;
break;
case PNG_BACKGROUND_GAMMA_FILE:
g = 1.0 / (png_ptr->gamma);
gs = 1.0 / (png_ptr->gamma * png_ptr->screen_gamma);
break;
case PNG_BACKGROUND_GAMMA_UNIQUE:
g = 1.0 / (png_ptr->background_gamma);
gs = 1.0 / (png_ptr->background_gamma *
png_ptr->screen_gamma);
break;
default:
g = 1.0; /* back_1 */
gs = 1.0; /* back */
}
1997-05-16 03:46:07 -04:00
1998-03-15 19:20:23 -05:00
if ( fabs(gs - 1.0) < PNG_GAMMA_THRESHOLD)
1997-05-16 03:46:07 -04:00
{
1998-03-10 00:02:06 -05:00
back.red = (png_byte)png_ptr->background.red;
1997-05-16 03:46:07 -04:00
back.green = (png_byte)png_ptr->background.green;
1998-03-10 00:02:06 -05:00
back.blue = (png_byte)png_ptr->background.blue;
1997-05-16 03:46:07 -04:00
}
else
{
1998-03-10 00:02:06 -05:00
back.red = (png_byte)(pow(
(double)png_ptr->background.red/255, gs) * 255.0 + .5);
back.green = (png_byte)(pow(
(double)png_ptr->background.green/255, gs) * 255.0 + .5);
back.blue = (png_byte)(pow(
(double)png_ptr->background.blue/255, gs) * 255.0 + .5);
1997-05-16 03:46:07 -04:00
}
1996-06-05 16:50:50 -04:00
1998-03-10 00:02:06 -05:00
back_1.red = (png_byte)(pow(
(double)png_ptr->background.red/255, g) * 255.0 + .5);
back_1.green = (png_byte)(pow(
(double)png_ptr->background.green/255, g) * 255.0 + .5);
back_1.blue = (png_byte)(pow(
(double)png_ptr->background.blue/255, g) * 255.0 + .5);
1997-05-16 03:46:07 -04:00
}
1996-06-05 16:50:50 -04:00
for (i = 0; i < num_palette; i++)
{
1997-05-16 03:46:07 -04:00
if (i < (int)png_ptr->num_trans && png_ptr->trans[i] != 0xff)
1996-06-05 16:50:50 -04:00
{
if (png_ptr->trans[i] == 0)
{
palette[i] = back;
}
1997-05-16 03:46:07 -04:00
else /* if (png_ptr->trans[i] != 0xff) */
1996-06-05 16:50:50 -04:00
{
1997-05-16 03:46:07 -04:00
png_byte v, w;
1996-06-05 16:50:50 -04:00
v = png_ptr->gamma_to_1[palette[i].red];
1997-05-16 03:46:07 -04:00
png_composite(w, v, png_ptr->trans[i], back_1.red);
1996-06-05 16:50:50 -04:00
palette[i].red = png_ptr->gamma_from_1[w];
v = png_ptr->gamma_to_1[palette[i].green];
1997-05-16 03:46:07 -04:00
png_composite(w, v, png_ptr->trans[i], back_1.green);
1996-06-05 16:50:50 -04:00
palette[i].green = png_ptr->gamma_from_1[w];
v = png_ptr->gamma_to_1[palette[i].blue];
1997-05-16 03:46:07 -04:00
png_composite(w, v, png_ptr->trans[i], back_1.blue);
1996-06-05 16:50:50 -04:00
palette[i].blue = png_ptr->gamma_from_1[w];
}
}
else
{
palette[i].red = png_ptr->gamma_table[palette[i].red];
palette[i].green = png_ptr->gamma_table[palette[i].green];
palette[i].blue = png_ptr->gamma_table[palette[i].blue];
}
}
}
1997-05-16 03:46:07 -04:00
/* if (png_ptr->background_gamma_type!=PNG_BACKGROUND_GAMMA_UNKNOWN)*/
1998-02-28 08:00:24 -05:00
else
/* color_type != PNG_COLOR_TYPE_PALETTE */
1995-07-20 03:43:20 -04:00
{
1998-05-02 13:52:25 -04:00
double m = (double)(((png_uint_32)1 << png_ptr->bit_depth) - 1);
double g = 1.0;
double gs = 1.0;
1995-07-20 03:43:20 -04:00
switch (png_ptr->background_gamma_type)
1996-01-26 02:38:47 -05:00
{
1995-07-20 03:43:20 -04:00
case PNG_BACKGROUND_GAMMA_SCREEN:
1998-01-16 23:06:18 -05:00
g = (png_ptr->screen_gamma);
1995-07-20 03:43:20 -04:00
gs = 1.0;
break;
case PNG_BACKGROUND_GAMMA_FILE:
g = 1.0 / (png_ptr->gamma);
1998-01-16 23:06:18 -05:00
gs = 1.0 / (png_ptr->gamma * png_ptr->screen_gamma);
1995-07-20 03:43:20 -04:00
break;
case PNG_BACKGROUND_GAMMA_UNIQUE:
g = 1.0 / (png_ptr->background_gamma);
gs = 1.0 / (png_ptr->background_gamma *
1998-01-16 23:06:18 -05:00
png_ptr->screen_gamma);
1995-07-20 03:43:20 -04:00
break;
}
1996-01-26 02:38:47 -05:00
if (color_type & PNG_COLOR_MASK_COLOR)
1995-07-20 03:43:20 -04:00
{
1998-02-28 08:00:24 -05:00
/* RGB or RGBA */
1996-01-26 02:38:47 -05:00
png_ptr->background_1.red = (png_uint_16)(pow(
1995-07-20 03:43:20 -04:00
(double)png_ptr->background.red / m, g) * m + .5);
png_ptr->background_1.green = (png_uint_16)(pow(
(double)png_ptr->background.green / m, g) * m + .5);
png_ptr->background_1.blue = (png_uint_16)(pow(
(double)png_ptr->background.blue / m, g) * m + .5);
png_ptr->background.red = (png_uint_16)(pow(
(double)png_ptr->background.red / m, gs) * m + .5);
png_ptr->background.green = (png_uint_16)(pow(
(double)png_ptr->background.green / m, gs) * m + .5);
png_ptr->background.blue = (png_uint_16)(pow(
(double)png_ptr->background.blue / m, gs) * m + .5);
}
else
{
1998-02-28 08:00:24 -05:00
/* GRAY or GRAY ALPHA */
1995-07-20 03:43:20 -04:00
png_ptr->background_1.gray = (png_uint_16)(pow(
1996-01-26 02:38:47 -05:00
(double)png_ptr->background.gray / m, g) * m + .5);
1995-07-20 03:43:20 -04:00
png_ptr->background.gray = (png_uint_16)(pow(
1996-01-26 02:38:47 -05:00
(double)png_ptr->background.gray / m, gs) * m + .5);
1995-07-20 03:43:20 -04:00
}
}
}
1996-06-05 16:50:50 -04:00
else
1998-02-28 08:00:24 -05:00
/* transformation does not include PNG_BACKGROUND */
1996-06-05 16:50:50 -04:00
#endif
if (color_type == PNG_COLOR_TYPE_PALETTE)
{
1998-05-02 13:52:25 -04:00
png_colorp palette = png_ptr->palette;
int num_palette = png_ptr->num_palette;
int i;
1996-06-05 16:50:50 -04:00
for (i = 0; i < num_palette; i++)
{
palette[i].red = png_ptr->gamma_table[palette[i].red];
palette[i].green = png_ptr->gamma_table[palette[i].green];
palette[i].blue = png_ptr->gamma_table[palette[i].blue];
}
}
}
#if defined(PNG_READ_BACKGROUND_SUPPORTED)
else
1995-09-26 06:22:39 -04:00
#endif
1996-06-05 16:50:50 -04:00
#endif
#if defined(PNG_READ_BACKGROUND_SUPPORTED)
1998-02-28 08:00:24 -05:00
/* No GAMMA transformation */
1996-06-05 16:50:50 -04:00
if (png_ptr->transformations & PNG_BACKGROUND &&
color_type == PNG_COLOR_TYPE_PALETTE)
{
1998-05-02 13:52:25 -04:00
int i;
int istop = (int)png_ptr->num_trans;
1996-06-05 16:50:50 -04:00
png_color back;
1998-05-02 13:52:25 -04:00
png_colorp palette = png_ptr->palette;
1996-06-05 16:50:50 -04:00
back.red = (png_byte)png_ptr->background.red;
back.green = (png_byte)png_ptr->background.green;
back.blue = (png_byte)png_ptr->background.blue;
1998-04-21 16:03:57 -04:00
for (i = 0; i < istop; i++)
1996-06-05 16:50:50 -04:00
{
if (png_ptr->trans[i] == 0)
{
palette[i] = back;
}
else if (png_ptr->trans[i] != 0xff)
{
1998-05-02 13:52:25 -04:00
/* The png_composite() macro is defined in png.h */
1997-05-16 03:46:07 -04:00
png_composite(palette[i].red, palette[i].red,
png_ptr->trans[i], back.red);
png_composite(palette[i].green, palette[i].green,
png_ptr->trans[i], back.green);
png_composite(palette[i].blue, palette[i].blue,
png_ptr->trans[i], back.blue);
1996-06-05 16:50:50 -04:00
}
}
1995-09-26 06:22:39 -04:00
}
#endif
1995-12-19 04:22:19 -05:00
#if defined(PNG_READ_SHIFT_SUPPORTED)
1995-09-26 06:22:39 -04:00
if ((png_ptr->transformations & PNG_SHIFT) &&
1995-12-19 04:22:19 -05:00
color_type == PNG_COLOR_TYPE_PALETTE)
1995-09-26 06:22:39 -04:00
{
1998-05-02 13:52:25 -04:00
png_uint_16 i;
png_uint_16 istop = png_ptr->num_palette;
int sr = 8 - png_ptr->sig_bit.red;
int sg = 8 - png_ptr->sig_bit.green;
int sb = 8 - png_ptr->sig_bit.blue;
1995-09-26 06:22:39 -04:00
if (sr < 0 || sr > 8)
sr = 0;
if (sg < 0 || sg > 8)
sg = 0;
if (sb < 0 || sb > 8)
sb = 0;
1998-04-21 16:03:57 -04:00
for (i = 0; i < istop; i++)
1995-09-26 06:22:39 -04:00
{
png_ptr->palette[i].red >>= sr;
png_ptr->palette[i].green >>= sg;
png_ptr->palette[i].blue >>= sb;
}
}
#endif
1998-05-21 10:27:50 -04:00
}
1995-09-26 06:22:39 -04:00
}
1997-05-16 03:46:07 -04:00
/* Modify the info structure to reflect the transformations. The
1998-01-01 08:13:13 -05:00
* info should be updated so a PNG file could be written with it,
* assuming the transformations result in valid PNG data.
*/
1995-09-26 06:22:39 -04:00
void
1995-12-19 04:22:19 -05:00
png_read_transform_info(png_structp png_ptr, png_infop info_ptr)
1995-09-26 06:22:39 -04:00
{
1997-05-16 03:46:07 -04:00
png_debug(1, "in png_read_transform_info\n");
1995-09-26 06:22:39 -04:00
#if defined(PNG_READ_EXPAND_SUPPORTED)
1997-05-16 03:46:07 -04:00
if (png_ptr->transformations & PNG_EXPAND)
1995-09-26 06:22:39 -04:00
{
1997-05-16 03:46:07 -04:00
if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
{
if (png_ptr->num_trans)
info_ptr->color_type = PNG_COLOR_TYPE_RGB_ALPHA;
else
info_ptr->color_type = PNG_COLOR_TYPE_RGB;
1995-09-26 06:22:39 -04:00
info_ptr->bit_depth = 8;
1997-05-16 03:46:07 -04:00
info_ptr->num_trans = 0;
}
else
{
if (png_ptr->num_trans)
info_ptr->color_type |= PNG_COLOR_MASK_ALPHA;
if (info_ptr->bit_depth < 8)
info_ptr->bit_depth = 8;
info_ptr->num_trans = 0;
}
1995-09-26 06:22:39 -04:00
}
#endif
#if defined(PNG_READ_BACKGROUND_SUPPORTED)
if (png_ptr->transformations & PNG_BACKGROUND)
{
info_ptr->color_type &= ~PNG_COLOR_MASK_ALPHA;
info_ptr->num_trans = 0;
info_ptr->background = png_ptr->background;
}
#endif
#if defined(PNG_READ_16_TO_8_SUPPORTED)
if ((png_ptr->transformations & PNG_16_TO_8) && info_ptr->bit_depth == 16)
1996-01-26 02:38:47 -05:00
info_ptr->bit_depth = 8;
1995-09-26 06:22:39 -04:00
#endif
#if defined(PNG_READ_DITHER_SUPPORTED)
if (png_ptr->transformations & PNG_DITHER)
{
if (((info_ptr->color_type == PNG_COLOR_TYPE_RGB) ||
(info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)) &&
png_ptr->palette_lookup && info_ptr->bit_depth == 8)
{
info_ptr->color_type = PNG_COLOR_TYPE_PALETTE;
}
1995-07-20 03:43:20 -04:00
}
1995-09-26 06:22:39 -04:00
#endif
#if defined(PNG_READ_PACK_SUPPORTED)
if ((png_ptr->transformations & PNG_PACK) && info_ptr->bit_depth < 8)
info_ptr->bit_depth = 8;
#endif
#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
1998-03-15 19:20:23 -05:00
if (png_ptr->transformations & PNG_GRAY_TO_RGB)
1995-09-26 06:22:39 -04:00
info_ptr->color_type |= PNG_COLOR_MASK_COLOR;
#endif
1997-05-16 03:46:07 -04:00
1996-01-26 02:38:47 -05:00
if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
1995-09-26 06:22:39 -04:00
info_ptr->channels = 1;
else if (info_ptr->color_type & PNG_COLOR_MASK_COLOR)
info_ptr->channels = 3;
else
info_ptr->channels = 1;
1997-05-16 03:46:07 -04:00
1998-01-16 23:06:18 -05:00
#if defined(PNG_READ_STRIP_ALPHA_SUPPORTED)
1998-03-15 19:20:23 -05:00
if (png_ptr->transformations & PNG_STRIP_ALPHA)
1997-05-16 03:46:07 -04:00
info_ptr->color_type &= ~PNG_COLOR_MASK_ALPHA;
#endif
1998-05-02 13:52:25 -04:00
if (info_ptr->color_type & PNG_COLOR_MASK_ALPHA)
info_ptr->channels++;
1997-05-16 03:46:07 -04:00
#if defined(PNG_READ_FILLER_SUPPORTED)
1998-05-02 13:52:25 -04:00
/* STRIP_ALPHA and FILLER allowed: MASK_ALPHA bit stripped above */
if (png_ptr->transformations & PNG_FILLER &&
(info_ptr->color_type == PNG_COLOR_TYPE_RGB ||
info_ptr->color_type == PNG_COLOR_TYPE_GRAY))
++info_ptr->channels;
1997-05-16 03:46:07 -04:00
#endif
1996-01-26 02:38:47 -05:00
info_ptr->pixel_depth = (png_byte)(info_ptr->channels *
info_ptr->bit_depth);
1998-02-07 11:20:57 -05:00
info_ptr->rowbytes = ((info_ptr->width * info_ptr->pixel_depth + 7) >> 3);
1995-07-20 03:43:20 -04:00
}
1998-01-01 08:13:13 -05:00
/* Transform the row. The order of transformations is significant,
* and is very touchy. If you add a transformation, take care to
* decide how it fits in with the other transformations here.
*/
1995-07-20 03:43:20 -04:00
void
1995-12-19 04:22:19 -05:00
png_do_read_transformations(png_structp png_ptr)
1995-07-20 03:43:20 -04:00
{
1997-05-16 03:46:07 -04:00
png_debug(1, "in png_do_read_transformations\n");
#if !defined(PNG_USELESS_TESTS_SUPPORTED)
if (png_ptr->row_buf == NULL)
1995-07-20 03:43:20 -04:00
{
1998-01-03 23:40:55 -05:00
#if !defined(PNG_NO_STDIO)
1997-05-16 03:46:07 -04:00
char msg[50];
sprintf(msg, "NULL row buffer for row %ld, pass %d", png_ptr->row_number,
png_ptr->pass);
png_error(png_ptr, msg);
1998-01-03 23:40:55 -05:00
#else
png_error(png_ptr, "NULL row buffer");
#endif
1995-07-20 03:43:20 -04:00
}
1997-05-16 03:46:07 -04:00
#endif
#if defined(PNG_READ_EXPAND_SUPPORTED)
if (png_ptr->transformations & PNG_EXPAND)
1995-07-20 03:43:20 -04:00
{
1997-05-16 03:46:07 -04:00
if (png_ptr->row_info.color_type == PNG_COLOR_TYPE_PALETTE)
{
png_do_expand_palette(&(png_ptr->row_info), png_ptr->row_buf + 1,
png_ptr->palette, png_ptr->trans, png_ptr->num_trans);
}
else if (png_ptr->transformations & PNG_EXPAND)
{
if (png_ptr->num_trans)
png_do_expand(&(png_ptr->row_info), png_ptr->row_buf + 1,
&(png_ptr->trans_values));
else
png_do_expand(&(png_ptr->row_info), png_ptr->row_buf + 1,
NULL);
}
1995-07-20 03:43:20 -04:00
}
1995-09-26 06:22:39 -04:00
#endif
1997-05-16 03:46:07 -04:00
#if defined(PNG_READ_STRIP_ALPHA_SUPPORTED)
if (png_ptr->transformations & PNG_STRIP_ALPHA)
png_do_strip_filler(&(png_ptr->row_info), png_ptr->row_buf + 1,
PNG_FLAG_FILLER_AFTER);
#endif
1998-05-02 13:52:25 -04:00
/*
From Andreas Dilger e-mail to png-implement, 26 March 1998:
In most cases, the "simple transparency" should be done prior to doing
gray-to-RGB, or you will have to test 3x as many bytes to check if a
pixel is transparent. You would also need to make sure that the
transparency information is upgraded to RGB.
To summarize, the current flow is:
- Gray + simple transparency -> compare 1 or 2 gray bytes and composite
with background "in place" if transparent,
convert to RGB if necessary
- Gray + alpha -> composite with gray background and remove alpha bytes,
convert to RGB if necessary
To support RGB backgrounds for gray images we need:
- Gray + simple transparency -> convert to RGB + simple transparency, compare
3 or 6 bytes and composite with background
"in place" if transparent (3x compare/pixel
compared to doing composite with gray bkgrnd)
- Gray + alpha -> convert to RGB + alpha, composite with background and
remove alpha bytes (3x float operations/pixel
compared with composite on gray background)
Greg's change will do this. The reason it wasn't done before is for
performance, as this increases the per-pixel operations. If we would check
in advance if the background was gray or RGB, and position the gray-to-RGB
transform appropriately, then it would save a lot of work/time.
*/
#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
/* if gray -> RGB, do so now only if background is non-gray; else do later
* for performance reasons */
if (png_ptr->transformations & PNG_GRAY_TO_RGB &&
!(png_ptr->flags & PNG_FLAG_BACKGROUND_IS_GRAY))
png_do_gray_to_rgb(&(png_ptr->row_info), png_ptr->row_buf + 1);
#endif
1995-09-26 06:22:39 -04:00
#if defined(PNG_READ_BACKGROUND_SUPPORTED)
1998-01-01 08:13:13 -05:00
if ((png_ptr->transformations & PNG_BACKGROUND) &&
((png_ptr->num_trans != 0 ) ||
(png_ptr->color_type & PNG_COLOR_MASK_ALPHA)))
1995-07-20 03:43:20 -04:00
png_do_background(&(png_ptr->row_info), png_ptr->row_buf + 1,
&(png_ptr->trans_values), &(png_ptr->background),
&(png_ptr->background_1),
png_ptr->gamma_table, png_ptr->gamma_from_1,
png_ptr->gamma_to_1, png_ptr->gamma_16_table,
png_ptr->gamma_16_from_1, png_ptr->gamma_16_to_1,
png_ptr->gamma_shift);
1995-09-26 06:22:39 -04:00
#endif
#if defined(PNG_READ_GAMMA_SUPPORTED)
if ((png_ptr->transformations & PNG_GAMMA) &&
1997-01-17 02:34:35 -05:00
!(png_ptr->transformations & PNG_BACKGROUND) &&
(png_ptr->color_type != PNG_COLOR_TYPE_PALETTE))
1995-07-20 03:43:20 -04:00
png_do_gamma(&(png_ptr->row_info), png_ptr->row_buf + 1,
png_ptr->gamma_table, png_ptr->gamma_16_table,
png_ptr->gamma_shift);
1995-09-26 06:22:39 -04:00
#endif
1998-03-07 07:06:55 -05:00
#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
1997-01-17 02:34:35 -05:00
if (png_ptr->transformations & PNG_RGB_TO_GRAY)
png_do_rgb_to_gray(&(png_ptr->row_info), png_ptr->row_buf + 1);
#endif
1995-09-26 06:22:39 -04:00
#if defined(PNG_READ_16_TO_8_SUPPORTED)
1995-07-20 03:43:20 -04:00
if (png_ptr->transformations & PNG_16_TO_8)
png_do_chop(&(png_ptr->row_info), png_ptr->row_buf + 1);
1995-09-26 06:22:39 -04:00
#endif
#if defined(PNG_READ_DITHER_SUPPORTED)
1995-07-20 03:43:20 -04:00
if (png_ptr->transformations & PNG_DITHER)
1995-09-26 06:22:39 -04:00
{
1997-05-16 03:46:07 -04:00
png_do_dither((png_row_infop)&(png_ptr->row_info), png_ptr->row_buf + 1,
png_ptr->palette_lookup, png_ptr->dither_index);
1998-02-07 11:20:57 -05:00
if(png_ptr->row_info.rowbytes == (png_uint_32)0)
png_error(png_ptr, "png_do_dither returned rowbytes=0");
1997-05-16 03:46:07 -04:00
}
1995-09-26 06:22:39 -04:00
#endif
#if defined(PNG_READ_INVERT_SUPPORTED)
1995-07-20 03:43:20 -04:00
if (png_ptr->transformations & PNG_INVERT_MONO)
1996-01-26 02:38:47 -05:00
png_do_invert(&(png_ptr->row_info), png_ptr->row_buf + 1);
1995-09-26 06:22:39 -04:00
#endif
#if defined(PNG_READ_SHIFT_SUPPORTED)
1995-07-20 03:43:20 -04:00
if (png_ptr->transformations & PNG_SHIFT)
png_do_unshift(&(png_ptr->row_info), png_ptr->row_buf + 1,
&(png_ptr->shift));
1995-09-26 06:22:39 -04:00
#endif
#if defined(PNG_READ_PACK_SUPPORTED)
1995-07-20 03:43:20 -04:00
if (png_ptr->transformations & PNG_PACK)
1996-01-26 02:38:47 -05:00
png_do_unpack(&(png_ptr->row_info), png_ptr->row_buf + 1);
1995-09-26 06:22:39 -04:00
#endif
#if defined(PNG_READ_BGR_SUPPORTED)
1995-07-20 03:43:20 -04:00
if (png_ptr->transformations & PNG_BGR)
png_do_bgr(&(png_ptr->row_info), png_ptr->row_buf + 1);
1995-09-26 06:22:39 -04:00
#endif
1997-05-16 03:46:07 -04:00
#if defined(PNG_READ_PACKSWAP_SUPPORTED)
if (png_ptr->transformations & PNG_PACKSWAP)
png_do_packswap(&(png_ptr->row_info), png_ptr->row_buf + 1);
#endif
1995-09-26 06:22:39 -04:00
#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
1998-05-02 13:52:25 -04:00
/* if gray -> RGB, do so now only if we did not do so above */
if (png_ptr->transformations & PNG_GRAY_TO_RGB &&
png_ptr->flags & PNG_FLAG_BACKGROUND_IS_GRAY)
1995-07-20 03:43:20 -04:00
png_do_gray_to_rgb(&(png_ptr->row_info), png_ptr->row_buf + 1);
1995-09-26 06:22:39 -04:00
#endif
#if defined(PNG_READ_FILLER_SUPPORTED)
if (png_ptr->transformations & PNG_FILLER)
png_do_read_filler(&(png_ptr->row_info), png_ptr->row_buf + 1,
1997-05-16 03:46:07 -04:00
(png_uint_32)png_ptr->filler, png_ptr->flags);
#endif
1998-01-16 23:06:18 -05:00
#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED)
if (png_ptr->transformations & PNG_INVERT_ALPHA)
png_do_read_invert_alpha(&(png_ptr->row_info), png_ptr->row_buf + 1);
#endif
1998-02-28 08:00:24 -05:00
#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED)
if (png_ptr->transformations & PNG_SWAP_ALPHA)
png_do_read_swap_alpha(&(png_ptr->row_info), png_ptr->row_buf + 1);
#endif
1997-05-16 03:46:07 -04:00
#if defined(PNG_READ_SWAP_SUPPORTED)
if (png_ptr->transformations & PNG_SWAP_BYTES)
png_do_swap(&(png_ptr->row_info), png_ptr->row_buf + 1);
1995-09-26 06:22:39 -04:00
#endif
1998-03-07 07:06:55 -05:00
#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
if (png_ptr->transformations & PNG_USER_TRANSFORM)
if(png_ptr->read_user_transform_fn != NULL)
(*(png_ptr->read_user_transform_fn)) /* user read transform function */
(png_ptr, /* png_ptr */
&(png_ptr->row_info), /* row_info: */
/* png_uint_32 width; width of row */
/* png_uint_32 rowbytes; number of bytes in row */
/* png_byte color_type; color type of pixels */
/* png_byte bit_depth; bit depth of samples */
/* png_byte channels; number of channels (1-4) */
/* png_byte pixel_depth; bits per pixel (depth*channels) */
png_ptr->row_buf + 1); /* start of pixel data for row */
#endif
1995-07-20 03:43:20 -04:00
}
1995-09-26 06:22:39 -04:00
#if defined(PNG_READ_PACK_SUPPORTED)
1998-01-01 08:13:13 -05:00
/* Unpack pixels of 1, 2, or 4 bits per pixel into 1 byte per pixel,
* without changing the actual values. Thus, if you had a row with
* a bit depth of 1, you would end up with bytes that only contained
* the numbers 0 or 1. If you would rather they contain 0 and 255, use
* png_do_shift() after this.
*/
1995-07-20 03:43:20 -04:00
void
1995-12-19 04:22:19 -05:00
png_do_unpack(png_row_infop row_info, png_bytep row)
1995-07-20 03:43:20 -04:00
{
1997-05-16 03:46:07 -04:00
png_debug(1, "in png_do_unpack\n");
#if defined(PNG_USELESS_TESTS_SUPPORTED)
if (row != NULL && row_info != NULL && row_info->bit_depth < 8)
#else
if (row_info->bit_depth < 8)
#endif
1995-07-20 03:43:20 -04:00
{
1998-05-02 13:52:25 -04:00
png_uint_32 i;
1998-04-21 16:03:57 -04:00
png_uint_32 row_width=row_info->width;
1997-05-16 03:46:07 -04:00
1995-07-20 03:43:20 -04:00
switch (row_info->bit_depth)
{
case 1:
{
1998-05-02 13:52:25 -04:00
png_bytep sp = row + (png_size_t)((row_width - 1) >> 3);
png_bytep dp = row + (png_size_t)row_width - 1;
png_uint_32 shift = 7 - (int)((row_width + 7) & 7);
1998-04-21 16:03:57 -04:00
for (i = 0; i < row_width; i++)
1995-07-20 03:43:20 -04:00
{
1996-01-26 02:38:47 -05:00
*dp = (png_byte)((*sp >> shift) & 0x1);
1995-07-20 03:43:20 -04:00
if (shift == 7)
{
shift = 0;
sp--;
1996-01-26 02:38:47 -05:00
}
1995-07-20 03:43:20 -04:00
else
shift++;
dp--;
}
break;
}
case 2:
{
1998-05-02 13:52:25 -04:00
png_bytep sp = row + (png_size_t)((row_width - 1) >> 2);
png_bytep dp = row + (png_size_t)row_width - 1;
png_uint_32 shift = (int)((3 - ((row_width + 3) & 3)) << 1);
1998-04-21 16:03:57 -04:00
for (i = 0; i < row_width; i++)
1995-07-20 03:43:20 -04:00
{
1996-01-26 02:38:47 -05:00
*dp = (png_byte)((*sp >> shift) & 0x3);
1995-07-20 03:43:20 -04:00
if (shift == 6)
{
shift = 0;
sp--;
}
else
shift += 2;
dp--;
}
break;
}
case 4:
{
1998-05-02 13:52:25 -04:00
png_bytep sp = row + (png_size_t)((row_width - 1) >> 1);
png_bytep dp = row + (png_size_t)row_width - 1;
png_uint_32 shift = (int)((1 - ((row_width + 1) & 1)) << 2);
1998-04-21 16:03:57 -04:00
for (i = 0; i < row_width; i++)
1995-07-20 03:43:20 -04:00
{
1996-01-26 02:38:47 -05:00
*dp = (png_byte)((*sp >> shift) & 0xf);
1995-07-20 03:43:20 -04:00
if (shift == 4)
{
shift = 0;
sp--;
}
else
shift = 4;
dp--;
}
break;
}
}
row_info->bit_depth = 8;
1996-01-26 02:38:47 -05:00
row_info->pixel_depth = (png_byte)(8 * row_info->channels);
1998-04-21 16:03:57 -04:00
row_info->rowbytes = row_width * row_info->channels;
1995-07-20 03:43:20 -04:00
}
}
1995-09-26 06:22:39 -04:00
#endif
1995-07-20 03:43:20 -04:00
1995-09-26 06:22:39 -04:00
#if defined(PNG_READ_SHIFT_SUPPORTED)
1998-01-01 08:13:13 -05:00
/* Reverse the effects of png_do_shift. This routine merely shifts the
* pixels back to their significant bits values. Thus, if you have
* a row of bit depth 8, but only 5 are significant, this will shift
* the values back to 0 through 31.
*/
1995-07-20 03:43:20 -04:00
void
1997-05-16 03:46:07 -04:00
png_do_unshift(png_row_infop row_info, png_bytep row, png_color_8p sig_bits)
1995-07-20 03:43:20 -04:00
{
1997-05-16 03:46:07 -04:00
png_debug(1, "in png_do_unshift\n");
if (
#if defined(PNG_USELESS_TESTS_SUPPORTED)
row != NULL && row_info != NULL && sig_bits != NULL &&
#endif
row_info->color_type != PNG_COLOR_TYPE_PALETTE)
1995-07-20 03:43:20 -04:00
{
int shift[4];
1998-05-02 13:52:25 -04:00
int channels = 0;
int c;
png_uint_16 value = 0;
1998-04-21 16:03:57 -04:00
png_uint_32 row_width = row_info->width;
1995-07-20 03:43:20 -04:00
if (row_info->color_type & PNG_COLOR_MASK_COLOR)
{
1995-12-19 04:22:19 -05:00
shift[channels++] = row_info->bit_depth - sig_bits->red;
shift[channels++] = row_info->bit_depth - sig_bits->green;
shift[channels++] = row_info->bit_depth - sig_bits->blue;
1995-07-20 03:43:20 -04:00
}
else
{
1995-12-19 04:22:19 -05:00
shift[channels++] = row_info->bit_depth - sig_bits->gray;
1995-07-20 03:43:20 -04:00
}
if (row_info->color_type & PNG_COLOR_MASK_ALPHA)
{
1995-12-19 04:22:19 -05:00
shift[channels++] = row_info->bit_depth - sig_bits->alpha;
1996-01-26 02:38:47 -05:00
}
1995-11-28 12:22:13 -05:00
1997-05-16 03:46:07 -04:00
for (c = 0; c < channels; c++)
1996-01-26 02:38:47 -05:00
{
1997-05-16 03:46:07 -04:00
if (shift[c] <= 0)
shift[c] = 0;
1996-01-26 02:38:47 -05:00
else
value = 1;
}
1995-07-20 03:43:20 -04:00
1996-01-26 02:38:47 -05:00
if (!value)
return;
1995-11-28 12:22:13 -05:00
1996-01-26 02:38:47 -05:00
switch (row_info->bit_depth)
1995-07-20 03:43:20 -04:00
{
case 2:
{
1997-05-16 03:46:07 -04:00
png_bytep bp;
1998-05-02 13:52:25 -04:00
png_uint_32 i;
png_uint_32 istop = row_info->rowbytes;
1997-05-16 03:46:07 -04:00
1998-05-09 11:02:29 -04:00
for (bp = row, i = 0; i < istop; i++)
1995-07-20 03:43:20 -04:00
{
*bp >>= 1;
1998-05-09 11:02:29 -04:00
*bp++ &= 0x55;
1995-07-20 03:43:20 -04:00
}
break;
}
case 4:
{
1998-05-21 10:27:50 -04:00
png_bytep bp = row;
1998-05-02 13:52:25 -04:00
png_uint_32 i;
png_uint_32 istop = row_info->rowbytes;
png_byte mask = (png_byte)(((int)0xf0 >> shift[0]) & (int)0xf0) |
1996-01-26 02:38:47 -05:00
(png_byte)((int)0xf >> shift[0]);
1998-05-02 13:52:25 -04:00
1998-05-21 10:27:50 -04:00
for (i = 0; i < istop; i++)
1995-07-20 03:43:20 -04:00
{
*bp >>= shift[0];
1998-05-09 11:02:29 -04:00
*bp++ &= mask;
1995-07-20 03:43:20 -04:00
}
break;
}
1998-05-21 10:27:50 -04:00
#ifndef PNG_SLOW_SHIFT
1995-07-20 03:43:20 -04:00
case 8:
{
1998-05-09 11:02:29 -04:00
png_bytep bp = row;
1998-02-07 11:20:57 -05:00
png_uint_32 i;
1998-05-09 11:02:29 -04:00
png_uint_32 istop = row_width * channels;
1995-07-20 03:43:20 -04:00
1998-05-09 11:02:29 -04:00
for (i = 0; i < istop; i++)
1997-05-16 03:46:07 -04:00
{
1998-05-09 11:02:29 -04:00
*bp++ >>= shift[i%channels];
1995-07-20 03:43:20 -04:00
}
break;
}
case 16:
{
1998-05-09 11:02:29 -04:00
png_bytep bp = row;
png_uint_32 i;
png_uint_32 istop = channels * row_width;
1995-07-20 03:43:20 -04:00
1998-05-09 11:02:29 -04:00
for (i = 0; i < istop; i++)
1997-05-16 03:46:07 -04:00
{
1998-05-09 11:02:29 -04:00
value = (png_uint_16)((*bp << 8) + *(bp + 1));
value >>= shift[i%channels];
*bp++ = (png_byte)(value >> 8);
*bp++ = (png_byte)(value & 0xff);
1995-07-20 03:43:20 -04:00
}
break;
}
1998-05-21 10:27:50 -04:00
#else
case 8:
{
png_bytep bp;
png_uint_32 i;
int cstop;
cstop=(int)row_info->channels;
for (bp = row, i = 0; i < row_width; i++)
{
for (c = 0; c < cstop; c++, bp++)
{
*bp >>= shift[c];
}
}
break;
}
case 16:
{
png_bytep bp;
png_size_t i;
int cstop;
cstop=(int)row_info->channels;
for (bp = row, i = 0; i < row_width; i++)
{
for (c = 0; c < cstop; c++, bp += 2)
{
value = (png_uint_16)((*bp << 8) + *(bp + 1));
value >>= shift[c];
*bp = (png_byte)(value >> 8);
*(bp + 1) = (png_byte)(value & 0xff);
}
}
break;
}
#endif
1995-07-20 03:43:20 -04:00
}
}
}
1995-09-26 06:22:39 -04:00
#endif
1995-07-20 03:43:20 -04:00
1995-09-26 06:22:39 -04:00
#if defined(PNG_READ_16_TO_8_SUPPORTED)
1995-07-20 03:43:20 -04:00
/* chop rows of bit depth 16 down to 8 */
void
1995-12-19 04:22:19 -05:00
png_do_chop(png_row_infop row_info, png_bytep row)
1995-07-20 03:43:20 -04:00
{
1997-05-16 03:46:07 -04:00
png_debug(1, "in png_do_chop\n");
#if defined(PNG_USELESS_TESTS_SUPPORTED)
if (row != NULL && row_info != NULL && row_info->bit_depth == 16)
#else
if (row_info->bit_depth == 16)
#endif
1995-07-20 03:43:20 -04:00
{
1998-05-02 13:52:25 -04:00
png_bytep sp = row;
png_bytep dp = row;
png_uint_32 i;
png_uint_32 istop = row_info->width * row_info->channels;
1997-05-16 03:46:07 -04:00
1998-04-21 16:03:57 -04:00
for (i = 0; i<istop; i++, sp += 2, dp++)
1995-07-20 03:43:20 -04:00
{
1997-05-16 03:46:07 -04:00
#if defined(PNG_READ_16_TO_8_ACCURATE_SCALE_SUPPORTED)
1998-04-21 16:03:57 -04:00
/* This does a more accurate scaling of the 16-bit color
* value, rather than a simple low-byte truncation.
*
* What the ideal calculation should be:
* *dp = (((((png_uint_32)(*sp) << 8) |
* (png_uint_32)(*(sp + 1))) * 255 + 127) / (png_uint_32)65535L;
*
* GRR: no, I think this is what it really should be:
* *dp = (((((png_uint_32)(*sp) << 8) |
* (png_uint_32)(*(sp + 1))) + 128L) / (png_uint_32)257L;
*
* GRR: here's the exact calculation with shifts:
* temp = (((png_uint_32)(*sp) << 8) | (png_uint_32)(*(sp + 1))) + 128L;
* *dp = (temp - (temp >> 8)) >> 8;
*
* Approximate calculation with shift/add instead of multiply/divide:
* *dp = ((((png_uint_32)(*sp) << 8) |
* (png_uint_32)((int)(*(sp + 1)) - *sp)) + 128) >> 8;
*
* What we actually do to avoid extra shifting and conversion:
*/
1998-01-07 21:54:20 -05:00
1997-05-16 03:46:07 -04:00
*dp = *sp + ((((int)(*(sp + 1)) - *sp) > 128) ? 1 : 0);
#else
1998-04-21 16:03:57 -04:00
/* Simply discard the low order byte */
1996-01-26 02:38:47 -05:00
*dp = *sp;
1997-05-16 03:46:07 -04:00
#endif
1995-07-20 03:43:20 -04:00
}
row_info->bit_depth = 8;
1996-01-26 02:38:47 -05:00
row_info->pixel_depth = (png_byte)(8 * row_info->channels);
1998-02-07 11:20:57 -05:00
row_info->rowbytes = row_info->width * row_info->channels;
1997-05-16 03:46:07 -04:00
}
}
#endif
#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED)
void
png_do_read_swap_alpha(png_row_infop row_info, png_bytep row)
{
png_debug(1, "in png_do_read_swap_alpha\n");
#if defined(PNG_USELESS_TESTS_SUPPORTED)
if (row != NULL && row_info != NULL)
#endif
{
1998-04-21 16:03:57 -04:00
png_uint_32 row_width = row_info->width;
1997-05-16 03:46:07 -04:00
if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
{
/* This converts from RGBA to ARGB */
if (row_info->bit_depth == 8)
{
1998-05-02 13:52:25 -04:00
png_bytep sp = row + row_info->rowbytes;
png_bytep dp = sp;
1997-05-16 03:46:07 -04:00
png_byte save;
png_uint_32 i;
1998-05-02 13:52:25 -04:00
1998-04-21 16:03:57 -04:00
for (i = 0; i < row_width; i++)
1997-05-16 03:46:07 -04:00
{
save = *(--sp);
*(--dp) = *(--sp);
*(--dp) = *(--sp);
*(--dp) = *(--sp);
*(--dp) = save;
}
}
/* This converts from RRGGBBAA to AARRGGBB */
else
{
1998-05-02 13:52:25 -04:00
png_bytep sp = row + row_info->rowbytes;
png_bytep dp = sp;
1997-05-16 03:46:07 -04:00
png_byte save[2];
png_uint_32 i;
1998-05-02 13:52:25 -04:00
1998-04-21 16:03:57 -04:00
for (i = 0; i < row_width; i++)
1997-05-16 03:46:07 -04:00
{
save[0] = *(--sp);
save[1] = *(--sp);
*(--dp) = *(--sp);
*(--dp) = *(--sp);
*(--dp) = *(--sp);
*(--dp) = *(--sp);
*(--dp) = *(--sp);
*(--dp) = *(--sp);
*(--dp) = save[0];
*(--dp) = save[1];
}
}
}
else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
{
/* This converts from GA to AG */
if (row_info->bit_depth == 8)
{
1998-05-02 13:52:25 -04:00
png_bytep sp = row + row_info->rowbytes;
png_bytep dp = sp;
1997-05-16 03:46:07 -04:00
png_byte save;
png_uint_32 i;
1998-05-02 13:52:25 -04:00
1998-04-21 16:03:57 -04:00
for (i = 0; i < row_width; i++)
1997-05-16 03:46:07 -04:00
{
save = *(--sp);
*(--dp) = *(--sp);
*(--dp) = save;
}
}
/* This converts from GGAA to AAGG */
else
{
1998-05-02 13:52:25 -04:00
png_bytep sp = row + row_info->rowbytes;
png_bytep dp = sp;
1997-05-16 03:46:07 -04:00
png_byte save[2];
png_uint_32 i;
1998-04-21 16:03:57 -04:00
for (i = 0; i < row_width; i++)
1997-05-16 03:46:07 -04:00
{
save[0] = *(--sp);
save[1] = *(--sp);
*(--dp) = *(--sp);
*(--dp) = *(--sp);
*(--dp) = save[0];
*(--dp) = save[1];
}
}
}
1995-07-20 03:43:20 -04:00
}
}
1995-09-26 06:22:39 -04:00
#endif
1995-07-20 03:43:20 -04:00
1998-01-16 23:06:18 -05:00
#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED)
void
png_do_read_invert_alpha(png_row_infop row_info, png_bytep row)
{
png_debug(1, "in png_do_read_invert_alpha\n");
#if defined(PNG_USELESS_TESTS_SUPPORTED)
if (row != NULL && row_info != NULL)
#endif
{
1998-04-21 16:03:57 -04:00
png_uint_32 row_width = row_info->width;
1998-01-16 23:06:18 -05:00
if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
{
/* This inverts the alpha channel in RGBA */
if (row_info->bit_depth == 8)
{
1998-05-02 13:52:25 -04:00
png_bytep sp = row + row_info->rowbytes;
png_bytep dp = sp;
1998-01-16 23:06:18 -05:00
png_uint_32 i;
1998-04-21 16:03:57 -04:00
for (i = 0; i < row_width; i++)
1998-01-16 23:06:18 -05:00
{
1998-02-28 08:00:24 -05:00
*(--dp) = 255 - *(--sp);
1998-01-16 23:06:18 -05:00
*(--dp) = *(--sp);
*(--dp) = *(--sp);
*(--dp) = *(--sp);
}
}
/* This inverts the alpha channel in RRGGBBAA */
else
{
1998-05-02 13:52:25 -04:00
png_bytep sp = row + row_info->rowbytes;
png_bytep dp = sp;
1998-01-16 23:06:18 -05:00
png_uint_32 i;
1998-04-21 16:03:57 -04:00
for (i = 0; i < row_width; i++)
1998-01-16 23:06:18 -05:00
{
1998-02-28 08:00:24 -05:00
*(--dp) = 255 - *(--sp);
*(--dp) = 255 - *(--sp);
1998-01-16 23:06:18 -05:00
*(--dp) = *(--sp);
*(--dp) = *(--sp);
*(--dp) = *(--sp);
*(--dp) = *(--sp);
*(--dp) = *(--sp);
*(--dp) = *(--sp);
}
}
}
else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
{
1998-02-28 08:00:24 -05:00
/* This inverts the alpha channel in GA */
1998-01-16 23:06:18 -05:00
if (row_info->bit_depth == 8)
{
1998-05-02 13:52:25 -04:00
png_bytep sp = row + row_info->rowbytes;
png_bytep dp = sp;
1998-01-16 23:06:18 -05:00
png_uint_32 i;
1998-04-21 16:03:57 -04:00
for (i = 0; i < row_width; i++)
1998-01-16 23:06:18 -05:00
{
*(--dp) = 255 - *(--sp);
1998-02-28 08:00:24 -05:00
*(--dp) = *(--sp);
1998-01-16 23:06:18 -05:00
}
}
1998-02-28 08:00:24 -05:00
/* This inverts the alpha channel in GGAA */
1998-01-16 23:06:18 -05:00
else
{
1998-05-02 13:52:25 -04:00
png_bytep sp = row + row_info->rowbytes;
png_bytep dp = sp;
1998-01-16 23:06:18 -05:00
png_uint_32 i;
1998-04-21 16:03:57 -04:00
for (i = 0; i < row_width; i++)
1998-01-16 23:06:18 -05:00
{
*(--dp) = 255 - *(--sp);
*(--dp) = 255 - *(--sp);
1998-02-28 08:00:24 -05:00
*(--dp) = *(--sp);
*(--dp) = *(--sp);
1998-01-16 23:06:18 -05:00
}
}
}
}
}
#endif
1995-09-26 06:22:39 -04:00
#if defined(PNG_READ_FILLER_SUPPORTED)
1997-05-16 03:46:07 -04:00
/* Add filler channel if we have RGB color */
1995-07-20 03:43:20 -04:00
void
1995-12-19 04:22:19 -05:00
png_do_read_filler(png_row_infop row_info, png_bytep row,
1997-05-16 03:46:07 -04:00
png_uint_32 filler, png_uint_32 flags)
1995-07-20 03:43:20 -04:00
{
1995-09-26 06:22:39 -04:00
png_uint_32 i;
1998-04-21 16:03:57 -04:00
png_uint_32 row_width = row_info->width;
1998-05-09 11:02:29 -04:00
png_byte hi_filler = (png_byte)((filler>>8) & 0xff);
png_byte low_filler = (png_byte)(filler & 0xff);
1997-05-16 03:46:07 -04:00
png_debug(1, "in png_do_read_filler\n");
if (
#if defined(PNG_USELESS_TESTS_SUPPORTED)
row != NULL && row_info != NULL &&
#endif
1998-04-21 16:03:57 -04:00
row_info->color_type == PNG_COLOR_TYPE_GRAY)
1995-07-20 03:43:20 -04:00
{
1998-04-21 16:03:57 -04:00
if(row_info->bit_depth == 8)
1995-07-20 03:43:20 -04:00
{
1998-04-21 16:03:57 -04:00
/* This changes the data from G to GX */
if (flags & PNG_FLAG_FILLER_AFTER)
1995-09-26 06:22:39 -04:00
{
1998-05-02 13:52:25 -04:00
png_bytep sp = row + (png_size_t)row_width;
png_bytep dp = sp + (png_size_t)row_width;
1998-04-21 16:03:57 -04:00
for (i = 1; i < row_width; i++)
{
*(--dp) = low_filler;
*(--dp) = *(--sp);
}
row_info->channels = 2;
row_info->pixel_depth = 16;
row_info->rowbytes = row_width * 2;
}
/* This changes the data from G to XG */
else
{
1998-05-02 13:52:25 -04:00
png_bytep sp = row + (png_size_t)row_width;
png_bytep dp = sp + (png_size_t)row_width;
1998-04-21 16:03:57 -04:00
for (i = 0; i < row_width; i++)
{
*(--dp) = *(--sp);
*(--dp) = low_filler;
}
row_info->channels = 2;
row_info->pixel_depth = 16;
row_info->rowbytes = row_width * 2;
}
}
else if(row_info->bit_depth == 16)
{
/* This changes the data from GG to GGXX */
if (flags & PNG_FLAG_FILLER_AFTER)
{
1998-05-02 13:52:25 -04:00
png_bytep sp = row + (png_size_t)row_width;
png_bytep dp = sp + (png_size_t)row_width;
1998-04-21 16:03:57 -04:00
for (i = 1; i < row_width; i++)
{
*(--dp) = hi_filler;
*(--dp) = low_filler;
*(--dp) = *(--sp);
*(--dp) = *(--sp);
}
row_info->channels = 2;
row_info->pixel_depth = 32;
row_info->rowbytes = row_width * 2;
}
/* This changes the data from GG to XXGG */
else
{
1998-05-02 13:52:25 -04:00
png_bytep sp = row + (png_size_t)row_width;
png_bytep dp = sp + (png_size_t)row_width;
1998-04-21 16:03:57 -04:00
for (i = 0; i < row_width; i++)
{
*(--dp) = *(--sp);
*(--dp) = *(--sp);
*(--dp) = hi_filler;
*(--dp) = low_filler;
}
row_info->channels = 2;
row_info->pixel_depth = 16;
row_info->rowbytes = row_width * 2;
1995-09-26 06:22:39 -04:00
}
1995-07-20 03:43:20 -04:00
}
1998-04-21 16:03:57 -04:00
} /* COLOR_TYPE == GRAY */
else if (row_info->color_type == PNG_COLOR_TYPE_RGB)
{
if(row_info->bit_depth == 8)
{
/* This changes the data from RGB to RGBX */
if (flags & PNG_FLAG_FILLER_AFTER)
{
1998-05-02 13:52:25 -04:00
png_bytep sp = row + (png_size_t)row_width * 3;
png_bytep dp = sp + (png_size_t)row_width;
1998-04-21 16:03:57 -04:00
for (i = 1; i < row_width; i++)
{
*(--dp) = low_filler;
*(--dp) = *(--sp);
*(--dp) = *(--sp);
*(--dp) = *(--sp);
}
row_info->channels = 4;
row_info->pixel_depth = 32;
row_info->rowbytes = row_width * 4;
}
1997-05-16 03:46:07 -04:00
/* This changes the data from RGB to XRGB */
1998-04-21 16:03:57 -04:00
else
{
1998-05-02 13:52:25 -04:00
png_bytep sp = row + (png_size_t)row_width * 3;
png_bytep dp = sp + (png_size_t)row_width;
1998-04-21 16:03:57 -04:00
for (i = 0; i < row_width; i++)
{
*(--dp) = *(--sp);
*(--dp) = *(--sp);
*(--dp) = *(--sp);
*(--dp) = low_filler;
}
row_info->channels = 4;
row_info->pixel_depth = 32;
row_info->rowbytes = row_width * 4;
}
}
else if(row_info->bit_depth == 16)
1995-07-20 03:43:20 -04:00
{
1998-04-21 16:03:57 -04:00
/* This changes the data from RRGGBB to RRGGBBXX */
if (flags & PNG_FLAG_FILLER_AFTER)
1995-09-26 06:22:39 -04:00
{
1998-05-02 13:52:25 -04:00
png_bytep sp = row + (png_size_t)row_width * 3;
png_bytep dp = sp + (png_size_t)row_width;
1998-04-21 16:03:57 -04:00
for (i = 1; i < row_width; i++)
{
*(--dp) = hi_filler;
*(--dp) = low_filler;
*(--dp) = *(--sp);
*(--dp) = *(--sp);
*(--dp) = *(--sp);
*(--dp) = *(--sp);
*(--dp) = *(--sp);
*(--dp) = *(--sp);
}
row_info->channels = 4;
row_info->pixel_depth = 64;
row_info->rowbytes = row_width * 4;
}
/* This changes the data from RRGGBB to XXRRGGBB */
else
{
1998-05-02 13:52:25 -04:00
png_bytep sp = row + (png_size_t)row_width * 3;
png_bytep dp = sp + (png_size_t)row_width;
1998-04-21 16:03:57 -04:00
for (i = 0; i < row_width; i++)
{
*(--dp) = *(--sp);
*(--dp) = *(--sp);
*(--dp) = *(--sp);
*(--dp) = *(--sp);
*(--dp) = *(--sp);
*(--dp) = *(--sp);
*(--dp) = hi_filler;
*(--dp) = low_filler;
}
row_info->channels = 4;
row_info->pixel_depth = 64;
row_info->rowbytes = row_width * 4;
1995-09-26 06:22:39 -04:00
}
1995-07-20 03:43:20 -04:00
}
1998-04-21 16:03:57 -04:00
} /* COLOR_TYPE == RGB */
1995-07-20 03:43:20 -04:00
}
1995-09-26 06:22:39 -04:00
#endif
1995-07-20 03:43:20 -04:00
1995-09-26 06:22:39 -04:00
#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
1997-05-16 03:46:07 -04:00
/* expand grayscale files to RGB, with or without alpha */
1995-07-20 03:43:20 -04:00
void
1995-12-19 04:22:19 -05:00
png_do_gray_to_rgb(png_row_infop row_info, png_bytep row)
1995-07-20 03:43:20 -04:00
{
1995-09-26 06:22:39 -04:00
png_uint_32 i;
1998-04-21 16:03:57 -04:00
png_uint_32 row_width = row_info->width;
1995-12-19 04:22:19 -05:00
1997-05-16 03:46:07 -04:00
png_debug(1, "in png_do_gray_to_rgb\n");
if (row_info->bit_depth >= 8 &&
#if defined(PNG_USELESS_TESTS_SUPPORTED)
row != NULL && row_info != NULL &&
#endif
1995-07-20 03:43:20 -04:00
!(row_info->color_type & PNG_COLOR_MASK_COLOR))
{
if (row_info->color_type == PNG_COLOR_TYPE_GRAY)
{
if (row_info->bit_depth == 8)
{
1998-05-02 13:52:25 -04:00
png_bytep sp = row + (png_size_t)row_width - 1;
png_bytep dp = sp + (png_size_t)row_width * 2;
1998-04-21 16:03:57 -04:00
for (i = 0; i < row_width; i++)
1995-07-20 03:43:20 -04:00
{
*(dp--) = *sp;
*(dp--) = *sp;
*(dp--) = *sp;
sp--;
}
}
else
{
1998-05-02 13:52:25 -04:00
png_bytep sp = row + (png_size_t)row_width * 2 - 1;
png_bytep dp = sp + (png_size_t)row_width * 4;
1998-04-21 16:03:57 -04:00
for (i = 0; i < row_width; i++)
1995-07-20 03:43:20 -04:00
{
*(dp--) = *sp;
*(dp--) = *(sp - 1);
*(dp--) = *sp;
*(dp--) = *(sp - 1);
*(dp--) = *sp;
*(dp--) = *(sp - 1);
sp--;
sp--;
}
}
}
else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
{
if (row_info->bit_depth == 8)
{
1998-05-02 13:52:25 -04:00
png_bytep sp = row + (png_size_t)row_width * 2 - 1;
png_bytep dp = sp + (png_size_t)row_width * 2;
1998-04-21 16:03:57 -04:00
for (i = 0; i < row_width; i++)
1995-07-20 03:43:20 -04:00
{
*(dp--) = *(sp--);
*(dp--) = *sp;
*(dp--) = *sp;
*(dp--) = *sp;
sp--;
}
}
else
{
1998-05-02 13:52:25 -04:00
png_bytep sp = row + (png_size_t)row_width * 4 - 1;
png_bytep dp = sp + (png_size_t)row_width * 4;
1998-04-21 16:03:57 -04:00
for (i = 0; i < row_width; i++)
1995-07-20 03:43:20 -04:00
{
*(dp--) = *(sp--);
*(dp--) = *(sp--);
*(dp--) = *sp;
*(dp--) = *(sp - 1);
*(dp--) = *sp;
*(dp--) = *(sp - 1);
*(dp--) = *sp;
*(dp--) = *(sp - 1);
sp--;
sp--;
}
}
}
1996-01-26 02:38:47 -05:00
row_info->channels += (png_byte)2;
1995-07-20 03:43:20 -04:00
row_info->color_type |= PNG_COLOR_MASK_COLOR;
1996-01-26 02:38:47 -05:00
row_info->pixel_depth = (png_byte)(row_info->channels *
row_info->bit_depth);
1998-04-21 16:03:57 -04:00
row_info->rowbytes = ((row_width *
1995-07-20 03:43:20 -04:00
row_info->pixel_depth + 7) >> 3);
}
}
1995-09-26 06:22:39 -04:00
#endif
1995-07-20 03:43:20 -04:00
1998-01-01 08:13:13 -05:00
/* Build a grayscale palette. Palette is assumed to be 1 << bit_depth
* large of png_color. This lets grayscale images be treated as
* paletted. Most useful for gamma correction and simplification
* of code.
*/
1995-07-20 03:43:20 -04:00
void
1995-12-19 04:22:19 -05:00
png_build_grayscale_palette(int bit_depth, png_colorp palette)
1995-07-20 03:43:20 -04:00
{
int num_palette;
int color_inc;
int i;
int v;
1997-05-16 03:46:07 -04:00
png_debug(1, "in png_do_build_grayscale_palette\n");
if (palette == NULL)
1995-07-20 03:43:20 -04:00
return;
switch (bit_depth)
{
case 1:
num_palette = 2;
color_inc = 0xff;
break;
case 2:
num_palette = 4;
color_inc = 0x55;
break;
case 4:
num_palette = 16;
color_inc = 0x11;
break;
case 8:
num_palette = 256;
color_inc = 1;
break;
default:
1996-01-26 02:38:47 -05:00
num_palette = 0;
1996-01-10 03:56:49 -05:00
color_inc = 0;
1995-07-20 03:43:20 -04:00
break;
}
for (i = 0, v = 0; i < num_palette; i++, v += color_inc)
{
1996-01-26 02:38:47 -05:00
palette[i].red = (png_byte)v;
palette[i].green = (png_byte)v;
palette[i].blue = (png_byte)v;
1995-07-20 03:43:20 -04:00
}
}
1997-01-17 02:34:35 -05:00
/* This function is currently unused. Do we really need it? */
#if defined(PNG_READ_DITHER_SUPPORTED) && defined(PNG_CORRECT_PALETTE_SUPPORTED)
1995-07-20 03:43:20 -04:00
void
1995-12-19 04:22:19 -05:00
png_correct_palette(png_structp png_ptr, png_colorp palette,
1995-07-20 03:43:20 -04:00
int num_palette)
{
1997-05-16 03:46:07 -04:00
png_debug(1, "in png_correct_palette\n");
1996-06-05 16:50:50 -04:00
#if defined(PNG_READ_BACKGROUND_SUPPORTED) && defined(PNG_READ_GAMMA_SUPPORTED)
1995-07-20 03:43:20 -04:00
if ((png_ptr->transformations & (PNG_GAMMA)) &&
(png_ptr->transformations & (PNG_BACKGROUND)))
{
1997-05-16 03:46:07 -04:00
png_color back, back_1;
1995-07-20 03:43:20 -04:00
1997-05-16 03:46:07 -04:00
if (png_ptr->background_gamma_type == PNG_BACKGROUND_GAMMA_FILE)
{
1996-06-05 16:50:50 -04:00
back.red = png_ptr->gamma_table[png_ptr->background.red];
back.green = png_ptr->gamma_table[png_ptr->background.green];
back.blue = png_ptr->gamma_table[png_ptr->background.blue];
1995-07-20 03:43:20 -04:00
1996-06-05 16:50:50 -04:00
back_1.red = png_ptr->gamma_to_1[png_ptr->background.red];
back_1.green = png_ptr->gamma_to_1[png_ptr->background.green];
back_1.blue = png_ptr->gamma_to_1[png_ptr->background.blue];
1997-05-16 03:46:07 -04:00
}
else
{
double g;
1995-07-20 03:43:20 -04:00
1998-01-16 23:06:18 -05:00
g = 1.0 / (png_ptr->background_gamma * png_ptr->screen_gamma);
1997-05-16 03:46:07 -04:00
if (png_ptr->background_gamma_type == PNG_BACKGROUND_GAMMA_SCREEN ||
fabs(g - 1.0) < PNG_GAMMA_THRESHOLD)
1995-07-20 03:43:20 -04:00
{
1997-05-16 03:46:07 -04:00
back.red = png_ptr->background.red;
back.green = png_ptr->background.green;
back.blue = png_ptr->background.blue;
}
else
{
back.red =
(png_byte)(pow((double)png_ptr->background.red/255, g) *
255.0 + 0.5);
back.green =
(png_byte)(pow((double)png_ptr->background.green/255, g) *
255.0 + 0.5);
back.blue =
(png_byte)(pow((double)png_ptr->background.blue/255, g) *
255.0 + 0.5);
}
g = 1.0 / png_ptr->background_gamma;
back_1.red =
(png_byte)(pow((double)png_ptr->background.red/255, g) *
255.0 + 0.5);
back_1.green =
(png_byte)(pow((double)png_ptr->background.green/255, g) *
255.0 + 0.5);
back_1.blue =
(png_byte)(pow((double)png_ptr->background.blue/255, g) *
255.0 + 0.5);
}
if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
{
png_uint_32 i;
for (i = 0; i < (png_uint_32)num_palette; i++)
{
if (i < png_ptr->num_trans && png_ptr->trans[i] == 0)
1995-07-20 03:43:20 -04:00
{
palette[i] = back;
}
1997-05-16 03:46:07 -04:00
else if (i < png_ptr->num_trans && png_ptr->trans[i] != 0xff)
1995-07-20 03:43:20 -04:00
{
1997-05-16 03:46:07 -04:00
png_byte v, w;
1995-07-20 03:43:20 -04:00
v = png_ptr->gamma_to_1[png_ptr->palette[i].red];
1997-05-16 03:46:07 -04:00
png_composite(w, v, png_ptr->trans[i], back_1.red);
palette[i].red = png_ptr->gamma_from_1[w];
1995-07-20 03:43:20 -04:00
v = png_ptr->gamma_to_1[png_ptr->palette[i].green];
1997-05-16 03:46:07 -04:00
png_composite(w, v, png_ptr->trans[i], back_1.green);
palette[i].green = png_ptr->gamma_from_1[w];
1995-07-20 03:43:20 -04:00
v = png_ptr->gamma_to_1[png_ptr->palette[i].blue];
1997-05-16 03:46:07 -04:00
png_composite(w, v, png_ptr->trans[i], back_1.blue);
palette[i].blue = png_ptr->gamma_from_1[w];
1995-07-20 03:43:20 -04:00
}
else
{
palette[i].red = png_ptr->gamma_table[palette[i].red];
palette[i].green = png_ptr->gamma_table[palette[i].green];
palette[i].blue = png_ptr->gamma_table[palette[i].blue];
}
}
}
else
{
1996-06-05 16:50:50 -04:00
int i;
1995-07-20 03:43:20 -04:00
for (i = 0; i < num_palette; i++)
{
1997-05-16 03:46:07 -04:00
if (palette[i].red == (png_byte)png_ptr->trans_values.gray)
1995-07-20 03:43:20 -04:00
{
1996-06-05 16:50:50 -04:00
palette[i] = back;
1995-07-20 03:43:20 -04:00
}
else
{
palette[i].red = png_ptr->gamma_table[palette[i].red];
palette[i].green = png_ptr->gamma_table[palette[i].green];
palette[i].blue = png_ptr->gamma_table[palette[i].blue];
}
}
}
}
1996-06-05 16:50:50 -04:00
else
#endif
#if defined(PNG_READ_GAMMA_SUPPORTED)
1997-05-16 03:46:07 -04:00
if (png_ptr->transformations & PNG_GAMMA)
1995-07-20 03:43:20 -04:00
{
int i;
for (i = 0; i < num_palette; i++)
{
palette[i].red = png_ptr->gamma_table[palette[i].red];
palette[i].green = png_ptr->gamma_table[palette[i].green];
palette[i].blue = png_ptr->gamma_table[palette[i].blue];
}
}
1996-06-05 16:50:50 -04:00
#if defined(PNG_READ_BACKGROUND_SUPPORTED)
else
#endif
#endif
#if defined(PNG_READ_BACKGROUND_SUPPORTED)
1997-05-16 03:46:07 -04:00
if (png_ptr->transformations & PNG_BACKGROUND)
1995-07-20 03:43:20 -04:00
{
1996-06-05 16:50:50 -04:00
if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
1995-07-20 03:43:20 -04:00
{
1996-06-05 16:50:50 -04:00
png_color back;
1995-07-20 03:43:20 -04:00
1996-06-05 16:50:50 -04:00
back.red = (png_byte)png_ptr->background.red;
back.green = (png_byte)png_ptr->background.green;
back.blue = (png_byte)png_ptr->background.blue;
1995-07-20 03:43:20 -04:00
1998-02-28 08:00:24 -05:00
for (i = 0; i < (int)png_ptr->num_trans; i++)
1995-07-20 03:43:20 -04:00
{
1998-02-08 21:56:40 -05:00
if (png_ptr->trans[i] == 0)
1995-07-20 03:43:20 -04:00
{
1996-06-05 16:50:50 -04:00
palette[i].red = back.red;
palette[i].green = back.green;
palette[i].blue = back.blue;
1995-07-20 03:43:20 -04:00
}
1998-02-08 21:56:40 -05:00
else if (png_ptr->trans[i] != 0xff)
1995-07-20 03:43:20 -04:00
{
1997-05-16 03:46:07 -04:00
png_composite(palette[i].red, png_ptr->palette[i].red,
png_ptr->trans[i], back.red);
png_composite(palette[i].green, png_ptr->palette[i].green,
png_ptr->trans[i], back.green);
png_composite(palette[i].blue, png_ptr->palette[i].blue,
png_ptr->trans[i], back.blue);
1995-07-20 03:43:20 -04:00
}
}
}
else /* assume grayscale palette (what else could it be?) */
{
int i;
for (i = 0; i < num_palette; i++)
{
1997-05-16 03:46:07 -04:00
if (i == (png_byte)png_ptr->trans_values.gray)
1995-07-20 03:43:20 -04:00
{
1996-06-05 16:50:50 -04:00
palette[i].red = (png_byte)png_ptr->background.red;
palette[i].green = (png_byte)png_ptr->background.green;
palette[i].blue = (png_byte)png_ptr->background.blue;
1995-07-20 03:43:20 -04:00
}
}
}
}
1996-06-05 16:50:50 -04:00
#endif
1995-07-20 03:43:20 -04:00
}
1995-09-26 06:22:39 -04:00
#endif
1995-07-20 03:43:20 -04:00
1995-09-26 06:22:39 -04:00
#if defined(PNG_READ_BACKGROUND_SUPPORTED)
1997-05-16 03:46:07 -04:00
/* Replace any alpha or transparency with the supplied background color.
1998-01-01 08:13:13 -05:00
* "background" is already in the screen gamma, while "background_1" is
* at a gamma of 1.0. Paletted files have already been taken care of.
*/
1995-07-20 03:43:20 -04:00
void
1995-12-19 04:22:19 -05:00
png_do_background(png_row_infop row_info, png_bytep row,
png_color_16p trans_values, png_color_16p background,
png_color_16p background_1,
png_bytep gamma_table, png_bytep gamma_from_1, png_bytep gamma_to_1,
1996-01-26 02:38:47 -05:00
png_uint_16pp gamma_16, png_uint_16pp gamma_16_from_1,
png_uint_16pp gamma_16_to_1, int gamma_shift)
1995-07-20 03:43:20 -04:00
{
1995-12-19 04:22:19 -05:00
png_bytep sp, dp;
1995-09-26 06:22:39 -04:00
png_uint_32 i;
1998-04-21 16:03:57 -04:00
png_uint_32 row_width=row_info->width;
1995-09-26 06:22:39 -04:00
int shift;
1996-06-05 16:50:50 -04:00
1997-05-16 03:46:07 -04:00
png_debug(1, "in png_do_background\n");
if (background != NULL &&
#if defined(PNG_USELESS_TESTS_SUPPORTED)
row != NULL && row_info != NULL &&
#endif
1995-07-20 03:43:20 -04:00
(!(row_info->color_type & PNG_COLOR_MASK_ALPHA) ||
1997-05-16 03:46:07 -04:00
(row_info->color_type != PNG_COLOR_TYPE_PALETTE && trans_values)))
1995-07-20 03:43:20 -04:00
{
switch (row_info->color_type)
{
case PNG_COLOR_TYPE_GRAY:
{
switch (row_info->bit_depth)
{
case 1:
{
sp = row;
shift = 7;
1998-04-21 16:03:57 -04:00
for (i = 0; i < row_width; i++)
1995-07-20 03:43:20 -04:00
{
1998-02-07 11:20:57 -05:00
if ((png_uint_16)((*sp >> shift) & 0x1)
== trans_values->gray)
1995-07-20 03:43:20 -04:00
{
1996-01-26 02:38:47 -05:00
*sp &= (png_byte)((0x7f7f >> (7 - shift)) & 0xff);
*sp |= (png_byte)(background->gray << shift);
1995-07-20 03:43:20 -04:00
}
if (!shift)
{
shift = 7;
sp++;
}
else
shift--;
}
break;
}
case 2:
{
sp = row;
shift = 6;
1998-04-21 16:03:57 -04:00
for (i = 0; i < row_width; i++)
1995-07-20 03:43:20 -04:00
{
1998-02-07 11:20:57 -05:00
if ((png_uint_16)((*sp >> shift) & 0x3)
== trans_values->gray)
1995-07-20 03:43:20 -04:00
{
1996-01-26 02:38:47 -05:00
*sp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff);
*sp |= (png_byte)(background->gray << shift);
1995-07-20 03:43:20 -04:00
}
if (!shift)
{
shift = 6;
sp++;
}
else
shift -= 2;
}
break;
}
case 4:
{
1996-06-05 16:50:50 -04:00
sp = row;
1995-07-20 03:43:20 -04:00
shift = 4;
1998-04-21 16:03:57 -04:00
for (i = 0; i < row_width; i++)
1995-07-20 03:43:20 -04:00
{
1998-02-07 11:20:57 -05:00
if ((png_uint_16)((*sp >> shift) & 0xf)
== trans_values->gray)
1995-07-20 03:43:20 -04:00
{
1996-01-26 02:38:47 -05:00
*sp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff);
*sp |= (png_byte)(background->gray << shift);
1995-07-20 03:43:20 -04:00
}
if (!shift)
{
shift = 4;
sp++;
}
else
shift -= 4;
}
break;
}
case 8:
{
1995-09-26 06:22:39 -04:00
#if defined(PNG_READ_GAMMA_SUPPORTED)
1997-05-16 03:46:07 -04:00
if (gamma_table != NULL)
1995-07-20 03:43:20 -04:00
{
1998-04-21 16:03:57 -04:00
sp = row;
for (i = 0; i < row_width; i++, sp++)
1995-07-20 03:43:20 -04:00
{
if (*sp == trans_values->gray)
{
1997-05-16 03:46:07 -04:00
*sp = (png_byte)background->gray;
1995-07-20 03:43:20 -04:00
}
else
{
*sp = gamma_table[*sp];
}
}
}
else
1995-09-26 06:22:39 -04:00
#endif
1995-07-20 03:43:20 -04:00
{
1998-04-21 16:03:57 -04:00
sp = row;
for (i = 0; i < row_width; i++, sp++)
1995-07-20 03:43:20 -04:00
{
if (*sp == trans_values->gray)
{
1997-05-16 03:46:07 -04:00
*sp = (png_byte)background->gray;
1995-07-20 03:43:20 -04:00
}
}
}
break;
}
case 16:
{
1995-09-26 06:22:39 -04:00
#if defined(PNG_READ_GAMMA_SUPPORTED)
1997-05-16 03:46:07 -04:00
if (gamma_16 != NULL)
1995-07-20 03:43:20 -04:00
{
1998-04-21 16:03:57 -04:00
sp = row;
for (i = 0; i < row_width; i++, sp += 2)
1995-07-20 03:43:20 -04:00
{
png_uint_16 v;
1997-05-16 03:46:07 -04:00
v = ((png_uint_16)(*sp) << 8) + *(sp + 1);
1995-07-20 03:43:20 -04:00
if (v == trans_values->gray)
{
1997-05-16 03:46:07 -04:00
/* background is already in screen gamma */
1996-01-26 02:38:47 -05:00
*sp = (png_byte)((background->gray >> 8) & 0xff);
*(sp + 1) = (png_byte)(background->gray & 0xff);
1995-07-20 03:43:20 -04:00
}
else
{
1997-05-16 03:46:07 -04:00
v = gamma_16[*(sp + 1) >> gamma_shift][*sp];
1996-01-26 02:38:47 -05:00
*sp = (png_byte)((v >> 8) & 0xff);
1996-01-16 02:51:56 -05:00
*(sp + 1) = (png_byte)(v & 0xff);
1995-07-20 03:43:20 -04:00
}
1996-01-26 02:38:47 -05:00
}
1995-07-20 03:43:20 -04:00
}
else
1995-09-26 06:22:39 -04:00
#endif
1995-07-20 03:43:20 -04:00
{
1998-04-21 16:03:57 -04:00
sp = row;
for (i = 0; i < row_width; i++, sp += 2)
1995-07-20 03:43:20 -04:00
{
png_uint_16 v;
1997-05-16 03:46:07 -04:00
v = ((png_uint_16)(*sp) << 8) + *(sp + 1);
1995-07-20 03:43:20 -04:00
if (v == trans_values->gray)
{
1996-01-26 02:38:47 -05:00
*sp = (png_byte)((background->gray >> 8) & 0xff);
*(sp + 1) = (png_byte)(background->gray & 0xff);
1995-07-20 03:43:20 -04:00
}
}
}
break;
}
}
break;
}
case PNG_COLOR_TYPE_RGB:
{
if (row_info->bit_depth == 8)
{
1995-09-26 06:22:39 -04:00
#if defined(PNG_READ_GAMMA_SUPPORTED)
1997-05-16 03:46:07 -04:00
if (gamma_table != NULL)
1995-07-20 03:43:20 -04:00
{
1998-04-21 16:03:57 -04:00
sp = row;
for (i = 0; i < row_width; i++, sp += 3)
1995-07-20 03:43:20 -04:00
{
if (*sp == trans_values->red &&
*(sp + 1) == trans_values->green &&
*(sp + 2) == trans_values->blue)
{
1997-05-16 03:46:07 -04:00
*sp = (png_byte)background->red;
*(sp + 1) = (png_byte)background->green;
*(sp + 2) = (png_byte)background->blue;
1995-07-20 03:43:20 -04:00
}
else
{
*sp = gamma_table[*sp];
*(sp + 1) = gamma_table[*(sp + 1)];
*(sp + 2) = gamma_table[*(sp + 2)];
}
}
}
else
1995-09-26 06:22:39 -04:00
#endif
1995-07-20 03:43:20 -04:00
{
1998-04-21 16:03:57 -04:00
sp = row;
for (i = 0; i < row_width; i++, sp += 3)
1995-07-20 03:43:20 -04:00
{
if (*sp == trans_values->red &&
*(sp + 1) == trans_values->green &&
*(sp + 2) == trans_values->blue)
{
1997-05-16 03:46:07 -04:00
*sp = (png_byte)background->red;
*(sp + 1) = (png_byte)background->green;
*(sp + 2) = (png_byte)background->blue;
1995-07-20 03:43:20 -04:00
}
}
}
}
1997-05-16 03:46:07 -04:00
else /* if (row_info->bit_depth == 16) */
1995-07-20 03:43:20 -04:00
{
1995-09-26 06:22:39 -04:00
#if defined(PNG_READ_GAMMA_SUPPORTED)
1997-05-16 03:46:07 -04:00
if (gamma_16 != NULL)
1995-07-20 03:43:20 -04:00
{
1998-04-21 16:03:57 -04:00
sp = row;
for (i = 0; i < row_width; i++, sp += 6)
1996-01-26 02:38:47 -05:00
{
1998-05-02 13:52:25 -04:00
png_uint_16 r = ((png_uint_16)(*sp) << 8) + *(sp + 1);
png_uint_16 g = ((png_uint_16)(*(sp + 2)) << 8) + *(sp + 3);
png_uint_16 b = ((png_uint_16)(*(sp + 4)) << 8) + *(sp + 5);
1997-05-16 03:46:07 -04:00
if (r == trans_values->red && g == trans_values->green &&
1995-07-20 03:43:20 -04:00
b == trans_values->blue)
{
1997-05-16 03:46:07 -04:00
/* background is already in screen gamma */
1996-01-26 02:38:47 -05:00
*sp = (png_byte)((background->red >> 8) & 0xff);
*(sp + 1) = (png_byte)(background->red & 0xff);
*(sp + 2) = (png_byte)((background->green >> 8) & 0xff);
*(sp + 3) = (png_byte)(background->green & 0xff);
*(sp + 4) = (png_byte)((background->blue >> 8) & 0xff);
*(sp + 5) = (png_byte)(background->blue & 0xff);
1995-07-20 03:43:20 -04:00
}
else
{
1998-05-02 13:52:25 -04:00
png_uint_16 v = gamma_16[*(sp + 1) >> gamma_shift][*sp];
1996-01-26 02:38:47 -05:00
*sp = (png_byte)((v >> 8) & 0xff);
1996-01-16 02:51:56 -05:00
*(sp + 1) = (png_byte)(v & 0xff);
1997-05-16 03:46:07 -04:00
v = gamma_16[*(sp + 3) >> gamma_shift][*(sp + 2)];
1996-01-26 02:38:47 -05:00
*(sp + 2) = (png_byte)((v >> 8) & 0xff);
*(sp + 3) = (png_byte)(v & 0xff);
1997-05-16 03:46:07 -04:00
v = gamma_16[*(sp + 5) >> gamma_shift][*(sp + 4)];
1996-01-26 02:38:47 -05:00
*(sp + 4) = (png_byte)((v >> 8) & 0xff);
*(sp + 5) = (png_byte)(v & 0xff);
1995-07-20 03:43:20 -04:00
}
}
}
else
1995-09-26 06:22:39 -04:00
#endif
1995-07-20 03:43:20 -04:00
{
1998-04-21 16:03:57 -04:00
sp = row;
for (i = 0; i < row_width; i++, sp += 6)
1995-07-20 03:43:20 -04:00
{
1998-05-02 13:52:25 -04:00
png_uint_16 r = ((png_uint_16)(*sp) << 8) + *(sp + 1);
png_uint_16 g = ((png_uint_16)(*(sp + 2)) << 8) + *(sp + 3);
png_uint_16 b = ((png_uint_16)(*(sp + 4)) << 8) + *(sp + 5);
1995-07-20 03:43:20 -04:00
1997-05-16 03:46:07 -04:00
if (r == trans_values->red && g == trans_values->green &&
1995-07-20 03:43:20 -04:00
b == trans_values->blue)
1996-01-26 02:38:47 -05:00
{
*sp = (png_byte)((background->red >> 8) & 0xff);
*(sp + 1) = (png_byte)(background->red & 0xff);
*(sp + 2) = (png_byte)((background->green >> 8) & 0xff);
*(sp + 3) = (png_byte)(background->green & 0xff);
*(sp + 4) = (png_byte)((background->blue >> 8) & 0xff);
*(sp + 5) = (png_byte)(background->blue & 0xff);
}
}
}
}
break;
}
case PNG_COLOR_TYPE_GRAY_ALPHA:
1995-07-20 03:43:20 -04:00
{
1997-05-16 03:46:07 -04:00
if (row_info->bit_depth == 8)
1995-07-20 03:43:20 -04:00
{
1995-09-26 06:22:39 -04:00
#if defined(PNG_READ_GAMMA_SUPPORTED)
1997-05-16 03:46:07 -04:00
if (gamma_to_1 != NULL && gamma_from_1 != NULL &&
gamma_table != NULL)
{
1998-04-21 16:03:57 -04:00
sp = row;
dp = row;
for (i = 0; i < row_width; i++, sp += 2, dp++)
1995-07-20 03:43:20 -04:00
{
1998-05-02 13:52:25 -04:00
png_uint_16 a = *(sp + 1);
1995-07-20 03:43:20 -04:00
1997-05-16 03:46:07 -04:00
if (a == 0xff)
{
*dp = gamma_table[*sp];
}
else if (a == 0)
{
/* background is already in screen gamma */
*dp = (png_byte)background->gray;
}
else
{
png_byte v, w;
1995-07-20 03:43:20 -04:00
1997-05-16 03:46:07 -04:00
v = gamma_to_1[*sp];
png_composite(w, v, a, background_1->gray);
*dp = gamma_from_1[w];
1995-07-20 03:43:20 -04:00
}
}
1997-05-16 03:46:07 -04:00
}
else
1995-09-26 06:22:39 -04:00
#endif
1997-05-16 03:46:07 -04:00
{
1998-04-21 16:03:57 -04:00
sp = row;
dp = row;
for (i = 0; i < row_width; i++, sp += 2, dp++)
1995-07-20 03:43:20 -04:00
{
1998-05-02 13:52:25 -04:00
png_byte a = *(sp + 1);
1995-07-20 03:43:20 -04:00
1997-05-16 03:46:07 -04:00
if (a == 0xff)
{
*dp = *sp;
}
else if (a == 0)
{
*dp = (png_byte)background->gray;
}
else
{
png_composite(*dp, *sp, a, background_1->gray);
1995-07-20 03:43:20 -04:00
}
}
}
1997-05-16 03:46:07 -04:00
}
else /* if (png_ptr->bit_depth == 16) */
{
1995-09-26 06:22:39 -04:00
#if defined(PNG_READ_GAMMA_SUPPORTED)
1997-05-16 03:46:07 -04:00
if (gamma_16 != NULL && gamma_16_from_1 != NULL &&
gamma_16_to_1 != NULL)
{
1998-04-21 16:03:57 -04:00
sp = row;
dp = row;
for (i = 0; i < row_width; i++, sp += 4, dp += 2)
1995-07-20 03:43:20 -04:00
{
1998-05-02 13:52:25 -04:00
png_uint_16 a = ((png_uint_16)(*(sp + 2)) << 8) + *(sp + 3);
1997-05-16 03:46:07 -04:00
if (a == (png_uint_16)0xffff)
1995-07-20 03:43:20 -04:00
{
1997-05-16 03:46:07 -04:00
png_uint_16 v;
1995-07-20 03:43:20 -04:00
1997-05-16 03:46:07 -04:00
v = gamma_16[*(sp + 1) >> gamma_shift][*sp];
*dp = (png_byte)((v >> 8) & 0xff);
*(dp + 1) = (png_byte)(v & 0xff);
}
else if (a == 0)
{
/* background is already in screen gamma */
*dp = (png_byte)((background->gray >> 8) & 0xff);
*(dp + 1) = (png_byte)(background->gray & 0xff);
}
else
{
png_uint_16 g, v, w;
1995-07-20 03:43:20 -04:00
1997-05-16 03:46:07 -04:00
g = gamma_16_to_1[*(sp + 1) >> gamma_shift][*sp];
png_composite_16(v, g, a, background_1->gray);
w = gamma_16_from_1[(v&0xff) >> gamma_shift][v >> 8];
*dp = (png_byte)((w >> 8) & 0xff);
*(dp + 1) = (png_byte)(w & 0xff);
1995-07-20 03:43:20 -04:00
}
}
1997-05-16 03:46:07 -04:00
}
else
1995-09-26 06:22:39 -04:00
#endif
1997-05-16 03:46:07 -04:00
{
1998-04-21 16:03:57 -04:00
sp = row;
dp = row;
for (i = 0; i < row_width; i++, sp += 4, dp += 2)
1995-07-20 03:43:20 -04:00
{
1998-05-02 13:52:25 -04:00
png_uint_16 a = ((png_uint_16)(*(sp + 2)) << 8) + *(sp + 3);
1997-05-16 03:46:07 -04:00
if (a == (png_uint_16)0xffff)
1995-07-20 03:43:20 -04:00
{
1997-05-16 03:46:07 -04:00
png_memcpy(dp, sp, 2);
}
else if (a == 0)
{
*dp = (png_byte)((background->gray >> 8) & 0xff);
*(dp + 1) = (png_byte)(background->gray & 0xff);
}
else
{
png_uint_16 g, v;
1995-07-20 03:43:20 -04:00
1997-05-16 03:46:07 -04:00
g = ((png_uint_16)(*sp) << 8) + *(sp + 1);
png_composite_16(v, g, a, background_1->gray);
*dp = (png_byte)((v >> 8) & 0xff);
*(dp + 1) = (png_byte)(v & 0xff);
1995-07-20 03:43:20 -04:00
}
}
}
}
break;
}
case PNG_COLOR_TYPE_RGB_ALPHA:
{
if (row_info->bit_depth == 8)
{
1995-09-26 06:22:39 -04:00
#if defined(PNG_READ_GAMMA_SUPPORTED)
1997-05-16 03:46:07 -04:00
if (gamma_to_1 != NULL && gamma_from_1 != NULL &&
gamma_table != NULL)
1995-07-20 03:43:20 -04:00
{
1998-04-21 16:03:57 -04:00
sp = row;
dp = row;
for (i = 0; i < row_width; i++, sp += 4, dp += 3)
1995-07-20 03:43:20 -04:00
{
1998-05-02 13:52:25 -04:00
png_byte a = *(sp + 3);
1995-07-20 03:43:20 -04:00
if (a == 0xff)
{
*dp = gamma_table[*sp];
*(dp + 1) = gamma_table[*(sp + 1)];
*(dp + 2) = gamma_table[*(sp + 2)];
}
else if (a == 0)
{
1997-05-16 03:46:07 -04:00
/* background is already in screen gamma */
*dp = (png_byte)background->red;
*(dp + 1) = (png_byte)background->green;
*(dp + 2) = (png_byte)background->blue;
1995-07-20 03:43:20 -04:00
}
else
{
1997-05-16 03:46:07 -04:00
png_byte v, w;
1995-07-20 03:43:20 -04:00
v = gamma_to_1[*sp];
1997-05-16 03:46:07 -04:00
png_composite(w, v, a, background_1->red);
*dp = gamma_from_1[w];
1995-07-20 03:43:20 -04:00
v = gamma_to_1[*(sp + 1)];
1997-05-16 03:46:07 -04:00
png_composite(w, v, a, background_1->green);
*(dp + 1) = gamma_from_1[w];
1995-07-20 03:43:20 -04:00
v = gamma_to_1[*(sp + 2)];
1997-05-16 03:46:07 -04:00
png_composite(w, v, a, background_1->blue);
*(dp + 2) = gamma_from_1[w];
1995-07-20 03:43:20 -04:00
}
}
}
else
1995-09-26 06:22:39 -04:00
#endif
1995-07-20 03:43:20 -04:00
{
1998-04-21 16:03:57 -04:00
sp = row;
dp = row;
for (i = 0; i < row_width; i++, sp += 4, dp += 3)
1995-07-20 03:43:20 -04:00
{
1998-05-02 13:52:25 -04:00
png_byte a = *(sp + 3);
1995-07-20 03:43:20 -04:00
if (a == 0xff)
{
*dp = *sp;
*(dp + 1) = *(sp + 1);
*(dp + 2) = *(sp + 2);
}
else if (a == 0)
{
1997-05-16 03:46:07 -04:00
*dp = (png_byte)background->red;
*(dp + 1) = (png_byte)background->green;
*(dp + 2) = (png_byte)background->blue;
1995-07-20 03:43:20 -04:00
}
else
{
1997-05-16 03:46:07 -04:00
png_composite(*dp, *sp, a, background->red);
png_composite(*(dp + 1), *(sp + 1), a,
background->green);
png_composite(*(dp + 2), *(sp + 2), a,
background->blue);
1995-07-20 03:43:20 -04:00
}
}
}
}
1997-05-16 03:46:07 -04:00
else /* if (row_info->bit_depth == 16) */
1995-07-20 03:43:20 -04:00
{
1995-09-26 06:22:39 -04:00
#if defined(PNG_READ_GAMMA_SUPPORTED)
1997-05-16 03:46:07 -04:00
if (gamma_16 != NULL && gamma_16_from_1 != NULL &&
gamma_16_to_1 != NULL)
1995-07-20 03:43:20 -04:00
{
1998-04-21 16:03:57 -04:00
sp = row;
dp = row;
for (i = 0; i < row_width; i++, sp += 8, dp += 6)
1995-07-20 03:43:20 -04:00
{
1998-05-02 13:52:25 -04:00
png_uint_16 a = (png_uint_16)(((png_uint_16)(*(sp + 6))
<< 8) + (png_uint_16)(*(sp + 7)));
1995-07-20 03:43:20 -04:00
if (a == (png_uint_16)0xffff)
{
png_uint_16 v;
1997-05-16 03:46:07 -04:00
v = gamma_16[*(sp + 1) >> gamma_shift][*sp];
1996-01-26 02:38:47 -05:00
*dp = (png_byte)((v >> 8) & 0xff);
*(dp + 1) = (png_byte)(v & 0xff);
1997-05-16 03:46:07 -04:00
v = gamma_16[*(sp + 3) >> gamma_shift][*(sp + 2)];
1996-01-26 02:38:47 -05:00
*(dp + 2) = (png_byte)((v >> 8) & 0xff);
*(dp + 3) = (png_byte)(v & 0xff);
1997-05-16 03:46:07 -04:00
v = gamma_16[*(sp + 5) >> gamma_shift][*(sp + 4)];
1996-01-26 02:38:47 -05:00
*(dp + 4) = (png_byte)((v >> 8) & 0xff);
*(dp + 5) = (png_byte)(v & 0xff);
1995-07-20 03:43:20 -04:00
}
else if (a == 0)
{
1997-05-16 03:46:07 -04:00
/* background is already in screen gamma */
1996-01-26 02:38:47 -05:00
*dp = (png_byte)((background->red >> 8) & 0xff);
*(dp + 1) = (png_byte)(background->red & 0xff);
*(dp + 2) = (png_byte)((background->green >> 8) & 0xff);
*(dp + 3) = (png_byte)(background->green & 0xff);
*(dp + 4) = (png_byte)((background->blue >> 8) & 0xff);
*(dp + 5) = (png_byte)(background->blue & 0xff);
1995-07-20 03:43:20 -04:00
}
else
{
1997-05-16 03:46:07 -04:00
png_uint_16 v, w, x;
v = gamma_16_to_1[*(sp + 1) >> gamma_shift][*sp];
png_composite_16(w, v, a, background->red);
x = gamma_16_from_1[((w&0xff) >> gamma_shift)][w >> 8];
*dp = (png_byte)((x >> 8) & 0xff);
*(dp + 1) = (png_byte)(x & 0xff);
v = gamma_16_to_1[*(sp + 3) >> gamma_shift][*(sp + 2)];
png_composite_16(w, v, a, background->green);
x = gamma_16_from_1[((w&0xff) >> gamma_shift)][w >> 8];
*(dp + 2) = (png_byte)((x >> 8) & 0xff);
*(dp + 3) = (png_byte)(x & 0xff);
v = gamma_16_to_1[*(sp + 5) >> gamma_shift][*(sp + 4)];
png_composite_16(w, v, a, background->blue);
x = gamma_16_from_1[(w & 0xff) >> gamma_shift][w >> 8];
*(dp + 4) = (png_byte)((x >> 8) & 0xff);
*(dp + 5) = (png_byte)(x & 0xff);
1995-07-20 03:43:20 -04:00
}
}
}
else
1995-09-26 06:22:39 -04:00
#endif
1995-07-20 03:43:20 -04:00
{
1998-04-21 16:03:57 -04:00
sp = row;
dp = row;
for (i = 0; i < row_width; i++, sp += 8, dp += 6)
1995-07-20 03:43:20 -04:00
{
1998-05-02 13:52:25 -04:00
png_uint_16 a = (png_uint_16)(((png_uint_16)(*(sp + 6))
<< 8) + (png_uint_16)(*(sp + 7)));
1995-07-20 03:43:20 -04:00
if (a == (png_uint_16)0xffff)
{
1995-09-26 06:22:39 -04:00
png_memcpy(dp, sp, 6);
1995-07-20 03:43:20 -04:00
}
else if (a == 0)
{
1996-01-26 02:38:47 -05:00
*dp = (png_byte)((background->red >> 8) & 0xff);
*(dp + 1) = (png_byte)(background->red & 0xff);
*(dp + 2) = (png_byte)((background->green >> 8) & 0xff);
*(dp + 3) = (png_byte)(background->green & 0xff);
*(dp + 4) = (png_byte)((background->blue >> 8) & 0xff);
*(dp + 5) = (png_byte)(background->blue & 0xff);
}
else
1995-07-20 03:43:20 -04:00
{
1998-05-02 13:52:25 -04:00
png_uint_16 v;
1997-05-16 03:46:07 -04:00
1998-05-02 13:52:25 -04:00
png_uint_16 r = ((png_uint_16)(*sp) << 8) + *(sp + 1);
png_uint_16 g = ((png_uint_16)(*(sp + 2)) << 8)
+ *(sp + 3);
png_uint_16 b = ((png_uint_16)(*(sp + 4)) << 8)
+ *(sp + 5);
1997-05-16 03:46:07 -04:00
png_composite_16(v, r, a, background->red);
1995-07-20 03:43:20 -04:00
*dp = (png_byte)((v >> 8) & 0xff);
*(dp + 1) = (png_byte)(v & 0xff);
1997-05-16 03:46:07 -04:00
png_composite_16(v, g, a, background->green);
1995-07-20 03:43:20 -04:00
*(dp + 2) = (png_byte)((v >> 8) & 0xff);
*(dp + 3) = (png_byte)(v & 0xff);
1998-01-01 08:13:13 -05:00
png_composite_16(v, b, a, background->blue);
1995-07-20 03:43:20 -04:00
*(dp + 4) = (png_byte)((v >> 8) & 0xff);
*(dp + 5) = (png_byte)(v & 0xff);
}
}
}
}
break;
}
}
1997-01-17 02:34:35 -05:00
1995-07-20 03:43:20 -04:00
if (row_info->color_type & PNG_COLOR_MASK_ALPHA)
{
row_info->color_type &= ~PNG_COLOR_MASK_ALPHA;
1996-06-05 16:50:50 -04:00
row_info->channels--;
1996-01-26 02:38:47 -05:00
row_info->pixel_depth = (png_byte)(row_info->channels *
row_info->bit_depth);
1998-04-21 16:03:57 -04:00
row_info->rowbytes = ((row_width *
1995-07-20 03:43:20 -04:00
row_info->pixel_depth + 7) >> 3);
}
}
}
1995-09-26 06:22:39 -04:00
#endif
1995-07-20 03:43:20 -04:00
1995-09-26 06:22:39 -04:00
#if defined(PNG_READ_GAMMA_SUPPORTED)
1997-05-16 03:46:07 -04:00
/* Gamma correct the image, avoiding the alpha channel. Make sure
1998-01-01 08:13:13 -05:00
* you do this after you deal with the trasparency issue on grayscale
* or rgb images. If your bit depth is 8, use gamma_table, if it
* is 16, use gamma_16_table and gamma_shift. Build these with
* build_gamma_table().
*/
1995-07-20 03:43:20 -04:00
void
1995-12-19 04:22:19 -05:00
png_do_gamma(png_row_infop row_info, png_bytep row,
png_bytep gamma_table, png_uint_16pp gamma_16_table,
1995-07-20 03:43:20 -04:00
int gamma_shift)
{
1995-12-19 04:22:19 -05:00
png_bytep sp;
1995-09-26 06:22:39 -04:00
png_uint_32 i;
1998-04-21 16:03:57 -04:00
png_uint_32 row_width=row_info->width;
1995-12-19 04:22:19 -05:00
1997-05-16 03:46:07 -04:00
png_debug(1, "in png_do_gamma\n");
if (
#if defined(PNG_USELESS_TESTS_SUPPORTED)
row != NULL && row_info != NULL &&
#endif
((row_info->bit_depth <= 8 && gamma_table != NULL) ||
(row_info->bit_depth == 16 && gamma_16_table != NULL)))
1995-07-20 03:43:20 -04:00
{
switch (row_info->color_type)
{
case PNG_COLOR_TYPE_RGB:
{
if (row_info->bit_depth == 8)
{
1998-04-21 16:03:57 -04:00
sp = row;
for (i = 0; i < row_width; i++)
1995-07-20 03:43:20 -04:00
{
*sp = gamma_table[*sp];
sp++;
*sp = gamma_table[*sp];
sp++;
*sp = gamma_table[*sp];
sp++;
}
}
1997-05-16 03:46:07 -04:00
else /* if (row_info->bit_depth == 16) */
1995-07-20 03:43:20 -04:00
{
1998-04-21 16:03:57 -04:00
sp = row;
for (i = 0; i < row_width; i++)
1995-07-20 03:43:20 -04:00
{
png_uint_16 v;
1997-05-16 03:46:07 -04:00
v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
1996-01-26 02:38:47 -05:00
*sp = (png_byte)((v >> 8) & 0xff);
*(sp + 1) = (png_byte)(v & 0xff);
sp += 2;
1997-05-16 03:46:07 -04:00
v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
1996-01-26 02:38:47 -05:00
*sp = (png_byte)((v >> 8) & 0xff);
*(sp + 1) = (png_byte)(v & 0xff);
1995-07-20 03:43:20 -04:00
sp += 2;
1997-05-16 03:46:07 -04:00
v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
1996-01-26 02:38:47 -05:00
*sp = (png_byte)((v >> 8) & 0xff);
*(sp + 1) = (png_byte)(v & 0xff);
sp += 2;
}
}
break;
}
case PNG_COLOR_TYPE_RGB_ALPHA:
{
if (row_info->bit_depth == 8)
{
1998-04-21 16:03:57 -04:00
sp = row;
for (i = 0; i < row_width; i++)
1996-01-26 02:38:47 -05:00
{
1995-07-20 03:43:20 -04:00
*sp = gamma_table[*sp];
sp++;
*sp = gamma_table[*sp];
sp++;
*sp = gamma_table[*sp];
sp++;
sp++;
}
}
1997-05-16 03:46:07 -04:00
else /* if (row_info->bit_depth == 16) */
1995-07-20 03:43:20 -04:00
{
1998-04-21 16:03:57 -04:00
sp = row;
for (i = 0; i < row_width; i++)
1995-07-20 03:43:20 -04:00
{
1998-05-02 13:52:25 -04:00
png_uint_16 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
1996-01-26 02:38:47 -05:00
*sp = (png_byte)((v >> 8) & 0xff);
*(sp + 1) = (png_byte)(v & 0xff);
1995-07-20 03:43:20 -04:00
sp += 2;
1997-05-16 03:46:07 -04:00
v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
1996-01-26 02:38:47 -05:00
*sp = (png_byte)((v >> 8) & 0xff);
*(sp + 1) = (png_byte)(v & 0xff);
sp += 2;
1997-05-16 03:46:07 -04:00
v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
1996-01-26 02:38:47 -05:00
*sp = (png_byte)((v >> 8) & 0xff);
*(sp + 1) = (png_byte)(v & 0xff);
sp += 4;
}
}
1995-07-20 03:43:20 -04:00
break;
}
case PNG_COLOR_TYPE_GRAY_ALPHA:
{
if (row_info->bit_depth == 8)
{
1998-04-21 16:03:57 -04:00
sp = row;
for (i = 0; i < row_width; i++)
1995-07-20 03:43:20 -04:00
{
*sp = gamma_table[*sp];
1997-05-16 03:46:07 -04:00
sp += 2;
1995-07-20 03:43:20 -04:00
}
}
1997-05-16 03:46:07 -04:00
else /* if (row_info->bit_depth == 16) */
1995-07-20 03:43:20 -04:00
{
1998-04-21 16:03:57 -04:00
sp = row;
for (i = 0; i < row_width; i++)
1995-07-20 03:43:20 -04:00
{
1998-05-02 13:52:25 -04:00
png_uint_16 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
1996-01-26 02:38:47 -05:00
*sp = (png_byte)((v >> 8) & 0xff);
*(sp + 1) = (png_byte)(v & 0xff);
1995-07-20 03:43:20 -04:00
sp += 4;
}
}
break;
}
case PNG_COLOR_TYPE_GRAY:
{
1998-01-07 21:54:20 -05:00
if (row_info->bit_depth == 2)
{
1998-04-21 16:03:57 -04:00
sp = row;
for (i = 0; i < row_width; i += 4)
1998-01-07 21:54:20 -05:00
{
int a = *sp & 0xc0;
int b = *sp & 0x30;
int c = *sp & 0x0c;
int d = *sp & 0x03;
*sp = ((((int)gamma_table[a|(a>>2)|(a>>4)|(a>>6)]) ) & 0xc0)|
((((int)gamma_table[(b<<2)|b|(b>>2)|(b>>4)])>>2) & 0x30)|
((((int)gamma_table[(c<<4)|(c<<2)|c|(c>>2)])>>4) & 0x0c)|
((((int)gamma_table[(d<<6)|(d<<4)|(d<<2)|d])>>6) );
sp++;
}
}
1997-05-16 03:46:07 -04:00
if (row_info->bit_depth == 4)
1995-07-20 03:43:20 -04:00
{
1998-04-21 16:03:57 -04:00
sp = row;
for (i = 0; i < row_width; i += 2)
1997-05-16 03:46:07 -04:00
{
int msb = *sp & 0xf0;
int lsb = *sp & 0x0f;
1998-01-01 08:13:13 -05:00
*sp = (((int)gamma_table[msb | (msb >> 4)]) & 0xf0) |
(((int)gamma_table[(lsb << 4) | lsb]) >> 4);
1997-05-16 03:46:07 -04:00
sp++;
}
}
else if (row_info->bit_depth == 8)
{
1998-04-21 16:03:57 -04:00
sp = row;
for (i = 0; i < row_width; i++)
1995-07-20 03:43:20 -04:00
{
*sp = gamma_table[*sp];
sp++;
}
}
else if (row_info->bit_depth == 16)
{
1998-04-21 16:03:57 -04:00
sp = row;
for (i = 0; i < row_width; i++)
1995-07-20 03:43:20 -04:00
{
1998-05-02 13:52:25 -04:00
png_uint_16 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
1996-01-26 02:38:47 -05:00
*sp = (png_byte)((v >> 8) & 0xff);
*(sp + 1) = (png_byte)(v & 0xff);
1995-07-20 03:43:20 -04:00
sp += 2;
}
}
break;
}
}
}
}
1995-09-26 06:22:39 -04:00
#endif
1995-07-20 03:43:20 -04:00
1995-09-26 06:22:39 -04:00
#if defined(PNG_READ_EXPAND_SUPPORTED)
1998-01-01 08:13:13 -05:00
/* Expands a palette row to an rgb or rgba row depending
* upon whether you supply trans and num_trans.
*/
1995-07-20 03:43:20 -04:00
void
1995-12-19 04:22:19 -05:00
png_do_expand_palette(png_row_infop row_info, png_bytep row,
1997-05-16 03:46:07 -04:00
png_colorp palette, png_bytep trans, int num_trans)
1995-07-20 03:43:20 -04:00
{
1995-09-26 06:22:39 -04:00
int shift, value;
1995-12-19 04:22:19 -05:00
png_bytep sp, dp;
1995-09-26 06:22:39 -04:00
png_uint_32 i;
1998-04-21 16:03:57 -04:00
png_uint_32 row_width=row_info->width;
1995-12-19 04:22:19 -05:00
1997-05-16 03:46:07 -04:00
png_debug(1, "in png_do_expand_palette\n");
if (
#if defined(PNG_USELESS_TESTS_SUPPORTED)
row != NULL && row_info != NULL &&
#endif
row_info->color_type == PNG_COLOR_TYPE_PALETTE)
1995-07-20 03:43:20 -04:00
{
if (row_info->bit_depth < 8)
{
switch (row_info->bit_depth)
{
case 1:
{
1998-04-21 16:03:57 -04:00
sp = row + (png_size_t)((row_width - 1) >> 3);
dp = row + (png_size_t)row_width - 1;
shift = 7 - (int)((row_width + 7) & 7);
for (i = 0; i < row_width; i++)
1995-07-20 03:43:20 -04:00
{
if ((*sp >> shift) & 0x1)
*dp = 1;
else
*dp = 0;
if (shift == 7)
{
shift = 0;
sp--;
}
else
shift++;
dp--;
}
break;
}
case 2:
{
1998-04-21 16:03:57 -04:00
sp = row + (png_size_t)((row_width - 1) >> 2);
dp = row + (png_size_t)row_width - 1;
shift = (int)((3 - ((row_width + 3) & 3)) << 1);
for (i = 0; i < row_width; i++)
1995-07-20 03:43:20 -04:00
{
value = (*sp >> shift) & 0x3;
1996-01-26 02:38:47 -05:00
*dp = (png_byte)value;
1995-07-20 03:43:20 -04:00
if (shift == 6)
{
shift = 0;
sp--;
}
else
shift += 2;
dp--;
}
break;
}
case 4:
{
1998-04-21 16:03:57 -04:00
sp = row + (png_size_t)((row_width - 1) >> 1);
dp = row + (png_size_t)row_width - 1;
shift = (int)((row_width & 1) << 2);
for (i = 0; i < row_width; i++)
1995-07-20 03:43:20 -04:00
{
value = (*sp >> shift) & 0xf;
1996-01-26 02:38:47 -05:00
*dp = (png_byte)value;
1995-07-20 03:43:20 -04:00
if (shift == 4)
{
shift = 0;
sp--;
}
else
shift += 4;
dp--;
}
break;
}
}
row_info->bit_depth = 8;
row_info->pixel_depth = 8;
1998-04-21 16:03:57 -04:00
row_info->rowbytes = row_width;
1995-07-20 03:43:20 -04:00
}
switch (row_info->bit_depth)
{
case 8:
{
1997-05-16 03:46:07 -04:00
if (trans != NULL)
1995-07-20 03:43:20 -04:00
{
1998-04-21 16:03:57 -04:00
sp = row + (png_size_t)row_width - 1;
dp = row + (png_size_t)(row_width << 2) - 1;
1995-07-20 03:43:20 -04:00
1998-04-21 16:03:57 -04:00
for (i = 0; i < row_width; i++)
1995-07-20 03:43:20 -04:00
{
1997-05-16 03:46:07 -04:00
if ((int)(*sp) >= num_trans)
1995-07-20 03:43:20 -04:00
*dp-- = 0xff;
else
*dp-- = trans[*sp];
*dp-- = palette[*sp].blue;
*dp-- = palette[*sp].green;
*dp-- = palette[*sp].red;
sp--;
}
row_info->bit_depth = 8;
row_info->pixel_depth = 32;
1998-04-21 16:03:57 -04:00
row_info->rowbytes = row_width * 4;
1995-07-20 03:43:20 -04:00
row_info->color_type = 6;
row_info->channels = 4;
}
else
{
1998-04-21 16:03:57 -04:00
sp = row + (png_size_t)row_width - 1;
dp = row + (png_size_t)(row_width * 3) - 1;
1995-07-20 03:43:20 -04:00
1998-04-21 16:03:57 -04:00
for (i = 0; i < row_width; i++)
1995-07-20 03:43:20 -04:00
{
*dp-- = palette[*sp].blue;
*dp-- = palette[*sp].green;
*dp-- = palette[*sp].red;
sp--;
}
row_info->bit_depth = 8;
row_info->pixel_depth = 24;
1998-04-21 16:03:57 -04:00
row_info->rowbytes = row_width * 3;
1995-07-20 03:43:20 -04:00
row_info->color_type = 2;
row_info->channels = 3;
}
break;
}
}
}
}
1998-01-01 08:13:13 -05:00
/* If the bit depth < 8, it is expanded to 8. Also, if the
* transparency value is supplied, an alpha channel is built.
*/
1995-07-20 03:43:20 -04:00
void
1995-12-19 04:22:19 -05:00
png_do_expand(png_row_infop row_info, png_bytep row,
1996-01-26 02:38:47 -05:00
png_color_16p trans_value)
1995-07-20 03:43:20 -04:00
{
1995-09-26 06:22:39 -04:00
int shift, value;
1995-12-19 04:22:19 -05:00
png_bytep sp, dp;
1995-09-26 06:22:39 -04:00
png_uint_32 i;
1998-04-21 16:03:57 -04:00
png_uint_32 row_width=row_info->width;
1995-12-19 04:22:19 -05:00
1997-05-16 03:46:07 -04:00
png_debug(1, "in png_do_expand\n");
#if defined(PNG_USELESS_TESTS_SUPPORTED)
if (row != NULL && row_info != NULL)
#endif
1995-07-20 03:43:20 -04:00
{
1997-05-16 03:46:07 -04:00
if (row_info->color_type == PNG_COLOR_TYPE_GRAY)
1995-07-20 03:43:20 -04:00
{
1997-01-17 02:34:35 -05:00
png_uint_16 gray = trans_value ? trans_value->gray : 0;
if (row_info->bit_depth < 8)
1995-07-20 03:43:20 -04:00
{
1997-01-17 02:34:35 -05:00
switch (row_info->bit_depth)
1995-07-20 03:43:20 -04:00
{
1997-01-17 02:34:35 -05:00
case 1:
1995-07-20 03:43:20 -04:00
{
1997-01-17 02:34:35 -05:00
gray *= 0xff;
1998-04-21 16:03:57 -04:00
sp = row + (png_size_t)((row_width - 1) >> 3);
dp = row + (png_size_t)row_width - 1;
shift = 7 - (int)((row_width + 7) & 7);
for (i = 0; i < row_width; i++)
1995-07-20 03:43:20 -04:00
{
1997-01-17 02:34:35 -05:00
if ((*sp >> shift) & 0x1)
*dp = 0xff;
else
*dp = 0;
if (shift == 7)
{
shift = 0;
sp--;
}
else
shift++;
1995-07-20 03:43:20 -04:00
1997-01-17 02:34:35 -05:00
dp--;
}
break;
1995-07-20 03:43:20 -04:00
}
1997-01-17 02:34:35 -05:00
case 2:
1995-07-20 03:43:20 -04:00
{
1997-01-17 02:34:35 -05:00
gray *= 0x55;
1998-04-21 16:03:57 -04:00
sp = row + (png_size_t)((row_width - 1) >> 2);
dp = row + (png_size_t)row_width - 1;
shift = (int)((3 - ((row_width + 3) & 3)) << 1);
for (i = 0; i < row_width; i++)
1995-07-20 03:43:20 -04:00
{
1997-01-17 02:34:35 -05:00
value = (*sp >> shift) & 0x3;
*dp = (png_byte)(value | (value << 2) | (value << 4) |
(value << 6));
if (shift == 6)
{
shift = 0;
sp--;
}
else
shift += 2;
1995-07-20 03:43:20 -04:00
1997-01-17 02:34:35 -05:00
dp--;
}
break;
1995-07-20 03:43:20 -04:00
}
1997-01-17 02:34:35 -05:00
case 4:
1995-07-20 03:43:20 -04:00
{
1997-01-17 02:34:35 -05:00
gray *= 0x11;
1998-04-21 16:03:57 -04:00
sp = row + (png_size_t)((row_width - 1) >> 1);
dp = row + (png_size_t)row_width - 1;
shift = (int)((1 - ((row_width + 1) & 1)) << 2);
for (i = 0; i < row_width; i++)
1995-07-20 03:43:20 -04:00
{
1997-01-17 02:34:35 -05:00
value = (*sp >> shift) & 0xf;
*dp = (png_byte)(value | (value << 4));
if (shift == 4)
{
shift = 0;
sp--;
}
else
shift = 4;
1995-07-20 03:43:20 -04:00
1997-01-17 02:34:35 -05:00
dp--;
}
break;
1995-07-20 03:43:20 -04:00
}
}
1997-01-17 02:34:35 -05:00
row_info->bit_depth = 8;
row_info->pixel_depth = 8;
1998-04-21 16:03:57 -04:00
row_info->rowbytes = row_width;
1995-07-20 03:43:20 -04:00
}
1997-01-17 02:34:35 -05:00
1997-05-16 03:46:07 -04:00
if (trans_value != NULL)
1995-07-20 03:43:20 -04:00
{
1997-01-17 02:34:35 -05:00
if (row_info->bit_depth == 8)
1995-07-20 03:43:20 -04:00
{
1998-04-21 16:03:57 -04:00
sp = row + (png_size_t)row_width - 1;
dp = row + (png_size_t)(row_width << 1) - 1;
for (i = 0; i < row_width; i++)
1995-07-20 03:43:20 -04:00
{
1997-01-17 02:34:35 -05:00
if (*sp == gray)
*dp-- = 0;
else
*dp-- = 0xff;
*dp-- = *sp--;
1995-07-20 03:43:20 -04:00
}
1997-01-17 02:34:35 -05:00
}
else if (row_info->bit_depth == 16)
{
1997-05-16 03:46:07 -04:00
sp = row + row_info->rowbytes - 1;
dp = row + (row_info->rowbytes << 1) - 1;
1998-04-21 16:03:57 -04:00
for (i = 0; i < row_width; i++)
1995-07-20 03:43:20 -04:00
{
1997-01-17 02:34:35 -05:00
if (((png_uint_16)*(sp) |
((png_uint_16)*(sp - 1) << 8)) == gray)
{
*dp-- = 0;
*dp-- = 0;
}
else
{
*dp-- = 0xff;
*dp-- = 0xff;
}
*dp-- = *sp--;
*dp-- = *sp--;
1995-07-20 03:43:20 -04:00
}
}
1997-01-17 02:34:35 -05:00
row_info->color_type = PNG_COLOR_TYPE_GRAY_ALPHA;
row_info->channels = 2;
row_info->pixel_depth = (png_byte)(row_info->bit_depth << 1);
row_info->rowbytes =
1998-04-21 16:03:57 -04:00
((row_width * row_info->pixel_depth) >> 3);
1995-07-20 03:43:20 -04:00
}
}
else if (row_info->color_type == PNG_COLOR_TYPE_RGB && trans_value)
{
if (row_info->bit_depth == 8)
{
sp = row + (png_size_t)row_info->rowbytes - 1;
1998-04-21 16:03:57 -04:00
dp = row + (png_size_t)(row_width << 2) - 1;
for (i = 0; i < row_width; i++)
1995-07-20 03:43:20 -04:00
{
1996-01-26 02:38:47 -05:00
if (*(sp - 2) == trans_value->red &&
1995-07-20 03:43:20 -04:00
*(sp - 1) == trans_value->green &&
*(sp - 0) == trans_value->blue)
*dp-- = 0;
else
*dp-- = 0xff;
*dp-- = *sp--;
*dp-- = *sp--;
*dp-- = *sp--;
}
}
else if (row_info->bit_depth == 16)
{
1997-05-16 03:46:07 -04:00
sp = row + row_info->rowbytes - 1;
1998-04-21 16:03:57 -04:00
dp = row + (png_size_t)(row_width << 3) - 1;
for (i = 0; i < row_width; i++)
1995-07-20 03:43:20 -04:00
{
if ((((png_uint_16)*(sp - 4) |
1996-01-26 02:38:47 -05:00
((png_uint_16)*(sp - 5) << 8)) == trans_value->red) &&
1995-07-20 03:43:20 -04:00
(((png_uint_16)*(sp - 2) |
((png_uint_16)*(sp - 3) << 8)) == trans_value->green) &&
(((png_uint_16)*(sp - 0) |
((png_uint_16)*(sp - 1) << 8)) == trans_value->blue))
{
*dp-- = 0;
*dp-- = 0;
}
else
{
*dp-- = 0xff;
*dp-- = 0xff;
}
*dp-- = *sp--;
*dp-- = *sp--;
*dp-- = *sp--;
*dp-- = *sp--;
1996-01-26 02:38:47 -05:00
*dp-- = *sp--;
1995-07-20 03:43:20 -04:00
*dp-- = *sp--;
}
}
row_info->color_type = PNG_COLOR_TYPE_RGB_ALPHA;
row_info->channels = 4;
1996-01-26 02:38:47 -05:00
row_info->pixel_depth = (png_byte)(row_info->bit_depth << 2);
1995-07-20 03:43:20 -04:00
row_info->rowbytes =
1998-04-21 16:03:57 -04:00
((row_width * row_info->pixel_depth) >> 3);
1995-07-20 03:43:20 -04:00
}
}
}
1995-09-26 06:22:39 -04:00
#endif
1995-07-20 03:43:20 -04:00
1995-09-26 06:22:39 -04:00
#if defined(PNG_READ_DITHER_SUPPORTED)
1995-07-20 03:43:20 -04:00
void
1995-12-19 04:22:19 -05:00
png_do_dither(png_row_infop row_info, png_bytep row,
1996-01-26 02:38:47 -05:00
png_bytep palette_lookup, png_bytep dither_lookup)
1995-07-20 03:43:20 -04:00
{
1995-12-19 04:22:19 -05:00
png_bytep sp, dp;
1995-09-26 06:22:39 -04:00
png_uint_32 i;
1998-04-21 16:03:57 -04:00
png_uint_32 row_width=row_info->width;
1995-12-19 04:22:19 -05:00
1997-05-16 03:46:07 -04:00
png_debug(1, "in png_do_dither\n");
#if defined(PNG_USELESS_TESTS_SUPPORTED)
if (row != NULL && row_info != NULL)
#endif
1995-07-20 03:43:20 -04:00
{
if (row_info->color_type == PNG_COLOR_TYPE_RGB &&
palette_lookup && row_info->bit_depth == 8)
{
int r, g, b, p;
sp = row;
dp = row;
1998-04-21 16:03:57 -04:00
for (i = 0; i < row_width; i++)
1995-07-20 03:43:20 -04:00
{
r = *sp++;
g = *sp++;
b = *sp++;
/* this looks real messy, but the compiler will reduce
it down to a reasonable formula. For example, with
5 bits per color, we get:
p = (((r >> 3) & 0x1f) << 10) |
(((g >> 3) & 0x1f) << 5) |
((b >> 3) & 0x1f);
*/
p = (((r >> (8 - PNG_DITHER_RED_BITS)) &
((1 << PNG_DITHER_RED_BITS) - 1)) <<
(PNG_DITHER_GREEN_BITS + PNG_DITHER_BLUE_BITS)) |
(((g >> (8 - PNG_DITHER_GREEN_BITS)) &
1996-01-26 02:38:47 -05:00
((1 << PNG_DITHER_GREEN_BITS) - 1)) <<
1995-07-20 03:43:20 -04:00
(PNG_DITHER_BLUE_BITS)) |
((b >> (8 - PNG_DITHER_BLUE_BITS)) &
((1 << PNG_DITHER_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 =
1998-04-21 16:03:57 -04:00
((row_width * row_info->pixel_depth + 7) >> 3);
1995-07-20 03:43:20 -04:00
}
else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA &&
1997-05-16 03:46:07 -04:00
palette_lookup != NULL && row_info->bit_depth == 8)
1995-07-20 03:43:20 -04:00
{
int r, g, b, p;
sp = row;
dp = row;
1998-04-21 16:03:57 -04:00
for (i = 0; i < row_width; i++)
1995-07-20 03:43:20 -04:00
{
r = *sp++;
g = *sp++;
b = *sp++;
sp++;
p = (((r >> (8 - PNG_DITHER_RED_BITS)) &
1996-01-26 02:38:47 -05:00
((1 << PNG_DITHER_RED_BITS) - 1)) <<
1995-07-20 03:43:20 -04:00
(PNG_DITHER_GREEN_BITS + PNG_DITHER_BLUE_BITS)) |
(((g >> (8 - PNG_DITHER_GREEN_BITS)) &
((1 << PNG_DITHER_GREEN_BITS) - 1)) <<
(PNG_DITHER_BLUE_BITS)) |
((b >> (8 - PNG_DITHER_BLUE_BITS)) &
((1 << PNG_DITHER_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 =
1998-04-21 16:03:57 -04:00
((row_width * row_info->pixel_depth + 7) >> 3);
1995-07-20 03:43:20 -04:00
}
else if (row_info->color_type == PNG_COLOR_TYPE_PALETTE &&
dither_lookup && row_info->bit_depth == 8)
1996-01-26 02:38:47 -05:00
{
1995-07-20 03:43:20 -04:00
sp = row;
1998-04-21 16:03:57 -04:00
for (i = 0; i < row_width; i++, sp++)
1995-07-20 03:43:20 -04:00
{
*sp = dither_lookup[*sp];
}
}
}
}
1995-09-26 06:22:39 -04:00
#endif
1995-07-20 03:43:20 -04:00
1995-09-26 06:22:39 -04:00
#if defined(PNG_READ_GAMMA_SUPPORTED)
1995-07-20 03:43:20 -04:00
static int png_gamma_shift[] =
{0x10, 0x21, 0x42, 0x84, 0x110, 0x248, 0x550, 0xff0};
1997-05-16 03:46:07 -04:00
/* We build the 8- or 16-bit gamma tables here. Note that for 16-bit
1998-01-01 08:13:13 -05:00
* tables, we don't make a full table if we are reducing to 8-bit in
* the future. Note also how the gamma_16 tables are segmented so that
* we don't need to allocate > 64K chunks for a full 16-bit table.
*/
1995-07-20 03:43:20 -04:00
void
1995-12-19 04:22:19 -05:00
png_build_gamma_table(png_structp png_ptr)
1995-07-20 03:43:20 -04:00
{
1997-05-16 03:46:07 -04:00
png_debug(1, "in png_build_gamma_table\n");
1995-07-20 03:43:20 -04:00
if (png_ptr->bit_depth <= 8)
{
int i;
double g;
1998-01-16 23:06:18 -05:00
g = 1.0 / (png_ptr->gamma * png_ptr->screen_gamma);
1995-07-20 03:43:20 -04:00
1997-01-17 02:34:35 -05:00
png_ptr->gamma_table = (png_bytep)png_malloc(png_ptr,
1995-07-20 03:43:20 -04:00
(png_uint_32)256);
for (i = 0; i < 256; i++)
{
png_ptr->gamma_table[i] = (png_byte)(pow((double)i / 255.0,
g) * 255.0 + .5);
}
1997-05-16 03:46:07 -04:00
#if defined(PNG_READ_BACKGROUND_SUPPORTED)
1995-07-20 03:43:20 -04:00
if (png_ptr->transformations & PNG_BACKGROUND)
{
g = 1.0 / (png_ptr->gamma);
1997-01-17 02:34:35 -05:00
png_ptr->gamma_to_1 = (png_bytep)png_malloc(png_ptr,
1995-07-20 03:43:20 -04:00
(png_uint_32)256);
for (i = 0; i < 256; i++)
{
png_ptr->gamma_to_1[i] = (png_byte)(pow((double)i / 255.0,
g) * 255.0 + .5);
}
1998-01-16 23:06:18 -05:00
g = 1.0 / (png_ptr->screen_gamma);
1995-07-20 03:43:20 -04:00
1997-01-17 02:34:35 -05:00
png_ptr->gamma_from_1 = (png_bytep)png_malloc(png_ptr,
1995-07-20 03:43:20 -04:00
(png_uint_32)256);
for (i = 0; i < 256; i++)
{
png_ptr->gamma_from_1[i] = (png_byte)(pow((double)i / 255.0,
g) * 255.0 + .5);
}
}
1997-05-16 03:46:07 -04:00
#endif /* PNG_BACKGROUND_SUPPORTED */
1995-07-20 03:43:20 -04:00
}
1996-01-26 02:38:47 -05:00
else
1995-07-20 03:43:20 -04:00
{
double g;
1996-01-26 02:38:47 -05:00
int i, j, shift, num;
int sig_bit;
png_uint_32 ig;
1995-07-20 03:43:20 -04:00
if (png_ptr->color_type & PNG_COLOR_MASK_COLOR)
1996-01-26 02:38:47 -05:00
{
1995-07-20 03:43:20 -04:00
sig_bit = (int)png_ptr->sig_bit.red;
if ((int)png_ptr->sig_bit.green > sig_bit)
sig_bit = png_ptr->sig_bit.green;
if ((int)png_ptr->sig_bit.blue > sig_bit)
1996-01-26 02:38:47 -05:00
sig_bit = png_ptr->sig_bit.blue;
1995-07-20 03:43:20 -04:00
}
else
{
sig_bit = (int)png_ptr->sig_bit.gray;
1996-01-26 02:38:47 -05:00
}
1995-07-20 03:43:20 -04:00
if (sig_bit > 0)
shift = 16 - sig_bit;
else
1996-01-26 02:38:47 -05:00
shift = 0;
1995-07-20 03:43:20 -04:00
if (png_ptr->transformations & PNG_16_TO_8)
{
if (shift < (16 - PNG_MAX_GAMMA_8))
shift = (16 - PNG_MAX_GAMMA_8);
}
1996-01-26 02:38:47 -05:00
if (shift > 8)
1995-07-20 03:43:20 -04:00
shift = 8;
if (shift < 0)
shift = 0;
1996-01-26 02:38:47 -05:00
png_ptr->gamma_shift = (png_byte)shift;
1995-07-20 03:43:20 -04:00
1996-01-26 02:38:47 -05:00
num = (1 << (8 - shift));
1995-07-20 03:43:20 -04:00
1998-01-16 23:06:18 -05:00
g = 1.0 / (png_ptr->gamma * png_ptr->screen_gamma);
1995-07-20 03:43:20 -04:00
1997-01-17 02:34:35 -05:00
png_ptr->gamma_16_table = (png_uint_16pp)png_malloc(png_ptr,
1998-02-07 11:20:57 -05:00
(png_uint_32)(num * sizeof (png_uint_16p)));
1995-07-20 03:43:20 -04:00
1996-01-26 02:38:47 -05:00
if ((png_ptr->transformations & PNG_16_TO_8) &&
!(png_ptr->transformations & PNG_BACKGROUND))
{
double fin, fout;
png_uint_32 last, max;
for (i = 0; i < num; i++)
{
1997-01-17 02:34:35 -05:00
png_ptr->gamma_16_table[i] = (png_uint_16p)png_malloc(png_ptr,
1998-02-07 11:20:57 -05:00
(png_uint_32)(256 * sizeof (png_uint_16)));
1996-01-26 02:38:47 -05:00
}
g = 1.0 / g;
last = 0;
for (i = 0; i < 256; i++)
{
fout = ((double)i + 0.5) / 256.0;
fin = pow(fout, g);
max = (png_uint_32)(fin * (double)((png_uint_32)num << 8));
while (last <= max)
{
png_ptr->gamma_16_table[(int)(last & (0xff >> shift))]
[(int)(last >> (8 - shift))] = (png_uint_16)(
(png_uint_16)i | ((png_uint_16)i << 8));
last++;
}
}
while (last < ((png_uint_32)num << 8))
{
png_ptr->gamma_16_table[(int)(last & (0xff >> shift))]
1997-05-16 03:46:07 -04:00
[(int)(last >> (8 - shift))] = (png_uint_16)65535L;
1996-01-26 02:38:47 -05:00
last++;
1995-12-19 04:22:19 -05:00
}
1995-07-20 03:43:20 -04:00
}
1996-01-26 02:38:47 -05:00
else
{
for (i = 0; i < num; i++)
{
1997-01-17 02:34:35 -05:00
png_ptr->gamma_16_table[i] = (png_uint_16p)png_malloc(png_ptr,
1998-02-07 11:20:57 -05:00
(png_uint_32)(256 * sizeof (png_uint_16)));
1996-01-26 02:38:47 -05:00
1997-05-16 03:46:07 -04:00
ig = (((png_uint_32)i * (png_uint_32)png_gamma_shift[shift]) >> 4);
1996-01-26 02:38:47 -05:00
for (j = 0; j < 256; j++)
1995-07-20 03:43:20 -04:00
{
png_ptr->gamma_16_table[i][j] =
(png_uint_16)(pow((double)(ig + ((png_uint_32)j << 8)) /
65535.0, g) * 65535.0 + .5);
}
}
}
1997-05-16 03:46:07 -04:00
#if defined(PNG_READ_BACKGROUND_SUPPORTED)
1995-07-20 03:43:20 -04:00
if (png_ptr->transformations & PNG_BACKGROUND)
{
g = 1.0 / (png_ptr->gamma);
1997-01-17 02:34:35 -05:00
png_ptr->gamma_16_to_1 = (png_uint_16pp)png_malloc(png_ptr,
1998-02-07 11:20:57 -05:00
(png_uint_32)(num * sizeof (png_uint_16p )));
1995-07-20 03:43:20 -04:00
for (i = 0; i < num; i++)
{
1997-01-17 02:34:35 -05:00
png_ptr->gamma_16_to_1[i] = (png_uint_16p)png_malloc(png_ptr,
1998-02-07 11:20:57 -05:00
(png_uint_32)(256 * sizeof (png_uint_16)));
1995-07-20 03:43:20 -04:00
ig = (((png_uint_32)i *
(png_uint_32)png_gamma_shift[shift]) >> 4);
for (j = 0; j < 256; j++)
{
png_ptr->gamma_16_to_1[i][j] =
(png_uint_16)(pow((double)(ig + ((png_uint_32)j << 8)) /
65535.0, g) * 65535.0 + .5);
}
}
1998-01-16 23:06:18 -05:00
g = 1.0 / (png_ptr->screen_gamma);
1995-07-20 03:43:20 -04:00
1997-01-17 02:34:35 -05:00
png_ptr->gamma_16_from_1 = (png_uint_16pp)png_malloc(png_ptr,
1998-02-07 11:20:57 -05:00
(png_uint_32)(num * sizeof (png_uint_16p)));
1995-07-20 03:43:20 -04:00
for (i = 0; i < num; i++)
{
1997-01-17 02:34:35 -05:00
png_ptr->gamma_16_from_1[i] = (png_uint_16p)png_malloc(png_ptr,
1998-02-07 11:20:57 -05:00
(png_uint_32)(256 * sizeof (png_uint_16)));
1995-07-20 03:43:20 -04:00
ig = (((png_uint_32)i *
(png_uint_32)png_gamma_shift[shift]) >> 4);
for (j = 0; j < 256; j++)
{
png_ptr->gamma_16_from_1[i][j] =
(png_uint_16)(pow((double)(ig + ((png_uint_32)j << 8)) /
65535.0, g) * 65535.0 + .5);
}
}
}
1997-05-16 03:46:07 -04:00
#endif /* PNG_BACKGROUND_SUPPORTED */
1995-07-20 03:43:20 -04:00
}
}
1995-09-26 06:22:39 -04:00
#endif