Alien-FreeImage
view release on metacpan or search on metacpan
src/Source/LibPNG/pngread.c view on Meta::CPAN
switch (PNG_IMAGE_SAMPLE_CHANNELS(image->format))
{
case 4:
entry[afirst ? 0 : 3] = (png_byte)alpha;
case 3:
entry[afirst + (2 ^ bgr)] = (png_byte)blue;
entry[afirst + 1] = (png_byte)green;
entry[afirst + bgr] = (png_byte)red;
break;
case 2:
entry[1 ^ afirst] = (png_byte)alpha;
case 1:
entry[afirst] = (png_byte)green;
break;
default:
break;
}
}
# ifdef afirst
# undef afirst
# endif
# ifdef bgr
# undef bgr
# endif
}
}
static int
make_gray_file_colormap(png_image_read_control *display)
{
unsigned int i;
for (i=0; i<256; ++i)
png_create_colormap_entry(display, i, i, i, i, 255, P_FILE);
return i;
}
static int
make_gray_colormap(png_image_read_control *display)
{
unsigned int i;
for (i=0; i<256; ++i)
png_create_colormap_entry(display, i, i, i, i, 255, P_sRGB);
return i;
}
#define PNG_GRAY_COLORMAP_ENTRIES 256
static int
make_ga_colormap(png_image_read_control *display)
{
unsigned int i, a;
/* Alpha is retained, the output will be a color-map with entries
* selected by six levels of alpha. One transparent entry, 6 gray
* levels for all the intermediate alpha values, leaving 230 entries
* for the opaque grays. The color-map entries are the six values
* [0..5]*51, the GA processing uses PNG_DIV51(value) to find the
* relevant entry.
*
* if (alpha > 229) // opaque
* {
* // The 231 entries are selected to make the math below work:
* base = 0;
* entry = (231 * gray + 128) >> 8;
* }
* else if (alpha < 26) // transparent
* {
* base = 231;
* entry = 0;
* }
* else // partially opaque
* {
* base = 226 + 6 * PNG_DIV51(alpha);
* entry = PNG_DIV51(gray);
* }
*/
i = 0;
while (i < 231)
{
unsigned int gray = (i * 256 + 115) / 231;
png_create_colormap_entry(display, i++, gray, gray, gray, 255, P_sRGB);
}
/* 255 is used here for the component values for consistency with the code
* that undoes premultiplication in pngwrite.c.
*/
png_create_colormap_entry(display, i++, 255, 255, 255, 0, P_sRGB);
for (a=1; a<5; ++a)
{
unsigned int g;
for (g=0; g<6; ++g)
png_create_colormap_entry(display, i++, g*51, g*51, g*51, a*51,
P_sRGB);
}
return i;
}
#define PNG_GA_COLORMAP_ENTRIES 256
static int
make_rgb_colormap(png_image_read_control *display)
{
unsigned int i, r;
/* Build a 6x6x6 opaque RGB cube */
for (i=r=0; r<6; ++r)
{
unsigned int g;
for (g=0; g<6; ++g)
{
unsigned int b;
for (b=0; b<6; ++b)
png_create_colormap_entry(display, i++, r*51, g*51, b*51, 255,
P_sRGB);
}
}
return i;
}
#define PNG_RGB_COLORMAP_ENTRIES 216
src/Source/LibPNG/pngread.c view on Meta::CPAN
if ((output_format & PNG_FORMAT_FLAG_COLOR) != 0)
{
back_r = display->background->red;
back_b = display->background->blue;
}
else
back_b = back_r = back_g;
}
}
else if (output_encoding == P_LINEAR)
back_b = back_r = back_g = 65535;
else
back_b = back_r = back_g = 255;
/* Default the input file gamma if required - this is necessary because
* libpng assumes that if no gamma information is present the data is in the
* output format, but the simplified API deduces the gamma from the input
* format.
*/
if ((png_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_GAMMA) == 0)
{
/* Do this directly, not using the png_colorspace functions, to ensure
* that it happens even if the colorspace is invalid (though probably if
* it is the setting will be ignored) Note that the same thing can be
* achieved at the application interface with png_set_gAMA.
*/
if (png_ptr->bit_depth == 16 &&
(image->flags & PNG_IMAGE_FLAG_16BIT_sRGB) == 0)
png_ptr->colorspace.gamma = PNG_GAMMA_LINEAR;
else
png_ptr->colorspace.gamma = PNG_GAMMA_sRGB_INVERSE;
png_ptr->colorspace.flags |= PNG_COLORSPACE_HAVE_GAMMA;
}
/* Decide what to do based on the PNG color type of the input data. The
* utility function png_create_colormap_entry deals with most aspects of the
* output transformations; this code works out how to produce bytes of
* color-map entries from the original format.
*/
switch (png_ptr->color_type)
{
case PNG_COLOR_TYPE_GRAY:
if (png_ptr->bit_depth <= 8)
{
/* There at most 256 colors in the output, regardless of
* transparency.
*/
unsigned int step, i, val, trans = 256/*ignore*/, back_alpha = 0;
cmap_entries = 1U << png_ptr->bit_depth;
if (cmap_entries > image->colormap_entries)
png_error(png_ptr, "gray[8] color-map: too few entries");
step = 255 / (cmap_entries - 1);
output_processing = PNG_CMAP_NONE;
/* If there is a tRNS chunk then this either selects a transparent
* value or, if the output has no alpha, the background color.
*/
if (png_ptr->num_trans > 0)
{
trans = png_ptr->trans_color.gray;
if ((output_format & PNG_FORMAT_FLAG_ALPHA) == 0)
back_alpha = output_encoding == P_LINEAR ? 65535 : 255;
}
/* png_create_colormap_entry just takes an RGBA and writes the
* corresponding color-map entry using the format from 'image',
* including the required conversion to sRGB or linear as
* appropriate. The input values are always either sRGB (if the
* gamma correction flag is 0) or 0..255 scaled file encoded values
* (if the function must gamma correct them).
*/
for (i=val=0; i<cmap_entries; ++i, val += step)
{
/* 'i' is a file value. While this will result in duplicated
* entries for 8-bit non-sRGB encoded files it is necessary to
* have non-gamma corrected values to do tRNS handling.
*/
if (i != trans)
png_create_colormap_entry(display, i, val, val, val, 255,
P_FILE/*8-bit with file gamma*/);
/* Else this entry is transparent. The colors don't matter if
* there is an alpha channel (back_alpha == 0), but it does no
* harm to pass them in; the values are not set above so this
* passes in white.
*
* NOTE: this preserves the full precision of the application
* supplied background color when it is used.
*/
else
png_create_colormap_entry(display, i, back_r, back_g, back_b,
back_alpha, output_encoding);
}
/* We need libpng to preserve the original encoding. */
data_encoding = P_FILE;
/* The rows from libpng, while technically gray values, are now also
* color-map indices; however, they may need to be expanded to 1
* byte per pixel. This is what png_set_packing does (i.e., it
* unpacks the bit values into bytes.)
*/
if (png_ptr->bit_depth < 8)
png_set_packing(png_ptr);
}
else /* bit depth is 16 */
{
/* The 16-bit input values can be converted directly to 8-bit gamma
* encoded values; however, if a tRNS chunk is present 257 color-map
* entries are required. This means that the extra entry requires
* special processing; add an alpha channel, sacrifice gray level
* 254 and convert transparent (alpha==0) entries to that.
*
* Use libpng to chop the data to 8 bits. Convert it to sRGB at the
* same time to minimize quality loss. If a tRNS chunk is present
* this means libpng must handle it too; otherwise it is impossible
* to do the exact match on the 16-bit value.
*
* If the output has no alpha channel *and* the background color is
* gray then it is possible to let libpng handle the substitution by
* ensuring that the corresponding gray level matches the background
* color exactly.
*/
data_encoding = P_sRGB;
if (PNG_GRAY_COLORMAP_ENTRIES > image->colormap_entries)
png_error(png_ptr, "gray[16] color-map: too few entries");
cmap_entries = make_gray_colormap(display);
if (png_ptr->num_trans > 0)
{
unsigned int back_alpha;
if ((output_format & PNG_FORMAT_FLAG_ALPHA) != 0)
back_alpha = 0;
else
{
if (back_r == back_g && back_g == back_b)
{
/* Background is gray; no special processing will be
* required.
*/
png_color_16 c;
png_uint_32 gray = back_g;
if (output_encoding == P_LINEAR)
{
gray = PNG_sRGB_FROM_LINEAR(gray * 255);
/* And make sure the corresponding palette entry
* matches.
*/
png_create_colormap_entry(display, gray, back_g, back_g,
back_g, 65535, P_LINEAR);
}
/* The background passed to libpng, however, must be the
* sRGB value.
*/
c.index = 0; /*unused*/
c.gray = c.red = c.green = c.blue = (png_uint_16)gray;
/* NOTE: does this work without expanding tRNS to alpha?
* It should be the color->gray case below apparently
* doesn't.
*/
png_set_background_fixed(png_ptr, &c,
PNG_BACKGROUND_GAMMA_SCREEN, 0/*need_expand*/,
0/*gamma: not used*/);
output_processing = PNG_CMAP_NONE;
break;
}
back_alpha = output_encoding == P_LINEAR ? 65535 : 255;
}
/* output_processing means that the libpng-processed row will be
* 8-bit GA and it has to be processing to single byte color-map
* values. Entry 254 is replaced by either a completely
* transparent entry or by the background color at full
* precision (and the background color is not a simple gray
* level in this case.)
*/
expand_tRNS = 1;
output_processing = PNG_CMAP_TRANS;
background_index = 254;
/* And set (overwrite) color-map entry 254 to the actual
* background color at full precision.
*/
png_create_colormap_entry(display, 254, back_r, back_g, back_b,
back_alpha, output_encoding);
}
else
output_processing = PNG_CMAP_NONE;
}
break;
case PNG_COLOR_TYPE_GRAY_ALPHA:
/* 8-bit or 16-bit PNG with two channels - gray and alpha. A minimum
* of 65536 combinations. If, however, the alpha channel is to be
* removed there are only 256 possibilities if the background is gray.
* (Otherwise there is a subset of the 65536 possibilities defined by
* the triangle between black, white and the background color.)
*
* Reduce 16-bit files to 8-bit and sRGB encode the result. No need to
* worry about tRNS matching - tRNS is ignored if there is an alpha
* channel.
*/
data_encoding = P_sRGB;
if ((output_format & PNG_FORMAT_FLAG_ALPHA) != 0)
{
if (PNG_GA_COLORMAP_ENTRIES > image->colormap_entries)
png_error(png_ptr, "gray+alpha color-map: too few entries");
cmap_entries = make_ga_colormap(display);
background_index = PNG_CMAP_GA_BACKGROUND;
output_processing = PNG_CMAP_GA;
}
else /* alpha is removed */
{
/* Alpha must be removed as the PNG data is processed when the
* background is a color because the G and A channels are
* independent and the vector addition (non-parallel vectors) is a
* 2-D problem.
*
* This can be reduced to the same algorithm as above by making a
* colormap containing gray levels (for the opaque grays), a
* background entry (for a transparent pixel) and a set of four six
* level color values, one set for each intermediate alpha value.
* See the comments in make_ga_colormap for how this works in the
* per-pixel processing.
*
* If the background is gray, however, we only need a 256 entry gray
* level color map. It is sufficient to make the entry generated
* for the background color be exactly the color specified.
*/
if ((output_format & PNG_FORMAT_FLAG_COLOR) == 0 ||
(back_r == back_g && back_g == back_b))
{
/* Background is gray; no special processing will be required. */
png_color_16 c;
png_uint_32 gray = back_g;
if (PNG_GRAY_COLORMAP_ENTRIES > image->colormap_entries)
png_error(png_ptr, "gray-alpha color-map: too few entries");
cmap_entries = make_gray_colormap(display);
if (output_encoding == P_LINEAR)
{
gray = PNG_sRGB_FROM_LINEAR(gray * 255);
/* And make sure the corresponding palette entry matches. */
png_create_colormap_entry(display, gray, back_g, back_g,
back_g, 65535, P_LINEAR);
}
/* The background passed to libpng, however, must be the sRGB
* value.
*/
c.index = 0; /*unused*/
c.gray = c.red = c.green = c.blue = (png_uint_16)gray;
png_set_background_fixed(png_ptr, &c,
PNG_BACKGROUND_GAMMA_SCREEN, 0/*need_expand*/,
0/*gamma: not used*/);
output_processing = PNG_CMAP_NONE;
}
else
{
png_uint_32 i, a;
/* This is the same as png_make_ga_colormap, above, except that
* the entries are all opaque.
*/
if (PNG_GA_COLORMAP_ENTRIES > image->colormap_entries)
png_error(png_ptr, "ga-alpha color-map: too few entries");
i = 0;
while (i < 231)
{
png_uint_32 gray = (i * 256 + 115) / 231;
png_create_colormap_entry(display, i++, gray, gray, gray,
255, P_sRGB);
}
src/Source/LibPNG/pngread.c view on Meta::CPAN
/* For non-opaque input composite on the sRGB background - this
* requires inverting the encoding for each component. The input
* is still converted to the sRGB encoding because this is a
* reasonable approximate to the logarithmic curve of human
* visual sensitivity, at least over the narrow range which PNG
* represents. Consequently 'G' is always sRGB encoded, while
* 'A' is linear. We need the linear background colors.
*/
if (output_encoding == P_sRGB) /* else already linear */
{
/* This may produce a value not exactly matching the
* background, but that's ok because these numbers are only
* used when alpha != 0
*/
back_r = png_sRGB_table[back_r];
back_g = png_sRGB_table[back_g];
back_b = png_sRGB_table[back_b];
}
for (a=1; a<5; ++a)
{
unsigned int g;
/* PNG_sRGB_FROM_LINEAR expects a 16-bit linear value scaled
* by an 8-bit alpha value (0..255).
*/
png_uint_32 alpha = 51 * a;
png_uint_32 back_rx = (255-alpha) * back_r;
png_uint_32 back_gx = (255-alpha) * back_g;
png_uint_32 back_bx = (255-alpha) * back_b;
for (g=0; g<6; ++g)
{
png_uint_32 gray = png_sRGB_table[g*51] * alpha;
png_create_colormap_entry(display, i++,
PNG_sRGB_FROM_LINEAR(gray + back_rx),
PNG_sRGB_FROM_LINEAR(gray + back_gx),
PNG_sRGB_FROM_LINEAR(gray + back_bx), 255, P_sRGB);
}
}
cmap_entries = i;
output_processing = PNG_CMAP_GA;
}
}
break;
case PNG_COLOR_TYPE_RGB:
case PNG_COLOR_TYPE_RGB_ALPHA:
/* Exclude the case where the output is gray; we can always handle this
* with the cases above.
*/
if ((output_format & PNG_FORMAT_FLAG_COLOR) == 0)
{
/* The color-map will be grayscale, so we may as well convert the
* input RGB values to a simple grayscale and use the grayscale
* code above.
*
* NOTE: calling this apparently damages the recognition of the
* transparent color in background color handling; call
* png_set_tRNS_to_alpha before png_set_background_fixed.
*/
png_set_rgb_to_gray_fixed(png_ptr, PNG_ERROR_ACTION_NONE, -1,
-1);
data_encoding = P_sRGB;
/* The output will now be one or two 8-bit gray or gray+alpha
* channels. The more complex case arises when the input has alpha.
*/
if ((png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA ||
png_ptr->num_trans > 0) &&
(output_format & PNG_FORMAT_FLAG_ALPHA) != 0)
{
/* Both input and output have an alpha channel, so no background
* processing is required; just map the GA bytes to the right
* color-map entry.
*/
expand_tRNS = 1;
if (PNG_GA_COLORMAP_ENTRIES > image->colormap_entries)
png_error(png_ptr, "rgb[ga] color-map: too few entries");
cmap_entries = make_ga_colormap(display);
background_index = PNG_CMAP_GA_BACKGROUND;
output_processing = PNG_CMAP_GA;
}
else
{
/* Either the input or the output has no alpha channel, so there
* will be no non-opaque pixels in the color-map; it will just be
* grayscale.
*/
if (PNG_GRAY_COLORMAP_ENTRIES > image->colormap_entries)
png_error(png_ptr, "rgb[gray] color-map: too few entries");
/* Ideally this code would use libpng to do the gamma correction,
* but if an input alpha channel is to be removed we will hit the
* libpng bug in gamma+compose+rgb-to-gray (the double gamma
* correction bug). Fix this by dropping the gamma correction in
* this case and doing it in the palette; this will result in
* duplicate palette entries, but that's better than the
* alternative of double gamma correction.
*/
if ((png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA ||
png_ptr->num_trans > 0) &&
png_gamma_not_sRGB(png_ptr->colorspace.gamma) != 0)
{
cmap_entries = make_gray_file_colormap(display);
data_encoding = P_FILE;
}
else
cmap_entries = make_gray_colormap(display);
/* But if the input has alpha or transparency it must be removed
*/
if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA ||
png_ptr->num_trans > 0)
{
png_color_16 c;
png_uint_32 gray = back_g;
/* We need to ensure that the application background exists in
* the colormap and that completely transparent pixels map to
* it. Achieve this simply by ensuring that the entry
* selected for the background really is the background color.
*/
if (data_encoding == P_FILE) /* from the fixup above */
{
/* The app supplied a gray which is in output_encoding, we
* need to convert it to a value of the input (P_FILE)
* encoding then set this palette entry to the required
* output encoding.
*/
if (output_encoding == P_sRGB)
gray = png_sRGB_table[gray]; /* now P_LINEAR */
gray = PNG_DIV257(png_gamma_16bit_correct(gray,
png_ptr->colorspace.gamma)); /* now P_FILE */
/* And make sure the corresponding palette entry contains
* exactly the required sRGB value.
*/
png_create_colormap_entry(display, gray, back_g, back_g,
back_g, 0/*unused*/, output_encoding);
}
else if (output_encoding == P_LINEAR)
{
gray = PNG_sRGB_FROM_LINEAR(gray * 255);
/* And make sure the corresponding palette entry matches.
*/
png_create_colormap_entry(display, gray, back_g, back_g,
back_g, 0/*unused*/, P_LINEAR);
}
/* The background passed to libpng, however, must be the
* output (normally sRGB) value.
*/
c.index = 0; /*unused*/
c.gray = c.red = c.green = c.blue = (png_uint_16)gray;
/* NOTE: the following is apparently a bug in libpng. Without
* it the transparent color recognition in
* png_set_background_fixed seems to go wrong.
*/
expand_tRNS = 1;
png_set_background_fixed(png_ptr, &c,
PNG_BACKGROUND_GAMMA_SCREEN, 0/*need_expand*/,
0/*gamma: not used*/);
}
output_processing = PNG_CMAP_NONE;
}
}
else /* output is color */
{
/* We could use png_quantize here so long as there is no transparent
* color or alpha; png_quantize ignores alpha. Easier overall just
* to do it once and using PNG_DIV51 on the 6x6x6 reduced RGB cube.
* Consequently we always want libpng to produce sRGB data.
*/
data_encoding = P_sRGB;
/* Is there any transparency or alpha? */
if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA ||
png_ptr->num_trans > 0)
{
/* Is there alpha in the output too? If so all four channels are
* processed into a special RGB cube with alpha support.
*/
if ((output_format & PNG_FORMAT_FLAG_ALPHA) != 0)
{
png_uint_32 r;
if (PNG_RGB_COLORMAP_ENTRIES+1+27 > image->colormap_entries)
png_error(png_ptr, "rgb+alpha color-map: too few entries");
cmap_entries = make_rgb_colormap(display);
/* Add a transparent entry. */
png_create_colormap_entry(display, cmap_entries, 255, 255,
255, 0, P_sRGB);
/* This is stored as the background index for the processing
* algorithm.
*/
background_index = cmap_entries++;
/* Add 27 r,g,b entries each with alpha 0.5. */
for (r=0; r<256; r = (r << 1) | 0x7f)
{
png_uint_32 g;
for (g=0; g<256; g = (g << 1) | 0x7f)
{
png_uint_32 b;
/* This generates components with the values 0, 127 and
* 255
*/
for (b=0; b<256; b = (b << 1) | 0x7f)
png_create_colormap_entry(display, cmap_entries++,
r, g, b, 128, P_sRGB);
}
}
expand_tRNS = 1;
output_processing = PNG_CMAP_RGB_ALPHA;
}
else
{
/* Alpha/transparency must be removed. The background must
* exist in the color map (achieved by setting adding it after
* the 666 color-map). If the standard processing code will
* pick up this entry automatically that's all that is
* required; libpng can be called to do the background
* processing.
*/
unsigned int sample_size =
PNG_IMAGE_SAMPLE_SIZE(output_format);
png_uint_32 r, g, b; /* sRGB background */
if (PNG_RGB_COLORMAP_ENTRIES+1+27 > image->colormap_entries)
png_error(png_ptr, "rgb-alpha color-map: too few entries");
cmap_entries = make_rgb_colormap(display);
png_create_colormap_entry(display, cmap_entries, back_r,
back_g, back_b, 0/*unused*/, output_encoding);
if (output_encoding == P_LINEAR)
{
r = PNG_sRGB_FROM_LINEAR(back_r * 255);
g = PNG_sRGB_FROM_LINEAR(back_g * 255);
b = PNG_sRGB_FROM_LINEAR(back_b * 255);
}
else
{
src/Source/LibPNG/pngread.c view on Meta::CPAN
png_bytep first_row = png_voidcast(png_bytep, display->first_row);
ptrdiff_t step_row = display->row_bytes;
int pass;
for (pass = 0; pass < passes; ++pass)
{
unsigned int startx, stepx, stepy;
png_uint_32 y;
if (png_ptr->interlaced == PNG_INTERLACE_ADAM7)
{
/* The row may be empty for a short image: */
if (PNG_PASS_COLS(width, pass) == 0)
continue;
startx = PNG_PASS_START_COL(pass);
stepx = PNG_PASS_COL_OFFSET(pass);
y = PNG_PASS_START_ROW(pass);
stepy = PNG_PASS_ROW_OFFSET(pass);
}
else
{
y = 0;
startx = 0;
stepx = stepy = 1;
}
for (; y<height; y += stepy)
{
png_bytep inrow = png_voidcast(png_bytep, display->local_row);
png_bytep outrow = first_row + y * step_row;
png_const_bytep end_row = outrow + width;
/* Read read the libpng data into the temporary buffer. */
png_read_row(png_ptr, inrow, NULL);
/* Now process the row according to the processing option, note
* that the caller verifies that the format of the libpng output
* data is as required.
*/
outrow += startx;
switch (proc)
{
case PNG_CMAP_GA:
for (; outrow < end_row; outrow += stepx)
{
/* The data is always in the PNG order */
unsigned int gray = *inrow++;
unsigned int alpha = *inrow++;
unsigned int entry;
/* NOTE: this code is copied as a comment in
* make_ga_colormap above. Please update the
* comment if you change this code!
*/
if (alpha > 229) /* opaque */
{
entry = (231 * gray + 128) >> 8;
}
else if (alpha < 26) /* transparent */
{
entry = 231;
}
else /* partially opaque */
{
entry = 226 + 6 * PNG_DIV51(alpha) + PNG_DIV51(gray);
}
*outrow = (png_byte)entry;
}
break;
case PNG_CMAP_TRANS:
for (; outrow < end_row; outrow += stepx)
{
png_byte gray = *inrow++;
png_byte alpha = *inrow++;
if (alpha == 0)
*outrow = PNG_CMAP_TRANS_BACKGROUND;
else if (gray != PNG_CMAP_TRANS_BACKGROUND)
*outrow = gray;
else
*outrow = (png_byte)(PNG_CMAP_TRANS_BACKGROUND+1);
}
break;
case PNG_CMAP_RGB:
for (; outrow < end_row; outrow += stepx)
{
*outrow = PNG_RGB_INDEX(inrow[0], inrow[1], inrow[2]);
inrow += 3;
}
break;
case PNG_CMAP_RGB_ALPHA:
for (; outrow < end_row; outrow += stepx)
{
unsigned int alpha = inrow[3];
/* Because the alpha entries only hold alpha==0.5 values
* split the processing at alpha==0.25 (64) and 0.75
* (196).
*/
if (alpha >= 196)
*outrow = PNG_RGB_INDEX(inrow[0], inrow[1],
inrow[2]);
else if (alpha < 64)
*outrow = PNG_CMAP_RGB_ALPHA_BACKGROUND;
else
{
/* Likewise there are three entries for each of r, g
* and b. We could select the entry by popcount on
* the top two bits on those architectures that
* support it, this is what the code below does,
src/Source/LibPNG/pngread.c view on Meta::CPAN
if (png_muldiv(>est, output_gamma, png_ptr->colorspace.gamma,
PNG_FP_1) != 0 && png_gamma_significant(gtest) == 0)
do_local_background = 0;
else if (mode == PNG_ALPHA_STANDARD)
{
do_local_background = 2/*required*/;
mode = PNG_ALPHA_PNG; /* prevent libpng doing it */
}
/* else leave as 1 for the checks below */
}
/* If the bit-depth changes then handle that here. */
if ((change & PNG_FORMAT_FLAG_LINEAR) != 0)
{
if (linear != 0 /*16-bit output*/)
png_set_expand_16(png_ptr);
else /* 8-bit output */
png_set_scale_16(png_ptr);
change &= ~PNG_FORMAT_FLAG_LINEAR;
}
/* Now the background/alpha channel changes. */
if ((change & PNG_FORMAT_FLAG_ALPHA) != 0)
{
/* Removing an alpha channel requires composition for the 8-bit
* formats; for the 16-bit it is already done, above, by the
* pre-multiplication and the channel just needs to be stripped.
*/
if ((base_format & PNG_FORMAT_FLAG_ALPHA) != 0)
{
/* If RGB->gray is happening the alpha channel must be left and the
* operation completed locally.
*
* TODO: fix libpng and remove this.
*/
if (do_local_background != 0)
do_local_background = 2/*required*/;
/* 16-bit output: just remove the channel */
else if (linear != 0) /* compose on black (well, pre-multiply) */
png_set_strip_alpha(png_ptr);
/* 8-bit output: do an appropriate compose */
else if (display->background != NULL)
{
png_color_16 c;
c.index = 0; /*unused*/
c.red = display->background->red;
c.green = display->background->green;
c.blue = display->background->blue;
c.gray = display->background->green;
/* This is always an 8-bit sRGB value, using the 'green' channel
* for gray is much better than calculating the luminance here;
* we can get off-by-one errors in that calculation relative to
* the app expectations and that will show up in transparent
* pixels.
*/
png_set_background_fixed(png_ptr, &c,
PNG_BACKGROUND_GAMMA_SCREEN, 0/*need_expand*/,
0/*gamma: not used*/);
}
else /* compose on row: implemented below. */
{
do_local_compose = 1;
/* This leaves the alpha channel in the output, so it has to be
* removed by the code below. Set the encoding to the 'OPTIMIZE'
* one so the code only has to hack on the pixels that require
* composition.
*/
mode = PNG_ALPHA_OPTIMIZED;
}
}
else /* output needs an alpha channel */
{
/* This is tricky because it happens before the swap operation has
* been accomplished; however, the swap does *not* swap the added
* alpha channel (weird API), so it must be added in the correct
* place.
*/
png_uint_32 filler; /* opaque filler */
int where;
if (linear != 0)
filler = 65535;
else
filler = 255;
# ifdef PNG_FORMAT_AFIRST_SUPPORTED
if ((format & PNG_FORMAT_FLAG_AFIRST) != 0)
{
where = PNG_FILLER_BEFORE;
change &= ~PNG_FORMAT_FLAG_AFIRST;
}
else
# endif
where = PNG_FILLER_AFTER;
png_set_add_alpha(png_ptr, filler, where);
}
/* This stops the (irrelevant) call to swap_alpha below. */
change &= ~PNG_FORMAT_FLAG_ALPHA;
}
/* Now set the alpha mode correctly; this is always done, even if there is
* no alpha channel in either the input or the output because it correctly
* sets the output gamma.
*/
png_set_alpha_mode_fixed(png_ptr, mode, output_gamma);
# ifdef PNG_FORMAT_BGR_SUPPORTED
( run in 1.161 second using v1.01-cache-2.11-cpan-df04353d9ac )