media/libpng/pngrtran.c

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

michael@0 1
michael@0 2 /* pngrtran.c - transforms the data in a row for PNG readers
michael@0 3 *
michael@0 4 * Last changed in libpng 1.6.10 [March 6, 2014]
michael@0 5 * Copyright (c) 1998-2014 Glenn Randers-Pehrson
michael@0 6 * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
michael@0 7 * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
michael@0 8 *
michael@0 9 * This code is released under the libpng license.
michael@0 10 * For conditions of distribution and use, see the disclaimer
michael@0 11 * and license in png.h
michael@0 12 *
michael@0 13 * This file contains functions optionally called by an application
michael@0 14 * in order to tell libpng how to handle data when reading a PNG.
michael@0 15 * Transformations that are used in both reading and writing are
michael@0 16 * in pngtrans.c.
michael@0 17 */
michael@0 18
michael@0 19 #include "pngpriv.h"
michael@0 20
michael@0 21 #ifdef PNG_READ_SUPPORTED
michael@0 22
michael@0 23 /* Set the action on getting a CRC error for an ancillary or critical chunk. */
michael@0 24 void PNGAPI
michael@0 25 png_set_crc_action(png_structrp png_ptr, int crit_action, int ancil_action)
michael@0 26 {
michael@0 27 png_debug(1, "in png_set_crc_action");
michael@0 28
michael@0 29 if (png_ptr == NULL)
michael@0 30 return;
michael@0 31
michael@0 32 /* Tell libpng how we react to CRC errors in critical chunks */
michael@0 33 switch (crit_action)
michael@0 34 {
michael@0 35 case PNG_CRC_NO_CHANGE: /* Leave setting as is */
michael@0 36 break;
michael@0 37
michael@0 38 case PNG_CRC_WARN_USE: /* Warn/use data */
michael@0 39 png_ptr->flags &= ~PNG_FLAG_CRC_CRITICAL_MASK;
michael@0 40 png_ptr->flags |= PNG_FLAG_CRC_CRITICAL_USE;
michael@0 41 break;
michael@0 42
michael@0 43 case PNG_CRC_QUIET_USE: /* Quiet/use data */
michael@0 44 png_ptr->flags &= ~PNG_FLAG_CRC_CRITICAL_MASK;
michael@0 45 png_ptr->flags |= PNG_FLAG_CRC_CRITICAL_USE |
michael@0 46 PNG_FLAG_CRC_CRITICAL_IGNORE;
michael@0 47 break;
michael@0 48
michael@0 49 case PNG_CRC_WARN_DISCARD: /* Not a valid action for critical data */
michael@0 50 png_warning(png_ptr,
michael@0 51 "Can't discard critical data on CRC error");
michael@0 52 case PNG_CRC_ERROR_QUIT: /* Error/quit */
michael@0 53
michael@0 54 case PNG_CRC_DEFAULT:
michael@0 55 default:
michael@0 56 png_ptr->flags &= ~PNG_FLAG_CRC_CRITICAL_MASK;
michael@0 57 break;
michael@0 58 }
michael@0 59
michael@0 60 /* Tell libpng how we react to CRC errors in ancillary chunks */
michael@0 61 switch (ancil_action)
michael@0 62 {
michael@0 63 case PNG_CRC_NO_CHANGE: /* Leave setting as is */
michael@0 64 break;
michael@0 65
michael@0 66 case PNG_CRC_WARN_USE: /* Warn/use data */
michael@0 67 png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK;
michael@0 68 png_ptr->flags |= PNG_FLAG_CRC_ANCILLARY_USE;
michael@0 69 break;
michael@0 70
michael@0 71 case PNG_CRC_QUIET_USE: /* Quiet/use data */
michael@0 72 png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK;
michael@0 73 png_ptr->flags |= PNG_FLAG_CRC_ANCILLARY_USE |
michael@0 74 PNG_FLAG_CRC_ANCILLARY_NOWARN;
michael@0 75 break;
michael@0 76
michael@0 77 case PNG_CRC_ERROR_QUIT: /* Error/quit */
michael@0 78 png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK;
michael@0 79 png_ptr->flags |= PNG_FLAG_CRC_ANCILLARY_NOWARN;
michael@0 80 break;
michael@0 81
michael@0 82 case PNG_CRC_WARN_DISCARD: /* Warn/discard data */
michael@0 83
michael@0 84 case PNG_CRC_DEFAULT:
michael@0 85 default:
michael@0 86 png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK;
michael@0 87 break;
michael@0 88 }
michael@0 89 }
michael@0 90
michael@0 91 #ifdef PNG_READ_TRANSFORMS_SUPPORTED
michael@0 92 /* Is it OK to set a transformation now? Only if png_start_read_image or
michael@0 93 * png_read_update_info have not been called. It is not necessary for the IHDR
michael@0 94 * to have been read in all cases, the parameter allows for this check too.
michael@0 95 */
michael@0 96 static int
michael@0 97 png_rtran_ok(png_structrp png_ptr, int need_IHDR)
michael@0 98 {
michael@0 99 if (png_ptr != NULL)
michael@0 100 {
michael@0 101 if (png_ptr->flags & PNG_FLAG_ROW_INIT)
michael@0 102 png_app_error(png_ptr,
michael@0 103 "invalid after png_start_read_image or png_read_update_info");
michael@0 104
michael@0 105 else if (need_IHDR && (png_ptr->mode & PNG_HAVE_IHDR) == 0)
michael@0 106 png_app_error(png_ptr, "invalid before the PNG header has been read");
michael@0 107
michael@0 108 else
michael@0 109 {
michael@0 110 /* Turn on failure to initialize correctly for all transforms. */
michael@0 111 png_ptr->flags |= PNG_FLAG_DETECT_UNINITIALIZED;
michael@0 112
michael@0 113 return 1; /* Ok */
michael@0 114 }
michael@0 115 }
michael@0 116
michael@0 117 return 0; /* no png_error possible! */
michael@0 118 }
michael@0 119 #endif
michael@0 120
michael@0 121 #ifdef PNG_READ_BACKGROUND_SUPPORTED
michael@0 122 /* Handle alpha and tRNS via a background color */
michael@0 123 void PNGFAPI
michael@0 124 png_set_background_fixed(png_structrp png_ptr,
michael@0 125 png_const_color_16p background_color, int background_gamma_code,
michael@0 126 int need_expand, png_fixed_point background_gamma)
michael@0 127 {
michael@0 128 png_debug(1, "in png_set_background_fixed");
michael@0 129
michael@0 130 if (!png_rtran_ok(png_ptr, 0) || background_color == NULL)
michael@0 131 return;
michael@0 132
michael@0 133 if (background_gamma_code == PNG_BACKGROUND_GAMMA_UNKNOWN)
michael@0 134 {
michael@0 135 png_warning(png_ptr, "Application must supply a known background gamma");
michael@0 136 return;
michael@0 137 }
michael@0 138
michael@0 139 png_ptr->transformations |= PNG_COMPOSE | PNG_STRIP_ALPHA;
michael@0 140 png_ptr->transformations &= ~PNG_ENCODE_ALPHA;
michael@0 141 png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA;
michael@0 142
michael@0 143 png_ptr->background = *background_color;
michael@0 144 png_ptr->background_gamma = background_gamma;
michael@0 145 png_ptr->background_gamma_type = (png_byte)(background_gamma_code);
michael@0 146 if (need_expand)
michael@0 147 png_ptr->transformations |= PNG_BACKGROUND_EXPAND;
michael@0 148 else
michael@0 149 png_ptr->transformations &= ~PNG_BACKGROUND_EXPAND;
michael@0 150 }
michael@0 151
michael@0 152 # ifdef PNG_FLOATING_POINT_SUPPORTED
michael@0 153 void PNGAPI
michael@0 154 png_set_background(png_structrp png_ptr,
michael@0 155 png_const_color_16p background_color, int background_gamma_code,
michael@0 156 int need_expand, double background_gamma)
michael@0 157 {
michael@0 158 png_set_background_fixed(png_ptr, background_color, background_gamma_code,
michael@0 159 need_expand, png_fixed(png_ptr, background_gamma, "png_set_background"));
michael@0 160 }
michael@0 161 # endif /* FLOATING_POINT */
michael@0 162 #endif /* READ_BACKGROUND */
michael@0 163
michael@0 164 /* Scale 16-bit depth files to 8-bit depth. If both of these are set then the
michael@0 165 * one that pngrtran does first (scale) happens. This is necessary to allow the
michael@0 166 * TRANSFORM and API behavior to be somewhat consistent, and it's simpler.
michael@0 167 */
michael@0 168 #ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED
michael@0 169 void PNGAPI
michael@0 170 png_set_scale_16(png_structrp png_ptr)
michael@0 171 {
michael@0 172 png_debug(1, "in png_set_scale_16");
michael@0 173
michael@0 174 if (!png_rtran_ok(png_ptr, 0))
michael@0 175 return;
michael@0 176
michael@0 177 png_ptr->transformations |= PNG_SCALE_16_TO_8;
michael@0 178 }
michael@0 179 #endif
michael@0 180
michael@0 181 #ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED
michael@0 182 /* Chop 16-bit depth files to 8-bit depth */
michael@0 183 void PNGAPI
michael@0 184 png_set_strip_16(png_structrp png_ptr)
michael@0 185 {
michael@0 186 png_debug(1, "in png_set_strip_16");
michael@0 187
michael@0 188 if (!png_rtran_ok(png_ptr, 0))
michael@0 189 return;
michael@0 190
michael@0 191 png_ptr->transformations |= PNG_16_TO_8;
michael@0 192 }
michael@0 193 #endif
michael@0 194
michael@0 195 #ifdef PNG_READ_STRIP_ALPHA_SUPPORTED
michael@0 196 void PNGAPI
michael@0 197 png_set_strip_alpha(png_structrp png_ptr)
michael@0 198 {
michael@0 199 png_debug(1, "in png_set_strip_alpha");
michael@0 200
michael@0 201 if (!png_rtran_ok(png_ptr, 0))
michael@0 202 return;
michael@0 203
michael@0 204 png_ptr->transformations |= PNG_STRIP_ALPHA;
michael@0 205 }
michael@0 206 #endif
michael@0 207
michael@0 208 #if defined(PNG_READ_ALPHA_MODE_SUPPORTED) || defined(PNG_READ_GAMMA_SUPPORTED)
michael@0 209 static png_fixed_point
michael@0 210 translate_gamma_flags(png_structrp png_ptr, png_fixed_point output_gamma,
michael@0 211 int is_screen)
michael@0 212 {
michael@0 213 /* Check for flag values. The main reason for having the old Mac value as a
michael@0 214 * flag is that it is pretty near impossible to work out what the correct
michael@0 215 * value is from Apple documentation - a working Mac system is needed to
michael@0 216 * discover the value!
michael@0 217 */
michael@0 218 if (output_gamma == PNG_DEFAULT_sRGB ||
michael@0 219 output_gamma == PNG_FP_1 / PNG_DEFAULT_sRGB)
michael@0 220 {
michael@0 221 /* If there is no sRGB support this just sets the gamma to the standard
michael@0 222 * sRGB value. (This is a side effect of using this function!)
michael@0 223 */
michael@0 224 # ifdef PNG_READ_sRGB_SUPPORTED
michael@0 225 png_ptr->flags |= PNG_FLAG_ASSUME_sRGB;
michael@0 226 # else
michael@0 227 PNG_UNUSED(png_ptr)
michael@0 228 # endif
michael@0 229 if (is_screen)
michael@0 230 output_gamma = PNG_GAMMA_sRGB;
michael@0 231 else
michael@0 232 output_gamma = PNG_GAMMA_sRGB_INVERSE;
michael@0 233 }
michael@0 234
michael@0 235 else if (output_gamma == PNG_GAMMA_MAC_18 ||
michael@0 236 output_gamma == PNG_FP_1 / PNG_GAMMA_MAC_18)
michael@0 237 {
michael@0 238 if (is_screen)
michael@0 239 output_gamma = PNG_GAMMA_MAC_OLD;
michael@0 240 else
michael@0 241 output_gamma = PNG_GAMMA_MAC_INVERSE;
michael@0 242 }
michael@0 243
michael@0 244 return output_gamma;
michael@0 245 }
michael@0 246
michael@0 247 # ifdef PNG_FLOATING_POINT_SUPPORTED
michael@0 248 static png_fixed_point
michael@0 249 convert_gamma_value(png_structrp png_ptr, double output_gamma)
michael@0 250 {
michael@0 251 /* The following silently ignores cases where fixed point (times 100,000)
michael@0 252 * gamma values are passed to the floating point API. This is safe and it
michael@0 253 * means the fixed point constants work just fine with the floating point
michael@0 254 * API. The alternative would just lead to undetected errors and spurious
michael@0 255 * bug reports. Negative values fail inside the _fixed API unless they
michael@0 256 * correspond to the flag values.
michael@0 257 */
michael@0 258 if (output_gamma > 0 && output_gamma < 128)
michael@0 259 output_gamma *= PNG_FP_1;
michael@0 260
michael@0 261 /* This preserves -1 and -2 exactly: */
michael@0 262 output_gamma = floor(output_gamma + .5);
michael@0 263
michael@0 264 if (output_gamma > PNG_FP_MAX || output_gamma < PNG_FP_MIN)
michael@0 265 png_fixed_error(png_ptr, "gamma value");
michael@0 266
michael@0 267 return (png_fixed_point)output_gamma;
michael@0 268 }
michael@0 269 # endif
michael@0 270 #endif /* READ_ALPHA_MODE || READ_GAMMA */
michael@0 271
michael@0 272 #ifdef PNG_READ_ALPHA_MODE_SUPPORTED
michael@0 273 void PNGFAPI
michael@0 274 png_set_alpha_mode_fixed(png_structrp png_ptr, int mode,
michael@0 275 png_fixed_point output_gamma)
michael@0 276 {
michael@0 277 int compose = 0;
michael@0 278 png_fixed_point file_gamma;
michael@0 279
michael@0 280 png_debug(1, "in png_set_alpha_mode");
michael@0 281
michael@0 282 if (!png_rtran_ok(png_ptr, 0))
michael@0 283 return;
michael@0 284
michael@0 285 output_gamma = translate_gamma_flags(png_ptr, output_gamma, 1/*screen*/);
michael@0 286
michael@0 287 /* Validate the value to ensure it is in a reasonable range. The value
michael@0 288 * is expected to be 1 or greater, but this range test allows for some
michael@0 289 * viewing correction values. The intent is to weed out users of this API
michael@0 290 * who use the inverse of the gamma value accidentally! Since some of these
michael@0 291 * values are reasonable this may have to be changed.
michael@0 292 */
michael@0 293 if (output_gamma < 70000 || output_gamma > 300000)
michael@0 294 png_error(png_ptr, "output gamma out of expected range");
michael@0 295
michael@0 296 /* The default file gamma is the inverse of the output gamma; the output
michael@0 297 * gamma may be changed below so get the file value first:
michael@0 298 */
michael@0 299 file_gamma = png_reciprocal(output_gamma);
michael@0 300
michael@0 301 /* There are really 8 possibilities here, composed of any combination
michael@0 302 * of:
michael@0 303 *
michael@0 304 * premultiply the color channels
michael@0 305 * do not encode non-opaque pixels
michael@0 306 * encode the alpha as well as the color channels
michael@0 307 *
michael@0 308 * The differences disappear if the input/output ('screen') gamma is 1.0,
michael@0 309 * because then the encoding is a no-op and there is only the choice of
michael@0 310 * premultiplying the color channels or not.
michael@0 311 *
michael@0 312 * png_set_alpha_mode and png_set_background interact because both use
michael@0 313 * png_compose to do the work. Calling both is only useful when
michael@0 314 * png_set_alpha_mode is used to set the default mode - PNG_ALPHA_PNG - along
michael@0 315 * with a default gamma value. Otherwise PNG_COMPOSE must not be set.
michael@0 316 */
michael@0 317 switch (mode)
michael@0 318 {
michael@0 319 case PNG_ALPHA_PNG: /* default: png standard */
michael@0 320 /* No compose, but it may be set by png_set_background! */
michael@0 321 png_ptr->transformations &= ~PNG_ENCODE_ALPHA;
michael@0 322 png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA;
michael@0 323 break;
michael@0 324
michael@0 325 case PNG_ALPHA_ASSOCIATED: /* color channels premultiplied */
michael@0 326 compose = 1;
michael@0 327 png_ptr->transformations &= ~PNG_ENCODE_ALPHA;
michael@0 328 png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA;
michael@0 329 /* The output is linear: */
michael@0 330 output_gamma = PNG_FP_1;
michael@0 331 break;
michael@0 332
michael@0 333 case PNG_ALPHA_OPTIMIZED: /* associated, non-opaque pixels linear */
michael@0 334 compose = 1;
michael@0 335 png_ptr->transformations &= ~PNG_ENCODE_ALPHA;
michael@0 336 png_ptr->flags |= PNG_FLAG_OPTIMIZE_ALPHA;
michael@0 337 /* output_gamma records the encoding of opaque pixels! */
michael@0 338 break;
michael@0 339
michael@0 340 case PNG_ALPHA_BROKEN: /* associated, non-linear, alpha encoded */
michael@0 341 compose = 1;
michael@0 342 png_ptr->transformations |= PNG_ENCODE_ALPHA;
michael@0 343 png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA;
michael@0 344 break;
michael@0 345
michael@0 346 default:
michael@0 347 png_error(png_ptr, "invalid alpha mode");
michael@0 348 }
michael@0 349
michael@0 350 /* Only set the default gamma if the file gamma has not been set (this has
michael@0 351 * the side effect that the gamma in a second call to png_set_alpha_mode will
michael@0 352 * be ignored.)
michael@0 353 */
michael@0 354 if (png_ptr->colorspace.gamma == 0)
michael@0 355 {
michael@0 356 png_ptr->colorspace.gamma = file_gamma;
michael@0 357 png_ptr->colorspace.flags |= PNG_COLORSPACE_HAVE_GAMMA;
michael@0 358 }
michael@0 359
michael@0 360 /* But always set the output gamma: */
michael@0 361 png_ptr->screen_gamma = output_gamma;
michael@0 362
michael@0 363 /* Finally, if pre-multiplying, set the background fields to achieve the
michael@0 364 * desired result.
michael@0 365 */
michael@0 366 if (compose)
michael@0 367 {
michael@0 368 /* And obtain alpha pre-multiplication by composing on black: */
michael@0 369 memset(&png_ptr->background, 0, (sizeof png_ptr->background));
michael@0 370 png_ptr->background_gamma = png_ptr->colorspace.gamma; /* just in case */
michael@0 371 png_ptr->background_gamma_type = PNG_BACKGROUND_GAMMA_FILE;
michael@0 372 png_ptr->transformations &= ~PNG_BACKGROUND_EXPAND;
michael@0 373
michael@0 374 if (png_ptr->transformations & PNG_COMPOSE)
michael@0 375 png_error(png_ptr,
michael@0 376 "conflicting calls to set alpha mode and background");
michael@0 377
michael@0 378 png_ptr->transformations |= PNG_COMPOSE;
michael@0 379 }
michael@0 380 }
michael@0 381
michael@0 382 # ifdef PNG_FLOATING_POINT_SUPPORTED
michael@0 383 void PNGAPI
michael@0 384 png_set_alpha_mode(png_structrp png_ptr, int mode, double output_gamma)
michael@0 385 {
michael@0 386 png_set_alpha_mode_fixed(png_ptr, mode, convert_gamma_value(png_ptr,
michael@0 387 output_gamma));
michael@0 388 }
michael@0 389 # endif
michael@0 390 #endif
michael@0 391
michael@0 392 #ifdef PNG_READ_QUANTIZE_SUPPORTED
michael@0 393 /* Dither file to 8-bit. Supply a palette, the current number
michael@0 394 * of elements in the palette, the maximum number of elements
michael@0 395 * allowed, and a histogram if possible. If the current number
michael@0 396 * of colors is greater then the maximum number, the palette will be
michael@0 397 * modified to fit in the maximum number. "full_quantize" indicates
michael@0 398 * whether we need a quantizing cube set up for RGB images, or if we
michael@0 399 * simply are reducing the number of colors in a paletted image.
michael@0 400 */
michael@0 401
michael@0 402 typedef struct png_dsort_struct
michael@0 403 {
michael@0 404 struct png_dsort_struct * next;
michael@0 405 png_byte left;
michael@0 406 png_byte right;
michael@0 407 } png_dsort;
michael@0 408 typedef png_dsort * png_dsortp;
michael@0 409 typedef png_dsort * * png_dsortpp;
michael@0 410
michael@0 411 void PNGAPI
michael@0 412 png_set_quantize(png_structrp png_ptr, png_colorp palette,
michael@0 413 int num_palette, int maximum_colors, png_const_uint_16p histogram,
michael@0 414 int full_quantize)
michael@0 415 {
michael@0 416 png_debug(1, "in png_set_quantize");
michael@0 417
michael@0 418 if (!png_rtran_ok(png_ptr, 0))
michael@0 419 return;
michael@0 420
michael@0 421 png_ptr->transformations |= PNG_QUANTIZE;
michael@0 422
michael@0 423 if (!full_quantize)
michael@0 424 {
michael@0 425 int i;
michael@0 426
michael@0 427 png_ptr->quantize_index = (png_bytep)png_malloc(png_ptr,
michael@0 428 (png_uint_32)(num_palette * (sizeof (png_byte))));
michael@0 429 for (i = 0; i < num_palette; i++)
michael@0 430 png_ptr->quantize_index[i] = (png_byte)i;
michael@0 431 }
michael@0 432
michael@0 433 if (num_palette > maximum_colors)
michael@0 434 {
michael@0 435 if (histogram != NULL)
michael@0 436 {
michael@0 437 /* This is easy enough, just throw out the least used colors.
michael@0 438 * Perhaps not the best solution, but good enough.
michael@0 439 */
michael@0 440
michael@0 441 int i;
michael@0 442
michael@0 443 /* Initialize an array to sort colors */
michael@0 444 png_ptr->quantize_sort = (png_bytep)png_malloc(png_ptr,
michael@0 445 (png_uint_32)(num_palette * (sizeof (png_byte))));
michael@0 446
michael@0 447 /* Initialize the quantize_sort array */
michael@0 448 for (i = 0; i < num_palette; i++)
michael@0 449 png_ptr->quantize_sort[i] = (png_byte)i;
michael@0 450
michael@0 451 /* Find the least used palette entries by starting a
michael@0 452 * bubble sort, and running it until we have sorted
michael@0 453 * out enough colors. Note that we don't care about
michael@0 454 * sorting all the colors, just finding which are
michael@0 455 * least used.
michael@0 456 */
michael@0 457
michael@0 458 for (i = num_palette - 1; i >= maximum_colors; i--)
michael@0 459 {
michael@0 460 int done; /* To stop early if the list is pre-sorted */
michael@0 461 int j;
michael@0 462
michael@0 463 done = 1;
michael@0 464 for (j = 0; j < i; j++)
michael@0 465 {
michael@0 466 if (histogram[png_ptr->quantize_sort[j]]
michael@0 467 < histogram[png_ptr->quantize_sort[j + 1]])
michael@0 468 {
michael@0 469 png_byte t;
michael@0 470
michael@0 471 t = png_ptr->quantize_sort[j];
michael@0 472 png_ptr->quantize_sort[j] = png_ptr->quantize_sort[j + 1];
michael@0 473 png_ptr->quantize_sort[j + 1] = t;
michael@0 474 done = 0;
michael@0 475 }
michael@0 476 }
michael@0 477
michael@0 478 if (done)
michael@0 479 break;
michael@0 480 }
michael@0 481
michael@0 482 /* Swap the palette around, and set up a table, if necessary */
michael@0 483 if (full_quantize)
michael@0 484 {
michael@0 485 int j = num_palette;
michael@0 486
michael@0 487 /* Put all the useful colors within the max, but don't
michael@0 488 * move the others.
michael@0 489 */
michael@0 490 for (i = 0; i < maximum_colors; i++)
michael@0 491 {
michael@0 492 if ((int)png_ptr->quantize_sort[i] >= maximum_colors)
michael@0 493 {
michael@0 494 do
michael@0 495 j--;
michael@0 496 while ((int)png_ptr->quantize_sort[j] >= maximum_colors);
michael@0 497
michael@0 498 palette[i] = palette[j];
michael@0 499 }
michael@0 500 }
michael@0 501 }
michael@0 502 else
michael@0 503 {
michael@0 504 int j = num_palette;
michael@0 505
michael@0 506 /* Move all the used colors inside the max limit, and
michael@0 507 * develop a translation table.
michael@0 508 */
michael@0 509 for (i = 0; i < maximum_colors; i++)
michael@0 510 {
michael@0 511 /* Only move the colors we need to */
michael@0 512 if ((int)png_ptr->quantize_sort[i] >= maximum_colors)
michael@0 513 {
michael@0 514 png_color tmp_color;
michael@0 515
michael@0 516 do
michael@0 517 j--;
michael@0 518 while ((int)png_ptr->quantize_sort[j] >= maximum_colors);
michael@0 519
michael@0 520 tmp_color = palette[j];
michael@0 521 palette[j] = palette[i];
michael@0 522 palette[i] = tmp_color;
michael@0 523 /* Indicate where the color went */
michael@0 524 png_ptr->quantize_index[j] = (png_byte)i;
michael@0 525 png_ptr->quantize_index[i] = (png_byte)j;
michael@0 526 }
michael@0 527 }
michael@0 528
michael@0 529 /* Find closest color for those colors we are not using */
michael@0 530 for (i = 0; i < num_palette; i++)
michael@0 531 {
michael@0 532 if ((int)png_ptr->quantize_index[i] >= maximum_colors)
michael@0 533 {
michael@0 534 int min_d, k, min_k, d_index;
michael@0 535
michael@0 536 /* Find the closest color to one we threw out */
michael@0 537 d_index = png_ptr->quantize_index[i];
michael@0 538 min_d = PNG_COLOR_DIST(palette[d_index], palette[0]);
michael@0 539 for (k = 1, min_k = 0; k < maximum_colors; k++)
michael@0 540 {
michael@0 541 int d;
michael@0 542
michael@0 543 d = PNG_COLOR_DIST(palette[d_index], palette[k]);
michael@0 544
michael@0 545 if (d < min_d)
michael@0 546 {
michael@0 547 min_d = d;
michael@0 548 min_k = k;
michael@0 549 }
michael@0 550 }
michael@0 551 /* Point to closest color */
michael@0 552 png_ptr->quantize_index[i] = (png_byte)min_k;
michael@0 553 }
michael@0 554 }
michael@0 555 }
michael@0 556 png_free(png_ptr, png_ptr->quantize_sort);
michael@0 557 png_ptr->quantize_sort = NULL;
michael@0 558 }
michael@0 559 else
michael@0 560 {
michael@0 561 /* This is much harder to do simply (and quickly). Perhaps
michael@0 562 * we need to go through a median cut routine, but those
michael@0 563 * don't always behave themselves with only a few colors
michael@0 564 * as input. So we will just find the closest two colors,
michael@0 565 * and throw out one of them (chosen somewhat randomly).
michael@0 566 * [We don't understand this at all, so if someone wants to
michael@0 567 * work on improving it, be our guest - AED, GRP]
michael@0 568 */
michael@0 569 int i;
michael@0 570 int max_d;
michael@0 571 int num_new_palette;
michael@0 572 png_dsortp t;
michael@0 573 png_dsortpp hash;
michael@0 574
michael@0 575 t = NULL;
michael@0 576
michael@0 577 /* Initialize palette index arrays */
michael@0 578 png_ptr->index_to_palette = (png_bytep)png_malloc(png_ptr,
michael@0 579 (png_uint_32)(num_palette * (sizeof (png_byte))));
michael@0 580 png_ptr->palette_to_index = (png_bytep)png_malloc(png_ptr,
michael@0 581 (png_uint_32)(num_palette * (sizeof (png_byte))));
michael@0 582
michael@0 583 /* Initialize the sort array */
michael@0 584 for (i = 0; i < num_palette; i++)
michael@0 585 {
michael@0 586 png_ptr->index_to_palette[i] = (png_byte)i;
michael@0 587 png_ptr->palette_to_index[i] = (png_byte)i;
michael@0 588 }
michael@0 589
michael@0 590 hash = (png_dsortpp)png_calloc(png_ptr, (png_uint_32)(769 *
michael@0 591 (sizeof (png_dsortp))));
michael@0 592
michael@0 593 num_new_palette = num_palette;
michael@0 594
michael@0 595 /* Initial wild guess at how far apart the farthest pixel
michael@0 596 * pair we will be eliminating will be. Larger
michael@0 597 * numbers mean more areas will be allocated, Smaller
michael@0 598 * numbers run the risk of not saving enough data, and
michael@0 599 * having to do this all over again.
michael@0 600 *
michael@0 601 * I have not done extensive checking on this number.
michael@0 602 */
michael@0 603 max_d = 96;
michael@0 604
michael@0 605 while (num_new_palette > maximum_colors)
michael@0 606 {
michael@0 607 for (i = 0; i < num_new_palette - 1; i++)
michael@0 608 {
michael@0 609 int j;
michael@0 610
michael@0 611 for (j = i + 1; j < num_new_palette; j++)
michael@0 612 {
michael@0 613 int d;
michael@0 614
michael@0 615 d = PNG_COLOR_DIST(palette[i], palette[j]);
michael@0 616
michael@0 617 if (d <= max_d)
michael@0 618 {
michael@0 619
michael@0 620 t = (png_dsortp)png_malloc_warn(png_ptr,
michael@0 621 (png_uint_32)(sizeof (png_dsort)));
michael@0 622
michael@0 623 if (t == NULL)
michael@0 624 break;
michael@0 625
michael@0 626 t->next = hash[d];
michael@0 627 t->left = (png_byte)i;
michael@0 628 t->right = (png_byte)j;
michael@0 629 hash[d] = t;
michael@0 630 }
michael@0 631 }
michael@0 632 if (t == NULL)
michael@0 633 break;
michael@0 634 }
michael@0 635
michael@0 636 if (t != NULL)
michael@0 637 for (i = 0; i <= max_d; i++)
michael@0 638 {
michael@0 639 if (hash[i] != NULL)
michael@0 640 {
michael@0 641 png_dsortp p;
michael@0 642
michael@0 643 for (p = hash[i]; p; p = p->next)
michael@0 644 {
michael@0 645 if ((int)png_ptr->index_to_palette[p->left]
michael@0 646 < num_new_palette &&
michael@0 647 (int)png_ptr->index_to_palette[p->right]
michael@0 648 < num_new_palette)
michael@0 649 {
michael@0 650 int j, next_j;
michael@0 651
michael@0 652 if (num_new_palette & 0x01)
michael@0 653 {
michael@0 654 j = p->left;
michael@0 655 next_j = p->right;
michael@0 656 }
michael@0 657 else
michael@0 658 {
michael@0 659 j = p->right;
michael@0 660 next_j = p->left;
michael@0 661 }
michael@0 662
michael@0 663 num_new_palette--;
michael@0 664 palette[png_ptr->index_to_palette[j]]
michael@0 665 = palette[num_new_palette];
michael@0 666 if (!full_quantize)
michael@0 667 {
michael@0 668 int k;
michael@0 669
michael@0 670 for (k = 0; k < num_palette; k++)
michael@0 671 {
michael@0 672 if (png_ptr->quantize_index[k] ==
michael@0 673 png_ptr->index_to_palette[j])
michael@0 674 png_ptr->quantize_index[k] =
michael@0 675 png_ptr->index_to_palette[next_j];
michael@0 676
michael@0 677 if ((int)png_ptr->quantize_index[k] ==
michael@0 678 num_new_palette)
michael@0 679 png_ptr->quantize_index[k] =
michael@0 680 png_ptr->index_to_palette[j];
michael@0 681 }
michael@0 682 }
michael@0 683
michael@0 684 png_ptr->index_to_palette[png_ptr->palette_to_index
michael@0 685 [num_new_palette]] = png_ptr->index_to_palette[j];
michael@0 686
michael@0 687 png_ptr->palette_to_index[png_ptr->index_to_palette[j]]
michael@0 688 = png_ptr->palette_to_index[num_new_palette];
michael@0 689
michael@0 690 png_ptr->index_to_palette[j] =
michael@0 691 (png_byte)num_new_palette;
michael@0 692
michael@0 693 png_ptr->palette_to_index[num_new_palette] =
michael@0 694 (png_byte)j;
michael@0 695 }
michael@0 696 if (num_new_palette <= maximum_colors)
michael@0 697 break;
michael@0 698 }
michael@0 699 if (num_new_palette <= maximum_colors)
michael@0 700 break;
michael@0 701 }
michael@0 702 }
michael@0 703
michael@0 704 for (i = 0; i < 769; i++)
michael@0 705 {
michael@0 706 if (hash[i] != NULL)
michael@0 707 {
michael@0 708 png_dsortp p = hash[i];
michael@0 709 while (p)
michael@0 710 {
michael@0 711 t = p->next;
michael@0 712 png_free(png_ptr, p);
michael@0 713 p = t;
michael@0 714 }
michael@0 715 }
michael@0 716 hash[i] = 0;
michael@0 717 }
michael@0 718 max_d += 96;
michael@0 719 }
michael@0 720 png_free(png_ptr, hash);
michael@0 721 png_free(png_ptr, png_ptr->palette_to_index);
michael@0 722 png_free(png_ptr, png_ptr->index_to_palette);
michael@0 723 png_ptr->palette_to_index = NULL;
michael@0 724 png_ptr->index_to_palette = NULL;
michael@0 725 }
michael@0 726 num_palette = maximum_colors;
michael@0 727 }
michael@0 728 if (png_ptr->palette == NULL)
michael@0 729 {
michael@0 730 png_ptr->palette = palette;
michael@0 731 }
michael@0 732 png_ptr->num_palette = (png_uint_16)num_palette;
michael@0 733
michael@0 734 if (full_quantize)
michael@0 735 {
michael@0 736 int i;
michael@0 737 png_bytep distance;
michael@0 738 int total_bits = PNG_QUANTIZE_RED_BITS + PNG_QUANTIZE_GREEN_BITS +
michael@0 739 PNG_QUANTIZE_BLUE_BITS;
michael@0 740 int num_red = (1 << PNG_QUANTIZE_RED_BITS);
michael@0 741 int num_green = (1 << PNG_QUANTIZE_GREEN_BITS);
michael@0 742 int num_blue = (1 << PNG_QUANTIZE_BLUE_BITS);
michael@0 743 png_size_t num_entries = ((png_size_t)1 << total_bits);
michael@0 744
michael@0 745 png_ptr->palette_lookup = (png_bytep)png_calloc(png_ptr,
michael@0 746 (png_uint_32)(num_entries * (sizeof (png_byte))));
michael@0 747
michael@0 748 distance = (png_bytep)png_malloc(png_ptr, (png_uint_32)(num_entries *
michael@0 749 (sizeof (png_byte))));
michael@0 750
michael@0 751 memset(distance, 0xff, num_entries * (sizeof (png_byte)));
michael@0 752
michael@0 753 for (i = 0; i < num_palette; i++)
michael@0 754 {
michael@0 755 int ir, ig, ib;
michael@0 756 int r = (palette[i].red >> (8 - PNG_QUANTIZE_RED_BITS));
michael@0 757 int g = (palette[i].green >> (8 - PNG_QUANTIZE_GREEN_BITS));
michael@0 758 int b = (palette[i].blue >> (8 - PNG_QUANTIZE_BLUE_BITS));
michael@0 759
michael@0 760 for (ir = 0; ir < num_red; ir++)
michael@0 761 {
michael@0 762 /* int dr = abs(ir - r); */
michael@0 763 int dr = ((ir > r) ? ir - r : r - ir);
michael@0 764 int index_r = (ir << (PNG_QUANTIZE_BLUE_BITS +
michael@0 765 PNG_QUANTIZE_GREEN_BITS));
michael@0 766
michael@0 767 for (ig = 0; ig < num_green; ig++)
michael@0 768 {
michael@0 769 /* int dg = abs(ig - g); */
michael@0 770 int dg = ((ig > g) ? ig - g : g - ig);
michael@0 771 int dt = dr + dg;
michael@0 772 int dm = ((dr > dg) ? dr : dg);
michael@0 773 int index_g = index_r | (ig << PNG_QUANTIZE_BLUE_BITS);
michael@0 774
michael@0 775 for (ib = 0; ib < num_blue; ib++)
michael@0 776 {
michael@0 777 int d_index = index_g | ib;
michael@0 778 /* int db = abs(ib - b); */
michael@0 779 int db = ((ib > b) ? ib - b : b - ib);
michael@0 780 int dmax = ((dm > db) ? dm : db);
michael@0 781 int d = dmax + dt + db;
michael@0 782
michael@0 783 if (d < (int)distance[d_index])
michael@0 784 {
michael@0 785 distance[d_index] = (png_byte)d;
michael@0 786 png_ptr->palette_lookup[d_index] = (png_byte)i;
michael@0 787 }
michael@0 788 }
michael@0 789 }
michael@0 790 }
michael@0 791 }
michael@0 792
michael@0 793 png_free(png_ptr, distance);
michael@0 794 }
michael@0 795 }
michael@0 796 #endif /* PNG_READ_QUANTIZE_SUPPORTED */
michael@0 797
michael@0 798 #ifdef PNG_READ_GAMMA_SUPPORTED
michael@0 799 void PNGFAPI
michael@0 800 png_set_gamma_fixed(png_structrp png_ptr, png_fixed_point scrn_gamma,
michael@0 801 png_fixed_point file_gamma)
michael@0 802 {
michael@0 803 png_debug(1, "in png_set_gamma_fixed");
michael@0 804
michael@0 805 if (!png_rtran_ok(png_ptr, 0))
michael@0 806 return;
michael@0 807
michael@0 808 /* New in libpng-1.5.4 - reserve particular negative values as flags. */
michael@0 809 scrn_gamma = translate_gamma_flags(png_ptr, scrn_gamma, 1/*screen*/);
michael@0 810 file_gamma = translate_gamma_flags(png_ptr, file_gamma, 0/*file*/);
michael@0 811
michael@0 812 /* Checking the gamma values for being >0 was added in 1.5.4 along with the
michael@0 813 * premultiplied alpha support; this actually hides an undocumented feature
michael@0 814 * of the previous implementation which allowed gamma processing to be
michael@0 815 * disabled in background handling. There is no evidence (so far) that this
michael@0 816 * was being used; however, png_set_background itself accepted and must still
michael@0 817 * accept '0' for the gamma value it takes, because it isn't always used.
michael@0 818 *
michael@0 819 * Since this is an API change (albeit a very minor one that removes an
michael@0 820 * undocumented API feature) the following checks were only enabled in
michael@0 821 * libpng-1.6.0.
michael@0 822 */
michael@0 823 if (file_gamma <= 0)
michael@0 824 png_error(png_ptr, "invalid file gamma in png_set_gamma");
michael@0 825
michael@0 826 if (scrn_gamma <= 0)
michael@0 827 png_error(png_ptr, "invalid screen gamma in png_set_gamma");
michael@0 828
michael@0 829 /* Set the gamma values unconditionally - this overrides the value in the PNG
michael@0 830 * file if a gAMA chunk was present. png_set_alpha_mode provides a
michael@0 831 * different, easier, way to default the file gamma.
michael@0 832 */
michael@0 833 png_ptr->colorspace.gamma = file_gamma;
michael@0 834 png_ptr->colorspace.flags |= PNG_COLORSPACE_HAVE_GAMMA;
michael@0 835 png_ptr->screen_gamma = scrn_gamma;
michael@0 836 }
michael@0 837
michael@0 838 # ifdef PNG_FLOATING_POINT_SUPPORTED
michael@0 839 void PNGAPI
michael@0 840 png_set_gamma(png_structrp png_ptr, double scrn_gamma, double file_gamma)
michael@0 841 {
michael@0 842 png_set_gamma_fixed(png_ptr, convert_gamma_value(png_ptr, scrn_gamma),
michael@0 843 convert_gamma_value(png_ptr, file_gamma));
michael@0 844 }
michael@0 845 # endif /* FLOATING_POINT_SUPPORTED */
michael@0 846 #endif /* READ_GAMMA */
michael@0 847
michael@0 848 #ifdef PNG_READ_EXPAND_SUPPORTED
michael@0 849 /* Expand paletted images to RGB, expand grayscale images of
michael@0 850 * less than 8-bit depth to 8-bit depth, and expand tRNS chunks
michael@0 851 * to alpha channels.
michael@0 852 */
michael@0 853 void PNGAPI
michael@0 854 png_set_expand(png_structrp png_ptr)
michael@0 855 {
michael@0 856 png_debug(1, "in png_set_expand");
michael@0 857
michael@0 858 if (!png_rtran_ok(png_ptr, 0))
michael@0 859 return;
michael@0 860
michael@0 861 png_ptr->transformations |= (PNG_EXPAND | PNG_EXPAND_tRNS);
michael@0 862 }
michael@0 863
michael@0 864 /* GRR 19990627: the following three functions currently are identical
michael@0 865 * to png_set_expand(). However, it is entirely reasonable that someone
michael@0 866 * might wish to expand an indexed image to RGB but *not* expand a single,
michael@0 867 * fully transparent palette entry to a full alpha channel--perhaps instead
michael@0 868 * convert tRNS to the grayscale/RGB format (16-bit RGB value), or replace
michael@0 869 * the transparent color with a particular RGB value, or drop tRNS entirely.
michael@0 870 * IOW, a future version of the library may make the transformations flag
michael@0 871 * a bit more fine-grained, with separate bits for each of these three
michael@0 872 * functions.
michael@0 873 *
michael@0 874 * More to the point, these functions make it obvious what libpng will be
michael@0 875 * doing, whereas "expand" can (and does) mean any number of things.
michael@0 876 *
michael@0 877 * GRP 20060307: In libpng-1.2.9, png_set_gray_1_2_4_to_8() was modified
michael@0 878 * to expand only the sample depth but not to expand the tRNS to alpha
michael@0 879 * and its name was changed to png_set_expand_gray_1_2_4_to_8().
michael@0 880 */
michael@0 881
michael@0 882 /* Expand paletted images to RGB. */
michael@0 883 void PNGAPI
michael@0 884 png_set_palette_to_rgb(png_structrp png_ptr)
michael@0 885 {
michael@0 886 png_debug(1, "in png_set_palette_to_rgb");
michael@0 887
michael@0 888 if (!png_rtran_ok(png_ptr, 0))
michael@0 889 return;
michael@0 890
michael@0 891 png_ptr->transformations |= (PNG_EXPAND | PNG_EXPAND_tRNS);
michael@0 892 }
michael@0 893
michael@0 894 /* Expand grayscale images of less than 8-bit depth to 8 bits. */
michael@0 895 void PNGAPI
michael@0 896 png_set_expand_gray_1_2_4_to_8(png_structrp png_ptr)
michael@0 897 {
michael@0 898 png_debug(1, "in png_set_expand_gray_1_2_4_to_8");
michael@0 899
michael@0 900 if (!png_rtran_ok(png_ptr, 0))
michael@0 901 return;
michael@0 902
michael@0 903 png_ptr->transformations |= PNG_EXPAND;
michael@0 904 }
michael@0 905
michael@0 906 /* Expand tRNS chunks to alpha channels. */
michael@0 907 void PNGAPI
michael@0 908 png_set_tRNS_to_alpha(png_structrp png_ptr)
michael@0 909 {
michael@0 910 png_debug(1, "in png_set_tRNS_to_alpha");
michael@0 911
michael@0 912 if (!png_rtran_ok(png_ptr, 0))
michael@0 913 return;
michael@0 914
michael@0 915 png_ptr->transformations |= (PNG_EXPAND | PNG_EXPAND_tRNS);
michael@0 916 }
michael@0 917 #endif /* defined(PNG_READ_EXPAND_SUPPORTED) */
michael@0 918
michael@0 919 #ifdef PNG_READ_EXPAND_16_SUPPORTED
michael@0 920 /* Expand to 16-bit channels, expand the tRNS chunk too (because otherwise
michael@0 921 * it may not work correctly.)
michael@0 922 */
michael@0 923 void PNGAPI
michael@0 924 png_set_expand_16(png_structrp png_ptr)
michael@0 925 {
michael@0 926 png_debug(1, "in png_set_expand_16");
michael@0 927
michael@0 928 if (!png_rtran_ok(png_ptr, 0))
michael@0 929 return;
michael@0 930
michael@0 931 png_ptr->transformations |= (PNG_EXPAND_16 | PNG_EXPAND | PNG_EXPAND_tRNS);
michael@0 932 }
michael@0 933 #endif
michael@0 934
michael@0 935 #ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED
michael@0 936 void PNGAPI
michael@0 937 png_set_gray_to_rgb(png_structrp png_ptr)
michael@0 938 {
michael@0 939 png_debug(1, "in png_set_gray_to_rgb");
michael@0 940
michael@0 941 if (!png_rtran_ok(png_ptr, 0))
michael@0 942 return;
michael@0 943
michael@0 944 /* Because rgb must be 8 bits or more: */
michael@0 945 png_set_expand_gray_1_2_4_to_8(png_ptr);
michael@0 946 png_ptr->transformations |= PNG_GRAY_TO_RGB;
michael@0 947 }
michael@0 948 #endif
michael@0 949
michael@0 950 #ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED
michael@0 951 void PNGFAPI
michael@0 952 png_set_rgb_to_gray_fixed(png_structrp png_ptr, int error_action,
michael@0 953 png_fixed_point red, png_fixed_point green)
michael@0 954 {
michael@0 955 png_debug(1, "in png_set_rgb_to_gray");
michael@0 956
michael@0 957 /* Need the IHDR here because of the check on color_type below. */
michael@0 958 /* TODO: fix this */
michael@0 959 if (!png_rtran_ok(png_ptr, 1))
michael@0 960 return;
michael@0 961
michael@0 962 switch(error_action)
michael@0 963 {
michael@0 964 case PNG_ERROR_ACTION_NONE:
michael@0 965 png_ptr->transformations |= PNG_RGB_TO_GRAY;
michael@0 966 break;
michael@0 967
michael@0 968 case PNG_ERROR_ACTION_WARN:
michael@0 969 png_ptr->transformations |= PNG_RGB_TO_GRAY_WARN;
michael@0 970 break;
michael@0 971
michael@0 972 case PNG_ERROR_ACTION_ERROR:
michael@0 973 png_ptr->transformations |= PNG_RGB_TO_GRAY_ERR;
michael@0 974 break;
michael@0 975
michael@0 976 default:
michael@0 977 png_error(png_ptr, "invalid error action to rgb_to_gray");
michael@0 978 break;
michael@0 979 }
michael@0 980
michael@0 981 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
michael@0 982 #ifdef PNG_READ_EXPAND_SUPPORTED
michael@0 983 png_ptr->transformations |= PNG_EXPAND;
michael@0 984 #else
michael@0 985 {
michael@0 986 /* Make this an error in 1.6 because otherwise the application may assume
michael@0 987 * that it just worked and get a memory overwrite.
michael@0 988 */
michael@0 989 png_error(png_ptr,
michael@0 990 "Cannot do RGB_TO_GRAY without EXPAND_SUPPORTED");
michael@0 991
michael@0 992 /* png_ptr->transformations &= ~PNG_RGB_TO_GRAY; */
michael@0 993 }
michael@0 994 #endif
michael@0 995 {
michael@0 996 if (red >= 0 && green >= 0 && red + green <= PNG_FP_1)
michael@0 997 {
michael@0 998 png_uint_16 red_int, green_int;
michael@0 999
michael@0 1000 /* NOTE: this calculation does not round, but this behavior is retained
michael@0 1001 * for consistency, the inaccuracy is very small. The code here always
michael@0 1002 * overwrites the coefficients, regardless of whether they have been
michael@0 1003 * defaulted or set already.
michael@0 1004 */
michael@0 1005 red_int = (png_uint_16)(((png_uint_32)red*32768)/100000);
michael@0 1006 green_int = (png_uint_16)(((png_uint_32)green*32768)/100000);
michael@0 1007
michael@0 1008 png_ptr->rgb_to_gray_red_coeff = red_int;
michael@0 1009 png_ptr->rgb_to_gray_green_coeff = green_int;
michael@0 1010 png_ptr->rgb_to_gray_coefficients_set = 1;
michael@0 1011 }
michael@0 1012
michael@0 1013 else
michael@0 1014 {
michael@0 1015 if (red >= 0 && green >= 0)
michael@0 1016 png_app_warning(png_ptr,
michael@0 1017 "ignoring out of range rgb_to_gray coefficients");
michael@0 1018
michael@0 1019 /* Use the defaults, from the cHRM chunk if set, else the historical
michael@0 1020 * values which are close to the sRGB/HDTV/ITU-Rec 709 values. See
michael@0 1021 * png_do_rgb_to_gray for more discussion of the values. In this case
michael@0 1022 * the coefficients are not marked as 'set' and are not overwritten if
michael@0 1023 * something has already provided a default.
michael@0 1024 */
michael@0 1025 if (png_ptr->rgb_to_gray_red_coeff == 0 &&
michael@0 1026 png_ptr->rgb_to_gray_green_coeff == 0)
michael@0 1027 {
michael@0 1028 png_ptr->rgb_to_gray_red_coeff = 6968;
michael@0 1029 png_ptr->rgb_to_gray_green_coeff = 23434;
michael@0 1030 /* png_ptr->rgb_to_gray_blue_coeff = 2366; */
michael@0 1031 }
michael@0 1032 }
michael@0 1033 }
michael@0 1034 }
michael@0 1035
michael@0 1036 #ifdef PNG_FLOATING_POINT_SUPPORTED
michael@0 1037 /* Convert a RGB image to a grayscale of the same width. This allows us,
michael@0 1038 * for example, to convert a 24 bpp RGB image into an 8 bpp grayscale image.
michael@0 1039 */
michael@0 1040
michael@0 1041 void PNGAPI
michael@0 1042 png_set_rgb_to_gray(png_structrp png_ptr, int error_action, double red,
michael@0 1043 double green)
michael@0 1044 {
michael@0 1045 png_set_rgb_to_gray_fixed(png_ptr, error_action,
michael@0 1046 png_fixed(png_ptr, red, "rgb to gray red coefficient"),
michael@0 1047 png_fixed(png_ptr, green, "rgb to gray green coefficient"));
michael@0 1048 }
michael@0 1049 #endif /* FLOATING POINT */
michael@0 1050
michael@0 1051 #endif /* RGB_TO_GRAY */
michael@0 1052
michael@0 1053 #if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \
michael@0 1054 defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
michael@0 1055 void PNGAPI
michael@0 1056 png_set_read_user_transform_fn(png_structrp png_ptr, png_user_transform_ptr
michael@0 1057 read_user_transform_fn)
michael@0 1058 {
michael@0 1059 png_debug(1, "in png_set_read_user_transform_fn");
michael@0 1060
michael@0 1061 #ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
michael@0 1062 png_ptr->transformations |= PNG_USER_TRANSFORM;
michael@0 1063 png_ptr->read_user_transform_fn = read_user_transform_fn;
michael@0 1064 #endif
michael@0 1065 }
michael@0 1066 #endif
michael@0 1067
michael@0 1068 #ifdef PNG_READ_TRANSFORMS_SUPPORTED
michael@0 1069 #ifdef PNG_READ_GAMMA_SUPPORTED
michael@0 1070 /* In the case of gamma transformations only do transformations on images where
michael@0 1071 * the [file] gamma and screen_gamma are not close reciprocals, otherwise it
michael@0 1072 * slows things down slightly, and also needlessly introduces small errors.
michael@0 1073 */
michael@0 1074 static int /* PRIVATE */
michael@0 1075 png_gamma_threshold(png_fixed_point screen_gamma, png_fixed_point file_gamma)
michael@0 1076 {
michael@0 1077 /* PNG_GAMMA_THRESHOLD is the threshold for performing gamma
michael@0 1078 * correction as a difference of the overall transform from 1.0
michael@0 1079 *
michael@0 1080 * We want to compare the threshold with s*f - 1, if we get
michael@0 1081 * overflow here it is because of wacky gamma values so we
michael@0 1082 * turn on processing anyway.
michael@0 1083 */
michael@0 1084 png_fixed_point gtest;
michael@0 1085 return !png_muldiv(&gtest, screen_gamma, file_gamma, PNG_FP_1) ||
michael@0 1086 png_gamma_significant(gtest);
michael@0 1087 }
michael@0 1088 #endif
michael@0 1089
michael@0 1090 /* Initialize everything needed for the read. This includes modifying
michael@0 1091 * the palette.
michael@0 1092 */
michael@0 1093
michael@0 1094 /*For the moment 'png_init_palette_transformations' and
michael@0 1095 * 'png_init_rgb_transformations' only do some flag canceling optimizations.
michael@0 1096 * The intent is that these two routines should have palette or rgb operations
michael@0 1097 * extracted from 'png_init_read_transformations'.
michael@0 1098 */
michael@0 1099 static void /* PRIVATE */
michael@0 1100 png_init_palette_transformations(png_structrp png_ptr)
michael@0 1101 {
michael@0 1102 /* Called to handle the (input) palette case. In png_do_read_transformations
michael@0 1103 * the first step is to expand the palette if requested, so this code must
michael@0 1104 * take care to only make changes that are invariant with respect to the
michael@0 1105 * palette expansion, or only do them if there is no expansion.
michael@0 1106 *
michael@0 1107 * STRIP_ALPHA has already been handled in the caller (by setting num_trans
michael@0 1108 * to 0.)
michael@0 1109 */
michael@0 1110 int input_has_alpha = 0;
michael@0 1111 int input_has_transparency = 0;
michael@0 1112
michael@0 1113 if (png_ptr->num_trans > 0)
michael@0 1114 {
michael@0 1115 int i;
michael@0 1116
michael@0 1117 /* Ignore if all the entries are opaque (unlikely!) */
michael@0 1118 for (i=0; i<png_ptr->num_trans; ++i)
michael@0 1119 {
michael@0 1120 if (png_ptr->trans_alpha[i] == 255)
michael@0 1121 continue;
michael@0 1122 else if (png_ptr->trans_alpha[i] == 0)
michael@0 1123 input_has_transparency = 1;
michael@0 1124 else
michael@0 1125 {
michael@0 1126 input_has_transparency = 1;
michael@0 1127 input_has_alpha = 1;
michael@0 1128 break;
michael@0 1129 }
michael@0 1130 }
michael@0 1131 }
michael@0 1132
michael@0 1133 /* If no alpha we can optimize. */
michael@0 1134 if (!input_has_alpha)
michael@0 1135 {
michael@0 1136 /* Any alpha means background and associative alpha processing is
michael@0 1137 * required, however if the alpha is 0 or 1 throughout OPTIMIZE_ALPHA
michael@0 1138 * and ENCODE_ALPHA are irrelevant.
michael@0 1139 */
michael@0 1140 png_ptr->transformations &= ~PNG_ENCODE_ALPHA;
michael@0 1141 png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA;
michael@0 1142
michael@0 1143 if (!input_has_transparency)
michael@0 1144 png_ptr->transformations &= ~(PNG_COMPOSE | PNG_BACKGROUND_EXPAND);
michael@0 1145 }
michael@0 1146
michael@0 1147 #if defined(PNG_READ_EXPAND_SUPPORTED) && defined(PNG_READ_BACKGROUND_SUPPORTED)
michael@0 1148 /* png_set_background handling - deals with the complexity of whether the
michael@0 1149 * background color is in the file format or the screen format in the case
michael@0 1150 * where an 'expand' will happen.
michael@0 1151 */
michael@0 1152
michael@0 1153 /* The following code cannot be entered in the alpha pre-multiplication case
michael@0 1154 * because PNG_BACKGROUND_EXPAND is cancelled below.
michael@0 1155 */
michael@0 1156 if ((png_ptr->transformations & PNG_BACKGROUND_EXPAND) &&
michael@0 1157 (png_ptr->transformations & PNG_EXPAND))
michael@0 1158 {
michael@0 1159 {
michael@0 1160 png_ptr->background.red =
michael@0 1161 png_ptr->palette[png_ptr->background.index].red;
michael@0 1162 png_ptr->background.green =
michael@0 1163 png_ptr->palette[png_ptr->background.index].green;
michael@0 1164 png_ptr->background.blue =
michael@0 1165 png_ptr->palette[png_ptr->background.index].blue;
michael@0 1166
michael@0 1167 #ifdef PNG_READ_INVERT_ALPHA_SUPPORTED
michael@0 1168 if (png_ptr->transformations & PNG_INVERT_ALPHA)
michael@0 1169 {
michael@0 1170 if (!(png_ptr->transformations & PNG_EXPAND_tRNS))
michael@0 1171 {
michael@0 1172 /* Invert the alpha channel (in tRNS) unless the pixels are
michael@0 1173 * going to be expanded, in which case leave it for later
michael@0 1174 */
michael@0 1175 int i, istop = png_ptr->num_trans;
michael@0 1176
michael@0 1177 for (i=0; i<istop; i++)
michael@0 1178 png_ptr->trans_alpha[i] = (png_byte)(255 -
michael@0 1179 png_ptr->trans_alpha[i]);
michael@0 1180 }
michael@0 1181 }
michael@0 1182 #endif /* PNG_READ_INVERT_ALPHA_SUPPORTED */
michael@0 1183 }
michael@0 1184 } /* background expand and (therefore) no alpha association. */
michael@0 1185 #endif /* PNG_READ_EXPAND_SUPPORTED && PNG_READ_BACKGROUND_SUPPORTED */
michael@0 1186 }
michael@0 1187
michael@0 1188 static void /* PRIVATE */
michael@0 1189 png_init_rgb_transformations(png_structrp png_ptr)
michael@0 1190 {
michael@0 1191 /* Added to libpng-1.5.4: check the color type to determine whether there
michael@0 1192 * is any alpha or transparency in the image and simply cancel the
michael@0 1193 * background and alpha mode stuff if there isn't.
michael@0 1194 */
michael@0 1195 int input_has_alpha = (png_ptr->color_type & PNG_COLOR_MASK_ALPHA) != 0;
michael@0 1196 int input_has_transparency = png_ptr->num_trans > 0;
michael@0 1197
michael@0 1198 /* If no alpha we can optimize. */
michael@0 1199 if (!input_has_alpha)
michael@0 1200 {
michael@0 1201 /* Any alpha means background and associative alpha processing is
michael@0 1202 * required, however if the alpha is 0 or 1 throughout OPTIMIZE_ALPHA
michael@0 1203 * and ENCODE_ALPHA are irrelevant.
michael@0 1204 */
michael@0 1205 # ifdef PNG_READ_ALPHA_MODE_SUPPORTED
michael@0 1206 png_ptr->transformations &= ~PNG_ENCODE_ALPHA;
michael@0 1207 png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA;
michael@0 1208 # endif
michael@0 1209
michael@0 1210 if (!input_has_transparency)
michael@0 1211 png_ptr->transformations &= ~(PNG_COMPOSE | PNG_BACKGROUND_EXPAND);
michael@0 1212 }
michael@0 1213
michael@0 1214 #if defined(PNG_READ_EXPAND_SUPPORTED) && defined(PNG_READ_BACKGROUND_SUPPORTED)
michael@0 1215 /* png_set_background handling - deals with the complexity of whether the
michael@0 1216 * background color is in the file format or the screen format in the case
michael@0 1217 * where an 'expand' will happen.
michael@0 1218 */
michael@0 1219
michael@0 1220 /* The following code cannot be entered in the alpha pre-multiplication case
michael@0 1221 * because PNG_BACKGROUND_EXPAND is cancelled below.
michael@0 1222 */
michael@0 1223 if ((png_ptr->transformations & PNG_BACKGROUND_EXPAND) &&
michael@0 1224 (png_ptr->transformations & PNG_EXPAND) &&
michael@0 1225 !(png_ptr->color_type & PNG_COLOR_MASK_COLOR))
michael@0 1226 /* i.e., GRAY or GRAY_ALPHA */
michael@0 1227 {
michael@0 1228 {
michael@0 1229 /* Expand background and tRNS chunks */
michael@0 1230 int gray = png_ptr->background.gray;
michael@0 1231 int trans_gray = png_ptr->trans_color.gray;
michael@0 1232
michael@0 1233 switch (png_ptr->bit_depth)
michael@0 1234 {
michael@0 1235 case 1:
michael@0 1236 gray *= 0xff;
michael@0 1237 trans_gray *= 0xff;
michael@0 1238 break;
michael@0 1239
michael@0 1240 case 2:
michael@0 1241 gray *= 0x55;
michael@0 1242 trans_gray *= 0x55;
michael@0 1243 break;
michael@0 1244
michael@0 1245 case 4:
michael@0 1246 gray *= 0x11;
michael@0 1247 trans_gray *= 0x11;
michael@0 1248 break;
michael@0 1249
michael@0 1250 default:
michael@0 1251
michael@0 1252 case 8:
michael@0 1253 /* FALL THROUGH (Already 8 bits) */
michael@0 1254
michael@0 1255 case 16:
michael@0 1256 /* Already a full 16 bits */
michael@0 1257 break;
michael@0 1258 }
michael@0 1259
michael@0 1260 png_ptr->background.red = png_ptr->background.green =
michael@0 1261 png_ptr->background.blue = (png_uint_16)gray;
michael@0 1262
michael@0 1263 if (!(png_ptr->transformations & PNG_EXPAND_tRNS))
michael@0 1264 {
michael@0 1265 png_ptr->trans_color.red = png_ptr->trans_color.green =
michael@0 1266 png_ptr->trans_color.blue = (png_uint_16)trans_gray;
michael@0 1267 }
michael@0 1268 }
michael@0 1269 } /* background expand and (therefore) no alpha association. */
michael@0 1270 #endif /* PNG_READ_EXPAND_SUPPORTED && PNG_READ_BACKGROUND_SUPPORTED */
michael@0 1271 }
michael@0 1272
michael@0 1273 void /* PRIVATE */
michael@0 1274 png_init_read_transformations(png_structrp png_ptr)
michael@0 1275 {
michael@0 1276 png_debug(1, "in png_init_read_transformations");
michael@0 1277
michael@0 1278 /* This internal function is called from png_read_start_row in pngrutil.c
michael@0 1279 * and it is called before the 'rowbytes' calculation is done, so the code
michael@0 1280 * in here can change or update the transformations flags.
michael@0 1281 *
michael@0 1282 * First do updates that do not depend on the details of the PNG image data
michael@0 1283 * being processed.
michael@0 1284 */
michael@0 1285
michael@0 1286 #ifdef PNG_READ_GAMMA_SUPPORTED
michael@0 1287 /* Prior to 1.5.4 these tests were performed from png_set_gamma, 1.5.4 adds
michael@0 1288 * png_set_alpha_mode and this is another source for a default file gamma so
michael@0 1289 * the test needs to be performed later - here. In addition prior to 1.5.4
michael@0 1290 * the tests were repeated for the PALETTE color type here - this is no
michael@0 1291 * longer necessary (and doesn't seem to have been necessary before.)
michael@0 1292 */
michael@0 1293 {
michael@0 1294 /* The following temporary indicates if overall gamma correction is
michael@0 1295 * required.
michael@0 1296 */
michael@0 1297 int gamma_correction = 0;
michael@0 1298
michael@0 1299 if (png_ptr->colorspace.gamma != 0) /* has been set */
michael@0 1300 {
michael@0 1301 if (png_ptr->screen_gamma != 0) /* screen set too */
michael@0 1302 gamma_correction = png_gamma_threshold(png_ptr->colorspace.gamma,
michael@0 1303 png_ptr->screen_gamma);
michael@0 1304
michael@0 1305 else
michael@0 1306 /* Assume the output matches the input; a long time default behavior
michael@0 1307 * of libpng, although the standard has nothing to say about this.
michael@0 1308 */
michael@0 1309 png_ptr->screen_gamma = png_reciprocal(png_ptr->colorspace.gamma);
michael@0 1310 }
michael@0 1311
michael@0 1312 else if (png_ptr->screen_gamma != 0)
michael@0 1313 /* The converse - assume the file matches the screen, note that this
michael@0 1314 * perhaps undesireable default can (from 1.5.4) be changed by calling
michael@0 1315 * png_set_alpha_mode (even if the alpha handling mode isn't required
michael@0 1316 * or isn't changed from the default.)
michael@0 1317 */
michael@0 1318 png_ptr->colorspace.gamma = png_reciprocal(png_ptr->screen_gamma);
michael@0 1319
michael@0 1320 else /* neither are set */
michael@0 1321 /* Just in case the following prevents any processing - file and screen
michael@0 1322 * are both assumed to be linear and there is no way to introduce a
michael@0 1323 * third gamma value other than png_set_background with 'UNIQUE', and,
michael@0 1324 * prior to 1.5.4
michael@0 1325 */
michael@0 1326 png_ptr->screen_gamma = png_ptr->colorspace.gamma = PNG_FP_1;
michael@0 1327
michael@0 1328 /* We have a gamma value now. */
michael@0 1329 png_ptr->colorspace.flags |= PNG_COLORSPACE_HAVE_GAMMA;
michael@0 1330
michael@0 1331 /* Now turn the gamma transformation on or off as appropriate. Notice
michael@0 1332 * that PNG_GAMMA just refers to the file->screen correction. Alpha
michael@0 1333 * composition may independently cause gamma correction because it needs
michael@0 1334 * linear data (e.g. if the file has a gAMA chunk but the screen gamma
michael@0 1335 * hasn't been specified.) In any case this flag may get turned off in
michael@0 1336 * the code immediately below if the transform can be handled outside the
michael@0 1337 * row loop.
michael@0 1338 */
michael@0 1339 if (gamma_correction)
michael@0 1340 png_ptr->transformations |= PNG_GAMMA;
michael@0 1341
michael@0 1342 else
michael@0 1343 png_ptr->transformations &= ~PNG_GAMMA;
michael@0 1344 }
michael@0 1345 #endif
michael@0 1346
michael@0 1347 /* Certain transformations have the effect of preventing other
michael@0 1348 * transformations that happen afterward in png_do_read_transformations,
michael@0 1349 * resolve the interdependencies here. From the code of
michael@0 1350 * png_do_read_transformations the order is:
michael@0 1351 *
michael@0 1352 * 1) PNG_EXPAND (including PNG_EXPAND_tRNS)
michael@0 1353 * 2) PNG_STRIP_ALPHA (if no compose)
michael@0 1354 * 3) PNG_RGB_TO_GRAY
michael@0 1355 * 4) PNG_GRAY_TO_RGB iff !PNG_BACKGROUND_IS_GRAY
michael@0 1356 * 5) PNG_COMPOSE
michael@0 1357 * 6) PNG_GAMMA
michael@0 1358 * 7) PNG_STRIP_ALPHA (if compose)
michael@0 1359 * 8) PNG_ENCODE_ALPHA
michael@0 1360 * 9) PNG_SCALE_16_TO_8
michael@0 1361 * 10) PNG_16_TO_8
michael@0 1362 * 11) PNG_QUANTIZE (converts to palette)
michael@0 1363 * 12) PNG_EXPAND_16
michael@0 1364 * 13) PNG_GRAY_TO_RGB iff PNG_BACKGROUND_IS_GRAY
michael@0 1365 * 14) PNG_INVERT_MONO
michael@0 1366 * 15) PNG_INVERT_ALPHA
michael@0 1367 * 16) PNG_SHIFT
michael@0 1368 * 17) PNG_PACK
michael@0 1369 * 18) PNG_BGR
michael@0 1370 * 19) PNG_PACKSWAP
michael@0 1371 * 20) PNG_FILLER (includes PNG_ADD_ALPHA)
michael@0 1372 * 21) PNG_SWAP_ALPHA
michael@0 1373 * 22) PNG_SWAP_BYTES
michael@0 1374 * 23) PNG_USER_TRANSFORM [must be last]
michael@0 1375 */
michael@0 1376 #ifdef PNG_READ_STRIP_ALPHA_SUPPORTED
michael@0 1377 if ((png_ptr->transformations & PNG_STRIP_ALPHA) &&
michael@0 1378 !(png_ptr->transformations & PNG_COMPOSE))
michael@0 1379 {
michael@0 1380 /* Stripping the alpha channel happens immediately after the 'expand'
michael@0 1381 * transformations, before all other transformation, so it cancels out
michael@0 1382 * the alpha handling. It has the side effect negating the effect of
michael@0 1383 * PNG_EXPAND_tRNS too:
michael@0 1384 */
michael@0 1385 png_ptr->transformations &= ~(PNG_BACKGROUND_EXPAND | PNG_ENCODE_ALPHA |
michael@0 1386 PNG_EXPAND_tRNS);
michael@0 1387 png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA;
michael@0 1388
michael@0 1389 /* Kill the tRNS chunk itself too. Prior to 1.5.4 this did not happen
michael@0 1390 * so transparency information would remain just so long as it wasn't
michael@0 1391 * expanded. This produces unexpected API changes if the set of things
michael@0 1392 * that do PNG_EXPAND_tRNS changes (perfectly possible given the
michael@0 1393 * documentation - which says ask for what you want, accept what you
michael@0 1394 * get.) This makes the behavior consistent from 1.5.4:
michael@0 1395 */
michael@0 1396 png_ptr->num_trans = 0;
michael@0 1397 }
michael@0 1398 #endif /* STRIP_ALPHA supported, no COMPOSE */
michael@0 1399
michael@0 1400 #ifdef PNG_READ_ALPHA_MODE_SUPPORTED
michael@0 1401 /* If the screen gamma is about 1.0 then the OPTIMIZE_ALPHA and ENCODE_ALPHA
michael@0 1402 * settings will have no effect.
michael@0 1403 */
michael@0 1404 if (!png_gamma_significant(png_ptr->screen_gamma))
michael@0 1405 {
michael@0 1406 png_ptr->transformations &= ~PNG_ENCODE_ALPHA;
michael@0 1407 png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA;
michael@0 1408 }
michael@0 1409 #endif
michael@0 1410
michael@0 1411 #ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED
michael@0 1412 /* Make sure the coefficients for the rgb to gray conversion are set
michael@0 1413 * appropriately.
michael@0 1414 */
michael@0 1415 if (png_ptr->transformations & PNG_RGB_TO_GRAY)
michael@0 1416 png_colorspace_set_rgb_coefficients(png_ptr);
michael@0 1417 #endif
michael@0 1418
michael@0 1419 #ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED
michael@0 1420 #if defined(PNG_READ_EXPAND_SUPPORTED) && defined(PNG_READ_BACKGROUND_SUPPORTED)
michael@0 1421 /* Detect gray background and attempt to enable optimization for
michael@0 1422 * gray --> RGB case.
michael@0 1423 *
michael@0 1424 * Note: if PNG_BACKGROUND_EXPAND is set and color_type is either RGB or
michael@0 1425 * RGB_ALPHA (in which case need_expand is superfluous anyway), the
michael@0 1426 * background color might actually be gray yet not be flagged as such.
michael@0 1427 * This is not a problem for the current code, which uses
michael@0 1428 * PNG_BACKGROUND_IS_GRAY only to decide when to do the
michael@0 1429 * png_do_gray_to_rgb() transformation.
michael@0 1430 *
michael@0 1431 * TODO: this code needs to be revised to avoid the complexity and
michael@0 1432 * interdependencies. The color type of the background should be recorded in
michael@0 1433 * png_set_background, along with the bit depth, then the code has a record
michael@0 1434 * of exactly what color space the background is currently in.
michael@0 1435 */
michael@0 1436 if (png_ptr->transformations & PNG_BACKGROUND_EXPAND)
michael@0 1437 {
michael@0 1438 /* PNG_BACKGROUND_EXPAND: the background is in the file color space, so if
michael@0 1439 * the file was grayscale the background value is gray.
michael@0 1440 */
michael@0 1441 if (!(png_ptr->color_type & PNG_COLOR_MASK_COLOR))
michael@0 1442 png_ptr->mode |= PNG_BACKGROUND_IS_GRAY;
michael@0 1443 }
michael@0 1444
michael@0 1445 else if (png_ptr->transformations & PNG_COMPOSE)
michael@0 1446 {
michael@0 1447 /* PNG_COMPOSE: png_set_background was called with need_expand false,
michael@0 1448 * so the color is in the color space of the output or png_set_alpha_mode
michael@0 1449 * was called and the color is black. Ignore RGB_TO_GRAY because that
michael@0 1450 * happens before GRAY_TO_RGB.
michael@0 1451 */
michael@0 1452 if (png_ptr->transformations & PNG_GRAY_TO_RGB)
michael@0 1453 {
michael@0 1454 if (png_ptr->background.red == png_ptr->background.green &&
michael@0 1455 png_ptr->background.red == png_ptr->background.blue)
michael@0 1456 {
michael@0 1457 png_ptr->mode |= PNG_BACKGROUND_IS_GRAY;
michael@0 1458 png_ptr->background.gray = png_ptr->background.red;
michael@0 1459 }
michael@0 1460 }
michael@0 1461 }
michael@0 1462 #endif /* PNG_READ_EXPAND_SUPPORTED && PNG_READ_BACKGROUND_SUPPORTED */
michael@0 1463 #endif /* PNG_READ_GRAY_TO_RGB_SUPPORTED */
michael@0 1464
michael@0 1465 /* For indexed PNG data (PNG_COLOR_TYPE_PALETTE) many of the transformations
michael@0 1466 * can be performed directly on the palette, and some (such as rgb to gray)
michael@0 1467 * can be optimized inside the palette. This is particularly true of the
michael@0 1468 * composite (background and alpha) stuff, which can be pretty much all done
michael@0 1469 * in the palette even if the result is expanded to RGB or gray afterward.
michael@0 1470 *
michael@0 1471 * NOTE: this is Not Yet Implemented, the code behaves as in 1.5.1 and
michael@0 1472 * earlier and the palette stuff is actually handled on the first row. This
michael@0 1473 * leads to the reported bug that the palette returned by png_get_PLTE is not
michael@0 1474 * updated.
michael@0 1475 */
michael@0 1476 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
michael@0 1477 png_init_palette_transformations(png_ptr);
michael@0 1478
michael@0 1479 else
michael@0 1480 png_init_rgb_transformations(png_ptr);
michael@0 1481
michael@0 1482 #if defined(PNG_READ_BACKGROUND_SUPPORTED) && \
michael@0 1483 defined(PNG_READ_EXPAND_16_SUPPORTED)
michael@0 1484 if ((png_ptr->transformations & PNG_EXPAND_16) &&
michael@0 1485 (png_ptr->transformations & PNG_COMPOSE) &&
michael@0 1486 !(png_ptr->transformations & PNG_BACKGROUND_EXPAND) &&
michael@0 1487 png_ptr->bit_depth != 16)
michael@0 1488 {
michael@0 1489 /* TODO: fix this. Because the expand_16 operation is after the compose
michael@0 1490 * handling the background color must be 8, not 16, bits deep, but the
michael@0 1491 * application will supply a 16-bit value so reduce it here.
michael@0 1492 *
michael@0 1493 * The PNG_BACKGROUND_EXPAND code above does not expand to 16 bits at
michael@0 1494 * present, so that case is ok (until do_expand_16 is moved.)
michael@0 1495 *
michael@0 1496 * NOTE: this discards the low 16 bits of the user supplied background
michael@0 1497 * color, but until expand_16 works properly there is no choice!
michael@0 1498 */
michael@0 1499 # define CHOP(x) (x)=((png_uint_16)PNG_DIV257(x))
michael@0 1500 CHOP(png_ptr->background.red);
michael@0 1501 CHOP(png_ptr->background.green);
michael@0 1502 CHOP(png_ptr->background.blue);
michael@0 1503 CHOP(png_ptr->background.gray);
michael@0 1504 # undef CHOP
michael@0 1505 }
michael@0 1506 #endif /* PNG_READ_BACKGROUND_SUPPORTED && PNG_READ_EXPAND_16_SUPPORTED */
michael@0 1507
michael@0 1508 #if defined(PNG_READ_BACKGROUND_SUPPORTED) && \
michael@0 1509 (defined(PNG_READ_SCALE_16_TO_8_SUPPORTED) || \
michael@0 1510 defined(PNG_READ_STRIP_16_TO_8_SUPPORTED))
michael@0 1511 if ((png_ptr->transformations & (PNG_16_TO_8|PNG_SCALE_16_TO_8)) &&
michael@0 1512 (png_ptr->transformations & PNG_COMPOSE) &&
michael@0 1513 !(png_ptr->transformations & PNG_BACKGROUND_EXPAND) &&
michael@0 1514 png_ptr->bit_depth == 16)
michael@0 1515 {
michael@0 1516 /* On the other hand, if a 16-bit file is to be reduced to 8-bits per
michael@0 1517 * component this will also happen after PNG_COMPOSE and so the background
michael@0 1518 * color must be pre-expanded here.
michael@0 1519 *
michael@0 1520 * TODO: fix this too.
michael@0 1521 */
michael@0 1522 png_ptr->background.red = (png_uint_16)(png_ptr->background.red * 257);
michael@0 1523 png_ptr->background.green =
michael@0 1524 (png_uint_16)(png_ptr->background.green * 257);
michael@0 1525 png_ptr->background.blue = (png_uint_16)(png_ptr->background.blue * 257);
michael@0 1526 png_ptr->background.gray = (png_uint_16)(png_ptr->background.gray * 257);
michael@0 1527 }
michael@0 1528 #endif
michael@0 1529
michael@0 1530 /* NOTE: below 'PNG_READ_ALPHA_MODE_SUPPORTED' is presumed to also enable the
michael@0 1531 * background support (see the comments in scripts/pnglibconf.dfa), this
michael@0 1532 * allows pre-multiplication of the alpha channel to be implemented as
michael@0 1533 * compositing on black. This is probably sub-optimal and has been done in
michael@0 1534 * 1.5.4 betas simply to enable external critique and testing (i.e. to
michael@0 1535 * implement the new API quickly, without lots of internal changes.)
michael@0 1536 */
michael@0 1537
michael@0 1538 #ifdef PNG_READ_GAMMA_SUPPORTED
michael@0 1539 # ifdef PNG_READ_BACKGROUND_SUPPORTED
michael@0 1540 /* Includes ALPHA_MODE */
michael@0 1541 png_ptr->background_1 = png_ptr->background;
michael@0 1542 # endif
michael@0 1543
michael@0 1544 /* This needs to change - in the palette image case a whole set of tables are
michael@0 1545 * built when it would be quicker to just calculate the correct value for
michael@0 1546 * each palette entry directly. Also, the test is too tricky - why check
michael@0 1547 * PNG_RGB_TO_GRAY if PNG_GAMMA is not set? The answer seems to be that
michael@0 1548 * PNG_GAMMA is cancelled even if the gamma is known? The test excludes the
michael@0 1549 * PNG_COMPOSE case, so apparently if there is no *overall* gamma correction
michael@0 1550 * the gamma tables will not be built even if composition is required on a
michael@0 1551 * gamma encoded value.
michael@0 1552 *
michael@0 1553 * In 1.5.4 this is addressed below by an additional check on the individual
michael@0 1554 * file gamma - if it is not 1.0 both RGB_TO_GRAY and COMPOSE need the
michael@0 1555 * tables.
michael@0 1556 */
michael@0 1557 if ((png_ptr->transformations & PNG_GAMMA)
michael@0 1558 || ((png_ptr->transformations & PNG_RGB_TO_GRAY)
michael@0 1559 && (png_gamma_significant(png_ptr->colorspace.gamma) ||
michael@0 1560 png_gamma_significant(png_ptr->screen_gamma)))
michael@0 1561 || ((png_ptr->transformations & PNG_COMPOSE)
michael@0 1562 && (png_gamma_significant(png_ptr->colorspace.gamma)
michael@0 1563 || png_gamma_significant(png_ptr->screen_gamma)
michael@0 1564 # ifdef PNG_READ_BACKGROUND_SUPPORTED
michael@0 1565 || (png_ptr->background_gamma_type == PNG_BACKGROUND_GAMMA_UNIQUE
michael@0 1566 && png_gamma_significant(png_ptr->background_gamma))
michael@0 1567 # endif
michael@0 1568 )) || ((png_ptr->transformations & PNG_ENCODE_ALPHA)
michael@0 1569 && png_gamma_significant(png_ptr->screen_gamma))
michael@0 1570 )
michael@0 1571 {
michael@0 1572 png_build_gamma_table(png_ptr, png_ptr->bit_depth);
michael@0 1573
michael@0 1574 #ifdef PNG_READ_BACKGROUND_SUPPORTED
michael@0 1575 if (png_ptr->transformations & PNG_COMPOSE)
michael@0 1576 {
michael@0 1577 /* Issue a warning about this combination: because RGB_TO_GRAY is
michael@0 1578 * optimized to do the gamma transform if present yet do_background has
michael@0 1579 * to do the same thing if both options are set a
michael@0 1580 * double-gamma-correction happens. This is true in all versions of
michael@0 1581 * libpng to date.
michael@0 1582 */
michael@0 1583 if (png_ptr->transformations & PNG_RGB_TO_GRAY)
michael@0 1584 png_warning(png_ptr,
michael@0 1585 "libpng does not support gamma+background+rgb_to_gray");
michael@0 1586
michael@0 1587 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
michael@0 1588 {
michael@0 1589 /* We don't get to here unless there is a tRNS chunk with non-opaque
michael@0 1590 * entries - see the checking code at the start of this function.
michael@0 1591 */
michael@0 1592 png_color back, back_1;
michael@0 1593 png_colorp palette = png_ptr->palette;
michael@0 1594 int num_palette = png_ptr->num_palette;
michael@0 1595 int i;
michael@0 1596 if (png_ptr->background_gamma_type == PNG_BACKGROUND_GAMMA_FILE)
michael@0 1597 {
michael@0 1598
michael@0 1599 back.red = png_ptr->gamma_table[png_ptr->background.red];
michael@0 1600 back.green = png_ptr->gamma_table[png_ptr->background.green];
michael@0 1601 back.blue = png_ptr->gamma_table[png_ptr->background.blue];
michael@0 1602
michael@0 1603 back_1.red = png_ptr->gamma_to_1[png_ptr->background.red];
michael@0 1604 back_1.green = png_ptr->gamma_to_1[png_ptr->background.green];
michael@0 1605 back_1.blue = png_ptr->gamma_to_1[png_ptr->background.blue];
michael@0 1606 }
michael@0 1607 else
michael@0 1608 {
michael@0 1609 png_fixed_point g, gs;
michael@0 1610
michael@0 1611 switch (png_ptr->background_gamma_type)
michael@0 1612 {
michael@0 1613 case PNG_BACKGROUND_GAMMA_SCREEN:
michael@0 1614 g = (png_ptr->screen_gamma);
michael@0 1615 gs = PNG_FP_1;
michael@0 1616 break;
michael@0 1617
michael@0 1618 case PNG_BACKGROUND_GAMMA_FILE:
michael@0 1619 g = png_reciprocal(png_ptr->colorspace.gamma);
michael@0 1620 gs = png_reciprocal2(png_ptr->colorspace.gamma,
michael@0 1621 png_ptr->screen_gamma);
michael@0 1622 break;
michael@0 1623
michael@0 1624 case PNG_BACKGROUND_GAMMA_UNIQUE:
michael@0 1625 g = png_reciprocal(png_ptr->background_gamma);
michael@0 1626 gs = png_reciprocal2(png_ptr->background_gamma,
michael@0 1627 png_ptr->screen_gamma);
michael@0 1628 break;
michael@0 1629 default:
michael@0 1630 g = PNG_FP_1; /* back_1 */
michael@0 1631 gs = PNG_FP_1; /* back */
michael@0 1632 break;
michael@0 1633 }
michael@0 1634
michael@0 1635 if (png_gamma_significant(gs))
michael@0 1636 {
michael@0 1637 back.red = png_gamma_8bit_correct(png_ptr->background.red,
michael@0 1638 gs);
michael@0 1639 back.green = png_gamma_8bit_correct(png_ptr->background.green,
michael@0 1640 gs);
michael@0 1641 back.blue = png_gamma_8bit_correct(png_ptr->background.blue,
michael@0 1642 gs);
michael@0 1643 }
michael@0 1644
michael@0 1645 else
michael@0 1646 {
michael@0 1647 back.red = (png_byte)png_ptr->background.red;
michael@0 1648 back.green = (png_byte)png_ptr->background.green;
michael@0 1649 back.blue = (png_byte)png_ptr->background.blue;
michael@0 1650 }
michael@0 1651
michael@0 1652 if (png_gamma_significant(g))
michael@0 1653 {
michael@0 1654 back_1.red = png_gamma_8bit_correct(png_ptr->background.red,
michael@0 1655 g);
michael@0 1656 back_1.green = png_gamma_8bit_correct(
michael@0 1657 png_ptr->background.green, g);
michael@0 1658 back_1.blue = png_gamma_8bit_correct(png_ptr->background.blue,
michael@0 1659 g);
michael@0 1660 }
michael@0 1661
michael@0 1662 else
michael@0 1663 {
michael@0 1664 back_1.red = (png_byte)png_ptr->background.red;
michael@0 1665 back_1.green = (png_byte)png_ptr->background.green;
michael@0 1666 back_1.blue = (png_byte)png_ptr->background.blue;
michael@0 1667 }
michael@0 1668 }
michael@0 1669
michael@0 1670 for (i = 0; i < num_palette; i++)
michael@0 1671 {
michael@0 1672 if (i < (int)png_ptr->num_trans &&
michael@0 1673 png_ptr->trans_alpha[i] != 0xff)
michael@0 1674 {
michael@0 1675 if (png_ptr->trans_alpha[i] == 0)
michael@0 1676 {
michael@0 1677 palette[i] = back;
michael@0 1678 }
michael@0 1679 else /* if (png_ptr->trans_alpha[i] != 0xff) */
michael@0 1680 {
michael@0 1681 png_byte v, w;
michael@0 1682
michael@0 1683 v = png_ptr->gamma_to_1[palette[i].red];
michael@0 1684 png_composite(w, v, png_ptr->trans_alpha[i], back_1.red);
michael@0 1685 palette[i].red = png_ptr->gamma_from_1[w];
michael@0 1686
michael@0 1687 v = png_ptr->gamma_to_1[palette[i].green];
michael@0 1688 png_composite(w, v, png_ptr->trans_alpha[i], back_1.green);
michael@0 1689 palette[i].green = png_ptr->gamma_from_1[w];
michael@0 1690
michael@0 1691 v = png_ptr->gamma_to_1[palette[i].blue];
michael@0 1692 png_composite(w, v, png_ptr->trans_alpha[i], back_1.blue);
michael@0 1693 palette[i].blue = png_ptr->gamma_from_1[w];
michael@0 1694 }
michael@0 1695 }
michael@0 1696 else
michael@0 1697 {
michael@0 1698 palette[i].red = png_ptr->gamma_table[palette[i].red];
michael@0 1699 palette[i].green = png_ptr->gamma_table[palette[i].green];
michael@0 1700 palette[i].blue = png_ptr->gamma_table[palette[i].blue];
michael@0 1701 }
michael@0 1702 }
michael@0 1703
michael@0 1704 /* Prevent the transformations being done again.
michael@0 1705 *
michael@0 1706 * NOTE: this is highly dubious; it removes the transformations in
michael@0 1707 * place. This seems inconsistent with the general treatment of the
michael@0 1708 * transformations elsewhere.
michael@0 1709 */
michael@0 1710 png_ptr->transformations &= ~(PNG_COMPOSE | PNG_GAMMA);
michael@0 1711 } /* color_type == PNG_COLOR_TYPE_PALETTE */
michael@0 1712
michael@0 1713 /* if (png_ptr->background_gamma_type!=PNG_BACKGROUND_GAMMA_UNKNOWN) */
michael@0 1714 else /* color_type != PNG_COLOR_TYPE_PALETTE */
michael@0 1715 {
michael@0 1716 int gs_sig, g_sig;
michael@0 1717 png_fixed_point g = PNG_FP_1; /* Correction to linear */
michael@0 1718 png_fixed_point gs = PNG_FP_1; /* Correction to screen */
michael@0 1719
michael@0 1720 switch (png_ptr->background_gamma_type)
michael@0 1721 {
michael@0 1722 case PNG_BACKGROUND_GAMMA_SCREEN:
michael@0 1723 g = png_ptr->screen_gamma;
michael@0 1724 /* gs = PNG_FP_1; */
michael@0 1725 break;
michael@0 1726
michael@0 1727 case PNG_BACKGROUND_GAMMA_FILE:
michael@0 1728 g = png_reciprocal(png_ptr->colorspace.gamma);
michael@0 1729 gs = png_reciprocal2(png_ptr->colorspace.gamma,
michael@0 1730 png_ptr->screen_gamma);
michael@0 1731 break;
michael@0 1732
michael@0 1733 case PNG_BACKGROUND_GAMMA_UNIQUE:
michael@0 1734 g = png_reciprocal(png_ptr->background_gamma);
michael@0 1735 gs = png_reciprocal2(png_ptr->background_gamma,
michael@0 1736 png_ptr->screen_gamma);
michael@0 1737 break;
michael@0 1738
michael@0 1739 default:
michael@0 1740 png_error(png_ptr, "invalid background gamma type");
michael@0 1741 }
michael@0 1742
michael@0 1743 g_sig = png_gamma_significant(g);
michael@0 1744 gs_sig = png_gamma_significant(gs);
michael@0 1745
michael@0 1746 if (g_sig)
michael@0 1747 png_ptr->background_1.gray = png_gamma_correct(png_ptr,
michael@0 1748 png_ptr->background.gray, g);
michael@0 1749
michael@0 1750 if (gs_sig)
michael@0 1751 png_ptr->background.gray = png_gamma_correct(png_ptr,
michael@0 1752 png_ptr->background.gray, gs);
michael@0 1753
michael@0 1754 if ((png_ptr->background.red != png_ptr->background.green) ||
michael@0 1755 (png_ptr->background.red != png_ptr->background.blue) ||
michael@0 1756 (png_ptr->background.red != png_ptr->background.gray))
michael@0 1757 {
michael@0 1758 /* RGB or RGBA with color background */
michael@0 1759 if (g_sig)
michael@0 1760 {
michael@0 1761 png_ptr->background_1.red = png_gamma_correct(png_ptr,
michael@0 1762 png_ptr->background.red, g);
michael@0 1763
michael@0 1764 png_ptr->background_1.green = png_gamma_correct(png_ptr,
michael@0 1765 png_ptr->background.green, g);
michael@0 1766
michael@0 1767 png_ptr->background_1.blue = png_gamma_correct(png_ptr,
michael@0 1768 png_ptr->background.blue, g);
michael@0 1769 }
michael@0 1770
michael@0 1771 if (gs_sig)
michael@0 1772 {
michael@0 1773 png_ptr->background.red = png_gamma_correct(png_ptr,
michael@0 1774 png_ptr->background.red, gs);
michael@0 1775
michael@0 1776 png_ptr->background.green = png_gamma_correct(png_ptr,
michael@0 1777 png_ptr->background.green, gs);
michael@0 1778
michael@0 1779 png_ptr->background.blue = png_gamma_correct(png_ptr,
michael@0 1780 png_ptr->background.blue, gs);
michael@0 1781 }
michael@0 1782 }
michael@0 1783
michael@0 1784 else
michael@0 1785 {
michael@0 1786 /* GRAY, GRAY ALPHA, RGB, or RGBA with gray background */
michael@0 1787 png_ptr->background_1.red = png_ptr->background_1.green
michael@0 1788 = png_ptr->background_1.blue = png_ptr->background_1.gray;
michael@0 1789
michael@0 1790 png_ptr->background.red = png_ptr->background.green
michael@0 1791 = png_ptr->background.blue = png_ptr->background.gray;
michael@0 1792 }
michael@0 1793
michael@0 1794 /* The background is now in screen gamma: */
michael@0 1795 png_ptr->background_gamma_type = PNG_BACKGROUND_GAMMA_SCREEN;
michael@0 1796 } /* color_type != PNG_COLOR_TYPE_PALETTE */
michael@0 1797 }/* png_ptr->transformations & PNG_BACKGROUND */
michael@0 1798
michael@0 1799 else
michael@0 1800 /* Transformation does not include PNG_BACKGROUND */
michael@0 1801 #endif /* PNG_READ_BACKGROUND_SUPPORTED */
michael@0 1802 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE
michael@0 1803 #ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED
michael@0 1804 /* RGB_TO_GRAY needs to have non-gamma-corrected values! */
michael@0 1805 && ((png_ptr->transformations & PNG_EXPAND) == 0 ||
michael@0 1806 (png_ptr->transformations & PNG_RGB_TO_GRAY) == 0)
michael@0 1807 #endif
michael@0 1808 )
michael@0 1809 {
michael@0 1810 png_colorp palette = png_ptr->palette;
michael@0 1811 int num_palette = png_ptr->num_palette;
michael@0 1812 int i;
michael@0 1813
michael@0 1814 /* NOTE: there are other transformations that should probably be in
michael@0 1815 * here too.
michael@0 1816 */
michael@0 1817 for (i = 0; i < num_palette; i++)
michael@0 1818 {
michael@0 1819 palette[i].red = png_ptr->gamma_table[palette[i].red];
michael@0 1820 palette[i].green = png_ptr->gamma_table[palette[i].green];
michael@0 1821 palette[i].blue = png_ptr->gamma_table[palette[i].blue];
michael@0 1822 }
michael@0 1823
michael@0 1824 /* Done the gamma correction. */
michael@0 1825 png_ptr->transformations &= ~PNG_GAMMA;
michael@0 1826 } /* color_type == PALETTE && !PNG_BACKGROUND transformation */
michael@0 1827 }
michael@0 1828 #ifdef PNG_READ_BACKGROUND_SUPPORTED
michael@0 1829 else
michael@0 1830 #endif
michael@0 1831 #endif /* PNG_READ_GAMMA_SUPPORTED */
michael@0 1832
michael@0 1833 #ifdef PNG_READ_BACKGROUND_SUPPORTED
michael@0 1834 /* No GAMMA transformation (see the hanging else 4 lines above) */
michael@0 1835 if ((png_ptr->transformations & PNG_COMPOSE) &&
michael@0 1836 (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE))
michael@0 1837 {
michael@0 1838 int i;
michael@0 1839 int istop = (int)png_ptr->num_trans;
michael@0 1840 png_color back;
michael@0 1841 png_colorp palette = png_ptr->palette;
michael@0 1842
michael@0 1843 back.red = (png_byte)png_ptr->background.red;
michael@0 1844 back.green = (png_byte)png_ptr->background.green;
michael@0 1845 back.blue = (png_byte)png_ptr->background.blue;
michael@0 1846
michael@0 1847 for (i = 0; i < istop; i++)
michael@0 1848 {
michael@0 1849 if (png_ptr->trans_alpha[i] == 0)
michael@0 1850 {
michael@0 1851 palette[i] = back;
michael@0 1852 }
michael@0 1853
michael@0 1854 else if (png_ptr->trans_alpha[i] != 0xff)
michael@0 1855 {
michael@0 1856 /* The png_composite() macro is defined in png.h */
michael@0 1857 png_composite(palette[i].red, palette[i].red,
michael@0 1858 png_ptr->trans_alpha[i], back.red);
michael@0 1859
michael@0 1860 png_composite(palette[i].green, palette[i].green,
michael@0 1861 png_ptr->trans_alpha[i], back.green);
michael@0 1862
michael@0 1863 png_composite(palette[i].blue, palette[i].blue,
michael@0 1864 png_ptr->trans_alpha[i], back.blue);
michael@0 1865 }
michael@0 1866 }
michael@0 1867
michael@0 1868 png_ptr->transformations &= ~PNG_COMPOSE;
michael@0 1869 }
michael@0 1870 #endif /* PNG_READ_BACKGROUND_SUPPORTED */
michael@0 1871
michael@0 1872 #ifdef PNG_READ_SHIFT_SUPPORTED
michael@0 1873 if ((png_ptr->transformations & PNG_SHIFT) &&
michael@0 1874 !(png_ptr->transformations & PNG_EXPAND) &&
michael@0 1875 (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE))
michael@0 1876 {
michael@0 1877 int i;
michael@0 1878 int istop = png_ptr->num_palette;
michael@0 1879 int shift = 8 - png_ptr->sig_bit.red;
michael@0 1880
michael@0 1881 png_ptr->transformations &= ~PNG_SHIFT;
michael@0 1882
michael@0 1883 /* significant bits can be in the range 1 to 7 for a meaninful result, if
michael@0 1884 * the number of significant bits is 0 then no shift is done (this is an
michael@0 1885 * error condition which is silently ignored.)
michael@0 1886 */
michael@0 1887 if (shift > 0 && shift < 8)
michael@0 1888 for (i=0; i<istop; ++i)
michael@0 1889 {
michael@0 1890 int component = png_ptr->palette[i].red;
michael@0 1891
michael@0 1892 component >>= shift;
michael@0 1893 png_ptr->palette[i].red = (png_byte)component;
michael@0 1894 }
michael@0 1895
michael@0 1896 shift = 8 - png_ptr->sig_bit.green;
michael@0 1897 if (shift > 0 && shift < 8)
michael@0 1898 for (i=0; i<istop; ++i)
michael@0 1899 {
michael@0 1900 int component = png_ptr->palette[i].green;
michael@0 1901
michael@0 1902 component >>= shift;
michael@0 1903 png_ptr->palette[i].green = (png_byte)component;
michael@0 1904 }
michael@0 1905
michael@0 1906 shift = 8 - png_ptr->sig_bit.blue;
michael@0 1907 if (shift > 0 && shift < 8)
michael@0 1908 for (i=0; i<istop; ++i)
michael@0 1909 {
michael@0 1910 int component = png_ptr->palette[i].blue;
michael@0 1911
michael@0 1912 component >>= shift;
michael@0 1913 png_ptr->palette[i].blue = (png_byte)component;
michael@0 1914 }
michael@0 1915 }
michael@0 1916 #endif /* PNG_READ_SHIFT_SUPPORTED */
michael@0 1917 }
michael@0 1918
michael@0 1919 /* Modify the info structure to reflect the transformations. The
michael@0 1920 * info should be updated so a PNG file could be written with it,
michael@0 1921 * assuming the transformations result in valid PNG data.
michael@0 1922 */
michael@0 1923 void /* PRIVATE */
michael@0 1924 png_read_transform_info(png_structrp png_ptr, png_inforp info_ptr)
michael@0 1925 {
michael@0 1926 png_debug(1, "in png_read_transform_info");
michael@0 1927
michael@0 1928 #ifdef PNG_READ_EXPAND_SUPPORTED
michael@0 1929 if (png_ptr->transformations & PNG_EXPAND)
michael@0 1930 {
michael@0 1931 if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
michael@0 1932 {
michael@0 1933 /* This check must match what actually happens in
michael@0 1934 * png_do_expand_palette; if it ever checks the tRNS chunk to see if
michael@0 1935 * it is all opaque we must do the same (at present it does not.)
michael@0 1936 */
michael@0 1937 if (png_ptr->num_trans > 0)
michael@0 1938 info_ptr->color_type = PNG_COLOR_TYPE_RGB_ALPHA;
michael@0 1939
michael@0 1940 else
michael@0 1941 info_ptr->color_type = PNG_COLOR_TYPE_RGB;
michael@0 1942
michael@0 1943 info_ptr->bit_depth = 8;
michael@0 1944 info_ptr->num_trans = 0;
michael@0 1945
michael@0 1946 if (png_ptr->palette == NULL)
michael@0 1947 png_error (png_ptr, "Palette is NULL in indexed image");
michael@0 1948 }
michael@0 1949 else
michael@0 1950 {
michael@0 1951 if (png_ptr->num_trans)
michael@0 1952 {
michael@0 1953 if (png_ptr->transformations & PNG_EXPAND_tRNS)
michael@0 1954 info_ptr->color_type |= PNG_COLOR_MASK_ALPHA;
michael@0 1955 }
michael@0 1956 if (info_ptr->bit_depth < 8)
michael@0 1957 info_ptr->bit_depth = 8;
michael@0 1958
michael@0 1959 info_ptr->num_trans = 0;
michael@0 1960 }
michael@0 1961 }
michael@0 1962 #endif
michael@0 1963
michael@0 1964 #if defined(PNG_READ_BACKGROUND_SUPPORTED) ||\
michael@0 1965 defined(PNG_READ_ALPHA_MODE_SUPPORTED)
michael@0 1966 /* The following is almost certainly wrong unless the background value is in
michael@0 1967 * the screen space!
michael@0 1968 */
michael@0 1969 if (png_ptr->transformations & PNG_COMPOSE)
michael@0 1970 info_ptr->background = png_ptr->background;
michael@0 1971 #endif
michael@0 1972
michael@0 1973 #ifdef PNG_READ_GAMMA_SUPPORTED
michael@0 1974 /* The following used to be conditional on PNG_GAMMA (prior to 1.5.4),
michael@0 1975 * however it seems that the code in png_init_read_transformations, which has
michael@0 1976 * been called before this from png_read_update_info->png_read_start_row
michael@0 1977 * sometimes does the gamma transform and cancels the flag.
michael@0 1978 *
michael@0 1979 * TODO: this looks wrong; the info_ptr should end up with a gamma equal to
michael@0 1980 * the screen_gamma value. The following probably results in weirdness if
michael@0 1981 * the info_ptr is used by the app after the rows have been read.
michael@0 1982 */
michael@0 1983 info_ptr->colorspace.gamma = png_ptr->colorspace.gamma;
michael@0 1984 #endif
michael@0 1985
michael@0 1986 if (info_ptr->bit_depth == 16)
michael@0 1987 {
michael@0 1988 # ifdef PNG_READ_16BIT_SUPPORTED
michael@0 1989 # ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED
michael@0 1990 if (png_ptr->transformations & PNG_SCALE_16_TO_8)
michael@0 1991 info_ptr->bit_depth = 8;
michael@0 1992 # endif
michael@0 1993
michael@0 1994 # ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED
michael@0 1995 if (png_ptr->transformations & PNG_16_TO_8)
michael@0 1996 info_ptr->bit_depth = 8;
michael@0 1997 # endif
michael@0 1998
michael@0 1999 # else
michael@0 2000 /* No 16 bit support: force chopping 16-bit input down to 8, in this case
michael@0 2001 * the app program can chose if both APIs are available by setting the
michael@0 2002 * correct scaling to use.
michael@0 2003 */
michael@0 2004 # ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED
michael@0 2005 /* For compatibility with previous versions use the strip method by
michael@0 2006 * default. This code works because if PNG_SCALE_16_TO_8 is already
michael@0 2007 * set the code below will do that in preference to the chop.
michael@0 2008 */
michael@0 2009 png_ptr->transformations |= PNG_16_TO_8;
michael@0 2010 info_ptr->bit_depth = 8;
michael@0 2011 # else
michael@0 2012
michael@0 2013 # ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED
michael@0 2014 png_ptr->transformations |= PNG_SCALE_16_TO_8;
michael@0 2015 info_ptr->bit_depth = 8;
michael@0 2016 # else
michael@0 2017
michael@0 2018 CONFIGURATION ERROR: you must enable at least one 16 to 8 method
michael@0 2019 # endif
michael@0 2020 # endif
michael@0 2021 #endif /* !READ_16BIT_SUPPORTED */
michael@0 2022 }
michael@0 2023
michael@0 2024 #ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED
michael@0 2025 if (png_ptr->transformations & PNG_GRAY_TO_RGB)
michael@0 2026 info_ptr->color_type = (png_byte)(info_ptr->color_type |
michael@0 2027 PNG_COLOR_MASK_COLOR);
michael@0 2028 #endif
michael@0 2029
michael@0 2030 #ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED
michael@0 2031 if (png_ptr->transformations & PNG_RGB_TO_GRAY)
michael@0 2032 info_ptr->color_type = (png_byte)(info_ptr->color_type &
michael@0 2033 ~PNG_COLOR_MASK_COLOR);
michael@0 2034 #endif
michael@0 2035
michael@0 2036 #ifdef PNG_READ_QUANTIZE_SUPPORTED
michael@0 2037 if (png_ptr->transformations & PNG_QUANTIZE)
michael@0 2038 {
michael@0 2039 if (((info_ptr->color_type == PNG_COLOR_TYPE_RGB) ||
michael@0 2040 (info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)) &&
michael@0 2041 png_ptr->palette_lookup && info_ptr->bit_depth == 8)
michael@0 2042 {
michael@0 2043 info_ptr->color_type = PNG_COLOR_TYPE_PALETTE;
michael@0 2044 }
michael@0 2045 }
michael@0 2046 #endif
michael@0 2047
michael@0 2048 #ifdef PNG_READ_EXPAND_16_SUPPORTED
michael@0 2049 if (png_ptr->transformations & PNG_EXPAND_16 && info_ptr->bit_depth == 8 &&
michael@0 2050 info_ptr->color_type != PNG_COLOR_TYPE_PALETTE)
michael@0 2051 {
michael@0 2052 info_ptr->bit_depth = 16;
michael@0 2053 }
michael@0 2054 #endif
michael@0 2055
michael@0 2056 #ifdef PNG_READ_PACK_SUPPORTED
michael@0 2057 if ((png_ptr->transformations & PNG_PACK) && (info_ptr->bit_depth < 8))
michael@0 2058 info_ptr->bit_depth = 8;
michael@0 2059 #endif
michael@0 2060
michael@0 2061 if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
michael@0 2062 info_ptr->channels = 1;
michael@0 2063
michael@0 2064 else if (info_ptr->color_type & PNG_COLOR_MASK_COLOR)
michael@0 2065 info_ptr->channels = 3;
michael@0 2066
michael@0 2067 else
michael@0 2068 info_ptr->channels = 1;
michael@0 2069
michael@0 2070 #ifdef PNG_READ_STRIP_ALPHA_SUPPORTED
michael@0 2071 if (png_ptr->transformations & PNG_STRIP_ALPHA)
michael@0 2072 {
michael@0 2073 info_ptr->color_type = (png_byte)(info_ptr->color_type &
michael@0 2074 ~PNG_COLOR_MASK_ALPHA);
michael@0 2075 info_ptr->num_trans = 0;
michael@0 2076 }
michael@0 2077 #endif
michael@0 2078
michael@0 2079 if (info_ptr->color_type & PNG_COLOR_MASK_ALPHA)
michael@0 2080 info_ptr->channels++;
michael@0 2081
michael@0 2082 #ifdef PNG_READ_FILLER_SUPPORTED
michael@0 2083 /* STRIP_ALPHA and FILLER allowed: MASK_ALPHA bit stripped above */
michael@0 2084 if ((png_ptr->transformations & PNG_FILLER) &&
michael@0 2085 ((info_ptr->color_type == PNG_COLOR_TYPE_RGB) ||
michael@0 2086 (info_ptr->color_type == PNG_COLOR_TYPE_GRAY)))
michael@0 2087 {
michael@0 2088 info_ptr->channels++;
michael@0 2089 /* If adding a true alpha channel not just filler */
michael@0 2090 if (png_ptr->transformations & PNG_ADD_ALPHA)
michael@0 2091 info_ptr->color_type |= PNG_COLOR_MASK_ALPHA;
michael@0 2092 }
michael@0 2093 #endif
michael@0 2094
michael@0 2095 #if defined(PNG_USER_TRANSFORM_PTR_SUPPORTED) && \
michael@0 2096 defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
michael@0 2097 if (png_ptr->transformations & PNG_USER_TRANSFORM)
michael@0 2098 {
michael@0 2099 if (info_ptr->bit_depth < png_ptr->user_transform_depth)
michael@0 2100 info_ptr->bit_depth = png_ptr->user_transform_depth;
michael@0 2101
michael@0 2102 if (info_ptr->channels < png_ptr->user_transform_channels)
michael@0 2103 info_ptr->channels = png_ptr->user_transform_channels;
michael@0 2104 }
michael@0 2105 #endif
michael@0 2106
michael@0 2107 info_ptr->pixel_depth = (png_byte)(info_ptr->channels *
michael@0 2108 info_ptr->bit_depth);
michael@0 2109
michael@0 2110 info_ptr->rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth, info_ptr->width);
michael@0 2111
michael@0 2112 /* Adding in 1.5.4: cache the above value in png_struct so that we can later
michael@0 2113 * check in png_rowbytes that the user buffer won't get overwritten. Note
michael@0 2114 * that the field is not always set - if png_read_update_info isn't called
michael@0 2115 * the application has to either not do any transforms or get the calculation
michael@0 2116 * right itself.
michael@0 2117 */
michael@0 2118 png_ptr->info_rowbytes = info_ptr->rowbytes;
michael@0 2119
michael@0 2120 #ifndef PNG_READ_EXPAND_SUPPORTED
michael@0 2121 if (png_ptr)
michael@0 2122 return;
michael@0 2123 #endif
michael@0 2124 }
michael@0 2125
michael@0 2126 #ifdef PNG_READ_PACK_SUPPORTED
michael@0 2127 /* Unpack pixels of 1, 2, or 4 bits per pixel into 1 byte per pixel,
michael@0 2128 * without changing the actual values. Thus, if you had a row with
michael@0 2129 * a bit depth of 1, you would end up with bytes that only contained
michael@0 2130 * the numbers 0 or 1. If you would rather they contain 0 and 255, use
michael@0 2131 * png_do_shift() after this.
michael@0 2132 */
michael@0 2133 static void
michael@0 2134 png_do_unpack(png_row_infop row_info, png_bytep row)
michael@0 2135 {
michael@0 2136 png_debug(1, "in png_do_unpack");
michael@0 2137
michael@0 2138 if (row_info->bit_depth < 8)
michael@0 2139 {
michael@0 2140 png_uint_32 i;
michael@0 2141 png_uint_32 row_width=row_info->width;
michael@0 2142
michael@0 2143 switch (row_info->bit_depth)
michael@0 2144 {
michael@0 2145 case 1:
michael@0 2146 {
michael@0 2147 png_bytep sp = row + (png_size_t)((row_width - 1) >> 3);
michael@0 2148 png_bytep dp = row + (png_size_t)row_width - 1;
michael@0 2149 png_uint_32 shift = 7 - (int)((row_width + 7) & 0x07);
michael@0 2150 for (i = 0; i < row_width; i++)
michael@0 2151 {
michael@0 2152 *dp = (png_byte)((*sp >> shift) & 0x01);
michael@0 2153
michael@0 2154 if (shift == 7)
michael@0 2155 {
michael@0 2156 shift = 0;
michael@0 2157 sp--;
michael@0 2158 }
michael@0 2159
michael@0 2160 else
michael@0 2161 shift++;
michael@0 2162
michael@0 2163 dp--;
michael@0 2164 }
michael@0 2165 break;
michael@0 2166 }
michael@0 2167
michael@0 2168 case 2:
michael@0 2169 {
michael@0 2170
michael@0 2171 png_bytep sp = row + (png_size_t)((row_width - 1) >> 2);
michael@0 2172 png_bytep dp = row + (png_size_t)row_width - 1;
michael@0 2173 png_uint_32 shift = (int)((3 - ((row_width + 3) & 0x03)) << 1);
michael@0 2174 for (i = 0; i < row_width; i++)
michael@0 2175 {
michael@0 2176 *dp = (png_byte)((*sp >> shift) & 0x03);
michael@0 2177
michael@0 2178 if (shift == 6)
michael@0 2179 {
michael@0 2180 shift = 0;
michael@0 2181 sp--;
michael@0 2182 }
michael@0 2183
michael@0 2184 else
michael@0 2185 shift += 2;
michael@0 2186
michael@0 2187 dp--;
michael@0 2188 }
michael@0 2189 break;
michael@0 2190 }
michael@0 2191
michael@0 2192 case 4:
michael@0 2193 {
michael@0 2194 png_bytep sp = row + (png_size_t)((row_width - 1) >> 1);
michael@0 2195 png_bytep dp = row + (png_size_t)row_width - 1;
michael@0 2196 png_uint_32 shift = (int)((1 - ((row_width + 1) & 0x01)) << 2);
michael@0 2197 for (i = 0; i < row_width; i++)
michael@0 2198 {
michael@0 2199 *dp = (png_byte)((*sp >> shift) & 0x0f);
michael@0 2200
michael@0 2201 if (shift == 4)
michael@0 2202 {
michael@0 2203 shift = 0;
michael@0 2204 sp--;
michael@0 2205 }
michael@0 2206
michael@0 2207 else
michael@0 2208 shift = 4;
michael@0 2209
michael@0 2210 dp--;
michael@0 2211 }
michael@0 2212 break;
michael@0 2213 }
michael@0 2214
michael@0 2215 default:
michael@0 2216 break;
michael@0 2217 }
michael@0 2218 row_info->bit_depth = 8;
michael@0 2219 row_info->pixel_depth = (png_byte)(8 * row_info->channels);
michael@0 2220 row_info->rowbytes = row_width * row_info->channels;
michael@0 2221 }
michael@0 2222 }
michael@0 2223 #endif
michael@0 2224
michael@0 2225 #ifdef PNG_READ_SHIFT_SUPPORTED
michael@0 2226 /* Reverse the effects of png_do_shift. This routine merely shifts the
michael@0 2227 * pixels back to their significant bits values. Thus, if you have
michael@0 2228 * a row of bit depth 8, but only 5 are significant, this will shift
michael@0 2229 * the values back to 0 through 31.
michael@0 2230 */
michael@0 2231 static void
michael@0 2232 png_do_unshift(png_row_infop row_info, png_bytep row,
michael@0 2233 png_const_color_8p sig_bits)
michael@0 2234 {
michael@0 2235 int color_type;
michael@0 2236
michael@0 2237 png_debug(1, "in png_do_unshift");
michael@0 2238
michael@0 2239 /* The palette case has already been handled in the _init routine. */
michael@0 2240 color_type = row_info->color_type;
michael@0 2241
michael@0 2242 if (color_type != PNG_COLOR_TYPE_PALETTE)
michael@0 2243 {
michael@0 2244 int shift[4];
michael@0 2245 int channels = 0;
michael@0 2246 int bit_depth = row_info->bit_depth;
michael@0 2247
michael@0 2248 if (color_type & PNG_COLOR_MASK_COLOR)
michael@0 2249 {
michael@0 2250 shift[channels++] = bit_depth - sig_bits->red;
michael@0 2251 shift[channels++] = bit_depth - sig_bits->green;
michael@0 2252 shift[channels++] = bit_depth - sig_bits->blue;
michael@0 2253 }
michael@0 2254
michael@0 2255 else
michael@0 2256 {
michael@0 2257 shift[channels++] = bit_depth - sig_bits->gray;
michael@0 2258 }
michael@0 2259
michael@0 2260 if (color_type & PNG_COLOR_MASK_ALPHA)
michael@0 2261 {
michael@0 2262 shift[channels++] = bit_depth - sig_bits->alpha;
michael@0 2263 }
michael@0 2264
michael@0 2265 {
michael@0 2266 int c, have_shift;
michael@0 2267
michael@0 2268 for (c = have_shift = 0; c < channels; ++c)
michael@0 2269 {
michael@0 2270 /* A shift of more than the bit depth is an error condition but it
michael@0 2271 * gets ignored here.
michael@0 2272 */
michael@0 2273 if (shift[c] <= 0 || shift[c] >= bit_depth)
michael@0 2274 shift[c] = 0;
michael@0 2275
michael@0 2276 else
michael@0 2277 have_shift = 1;
michael@0 2278 }
michael@0 2279
michael@0 2280 if (!have_shift)
michael@0 2281 return;
michael@0 2282 }
michael@0 2283
michael@0 2284 switch (bit_depth)
michael@0 2285 {
michael@0 2286 default:
michael@0 2287 /* Must be 1bpp gray: should not be here! */
michael@0 2288 /* NOTREACHED */
michael@0 2289 break;
michael@0 2290
michael@0 2291 case 2:
michael@0 2292 /* Must be 2bpp gray */
michael@0 2293 /* assert(channels == 1 && shift[0] == 1) */
michael@0 2294 {
michael@0 2295 png_bytep bp = row;
michael@0 2296 png_bytep bp_end = bp + row_info->rowbytes;
michael@0 2297
michael@0 2298 while (bp < bp_end)
michael@0 2299 {
michael@0 2300 int b = (*bp >> 1) & 0x55;
michael@0 2301 *bp++ = (png_byte)b;
michael@0 2302 }
michael@0 2303 break;
michael@0 2304 }
michael@0 2305
michael@0 2306 case 4:
michael@0 2307 /* Must be 4bpp gray */
michael@0 2308 /* assert(channels == 1) */
michael@0 2309 {
michael@0 2310 png_bytep bp = row;
michael@0 2311 png_bytep bp_end = bp + row_info->rowbytes;
michael@0 2312 int gray_shift = shift[0];
michael@0 2313 int mask = 0xf >> gray_shift;
michael@0 2314
michael@0 2315 mask |= mask << 4;
michael@0 2316
michael@0 2317 while (bp < bp_end)
michael@0 2318 {
michael@0 2319 int b = (*bp >> gray_shift) & mask;
michael@0 2320 *bp++ = (png_byte)b;
michael@0 2321 }
michael@0 2322 break;
michael@0 2323 }
michael@0 2324
michael@0 2325 case 8:
michael@0 2326 /* Single byte components, G, GA, RGB, RGBA */
michael@0 2327 {
michael@0 2328 png_bytep bp = row;
michael@0 2329 png_bytep bp_end = bp + row_info->rowbytes;
michael@0 2330 int channel = 0;
michael@0 2331
michael@0 2332 while (bp < bp_end)
michael@0 2333 {
michael@0 2334 int b = *bp >> shift[channel];
michael@0 2335 if (++channel >= channels)
michael@0 2336 channel = 0;
michael@0 2337 *bp++ = (png_byte)b;
michael@0 2338 }
michael@0 2339 break;
michael@0 2340 }
michael@0 2341
michael@0 2342 #ifdef PNG_READ_16BIT_SUPPORTED
michael@0 2343 case 16:
michael@0 2344 /* Double byte components, G, GA, RGB, RGBA */
michael@0 2345 {
michael@0 2346 png_bytep bp = row;
michael@0 2347 png_bytep bp_end = bp + row_info->rowbytes;
michael@0 2348 int channel = 0;
michael@0 2349
michael@0 2350 while (bp < bp_end)
michael@0 2351 {
michael@0 2352 int value = (bp[0] << 8) + bp[1];
michael@0 2353
michael@0 2354 value >>= shift[channel];
michael@0 2355 if (++channel >= channels)
michael@0 2356 channel = 0;
michael@0 2357 *bp++ = (png_byte)(value >> 8);
michael@0 2358 *bp++ = (png_byte)(value & 0xff);
michael@0 2359 }
michael@0 2360 break;
michael@0 2361 }
michael@0 2362 #endif
michael@0 2363 }
michael@0 2364 }
michael@0 2365 }
michael@0 2366 #endif
michael@0 2367
michael@0 2368 #ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED
michael@0 2369 /* Scale rows of bit depth 16 down to 8 accurately */
michael@0 2370 static void
michael@0 2371 png_do_scale_16_to_8(png_row_infop row_info, png_bytep row)
michael@0 2372 {
michael@0 2373 png_debug(1, "in png_do_scale_16_to_8");
michael@0 2374
michael@0 2375 if (row_info->bit_depth == 16)
michael@0 2376 {
michael@0 2377 png_bytep sp = row; /* source */
michael@0 2378 png_bytep dp = row; /* destination */
michael@0 2379 png_bytep ep = sp + row_info->rowbytes; /* end+1 */
michael@0 2380
michael@0 2381 while (sp < ep)
michael@0 2382 {
michael@0 2383 /* The input is an array of 16 bit components, these must be scaled to
michael@0 2384 * 8 bits each. For a 16 bit value V the required value (from the PNG
michael@0 2385 * specification) is:
michael@0 2386 *
michael@0 2387 * (V * 255) / 65535
michael@0 2388 *
michael@0 2389 * This reduces to round(V / 257), or floor((V + 128.5)/257)
michael@0 2390 *
michael@0 2391 * Represent V as the two byte value vhi.vlo. Make a guess that the
michael@0 2392 * result is the top byte of V, vhi, then the correction to this value
michael@0 2393 * is:
michael@0 2394 *
michael@0 2395 * error = floor(((V-vhi.vhi) + 128.5) / 257)
michael@0 2396 * = floor(((vlo-vhi) + 128.5) / 257)
michael@0 2397 *
michael@0 2398 * This can be approximated using integer arithmetic (and a signed
michael@0 2399 * shift):
michael@0 2400 *
michael@0 2401 * error = (vlo-vhi+128) >> 8;
michael@0 2402 *
michael@0 2403 * The approximate differs from the exact answer only when (vlo-vhi) is
michael@0 2404 * 128; it then gives a correction of +1 when the exact correction is
michael@0 2405 * 0. This gives 128 errors. The exact answer (correct for all 16 bit
michael@0 2406 * input values) is:
michael@0 2407 *
michael@0 2408 * error = (vlo-vhi+128)*65535 >> 24;
michael@0 2409 *
michael@0 2410 * An alternative arithmetic calculation which also gives no errors is:
michael@0 2411 *
michael@0 2412 * (V * 255 + 32895) >> 16
michael@0 2413 */
michael@0 2414
michael@0 2415 png_int_32 tmp = *sp++; /* must be signed! */
michael@0 2416 tmp += (((int)*sp++ - tmp + 128) * 65535) >> 24;
michael@0 2417 *dp++ = (png_byte)tmp;
michael@0 2418 }
michael@0 2419
michael@0 2420 row_info->bit_depth = 8;
michael@0 2421 row_info->pixel_depth = (png_byte)(8 * row_info->channels);
michael@0 2422 row_info->rowbytes = row_info->width * row_info->channels;
michael@0 2423 }
michael@0 2424 }
michael@0 2425 #endif
michael@0 2426
michael@0 2427 #ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED
michael@0 2428 static void
michael@0 2429 /* Simply discard the low byte. This was the default behavior prior
michael@0 2430 * to libpng-1.5.4.
michael@0 2431 */
michael@0 2432 png_do_chop(png_row_infop row_info, png_bytep row)
michael@0 2433 {
michael@0 2434 png_debug(1, "in png_do_chop");
michael@0 2435
michael@0 2436 if (row_info->bit_depth == 16)
michael@0 2437 {
michael@0 2438 png_bytep sp = row; /* source */
michael@0 2439 png_bytep dp = row; /* destination */
michael@0 2440 png_bytep ep = sp + row_info->rowbytes; /* end+1 */
michael@0 2441
michael@0 2442 while (sp < ep)
michael@0 2443 {
michael@0 2444 *dp++ = *sp;
michael@0 2445 sp += 2; /* skip low byte */
michael@0 2446 }
michael@0 2447
michael@0 2448 row_info->bit_depth = 8;
michael@0 2449 row_info->pixel_depth = (png_byte)(8 * row_info->channels);
michael@0 2450 row_info->rowbytes = row_info->width * row_info->channels;
michael@0 2451 }
michael@0 2452 }
michael@0 2453 #endif
michael@0 2454
michael@0 2455 #ifdef PNG_READ_SWAP_ALPHA_SUPPORTED
michael@0 2456 static void
michael@0 2457 png_do_read_swap_alpha(png_row_infop row_info, png_bytep row)
michael@0 2458 {
michael@0 2459 png_debug(1, "in png_do_read_swap_alpha");
michael@0 2460
michael@0 2461 {
michael@0 2462 png_uint_32 row_width = row_info->width;
michael@0 2463 if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
michael@0 2464 {
michael@0 2465 /* This converts from RGBA to ARGB */
michael@0 2466 if (row_info->bit_depth == 8)
michael@0 2467 {
michael@0 2468 png_bytep sp = row + row_info->rowbytes;
michael@0 2469 png_bytep dp = sp;
michael@0 2470 png_byte save;
michael@0 2471 png_uint_32 i;
michael@0 2472
michael@0 2473 for (i = 0; i < row_width; i++)
michael@0 2474 {
michael@0 2475 save = *(--sp);
michael@0 2476 *(--dp) = *(--sp);
michael@0 2477 *(--dp) = *(--sp);
michael@0 2478 *(--dp) = *(--sp);
michael@0 2479 *(--dp) = save;
michael@0 2480 }
michael@0 2481 }
michael@0 2482
michael@0 2483 #ifdef PNG_READ_16BIT_SUPPORTED
michael@0 2484 /* This converts from RRGGBBAA to AARRGGBB */
michael@0 2485 else
michael@0 2486 {
michael@0 2487 png_bytep sp = row + row_info->rowbytes;
michael@0 2488 png_bytep dp = sp;
michael@0 2489 png_byte save[2];
michael@0 2490 png_uint_32 i;
michael@0 2491
michael@0 2492 for (i = 0; i < row_width; i++)
michael@0 2493 {
michael@0 2494 save[0] = *(--sp);
michael@0 2495 save[1] = *(--sp);
michael@0 2496 *(--dp) = *(--sp);
michael@0 2497 *(--dp) = *(--sp);
michael@0 2498 *(--dp) = *(--sp);
michael@0 2499 *(--dp) = *(--sp);
michael@0 2500 *(--dp) = *(--sp);
michael@0 2501 *(--dp) = *(--sp);
michael@0 2502 *(--dp) = save[0];
michael@0 2503 *(--dp) = save[1];
michael@0 2504 }
michael@0 2505 }
michael@0 2506 #endif
michael@0 2507 }
michael@0 2508
michael@0 2509 else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
michael@0 2510 {
michael@0 2511 /* This converts from GA to AG */
michael@0 2512 if (row_info->bit_depth == 8)
michael@0 2513 {
michael@0 2514 png_bytep sp = row + row_info->rowbytes;
michael@0 2515 png_bytep dp = sp;
michael@0 2516 png_byte save;
michael@0 2517 png_uint_32 i;
michael@0 2518
michael@0 2519 for (i = 0; i < row_width; i++)
michael@0 2520 {
michael@0 2521 save = *(--sp);
michael@0 2522 *(--dp) = *(--sp);
michael@0 2523 *(--dp) = save;
michael@0 2524 }
michael@0 2525 }
michael@0 2526
michael@0 2527 #ifdef PNG_READ_16BIT_SUPPORTED
michael@0 2528 /* This converts from GGAA to AAGG */
michael@0 2529 else
michael@0 2530 {
michael@0 2531 png_bytep sp = row + row_info->rowbytes;
michael@0 2532 png_bytep dp = sp;
michael@0 2533 png_byte save[2];
michael@0 2534 png_uint_32 i;
michael@0 2535
michael@0 2536 for (i = 0; i < row_width; i++)
michael@0 2537 {
michael@0 2538 save[0] = *(--sp);
michael@0 2539 save[1] = *(--sp);
michael@0 2540 *(--dp) = *(--sp);
michael@0 2541 *(--dp) = *(--sp);
michael@0 2542 *(--dp) = save[0];
michael@0 2543 *(--dp) = save[1];
michael@0 2544 }
michael@0 2545 }
michael@0 2546 #endif
michael@0 2547 }
michael@0 2548 }
michael@0 2549 }
michael@0 2550 #endif
michael@0 2551
michael@0 2552 #ifdef PNG_READ_INVERT_ALPHA_SUPPORTED
michael@0 2553 static void
michael@0 2554 png_do_read_invert_alpha(png_row_infop row_info, png_bytep row)
michael@0 2555 {
michael@0 2556 png_uint_32 row_width;
michael@0 2557 png_debug(1, "in png_do_read_invert_alpha");
michael@0 2558
michael@0 2559 row_width = row_info->width;
michael@0 2560 if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
michael@0 2561 {
michael@0 2562 if (row_info->bit_depth == 8)
michael@0 2563 {
michael@0 2564 /* This inverts the alpha channel in RGBA */
michael@0 2565 png_bytep sp = row + row_info->rowbytes;
michael@0 2566 png_bytep dp = sp;
michael@0 2567 png_uint_32 i;
michael@0 2568
michael@0 2569 for (i = 0; i < row_width; i++)
michael@0 2570 {
michael@0 2571 *(--dp) = (png_byte)(255 - *(--sp));
michael@0 2572
michael@0 2573 /* This does nothing:
michael@0 2574 *(--dp) = *(--sp);
michael@0 2575 *(--dp) = *(--sp);
michael@0 2576 *(--dp) = *(--sp);
michael@0 2577 We can replace it with:
michael@0 2578 */
michael@0 2579 sp-=3;
michael@0 2580 dp=sp;
michael@0 2581 }
michael@0 2582 }
michael@0 2583
michael@0 2584 #ifdef PNG_READ_16BIT_SUPPORTED
michael@0 2585 /* This inverts the alpha channel in RRGGBBAA */
michael@0 2586 else
michael@0 2587 {
michael@0 2588 png_bytep sp = row + row_info->rowbytes;
michael@0 2589 png_bytep dp = sp;
michael@0 2590 png_uint_32 i;
michael@0 2591
michael@0 2592 for (i = 0; i < row_width; i++)
michael@0 2593 {
michael@0 2594 *(--dp) = (png_byte)(255 - *(--sp));
michael@0 2595 *(--dp) = (png_byte)(255 - *(--sp));
michael@0 2596
michael@0 2597 /* This does nothing:
michael@0 2598 *(--dp) = *(--sp);
michael@0 2599 *(--dp) = *(--sp);
michael@0 2600 *(--dp) = *(--sp);
michael@0 2601 *(--dp) = *(--sp);
michael@0 2602 *(--dp) = *(--sp);
michael@0 2603 *(--dp) = *(--sp);
michael@0 2604 We can replace it with:
michael@0 2605 */
michael@0 2606 sp-=6;
michael@0 2607 dp=sp;
michael@0 2608 }
michael@0 2609 }
michael@0 2610 #endif
michael@0 2611 }
michael@0 2612 else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
michael@0 2613 {
michael@0 2614 if (row_info->bit_depth == 8)
michael@0 2615 {
michael@0 2616 /* This inverts the alpha channel in GA */
michael@0 2617 png_bytep sp = row + row_info->rowbytes;
michael@0 2618 png_bytep dp = sp;
michael@0 2619 png_uint_32 i;
michael@0 2620
michael@0 2621 for (i = 0; i < row_width; i++)
michael@0 2622 {
michael@0 2623 *(--dp) = (png_byte)(255 - *(--sp));
michael@0 2624 *(--dp) = *(--sp);
michael@0 2625 }
michael@0 2626 }
michael@0 2627
michael@0 2628 #ifdef PNG_READ_16BIT_SUPPORTED
michael@0 2629 else
michael@0 2630 {
michael@0 2631 /* This inverts the alpha channel in GGAA */
michael@0 2632 png_bytep sp = row + row_info->rowbytes;
michael@0 2633 png_bytep dp = sp;
michael@0 2634 png_uint_32 i;
michael@0 2635
michael@0 2636 for (i = 0; i < row_width; i++)
michael@0 2637 {
michael@0 2638 *(--dp) = (png_byte)(255 - *(--sp));
michael@0 2639 *(--dp) = (png_byte)(255 - *(--sp));
michael@0 2640 /*
michael@0 2641 *(--dp) = *(--sp);
michael@0 2642 *(--dp) = *(--sp);
michael@0 2643 */
michael@0 2644 sp-=2;
michael@0 2645 dp=sp;
michael@0 2646 }
michael@0 2647 }
michael@0 2648 #endif
michael@0 2649 }
michael@0 2650 }
michael@0 2651 #endif
michael@0 2652
michael@0 2653 #ifdef PNG_READ_FILLER_SUPPORTED
michael@0 2654 /* Add filler channel if we have RGB color */
michael@0 2655 static void
michael@0 2656 png_do_read_filler(png_row_infop row_info, png_bytep row,
michael@0 2657 png_uint_32 filler, png_uint_32 flags)
michael@0 2658 {
michael@0 2659 png_uint_32 i;
michael@0 2660 png_uint_32 row_width = row_info->width;
michael@0 2661
michael@0 2662 #ifdef PNG_READ_16BIT_SUPPORTED
michael@0 2663 png_byte hi_filler = (png_byte)((filler>>8) & 0xff);
michael@0 2664 #endif
michael@0 2665 png_byte lo_filler = (png_byte)(filler & 0xff);
michael@0 2666
michael@0 2667 png_debug(1, "in png_do_read_filler");
michael@0 2668
michael@0 2669 if (
michael@0 2670 row_info->color_type == PNG_COLOR_TYPE_GRAY)
michael@0 2671 {
michael@0 2672 if (row_info->bit_depth == 8)
michael@0 2673 {
michael@0 2674 if (flags & PNG_FLAG_FILLER_AFTER)
michael@0 2675 {
michael@0 2676 /* This changes the data from G to GX */
michael@0 2677 png_bytep sp = row + (png_size_t)row_width;
michael@0 2678 png_bytep dp = sp + (png_size_t)row_width;
michael@0 2679 for (i = 1; i < row_width; i++)
michael@0 2680 {
michael@0 2681 *(--dp) = lo_filler;
michael@0 2682 *(--dp) = *(--sp);
michael@0 2683 }
michael@0 2684 *(--dp) = lo_filler;
michael@0 2685 row_info->channels = 2;
michael@0 2686 row_info->pixel_depth = 16;
michael@0 2687 row_info->rowbytes = row_width * 2;
michael@0 2688 }
michael@0 2689
michael@0 2690 else
michael@0 2691 {
michael@0 2692 /* This changes the data from G to XG */
michael@0 2693 png_bytep sp = row + (png_size_t)row_width;
michael@0 2694 png_bytep dp = sp + (png_size_t)row_width;
michael@0 2695 for (i = 0; i < row_width; i++)
michael@0 2696 {
michael@0 2697 *(--dp) = *(--sp);
michael@0 2698 *(--dp) = lo_filler;
michael@0 2699 }
michael@0 2700 row_info->channels = 2;
michael@0 2701 row_info->pixel_depth = 16;
michael@0 2702 row_info->rowbytes = row_width * 2;
michael@0 2703 }
michael@0 2704 }
michael@0 2705
michael@0 2706 #ifdef PNG_READ_16BIT_SUPPORTED
michael@0 2707 else if (row_info->bit_depth == 16)
michael@0 2708 {
michael@0 2709 if (flags & PNG_FLAG_FILLER_AFTER)
michael@0 2710 {
michael@0 2711 /* This changes the data from GG to GGXX */
michael@0 2712 png_bytep sp = row + (png_size_t)row_width * 2;
michael@0 2713 png_bytep dp = sp + (png_size_t)row_width * 2;
michael@0 2714 for (i = 1; i < row_width; i++)
michael@0 2715 {
michael@0 2716 *(--dp) = hi_filler;
michael@0 2717 *(--dp) = lo_filler;
michael@0 2718 *(--dp) = *(--sp);
michael@0 2719 *(--dp) = *(--sp);
michael@0 2720 }
michael@0 2721 *(--dp) = hi_filler;
michael@0 2722 *(--dp) = lo_filler;
michael@0 2723 row_info->channels = 2;
michael@0 2724 row_info->pixel_depth = 32;
michael@0 2725 row_info->rowbytes = row_width * 4;
michael@0 2726 }
michael@0 2727
michael@0 2728 else
michael@0 2729 {
michael@0 2730 /* This changes the data from GG to XXGG */
michael@0 2731 png_bytep sp = row + (png_size_t)row_width * 2;
michael@0 2732 png_bytep dp = sp + (png_size_t)row_width * 2;
michael@0 2733 for (i = 0; i < row_width; i++)
michael@0 2734 {
michael@0 2735 *(--dp) = *(--sp);
michael@0 2736 *(--dp) = *(--sp);
michael@0 2737 *(--dp) = hi_filler;
michael@0 2738 *(--dp) = lo_filler;
michael@0 2739 }
michael@0 2740 row_info->channels = 2;
michael@0 2741 row_info->pixel_depth = 32;
michael@0 2742 row_info->rowbytes = row_width * 4;
michael@0 2743 }
michael@0 2744 }
michael@0 2745 #endif
michael@0 2746 } /* COLOR_TYPE == GRAY */
michael@0 2747 else if (row_info->color_type == PNG_COLOR_TYPE_RGB)
michael@0 2748 {
michael@0 2749 if (row_info->bit_depth == 8)
michael@0 2750 {
michael@0 2751 if (flags & PNG_FLAG_FILLER_AFTER)
michael@0 2752 {
michael@0 2753 /* This changes the data from RGB to RGBX */
michael@0 2754 png_bytep sp = row + (png_size_t)row_width * 3;
michael@0 2755 png_bytep dp = sp + (png_size_t)row_width;
michael@0 2756 for (i = 1; i < row_width; i++)
michael@0 2757 {
michael@0 2758 *(--dp) = lo_filler;
michael@0 2759 *(--dp) = *(--sp);
michael@0 2760 *(--dp) = *(--sp);
michael@0 2761 *(--dp) = *(--sp);
michael@0 2762 }
michael@0 2763 *(--dp) = lo_filler;
michael@0 2764 row_info->channels = 4;
michael@0 2765 row_info->pixel_depth = 32;
michael@0 2766 row_info->rowbytes = row_width * 4;
michael@0 2767 }
michael@0 2768
michael@0 2769 else
michael@0 2770 {
michael@0 2771 /* This changes the data from RGB to XRGB */
michael@0 2772 png_bytep sp = row + (png_size_t)row_width * 3;
michael@0 2773 png_bytep dp = sp + (png_size_t)row_width;
michael@0 2774 for (i = 0; i < row_width; i++)
michael@0 2775 {
michael@0 2776 *(--dp) = *(--sp);
michael@0 2777 *(--dp) = *(--sp);
michael@0 2778 *(--dp) = *(--sp);
michael@0 2779 *(--dp) = lo_filler;
michael@0 2780 }
michael@0 2781 row_info->channels = 4;
michael@0 2782 row_info->pixel_depth = 32;
michael@0 2783 row_info->rowbytes = row_width * 4;
michael@0 2784 }
michael@0 2785 }
michael@0 2786
michael@0 2787 #ifdef PNG_READ_16BIT_SUPPORTED
michael@0 2788 else if (row_info->bit_depth == 16)
michael@0 2789 {
michael@0 2790 if (flags & PNG_FLAG_FILLER_AFTER)
michael@0 2791 {
michael@0 2792 /* This changes the data from RRGGBB to RRGGBBXX */
michael@0 2793 png_bytep sp = row + (png_size_t)row_width * 6;
michael@0 2794 png_bytep dp = sp + (png_size_t)row_width * 2;
michael@0 2795 for (i = 1; i < row_width; i++)
michael@0 2796 {
michael@0 2797 *(--dp) = hi_filler;
michael@0 2798 *(--dp) = lo_filler;
michael@0 2799 *(--dp) = *(--sp);
michael@0 2800 *(--dp) = *(--sp);
michael@0 2801 *(--dp) = *(--sp);
michael@0 2802 *(--dp) = *(--sp);
michael@0 2803 *(--dp) = *(--sp);
michael@0 2804 *(--dp) = *(--sp);
michael@0 2805 }
michael@0 2806 *(--dp) = hi_filler;
michael@0 2807 *(--dp) = lo_filler;
michael@0 2808 row_info->channels = 4;
michael@0 2809 row_info->pixel_depth = 64;
michael@0 2810 row_info->rowbytes = row_width * 8;
michael@0 2811 }
michael@0 2812
michael@0 2813 else
michael@0 2814 {
michael@0 2815 /* This changes the data from RRGGBB to XXRRGGBB */
michael@0 2816 png_bytep sp = row + (png_size_t)row_width * 6;
michael@0 2817 png_bytep dp = sp + (png_size_t)row_width * 2;
michael@0 2818 for (i = 0; i < row_width; i++)
michael@0 2819 {
michael@0 2820 *(--dp) = *(--sp);
michael@0 2821 *(--dp) = *(--sp);
michael@0 2822 *(--dp) = *(--sp);
michael@0 2823 *(--dp) = *(--sp);
michael@0 2824 *(--dp) = *(--sp);
michael@0 2825 *(--dp) = *(--sp);
michael@0 2826 *(--dp) = hi_filler;
michael@0 2827 *(--dp) = lo_filler;
michael@0 2828 }
michael@0 2829
michael@0 2830 row_info->channels = 4;
michael@0 2831 row_info->pixel_depth = 64;
michael@0 2832 row_info->rowbytes = row_width * 8;
michael@0 2833 }
michael@0 2834 }
michael@0 2835 #endif
michael@0 2836 } /* COLOR_TYPE == RGB */
michael@0 2837 }
michael@0 2838 #endif
michael@0 2839
michael@0 2840 #ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED
michael@0 2841 /* Expand grayscale files to RGB, with or without alpha */
michael@0 2842 static void
michael@0 2843 png_do_gray_to_rgb(png_row_infop row_info, png_bytep row)
michael@0 2844 {
michael@0 2845 png_uint_32 i;
michael@0 2846 png_uint_32 row_width = row_info->width;
michael@0 2847
michael@0 2848 png_debug(1, "in png_do_gray_to_rgb");
michael@0 2849
michael@0 2850 if (row_info->bit_depth >= 8 &&
michael@0 2851 !(row_info->color_type & PNG_COLOR_MASK_COLOR))
michael@0 2852 {
michael@0 2853 if (row_info->color_type == PNG_COLOR_TYPE_GRAY)
michael@0 2854 {
michael@0 2855 if (row_info->bit_depth == 8)
michael@0 2856 {
michael@0 2857 /* This changes G to RGB */
michael@0 2858 png_bytep sp = row + (png_size_t)row_width - 1;
michael@0 2859 png_bytep dp = sp + (png_size_t)row_width * 2;
michael@0 2860 for (i = 0; i < row_width; i++)
michael@0 2861 {
michael@0 2862 *(dp--) = *sp;
michael@0 2863 *(dp--) = *sp;
michael@0 2864 *(dp--) = *(sp--);
michael@0 2865 }
michael@0 2866 }
michael@0 2867
michael@0 2868 else
michael@0 2869 {
michael@0 2870 /* This changes GG to RRGGBB */
michael@0 2871 png_bytep sp = row + (png_size_t)row_width * 2 - 1;
michael@0 2872 png_bytep dp = sp + (png_size_t)row_width * 4;
michael@0 2873 for (i = 0; i < row_width; i++)
michael@0 2874 {
michael@0 2875 *(dp--) = *sp;
michael@0 2876 *(dp--) = *(sp - 1);
michael@0 2877 *(dp--) = *sp;
michael@0 2878 *(dp--) = *(sp - 1);
michael@0 2879 *(dp--) = *(sp--);
michael@0 2880 *(dp--) = *(sp--);
michael@0 2881 }
michael@0 2882 }
michael@0 2883 }
michael@0 2884
michael@0 2885 else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
michael@0 2886 {
michael@0 2887 if (row_info->bit_depth == 8)
michael@0 2888 {
michael@0 2889 /* This changes GA to RGBA */
michael@0 2890 png_bytep sp = row + (png_size_t)row_width * 2 - 1;
michael@0 2891 png_bytep dp = sp + (png_size_t)row_width * 2;
michael@0 2892 for (i = 0; i < row_width; i++)
michael@0 2893 {
michael@0 2894 *(dp--) = *(sp--);
michael@0 2895 *(dp--) = *sp;
michael@0 2896 *(dp--) = *sp;
michael@0 2897 *(dp--) = *(sp--);
michael@0 2898 }
michael@0 2899 }
michael@0 2900
michael@0 2901 else
michael@0 2902 {
michael@0 2903 /* This changes GGAA to RRGGBBAA */
michael@0 2904 png_bytep sp = row + (png_size_t)row_width * 4 - 1;
michael@0 2905 png_bytep dp = sp + (png_size_t)row_width * 4;
michael@0 2906 for (i = 0; i < row_width; i++)
michael@0 2907 {
michael@0 2908 *(dp--) = *(sp--);
michael@0 2909 *(dp--) = *(sp--);
michael@0 2910 *(dp--) = *sp;
michael@0 2911 *(dp--) = *(sp - 1);
michael@0 2912 *(dp--) = *sp;
michael@0 2913 *(dp--) = *(sp - 1);
michael@0 2914 *(dp--) = *(sp--);
michael@0 2915 *(dp--) = *(sp--);
michael@0 2916 }
michael@0 2917 }
michael@0 2918 }
michael@0 2919 row_info->channels = (png_byte)(row_info->channels + 2);
michael@0 2920 row_info->color_type |= PNG_COLOR_MASK_COLOR;
michael@0 2921 row_info->pixel_depth = (png_byte)(row_info->channels *
michael@0 2922 row_info->bit_depth);
michael@0 2923 row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width);
michael@0 2924 }
michael@0 2925 }
michael@0 2926 #endif
michael@0 2927
michael@0 2928 #ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED
michael@0 2929 /* Reduce RGB files to grayscale, with or without alpha
michael@0 2930 * using the equation given in Poynton's ColorFAQ of 1998-01-04 at
michael@0 2931 * <http://www.inforamp.net/~poynton/> (THIS LINK IS DEAD June 2008 but
michael@0 2932 * versions dated 1998 through November 2002 have been archived at
michael@0 2933 * http://web.archive.org/web/20000816232553/http://www.inforamp.net/
michael@0 2934 * ~poynton/notes/colour_and_gamma/ColorFAQ.txt )
michael@0 2935 * Charles Poynton poynton at poynton.com
michael@0 2936 *
michael@0 2937 * Y = 0.212671 * R + 0.715160 * G + 0.072169 * B
michael@0 2938 *
michael@0 2939 * which can be expressed with integers as
michael@0 2940 *
michael@0 2941 * Y = (6969 * R + 23434 * G + 2365 * B)/32768
michael@0 2942 *
michael@0 2943 * Poynton's current link (as of January 2003 through July 2011):
michael@0 2944 * <http://www.poynton.com/notes/colour_and_gamma/>
michael@0 2945 * has changed the numbers slightly:
michael@0 2946 *
michael@0 2947 * Y = 0.2126*R + 0.7152*G + 0.0722*B
michael@0 2948 *
michael@0 2949 * which can be expressed with integers as
michael@0 2950 *
michael@0 2951 * Y = (6966 * R + 23436 * G + 2366 * B)/32768
michael@0 2952 *
michael@0 2953 * Historically, however, libpng uses numbers derived from the ITU-R Rec 709
michael@0 2954 * end point chromaticities and the D65 white point. Depending on the
michael@0 2955 * precision used for the D65 white point this produces a variety of different
michael@0 2956 * numbers, however if the four decimal place value used in ITU-R Rec 709 is
michael@0 2957 * used (0.3127,0.3290) the Y calculation would be:
michael@0 2958 *
michael@0 2959 * Y = (6968 * R + 23435 * G + 2366 * B)/32768
michael@0 2960 *
michael@0 2961 * While this is correct the rounding results in an overflow for white, because
michael@0 2962 * the sum of the rounded coefficients is 32769, not 32768. Consequently
michael@0 2963 * libpng uses, instead, the closest non-overflowing approximation:
michael@0 2964 *
michael@0 2965 * Y = (6968 * R + 23434 * G + 2366 * B)/32768
michael@0 2966 *
michael@0 2967 * Starting with libpng-1.5.5, if the image being converted has a cHRM chunk
michael@0 2968 * (including an sRGB chunk) then the chromaticities are used to calculate the
michael@0 2969 * coefficients. See the chunk handling in pngrutil.c for more information.
michael@0 2970 *
michael@0 2971 * In all cases the calculation is to be done in a linear colorspace. If no
michael@0 2972 * gamma information is available to correct the encoding of the original RGB
michael@0 2973 * values this results in an implicit assumption that the original PNG RGB
michael@0 2974 * values were linear.
michael@0 2975 *
michael@0 2976 * Other integer coefficents can be used via png_set_rgb_to_gray(). Because
michael@0 2977 * the API takes just red and green coefficients the blue coefficient is
michael@0 2978 * calculated to make the sum 32768. This will result in different rounding
michael@0 2979 * to that used above.
michael@0 2980 */
michael@0 2981 static int
michael@0 2982 png_do_rgb_to_gray(png_structrp png_ptr, png_row_infop row_info, png_bytep row)
michael@0 2983
michael@0 2984 {
michael@0 2985 int rgb_error = 0;
michael@0 2986
michael@0 2987 png_debug(1, "in png_do_rgb_to_gray");
michael@0 2988
michael@0 2989 if (!(row_info->color_type & PNG_COLOR_MASK_PALETTE) &&
michael@0 2990 (row_info->color_type & PNG_COLOR_MASK_COLOR))
michael@0 2991 {
michael@0 2992 PNG_CONST png_uint_32 rc = png_ptr->rgb_to_gray_red_coeff;
michael@0 2993 PNG_CONST png_uint_32 gc = png_ptr->rgb_to_gray_green_coeff;
michael@0 2994 PNG_CONST png_uint_32 bc = 32768 - rc - gc;
michael@0 2995 PNG_CONST png_uint_32 row_width = row_info->width;
michael@0 2996 PNG_CONST int have_alpha =
michael@0 2997 (row_info->color_type & PNG_COLOR_MASK_ALPHA) != 0;
michael@0 2998
michael@0 2999 if (row_info->bit_depth == 8)
michael@0 3000 {
michael@0 3001 #ifdef PNG_READ_GAMMA_SUPPORTED
michael@0 3002 /* Notice that gamma to/from 1 are not necessarily inverses (if
michael@0 3003 * there is an overall gamma correction). Prior to 1.5.5 this code
michael@0 3004 * checked the linearized values for equality; this doesn't match
michael@0 3005 * the documentation, the original values must be checked.
michael@0 3006 */
michael@0 3007 if (png_ptr->gamma_from_1 != NULL && png_ptr->gamma_to_1 != NULL)
michael@0 3008 {
michael@0 3009 png_bytep sp = row;
michael@0 3010 png_bytep dp = row;
michael@0 3011 png_uint_32 i;
michael@0 3012
michael@0 3013 for (i = 0; i < row_width; i++)
michael@0 3014 {
michael@0 3015 png_byte red = *(sp++);
michael@0 3016 png_byte green = *(sp++);
michael@0 3017 png_byte blue = *(sp++);
michael@0 3018
michael@0 3019 if (red != green || red != blue)
michael@0 3020 {
michael@0 3021 red = png_ptr->gamma_to_1[red];
michael@0 3022 green = png_ptr->gamma_to_1[green];
michael@0 3023 blue = png_ptr->gamma_to_1[blue];
michael@0 3024
michael@0 3025 rgb_error |= 1;
michael@0 3026 *(dp++) = png_ptr->gamma_from_1[
michael@0 3027 (rc*red + gc*green + bc*blue + 16384)>>15];
michael@0 3028 }
michael@0 3029
michael@0 3030 else
michael@0 3031 {
michael@0 3032 /* If there is no overall correction the table will not be
michael@0 3033 * set.
michael@0 3034 */
michael@0 3035 if (png_ptr->gamma_table != NULL)
michael@0 3036 red = png_ptr->gamma_table[red];
michael@0 3037
michael@0 3038 *(dp++) = red;
michael@0 3039 }
michael@0 3040
michael@0 3041 if (have_alpha)
michael@0 3042 *(dp++) = *(sp++);
michael@0 3043 }
michael@0 3044 }
michael@0 3045 else
michael@0 3046 #endif
michael@0 3047 {
michael@0 3048 png_bytep sp = row;
michael@0 3049 png_bytep dp = row;
michael@0 3050 png_uint_32 i;
michael@0 3051
michael@0 3052 for (i = 0; i < row_width; i++)
michael@0 3053 {
michael@0 3054 png_byte red = *(sp++);
michael@0 3055 png_byte green = *(sp++);
michael@0 3056 png_byte blue = *(sp++);
michael@0 3057
michael@0 3058 if (red != green || red != blue)
michael@0 3059 {
michael@0 3060 rgb_error |= 1;
michael@0 3061 /* NOTE: this is the historical approach which simply
michael@0 3062 * truncates the results.
michael@0 3063 */
michael@0 3064 *(dp++) = (png_byte)((rc*red + gc*green + bc*blue)>>15);
michael@0 3065 }
michael@0 3066
michael@0 3067 else
michael@0 3068 *(dp++) = red;
michael@0 3069
michael@0 3070 if (have_alpha)
michael@0 3071 *(dp++) = *(sp++);
michael@0 3072 }
michael@0 3073 }
michael@0 3074 }
michael@0 3075
michael@0 3076 else /* RGB bit_depth == 16 */
michael@0 3077 {
michael@0 3078 #ifdef PNG_READ_GAMMA_SUPPORTED
michael@0 3079 if (png_ptr->gamma_16_to_1 != NULL && png_ptr->gamma_16_from_1 != NULL)
michael@0 3080 {
michael@0 3081 png_bytep sp = row;
michael@0 3082 png_bytep dp = row;
michael@0 3083 png_uint_32 i;
michael@0 3084
michael@0 3085 for (i = 0; i < row_width; i++)
michael@0 3086 {
michael@0 3087 png_uint_16 red, green, blue, w;
michael@0 3088
michael@0 3089 red = (png_uint_16)(((*(sp))<<8) | *(sp + 1)); sp += 2;
michael@0 3090 green = (png_uint_16)(((*(sp))<<8) | *(sp + 1)); sp += 2;
michael@0 3091 blue = (png_uint_16)(((*(sp))<<8) | *(sp + 1)); sp += 2;
michael@0 3092
michael@0 3093 if (red == green && red == blue)
michael@0 3094 {
michael@0 3095 if (png_ptr->gamma_16_table != NULL)
michael@0 3096 w = png_ptr->gamma_16_table[(red&0xff)
michael@0 3097 >> png_ptr->gamma_shift][red>>8];
michael@0 3098
michael@0 3099 else
michael@0 3100 w = red;
michael@0 3101 }
michael@0 3102
michael@0 3103 else
michael@0 3104 {
michael@0 3105 png_uint_16 red_1 = png_ptr->gamma_16_to_1[(red&0xff)
michael@0 3106 >> png_ptr->gamma_shift][red>>8];
michael@0 3107 png_uint_16 green_1 =
michael@0 3108 png_ptr->gamma_16_to_1[(green&0xff) >>
michael@0 3109 png_ptr->gamma_shift][green>>8];
michael@0 3110 png_uint_16 blue_1 = png_ptr->gamma_16_to_1[(blue&0xff)
michael@0 3111 >> png_ptr->gamma_shift][blue>>8];
michael@0 3112 png_uint_16 gray16 = (png_uint_16)((rc*red_1 + gc*green_1
michael@0 3113 + bc*blue_1 + 16384)>>15);
michael@0 3114 w = png_ptr->gamma_16_from_1[(gray16&0xff) >>
michael@0 3115 png_ptr->gamma_shift][gray16 >> 8];
michael@0 3116 rgb_error |= 1;
michael@0 3117 }
michael@0 3118
michael@0 3119 *(dp++) = (png_byte)((w>>8) & 0xff);
michael@0 3120 *(dp++) = (png_byte)(w & 0xff);
michael@0 3121
michael@0 3122 if (have_alpha)
michael@0 3123 {
michael@0 3124 *(dp++) = *(sp++);
michael@0 3125 *(dp++) = *(sp++);
michael@0 3126 }
michael@0 3127 }
michael@0 3128 }
michael@0 3129 else
michael@0 3130 #endif
michael@0 3131 {
michael@0 3132 png_bytep sp = row;
michael@0 3133 png_bytep dp = row;
michael@0 3134 png_uint_32 i;
michael@0 3135
michael@0 3136 for (i = 0; i < row_width; i++)
michael@0 3137 {
michael@0 3138 png_uint_16 red, green, blue, gray16;
michael@0 3139
michael@0 3140 red = (png_uint_16)(((*(sp))<<8) | *(sp + 1)); sp += 2;
michael@0 3141 green = (png_uint_16)(((*(sp))<<8) | *(sp + 1)); sp += 2;
michael@0 3142 blue = (png_uint_16)(((*(sp))<<8) | *(sp + 1)); sp += 2;
michael@0 3143
michael@0 3144 if (red != green || red != blue)
michael@0 3145 rgb_error |= 1;
michael@0 3146
michael@0 3147 /* From 1.5.5 in the 16 bit case do the accurate conversion even
michael@0 3148 * in the 'fast' case - this is because this is where the code
michael@0 3149 * ends up when handling linear 16 bit data.
michael@0 3150 */
michael@0 3151 gray16 = (png_uint_16)((rc*red + gc*green + bc*blue + 16384) >>
michael@0 3152 15);
michael@0 3153 *(dp++) = (png_byte)((gray16>>8) & 0xff);
michael@0 3154 *(dp++) = (png_byte)(gray16 & 0xff);
michael@0 3155
michael@0 3156 if (have_alpha)
michael@0 3157 {
michael@0 3158 *(dp++) = *(sp++);
michael@0 3159 *(dp++) = *(sp++);
michael@0 3160 }
michael@0 3161 }
michael@0 3162 }
michael@0 3163 }
michael@0 3164
michael@0 3165 row_info->channels = (png_byte)(row_info->channels - 2);
michael@0 3166 row_info->color_type = (png_byte)(row_info->color_type &
michael@0 3167 ~PNG_COLOR_MASK_COLOR);
michael@0 3168 row_info->pixel_depth = (png_byte)(row_info->channels *
michael@0 3169 row_info->bit_depth);
michael@0 3170 row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width);
michael@0 3171 }
michael@0 3172 return rgb_error;
michael@0 3173 }
michael@0 3174 #endif
michael@0 3175
michael@0 3176 #if defined(PNG_READ_BACKGROUND_SUPPORTED) ||\
michael@0 3177 defined(PNG_READ_ALPHA_MODE_SUPPORTED)
michael@0 3178 /* Replace any alpha or transparency with the supplied background color.
michael@0 3179 * "background" is already in the screen gamma, while "background_1" is
michael@0 3180 * at a gamma of 1.0. Paletted files have already been taken care of.
michael@0 3181 */
michael@0 3182 static void
michael@0 3183 png_do_compose(png_row_infop row_info, png_bytep row, png_structrp png_ptr)
michael@0 3184 {
michael@0 3185 #ifdef PNG_READ_GAMMA_SUPPORTED
michael@0 3186 png_const_bytep gamma_table = png_ptr->gamma_table;
michael@0 3187 png_const_bytep gamma_from_1 = png_ptr->gamma_from_1;
michael@0 3188 png_const_bytep gamma_to_1 = png_ptr->gamma_to_1;
michael@0 3189 png_const_uint_16pp gamma_16 = png_ptr->gamma_16_table;
michael@0 3190 png_const_uint_16pp gamma_16_from_1 = png_ptr->gamma_16_from_1;
michael@0 3191 png_const_uint_16pp gamma_16_to_1 = png_ptr->gamma_16_to_1;
michael@0 3192 int gamma_shift = png_ptr->gamma_shift;
michael@0 3193 int optimize = (png_ptr->flags & PNG_FLAG_OPTIMIZE_ALPHA) != 0;
michael@0 3194 #endif
michael@0 3195
michael@0 3196 png_bytep sp;
michael@0 3197 png_uint_32 i;
michael@0 3198 png_uint_32 row_width = row_info->width;
michael@0 3199 int shift;
michael@0 3200
michael@0 3201 png_debug(1, "in png_do_compose");
michael@0 3202
michael@0 3203 {
michael@0 3204 switch (row_info->color_type)
michael@0 3205 {
michael@0 3206 case PNG_COLOR_TYPE_GRAY:
michael@0 3207 {
michael@0 3208 switch (row_info->bit_depth)
michael@0 3209 {
michael@0 3210 case 1:
michael@0 3211 {
michael@0 3212 sp = row;
michael@0 3213 shift = 7;
michael@0 3214 for (i = 0; i < row_width; i++)
michael@0 3215 {
michael@0 3216 if ((png_uint_16)((*sp >> shift) & 0x01)
michael@0 3217 == png_ptr->trans_color.gray)
michael@0 3218 {
michael@0 3219 unsigned int tmp = *sp & (0x7f7f >> (7 - shift));
michael@0 3220 tmp |= png_ptr->background.gray << shift;
michael@0 3221 *sp = (png_byte)(tmp & 0xff);
michael@0 3222 }
michael@0 3223
michael@0 3224 if (!shift)
michael@0 3225 {
michael@0 3226 shift = 7;
michael@0 3227 sp++;
michael@0 3228 }
michael@0 3229
michael@0 3230 else
michael@0 3231 shift--;
michael@0 3232 }
michael@0 3233 break;
michael@0 3234 }
michael@0 3235
michael@0 3236 case 2:
michael@0 3237 {
michael@0 3238 #ifdef PNG_READ_GAMMA_SUPPORTED
michael@0 3239 if (gamma_table != NULL)
michael@0 3240 {
michael@0 3241 sp = row;
michael@0 3242 shift = 6;
michael@0 3243 for (i = 0; i < row_width; i++)
michael@0 3244 {
michael@0 3245 if ((png_uint_16)((*sp >> shift) & 0x03)
michael@0 3246 == png_ptr->trans_color.gray)
michael@0 3247 {
michael@0 3248 unsigned int tmp = *sp & (0x3f3f >> (6 - shift));
michael@0 3249 tmp |= png_ptr->background.gray << shift;
michael@0 3250 *sp = (png_byte)(tmp & 0xff);
michael@0 3251 }
michael@0 3252
michael@0 3253 else
michael@0 3254 {
michael@0 3255 unsigned int p = (*sp >> shift) & 0x03;
michael@0 3256 unsigned int g = (gamma_table [p | (p << 2) |
michael@0 3257 (p << 4) | (p << 6)] >> 6) & 0x03;
michael@0 3258 unsigned int tmp = *sp & (0x3f3f >> (6 - shift));
michael@0 3259 tmp |= g << shift;
michael@0 3260 *sp = (png_byte)(tmp & 0xff);
michael@0 3261 }
michael@0 3262
michael@0 3263 if (!shift)
michael@0 3264 {
michael@0 3265 shift = 6;
michael@0 3266 sp++;
michael@0 3267 }
michael@0 3268
michael@0 3269 else
michael@0 3270 shift -= 2;
michael@0 3271 }
michael@0 3272 }
michael@0 3273
michael@0 3274 else
michael@0 3275 #endif
michael@0 3276 {
michael@0 3277 sp = row;
michael@0 3278 shift = 6;
michael@0 3279 for (i = 0; i < row_width; i++)
michael@0 3280 {
michael@0 3281 if ((png_uint_16)((*sp >> shift) & 0x03)
michael@0 3282 == png_ptr->trans_color.gray)
michael@0 3283 {
michael@0 3284 unsigned int tmp = *sp & (0x3f3f >> (6 - shift));
michael@0 3285 tmp |= png_ptr->background.gray << shift;
michael@0 3286 *sp = (png_byte)(tmp & 0xff);
michael@0 3287 }
michael@0 3288
michael@0 3289 if (!shift)
michael@0 3290 {
michael@0 3291 shift = 6;
michael@0 3292 sp++;
michael@0 3293 }
michael@0 3294
michael@0 3295 else
michael@0 3296 shift -= 2;
michael@0 3297 }
michael@0 3298 }
michael@0 3299 break;
michael@0 3300 }
michael@0 3301
michael@0 3302 case 4:
michael@0 3303 {
michael@0 3304 #ifdef PNG_READ_GAMMA_SUPPORTED
michael@0 3305 if (gamma_table != NULL)
michael@0 3306 {
michael@0 3307 sp = row;
michael@0 3308 shift = 4;
michael@0 3309 for (i = 0; i < row_width; i++)
michael@0 3310 {
michael@0 3311 if ((png_uint_16)((*sp >> shift) & 0x0f)
michael@0 3312 == png_ptr->trans_color.gray)
michael@0 3313 {
michael@0 3314 unsigned int tmp = *sp & (0xf0f >> (4 - shift));
michael@0 3315 tmp |= png_ptr->background.gray << shift;
michael@0 3316 *sp = (png_byte)(tmp & 0xff);
michael@0 3317 }
michael@0 3318
michael@0 3319 else
michael@0 3320 {
michael@0 3321 unsigned int p = (*sp >> shift) & 0x0f;
michael@0 3322 unsigned int g = (gamma_table[p | (p << 4)] >> 4) &
michael@0 3323 0x0f;
michael@0 3324 unsigned int tmp = *sp & (0xf0f >> (4 - shift));
michael@0 3325 tmp |= g << shift;
michael@0 3326 *sp = (png_byte)(tmp & 0xff);
michael@0 3327 }
michael@0 3328
michael@0 3329 if (!shift)
michael@0 3330 {
michael@0 3331 shift = 4;
michael@0 3332 sp++;
michael@0 3333 }
michael@0 3334
michael@0 3335 else
michael@0 3336 shift -= 4;
michael@0 3337 }
michael@0 3338 }
michael@0 3339
michael@0 3340 else
michael@0 3341 #endif
michael@0 3342 {
michael@0 3343 sp = row;
michael@0 3344 shift = 4;
michael@0 3345 for (i = 0; i < row_width; i++)
michael@0 3346 {
michael@0 3347 if ((png_uint_16)((*sp >> shift) & 0x0f)
michael@0 3348 == png_ptr->trans_color.gray)
michael@0 3349 {
michael@0 3350 unsigned int tmp = *sp & (0xf0f >> (4 - shift));
michael@0 3351 tmp |= png_ptr->background.gray << shift;
michael@0 3352 *sp = (png_byte)(tmp & 0xff);
michael@0 3353 }
michael@0 3354
michael@0 3355 if (!shift)
michael@0 3356 {
michael@0 3357 shift = 4;
michael@0 3358 sp++;
michael@0 3359 }
michael@0 3360
michael@0 3361 else
michael@0 3362 shift -= 4;
michael@0 3363 }
michael@0 3364 }
michael@0 3365 break;
michael@0 3366 }
michael@0 3367
michael@0 3368 case 8:
michael@0 3369 {
michael@0 3370 #ifdef PNG_READ_GAMMA_SUPPORTED
michael@0 3371 if (gamma_table != NULL)
michael@0 3372 {
michael@0 3373 sp = row;
michael@0 3374 for (i = 0; i < row_width; i++, sp++)
michael@0 3375 {
michael@0 3376 if (*sp == png_ptr->trans_color.gray)
michael@0 3377 *sp = (png_byte)png_ptr->background.gray;
michael@0 3378
michael@0 3379 else
michael@0 3380 *sp = gamma_table[*sp];
michael@0 3381 }
michael@0 3382 }
michael@0 3383 else
michael@0 3384 #endif
michael@0 3385 {
michael@0 3386 sp = row;
michael@0 3387 for (i = 0; i < row_width; i++, sp++)
michael@0 3388 {
michael@0 3389 if (*sp == png_ptr->trans_color.gray)
michael@0 3390 *sp = (png_byte)png_ptr->background.gray;
michael@0 3391 }
michael@0 3392 }
michael@0 3393 break;
michael@0 3394 }
michael@0 3395
michael@0 3396 case 16:
michael@0 3397 {
michael@0 3398 #ifdef PNG_READ_GAMMA_SUPPORTED
michael@0 3399 if (gamma_16 != NULL)
michael@0 3400 {
michael@0 3401 sp = row;
michael@0 3402 for (i = 0; i < row_width; i++, sp += 2)
michael@0 3403 {
michael@0 3404 png_uint_16 v;
michael@0 3405
michael@0 3406 v = (png_uint_16)(((*sp) << 8) + *(sp + 1));
michael@0 3407
michael@0 3408 if (v == png_ptr->trans_color.gray)
michael@0 3409 {
michael@0 3410 /* Background is already in screen gamma */
michael@0 3411 *sp = (png_byte)((png_ptr->background.gray >> 8)
michael@0 3412 & 0xff);
michael@0 3413 *(sp + 1) = (png_byte)(png_ptr->background.gray
michael@0 3414 & 0xff);
michael@0 3415 }
michael@0 3416
michael@0 3417 else
michael@0 3418 {
michael@0 3419 v = gamma_16[*(sp + 1) >> gamma_shift][*sp];
michael@0 3420 *sp = (png_byte)((v >> 8) & 0xff);
michael@0 3421 *(sp + 1) = (png_byte)(v & 0xff);
michael@0 3422 }
michael@0 3423 }
michael@0 3424 }
michael@0 3425 else
michael@0 3426 #endif
michael@0 3427 {
michael@0 3428 sp = row;
michael@0 3429 for (i = 0; i < row_width; i++, sp += 2)
michael@0 3430 {
michael@0 3431 png_uint_16 v;
michael@0 3432
michael@0 3433 v = (png_uint_16)(((*sp) << 8) + *(sp + 1));
michael@0 3434
michael@0 3435 if (v == png_ptr->trans_color.gray)
michael@0 3436 {
michael@0 3437 *sp = (png_byte)((png_ptr->background.gray >> 8)
michael@0 3438 & 0xff);
michael@0 3439 *(sp + 1) = (png_byte)(png_ptr->background.gray
michael@0 3440 & 0xff);
michael@0 3441 }
michael@0 3442 }
michael@0 3443 }
michael@0 3444 break;
michael@0 3445 }
michael@0 3446
michael@0 3447 default:
michael@0 3448 break;
michael@0 3449 }
michael@0 3450 break;
michael@0 3451 }
michael@0 3452
michael@0 3453 case PNG_COLOR_TYPE_RGB:
michael@0 3454 {
michael@0 3455 if (row_info->bit_depth == 8)
michael@0 3456 {
michael@0 3457 #ifdef PNG_READ_GAMMA_SUPPORTED
michael@0 3458 if (gamma_table != NULL)
michael@0 3459 {
michael@0 3460 sp = row;
michael@0 3461 for (i = 0; i < row_width; i++, sp += 3)
michael@0 3462 {
michael@0 3463 if (*sp == png_ptr->trans_color.red &&
michael@0 3464 *(sp + 1) == png_ptr->trans_color.green &&
michael@0 3465 *(sp + 2) == png_ptr->trans_color.blue)
michael@0 3466 {
michael@0 3467 *sp = (png_byte)png_ptr->background.red;
michael@0 3468 *(sp + 1) = (png_byte)png_ptr->background.green;
michael@0 3469 *(sp + 2) = (png_byte)png_ptr->background.blue;
michael@0 3470 }
michael@0 3471
michael@0 3472 else
michael@0 3473 {
michael@0 3474 *sp = gamma_table[*sp];
michael@0 3475 *(sp + 1) = gamma_table[*(sp + 1)];
michael@0 3476 *(sp + 2) = gamma_table[*(sp + 2)];
michael@0 3477 }
michael@0 3478 }
michael@0 3479 }
michael@0 3480 else
michael@0 3481 #endif
michael@0 3482 {
michael@0 3483 sp = row;
michael@0 3484 for (i = 0; i < row_width; i++, sp += 3)
michael@0 3485 {
michael@0 3486 if (*sp == png_ptr->trans_color.red &&
michael@0 3487 *(sp + 1) == png_ptr->trans_color.green &&
michael@0 3488 *(sp + 2) == png_ptr->trans_color.blue)
michael@0 3489 {
michael@0 3490 *sp = (png_byte)png_ptr->background.red;
michael@0 3491 *(sp + 1) = (png_byte)png_ptr->background.green;
michael@0 3492 *(sp + 2) = (png_byte)png_ptr->background.blue;
michael@0 3493 }
michael@0 3494 }
michael@0 3495 }
michael@0 3496 }
michael@0 3497 else /* if (row_info->bit_depth == 16) */
michael@0 3498 {
michael@0 3499 #ifdef PNG_READ_GAMMA_SUPPORTED
michael@0 3500 if (gamma_16 != NULL)
michael@0 3501 {
michael@0 3502 sp = row;
michael@0 3503 for (i = 0; i < row_width; i++, sp += 6)
michael@0 3504 {
michael@0 3505 png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp + 1));
michael@0 3506
michael@0 3507 png_uint_16 g = (png_uint_16)(((*(sp + 2)) << 8)
michael@0 3508 + *(sp + 3));
michael@0 3509
michael@0 3510 png_uint_16 b = (png_uint_16)(((*(sp + 4)) << 8)
michael@0 3511 + *(sp + 5));
michael@0 3512
michael@0 3513 if (r == png_ptr->trans_color.red &&
michael@0 3514 g == png_ptr->trans_color.green &&
michael@0 3515 b == png_ptr->trans_color.blue)
michael@0 3516 {
michael@0 3517 /* Background is already in screen gamma */
michael@0 3518 *sp = (png_byte)((png_ptr->background.red >> 8) & 0xff);
michael@0 3519 *(sp + 1) = (png_byte)(png_ptr->background.red & 0xff);
michael@0 3520 *(sp + 2) = (png_byte)((png_ptr->background.green >> 8)
michael@0 3521 & 0xff);
michael@0 3522 *(sp + 3) = (png_byte)(png_ptr->background.green
michael@0 3523 & 0xff);
michael@0 3524 *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8)
michael@0 3525 & 0xff);
michael@0 3526 *(sp + 5) = (png_byte)(png_ptr->background.blue & 0xff);
michael@0 3527 }
michael@0 3528
michael@0 3529 else
michael@0 3530 {
michael@0 3531 png_uint_16 v = gamma_16[*(sp + 1) >> gamma_shift][*sp];
michael@0 3532 *sp = (png_byte)((v >> 8) & 0xff);
michael@0 3533 *(sp + 1) = (png_byte)(v & 0xff);
michael@0 3534
michael@0 3535 v = gamma_16[*(sp + 3) >> gamma_shift][*(sp + 2)];
michael@0 3536 *(sp + 2) = (png_byte)((v >> 8) & 0xff);
michael@0 3537 *(sp + 3) = (png_byte)(v & 0xff);
michael@0 3538
michael@0 3539 v = gamma_16[*(sp + 5) >> gamma_shift][*(sp + 4)];
michael@0 3540 *(sp + 4) = (png_byte)((v >> 8) & 0xff);
michael@0 3541 *(sp + 5) = (png_byte)(v & 0xff);
michael@0 3542 }
michael@0 3543 }
michael@0 3544 }
michael@0 3545
michael@0 3546 else
michael@0 3547 #endif
michael@0 3548 {
michael@0 3549 sp = row;
michael@0 3550 for (i = 0; i < row_width; i++, sp += 6)
michael@0 3551 {
michael@0 3552 png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp + 1));
michael@0 3553
michael@0 3554 png_uint_16 g = (png_uint_16)(((*(sp + 2)) << 8)
michael@0 3555 + *(sp + 3));
michael@0 3556
michael@0 3557 png_uint_16 b = (png_uint_16)(((*(sp + 4)) << 8)
michael@0 3558 + *(sp + 5));
michael@0 3559
michael@0 3560 if (r == png_ptr->trans_color.red &&
michael@0 3561 g == png_ptr->trans_color.green &&
michael@0 3562 b == png_ptr->trans_color.blue)
michael@0 3563 {
michael@0 3564 *sp = (png_byte)((png_ptr->background.red >> 8) & 0xff);
michael@0 3565 *(sp + 1) = (png_byte)(png_ptr->background.red & 0xff);
michael@0 3566 *(sp + 2) = (png_byte)((png_ptr->background.green >> 8)
michael@0 3567 & 0xff);
michael@0 3568 *(sp + 3) = (png_byte)(png_ptr->background.green
michael@0 3569 & 0xff);
michael@0 3570 *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8)
michael@0 3571 & 0xff);
michael@0 3572 *(sp + 5) = (png_byte)(png_ptr->background.blue & 0xff);
michael@0 3573 }
michael@0 3574 }
michael@0 3575 }
michael@0 3576 }
michael@0 3577 break;
michael@0 3578 }
michael@0 3579
michael@0 3580 case PNG_COLOR_TYPE_GRAY_ALPHA:
michael@0 3581 {
michael@0 3582 if (row_info->bit_depth == 8)
michael@0 3583 {
michael@0 3584 #ifdef PNG_READ_GAMMA_SUPPORTED
michael@0 3585 if (gamma_to_1 != NULL && gamma_from_1 != NULL &&
michael@0 3586 gamma_table != NULL)
michael@0 3587 {
michael@0 3588 sp = row;
michael@0 3589 for (i = 0; i < row_width; i++, sp += 2)
michael@0 3590 {
michael@0 3591 png_uint_16 a = *(sp + 1);
michael@0 3592
michael@0 3593 if (a == 0xff)
michael@0 3594 *sp = gamma_table[*sp];
michael@0 3595
michael@0 3596 else if (a == 0)
michael@0 3597 {
michael@0 3598 /* Background is already in screen gamma */
michael@0 3599 *sp = (png_byte)png_ptr->background.gray;
michael@0 3600 }
michael@0 3601
michael@0 3602 else
michael@0 3603 {
michael@0 3604 png_byte v, w;
michael@0 3605
michael@0 3606 v = gamma_to_1[*sp];
michael@0 3607 png_composite(w, v, a, png_ptr->background_1.gray);
michael@0 3608 if (!optimize)
michael@0 3609 w = gamma_from_1[w];
michael@0 3610 *sp = w;
michael@0 3611 }
michael@0 3612 }
michael@0 3613 }
michael@0 3614 else
michael@0 3615 #endif
michael@0 3616 {
michael@0 3617 sp = row;
michael@0 3618 for (i = 0; i < row_width; i++, sp += 2)
michael@0 3619 {
michael@0 3620 png_byte a = *(sp + 1);
michael@0 3621
michael@0 3622 if (a == 0)
michael@0 3623 *sp = (png_byte)png_ptr->background.gray;
michael@0 3624
michael@0 3625 else if (a < 0xff)
michael@0 3626 png_composite(*sp, *sp, a, png_ptr->background.gray);
michael@0 3627 }
michael@0 3628 }
michael@0 3629 }
michael@0 3630 else /* if (png_ptr->bit_depth == 16) */
michael@0 3631 {
michael@0 3632 #ifdef PNG_READ_GAMMA_SUPPORTED
michael@0 3633 if (gamma_16 != NULL && gamma_16_from_1 != NULL &&
michael@0 3634 gamma_16_to_1 != NULL)
michael@0 3635 {
michael@0 3636 sp = row;
michael@0 3637 for (i = 0; i < row_width; i++, sp += 4)
michael@0 3638 {
michael@0 3639 png_uint_16 a = (png_uint_16)(((*(sp + 2)) << 8)
michael@0 3640 + *(sp + 3));
michael@0 3641
michael@0 3642 if (a == (png_uint_16)0xffff)
michael@0 3643 {
michael@0 3644 png_uint_16 v;
michael@0 3645
michael@0 3646 v = gamma_16[*(sp + 1) >> gamma_shift][*sp];
michael@0 3647 *sp = (png_byte)((v >> 8) & 0xff);
michael@0 3648 *(sp + 1) = (png_byte)(v & 0xff);
michael@0 3649 }
michael@0 3650
michael@0 3651 else if (a == 0)
michael@0 3652 {
michael@0 3653 /* Background is already in screen gamma */
michael@0 3654 *sp = (png_byte)((png_ptr->background.gray >> 8)
michael@0 3655 & 0xff);
michael@0 3656 *(sp + 1) = (png_byte)(png_ptr->background.gray & 0xff);
michael@0 3657 }
michael@0 3658
michael@0 3659 else
michael@0 3660 {
michael@0 3661 png_uint_16 g, v, w;
michael@0 3662
michael@0 3663 g = gamma_16_to_1[*(sp + 1) >> gamma_shift][*sp];
michael@0 3664 png_composite_16(v, g, a, png_ptr->background_1.gray);
michael@0 3665 if (optimize)
michael@0 3666 w = v;
michael@0 3667 else
michael@0 3668 w = gamma_16_from_1[(v&0xff) >> gamma_shift][v >> 8];
michael@0 3669 *sp = (png_byte)((w >> 8) & 0xff);
michael@0 3670 *(sp + 1) = (png_byte)(w & 0xff);
michael@0 3671 }
michael@0 3672 }
michael@0 3673 }
michael@0 3674 else
michael@0 3675 #endif
michael@0 3676 {
michael@0 3677 sp = row;
michael@0 3678 for (i = 0; i < row_width; i++, sp += 4)
michael@0 3679 {
michael@0 3680 png_uint_16 a = (png_uint_16)(((*(sp + 2)) << 8)
michael@0 3681 + *(sp + 3));
michael@0 3682
michael@0 3683 if (a == 0)
michael@0 3684 {
michael@0 3685 *sp = (png_byte)((png_ptr->background.gray >> 8)
michael@0 3686 & 0xff);
michael@0 3687 *(sp + 1) = (png_byte)(png_ptr->background.gray & 0xff);
michael@0 3688 }
michael@0 3689
michael@0 3690 else if (a < 0xffff)
michael@0 3691 {
michael@0 3692 png_uint_16 g, v;
michael@0 3693
michael@0 3694 g = (png_uint_16)(((*sp) << 8) + *(sp + 1));
michael@0 3695 png_composite_16(v, g, a, png_ptr->background.gray);
michael@0 3696 *sp = (png_byte)((v >> 8) & 0xff);
michael@0 3697 *(sp + 1) = (png_byte)(v & 0xff);
michael@0 3698 }
michael@0 3699 }
michael@0 3700 }
michael@0 3701 }
michael@0 3702 break;
michael@0 3703 }
michael@0 3704
michael@0 3705 case PNG_COLOR_TYPE_RGB_ALPHA:
michael@0 3706 {
michael@0 3707 if (row_info->bit_depth == 8)
michael@0 3708 {
michael@0 3709 #ifdef PNG_READ_GAMMA_SUPPORTED
michael@0 3710 if (gamma_to_1 != NULL && gamma_from_1 != NULL &&
michael@0 3711 gamma_table != NULL)
michael@0 3712 {
michael@0 3713 sp = row;
michael@0 3714 for (i = 0; i < row_width; i++, sp += 4)
michael@0 3715 {
michael@0 3716 png_byte a = *(sp + 3);
michael@0 3717
michael@0 3718 if (a == 0xff)
michael@0 3719 {
michael@0 3720 *sp = gamma_table[*sp];
michael@0 3721 *(sp + 1) = gamma_table[*(sp + 1)];
michael@0 3722 *(sp + 2) = gamma_table[*(sp + 2)];
michael@0 3723 }
michael@0 3724
michael@0 3725 else if (a == 0)
michael@0 3726 {
michael@0 3727 /* Background is already in screen gamma */
michael@0 3728 *sp = (png_byte)png_ptr->background.red;
michael@0 3729 *(sp + 1) = (png_byte)png_ptr->background.green;
michael@0 3730 *(sp + 2) = (png_byte)png_ptr->background.blue;
michael@0 3731 }
michael@0 3732
michael@0 3733 else
michael@0 3734 {
michael@0 3735 png_byte v, w;
michael@0 3736
michael@0 3737 v = gamma_to_1[*sp];
michael@0 3738 png_composite(w, v, a, png_ptr->background_1.red);
michael@0 3739 if (!optimize) w = gamma_from_1[w];
michael@0 3740 *sp = w;
michael@0 3741
michael@0 3742 v = gamma_to_1[*(sp + 1)];
michael@0 3743 png_composite(w, v, a, png_ptr->background_1.green);
michael@0 3744 if (!optimize) w = gamma_from_1[w];
michael@0 3745 *(sp + 1) = w;
michael@0 3746
michael@0 3747 v = gamma_to_1[*(sp + 2)];
michael@0 3748 png_composite(w, v, a, png_ptr->background_1.blue);
michael@0 3749 if (!optimize) w = gamma_from_1[w];
michael@0 3750 *(sp + 2) = w;
michael@0 3751 }
michael@0 3752 }
michael@0 3753 }
michael@0 3754 else
michael@0 3755 #endif
michael@0 3756 {
michael@0 3757 sp = row;
michael@0 3758 for (i = 0; i < row_width; i++, sp += 4)
michael@0 3759 {
michael@0 3760 png_byte a = *(sp + 3);
michael@0 3761
michael@0 3762 if (a == 0)
michael@0 3763 {
michael@0 3764 *sp = (png_byte)png_ptr->background.red;
michael@0 3765 *(sp + 1) = (png_byte)png_ptr->background.green;
michael@0 3766 *(sp + 2) = (png_byte)png_ptr->background.blue;
michael@0 3767 }
michael@0 3768
michael@0 3769 else if (a < 0xff)
michael@0 3770 {
michael@0 3771 png_composite(*sp, *sp, a, png_ptr->background.red);
michael@0 3772
michael@0 3773 png_composite(*(sp + 1), *(sp + 1), a,
michael@0 3774 png_ptr->background.green);
michael@0 3775
michael@0 3776 png_composite(*(sp + 2), *(sp + 2), a,
michael@0 3777 png_ptr->background.blue);
michael@0 3778 }
michael@0 3779 }
michael@0 3780 }
michael@0 3781 }
michael@0 3782 else /* if (row_info->bit_depth == 16) */
michael@0 3783 {
michael@0 3784 #ifdef PNG_READ_GAMMA_SUPPORTED
michael@0 3785 if (gamma_16 != NULL && gamma_16_from_1 != NULL &&
michael@0 3786 gamma_16_to_1 != NULL)
michael@0 3787 {
michael@0 3788 sp = row;
michael@0 3789 for (i = 0; i < row_width; i++, sp += 8)
michael@0 3790 {
michael@0 3791 png_uint_16 a = (png_uint_16)(((png_uint_16)(*(sp + 6))
michael@0 3792 << 8) + (png_uint_16)(*(sp + 7)));
michael@0 3793
michael@0 3794 if (a == (png_uint_16)0xffff)
michael@0 3795 {
michael@0 3796 png_uint_16 v;
michael@0 3797
michael@0 3798 v = gamma_16[*(sp + 1) >> gamma_shift][*sp];
michael@0 3799 *sp = (png_byte)((v >> 8) & 0xff);
michael@0 3800 *(sp + 1) = (png_byte)(v & 0xff);
michael@0 3801
michael@0 3802 v = gamma_16[*(sp + 3) >> gamma_shift][*(sp + 2)];
michael@0 3803 *(sp + 2) = (png_byte)((v >> 8) & 0xff);
michael@0 3804 *(sp + 3) = (png_byte)(v & 0xff);
michael@0 3805
michael@0 3806 v = gamma_16[*(sp + 5) >> gamma_shift][*(sp + 4)];
michael@0 3807 *(sp + 4) = (png_byte)((v >> 8) & 0xff);
michael@0 3808 *(sp + 5) = (png_byte)(v & 0xff);
michael@0 3809 }
michael@0 3810
michael@0 3811 else if (a == 0)
michael@0 3812 {
michael@0 3813 /* Background is already in screen gamma */
michael@0 3814 *sp = (png_byte)((png_ptr->background.red >> 8) & 0xff);
michael@0 3815 *(sp + 1) = (png_byte)(png_ptr->background.red & 0xff);
michael@0 3816 *(sp + 2) = (png_byte)((png_ptr->background.green >> 8)
michael@0 3817 & 0xff);
michael@0 3818 *(sp + 3) = (png_byte)(png_ptr->background.green
michael@0 3819 & 0xff);
michael@0 3820 *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8)
michael@0 3821 & 0xff);
michael@0 3822 *(sp + 5) = (png_byte)(png_ptr->background.blue & 0xff);
michael@0 3823 }
michael@0 3824
michael@0 3825 else
michael@0 3826 {
michael@0 3827 png_uint_16 v, w;
michael@0 3828
michael@0 3829 v = gamma_16_to_1[*(sp + 1) >> gamma_shift][*sp];
michael@0 3830 png_composite_16(w, v, a, png_ptr->background_1.red);
michael@0 3831 if (!optimize)
michael@0 3832 w = gamma_16_from_1[((w&0xff) >> gamma_shift)][w >>
michael@0 3833 8];
michael@0 3834 *sp = (png_byte)((w >> 8) & 0xff);
michael@0 3835 *(sp + 1) = (png_byte)(w & 0xff);
michael@0 3836
michael@0 3837 v = gamma_16_to_1[*(sp + 3) >> gamma_shift][*(sp + 2)];
michael@0 3838 png_composite_16(w, v, a, png_ptr->background_1.green);
michael@0 3839 if (!optimize)
michael@0 3840 w = gamma_16_from_1[((w&0xff) >> gamma_shift)][w >>
michael@0 3841 8];
michael@0 3842
michael@0 3843 *(sp + 2) = (png_byte)((w >> 8) & 0xff);
michael@0 3844 *(sp + 3) = (png_byte)(w & 0xff);
michael@0 3845
michael@0 3846 v = gamma_16_to_1[*(sp + 5) >> gamma_shift][*(sp + 4)];
michael@0 3847 png_composite_16(w, v, a, png_ptr->background_1.blue);
michael@0 3848 if (!optimize)
michael@0 3849 w = gamma_16_from_1[((w&0xff) >> gamma_shift)][w >>
michael@0 3850 8];
michael@0 3851
michael@0 3852 *(sp + 4) = (png_byte)((w >> 8) & 0xff);
michael@0 3853 *(sp + 5) = (png_byte)(w & 0xff);
michael@0 3854 }
michael@0 3855 }
michael@0 3856 }
michael@0 3857
michael@0 3858 else
michael@0 3859 #endif
michael@0 3860 {
michael@0 3861 sp = row;
michael@0 3862 for (i = 0; i < row_width; i++, sp += 8)
michael@0 3863 {
michael@0 3864 png_uint_16 a = (png_uint_16)(((png_uint_16)(*(sp + 6))
michael@0 3865 << 8) + (png_uint_16)(*(sp + 7)));
michael@0 3866
michael@0 3867 if (a == 0)
michael@0 3868 {
michael@0 3869 *sp = (png_byte)((png_ptr->background.red >> 8) & 0xff);
michael@0 3870 *(sp + 1) = (png_byte)(png_ptr->background.red & 0xff);
michael@0 3871 *(sp + 2) = (png_byte)((png_ptr->background.green >> 8)
michael@0 3872 & 0xff);
michael@0 3873 *(sp + 3) = (png_byte)(png_ptr->background.green
michael@0 3874 & 0xff);
michael@0 3875 *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8)
michael@0 3876 & 0xff);
michael@0 3877 *(sp + 5) = (png_byte)(png_ptr->background.blue & 0xff);
michael@0 3878 }
michael@0 3879
michael@0 3880 else if (a < 0xffff)
michael@0 3881 {
michael@0 3882 png_uint_16 v;
michael@0 3883
michael@0 3884 png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp + 1));
michael@0 3885 png_uint_16 g = (png_uint_16)(((*(sp + 2)) << 8)
michael@0 3886 + *(sp + 3));
michael@0 3887 png_uint_16 b = (png_uint_16)(((*(sp + 4)) << 8)
michael@0 3888 + *(sp + 5));
michael@0 3889
michael@0 3890 png_composite_16(v, r, a, png_ptr->background.red);
michael@0 3891 *sp = (png_byte)((v >> 8) & 0xff);
michael@0 3892 *(sp + 1) = (png_byte)(v & 0xff);
michael@0 3893
michael@0 3894 png_composite_16(v, g, a, png_ptr->background.green);
michael@0 3895 *(sp + 2) = (png_byte)((v >> 8) & 0xff);
michael@0 3896 *(sp + 3) = (png_byte)(v & 0xff);
michael@0 3897
michael@0 3898 png_composite_16(v, b, a, png_ptr->background.blue);
michael@0 3899 *(sp + 4) = (png_byte)((v >> 8) & 0xff);
michael@0 3900 *(sp + 5) = (png_byte)(v & 0xff);
michael@0 3901 }
michael@0 3902 }
michael@0 3903 }
michael@0 3904 }
michael@0 3905 break;
michael@0 3906 }
michael@0 3907
michael@0 3908 default:
michael@0 3909 break;
michael@0 3910 }
michael@0 3911 }
michael@0 3912 }
michael@0 3913 #endif /* PNG_READ_BACKGROUND_SUPPORTED || PNG_READ_ALPHA_MODE_SUPPORTED */
michael@0 3914
michael@0 3915 #ifdef PNG_READ_GAMMA_SUPPORTED
michael@0 3916 /* Gamma correct the image, avoiding the alpha channel. Make sure
michael@0 3917 * you do this after you deal with the transparency issue on grayscale
michael@0 3918 * or RGB images. If your bit depth is 8, use gamma_table, if it
michael@0 3919 * is 16, use gamma_16_table and gamma_shift. Build these with
michael@0 3920 * build_gamma_table().
michael@0 3921 */
michael@0 3922 static void
michael@0 3923 png_do_gamma(png_row_infop row_info, png_bytep row, png_structrp png_ptr)
michael@0 3924 {
michael@0 3925 png_const_bytep gamma_table = png_ptr->gamma_table;
michael@0 3926 png_const_uint_16pp gamma_16_table = png_ptr->gamma_16_table;
michael@0 3927 int gamma_shift = png_ptr->gamma_shift;
michael@0 3928
michael@0 3929 png_bytep sp;
michael@0 3930 png_uint_32 i;
michael@0 3931 png_uint_32 row_width=row_info->width;
michael@0 3932
michael@0 3933 png_debug(1, "in png_do_gamma");
michael@0 3934
michael@0 3935 if (((row_info->bit_depth <= 8 && gamma_table != NULL) ||
michael@0 3936 (row_info->bit_depth == 16 && gamma_16_table != NULL)))
michael@0 3937 {
michael@0 3938 switch (row_info->color_type)
michael@0 3939 {
michael@0 3940 case PNG_COLOR_TYPE_RGB:
michael@0 3941 {
michael@0 3942 if (row_info->bit_depth == 8)
michael@0 3943 {
michael@0 3944 sp = row;
michael@0 3945 for (i = 0; i < row_width; i++)
michael@0 3946 {
michael@0 3947 *sp = gamma_table[*sp];
michael@0 3948 sp++;
michael@0 3949 *sp = gamma_table[*sp];
michael@0 3950 sp++;
michael@0 3951 *sp = gamma_table[*sp];
michael@0 3952 sp++;
michael@0 3953 }
michael@0 3954 }
michael@0 3955
michael@0 3956 else /* if (row_info->bit_depth == 16) */
michael@0 3957 {
michael@0 3958 sp = row;
michael@0 3959 for (i = 0; i < row_width; i++)
michael@0 3960 {
michael@0 3961 png_uint_16 v;
michael@0 3962
michael@0 3963 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
michael@0 3964 *sp = (png_byte)((v >> 8) & 0xff);
michael@0 3965 *(sp + 1) = (png_byte)(v & 0xff);
michael@0 3966 sp += 2;
michael@0 3967
michael@0 3968 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
michael@0 3969 *sp = (png_byte)((v >> 8) & 0xff);
michael@0 3970 *(sp + 1) = (png_byte)(v & 0xff);
michael@0 3971 sp += 2;
michael@0 3972
michael@0 3973 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
michael@0 3974 *sp = (png_byte)((v >> 8) & 0xff);
michael@0 3975 *(sp + 1) = (png_byte)(v & 0xff);
michael@0 3976 sp += 2;
michael@0 3977 }
michael@0 3978 }
michael@0 3979 break;
michael@0 3980 }
michael@0 3981
michael@0 3982 case PNG_COLOR_TYPE_RGB_ALPHA:
michael@0 3983 {
michael@0 3984 if (row_info->bit_depth == 8)
michael@0 3985 {
michael@0 3986 sp = row;
michael@0 3987 for (i = 0; i < row_width; i++)
michael@0 3988 {
michael@0 3989 *sp = gamma_table[*sp];
michael@0 3990 sp++;
michael@0 3991
michael@0 3992 *sp = gamma_table[*sp];
michael@0 3993 sp++;
michael@0 3994
michael@0 3995 *sp = gamma_table[*sp];
michael@0 3996 sp++;
michael@0 3997
michael@0 3998 sp++;
michael@0 3999 }
michael@0 4000 }
michael@0 4001
michael@0 4002 else /* if (row_info->bit_depth == 16) */
michael@0 4003 {
michael@0 4004 sp = row;
michael@0 4005 for (i = 0; i < row_width; i++)
michael@0 4006 {
michael@0 4007 png_uint_16 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
michael@0 4008 *sp = (png_byte)((v >> 8) & 0xff);
michael@0 4009 *(sp + 1) = (png_byte)(v & 0xff);
michael@0 4010 sp += 2;
michael@0 4011
michael@0 4012 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
michael@0 4013 *sp = (png_byte)((v >> 8) & 0xff);
michael@0 4014 *(sp + 1) = (png_byte)(v & 0xff);
michael@0 4015 sp += 2;
michael@0 4016
michael@0 4017 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
michael@0 4018 *sp = (png_byte)((v >> 8) & 0xff);
michael@0 4019 *(sp + 1) = (png_byte)(v & 0xff);
michael@0 4020 sp += 4;
michael@0 4021 }
michael@0 4022 }
michael@0 4023 break;
michael@0 4024 }
michael@0 4025
michael@0 4026 case PNG_COLOR_TYPE_GRAY_ALPHA:
michael@0 4027 {
michael@0 4028 if (row_info->bit_depth == 8)
michael@0 4029 {
michael@0 4030 sp = row;
michael@0 4031 for (i = 0; i < row_width; i++)
michael@0 4032 {
michael@0 4033 *sp = gamma_table[*sp];
michael@0 4034 sp += 2;
michael@0 4035 }
michael@0 4036 }
michael@0 4037
michael@0 4038 else /* if (row_info->bit_depth == 16) */
michael@0 4039 {
michael@0 4040 sp = row;
michael@0 4041 for (i = 0; i < row_width; i++)
michael@0 4042 {
michael@0 4043 png_uint_16 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
michael@0 4044 *sp = (png_byte)((v >> 8) & 0xff);
michael@0 4045 *(sp + 1) = (png_byte)(v & 0xff);
michael@0 4046 sp += 4;
michael@0 4047 }
michael@0 4048 }
michael@0 4049 break;
michael@0 4050 }
michael@0 4051
michael@0 4052 case PNG_COLOR_TYPE_GRAY:
michael@0 4053 {
michael@0 4054 if (row_info->bit_depth == 2)
michael@0 4055 {
michael@0 4056 sp = row;
michael@0 4057 for (i = 0; i < row_width; i += 4)
michael@0 4058 {
michael@0 4059 int a = *sp & 0xc0;
michael@0 4060 int b = *sp & 0x30;
michael@0 4061 int c = *sp & 0x0c;
michael@0 4062 int d = *sp & 0x03;
michael@0 4063
michael@0 4064 *sp = (png_byte)(
michael@0 4065 ((((int)gamma_table[a|(a>>2)|(a>>4)|(a>>6)]) ) & 0xc0)|
michael@0 4066 ((((int)gamma_table[(b<<2)|b|(b>>2)|(b>>4)])>>2) & 0x30)|
michael@0 4067 ((((int)gamma_table[(c<<4)|(c<<2)|c|(c>>2)])>>4) & 0x0c)|
michael@0 4068 ((((int)gamma_table[(d<<6)|(d<<4)|(d<<2)|d])>>6) ));
michael@0 4069 sp++;
michael@0 4070 }
michael@0 4071 }
michael@0 4072
michael@0 4073 if (row_info->bit_depth == 4)
michael@0 4074 {
michael@0 4075 sp = row;
michael@0 4076 for (i = 0; i < row_width; i += 2)
michael@0 4077 {
michael@0 4078 int msb = *sp & 0xf0;
michael@0 4079 int lsb = *sp & 0x0f;
michael@0 4080
michael@0 4081 *sp = (png_byte)((((int)gamma_table[msb | (msb >> 4)]) & 0xf0)
michael@0 4082 | (((int)gamma_table[(lsb << 4) | lsb]) >> 4));
michael@0 4083 sp++;
michael@0 4084 }
michael@0 4085 }
michael@0 4086
michael@0 4087 else if (row_info->bit_depth == 8)
michael@0 4088 {
michael@0 4089 sp = row;
michael@0 4090 for (i = 0; i < row_width; i++)
michael@0 4091 {
michael@0 4092 *sp = gamma_table[*sp];
michael@0 4093 sp++;
michael@0 4094 }
michael@0 4095 }
michael@0 4096
michael@0 4097 else if (row_info->bit_depth == 16)
michael@0 4098 {
michael@0 4099 sp = row;
michael@0 4100 for (i = 0; i < row_width; i++)
michael@0 4101 {
michael@0 4102 png_uint_16 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
michael@0 4103 *sp = (png_byte)((v >> 8) & 0xff);
michael@0 4104 *(sp + 1) = (png_byte)(v & 0xff);
michael@0 4105 sp += 2;
michael@0 4106 }
michael@0 4107 }
michael@0 4108 break;
michael@0 4109 }
michael@0 4110
michael@0 4111 default:
michael@0 4112 break;
michael@0 4113 }
michael@0 4114 }
michael@0 4115 }
michael@0 4116 #endif
michael@0 4117
michael@0 4118 #ifdef PNG_READ_ALPHA_MODE_SUPPORTED
michael@0 4119 /* Encode the alpha channel to the output gamma (the input channel is always
michael@0 4120 * linear.) Called only with color types that have an alpha channel. Needs the
michael@0 4121 * from_1 tables.
michael@0 4122 */
michael@0 4123 static void
michael@0 4124 png_do_encode_alpha(png_row_infop row_info, png_bytep row, png_structrp png_ptr)
michael@0 4125 {
michael@0 4126 png_uint_32 row_width = row_info->width;
michael@0 4127
michael@0 4128 png_debug(1, "in png_do_encode_alpha");
michael@0 4129
michael@0 4130 if (row_info->color_type & PNG_COLOR_MASK_ALPHA)
michael@0 4131 {
michael@0 4132 if (row_info->bit_depth == 8)
michael@0 4133 {
michael@0 4134 PNG_CONST png_bytep table = png_ptr->gamma_from_1;
michael@0 4135
michael@0 4136 if (table != NULL)
michael@0 4137 {
michael@0 4138 PNG_CONST int step =
michael@0 4139 (row_info->color_type & PNG_COLOR_MASK_COLOR) ? 4 : 2;
michael@0 4140
michael@0 4141 /* The alpha channel is the last component: */
michael@0 4142 row += step - 1;
michael@0 4143
michael@0 4144 for (; row_width > 0; --row_width, row += step)
michael@0 4145 *row = table[*row];
michael@0 4146
michael@0 4147 return;
michael@0 4148 }
michael@0 4149 }
michael@0 4150
michael@0 4151 else if (row_info->bit_depth == 16)
michael@0 4152 {
michael@0 4153 PNG_CONST png_uint_16pp table = png_ptr->gamma_16_from_1;
michael@0 4154 PNG_CONST int gamma_shift = png_ptr->gamma_shift;
michael@0 4155
michael@0 4156 if (table != NULL)
michael@0 4157 {
michael@0 4158 PNG_CONST int step =
michael@0 4159 (row_info->color_type & PNG_COLOR_MASK_COLOR) ? 8 : 4;
michael@0 4160
michael@0 4161 /* The alpha channel is the last component: */
michael@0 4162 row += step - 2;
michael@0 4163
michael@0 4164 for (; row_width > 0; --row_width, row += step)
michael@0 4165 {
michael@0 4166 png_uint_16 v;
michael@0 4167
michael@0 4168 v = table[*(row + 1) >> gamma_shift][*row];
michael@0 4169 *row = (png_byte)((v >> 8) & 0xff);
michael@0 4170 *(row + 1) = (png_byte)(v & 0xff);
michael@0 4171 }
michael@0 4172
michael@0 4173 return;
michael@0 4174 }
michael@0 4175 }
michael@0 4176 }
michael@0 4177
michael@0 4178 /* Only get to here if called with a weird row_info; no harm has been done,
michael@0 4179 * so just issue a warning.
michael@0 4180 */
michael@0 4181 png_warning(png_ptr, "png_do_encode_alpha: unexpected call");
michael@0 4182 }
michael@0 4183 #endif
michael@0 4184
michael@0 4185 #ifdef PNG_READ_EXPAND_SUPPORTED
michael@0 4186 /* Expands a palette row to an RGB or RGBA row depending
michael@0 4187 * upon whether you supply trans and num_trans.
michael@0 4188 */
michael@0 4189 static void
michael@0 4190 png_do_expand_palette(png_row_infop row_info, png_bytep row,
michael@0 4191 png_const_colorp palette, png_const_bytep trans_alpha, int num_trans)
michael@0 4192 {
michael@0 4193 int shift, value;
michael@0 4194 png_bytep sp, dp;
michael@0 4195 png_uint_32 i;
michael@0 4196 png_uint_32 row_width=row_info->width;
michael@0 4197
michael@0 4198 png_debug(1, "in png_do_expand_palette");
michael@0 4199
michael@0 4200 if (row_info->color_type == PNG_COLOR_TYPE_PALETTE)
michael@0 4201 {
michael@0 4202 if (row_info->bit_depth < 8)
michael@0 4203 {
michael@0 4204 switch (row_info->bit_depth)
michael@0 4205 {
michael@0 4206 case 1:
michael@0 4207 {
michael@0 4208 sp = row + (png_size_t)((row_width - 1) >> 3);
michael@0 4209 dp = row + (png_size_t)row_width - 1;
michael@0 4210 shift = 7 - (int)((row_width + 7) & 0x07);
michael@0 4211 for (i = 0; i < row_width; i++)
michael@0 4212 {
michael@0 4213 if ((*sp >> shift) & 0x01)
michael@0 4214 *dp = 1;
michael@0 4215
michael@0 4216 else
michael@0 4217 *dp = 0;
michael@0 4218
michael@0 4219 if (shift == 7)
michael@0 4220 {
michael@0 4221 shift = 0;
michael@0 4222 sp--;
michael@0 4223 }
michael@0 4224
michael@0 4225 else
michael@0 4226 shift++;
michael@0 4227
michael@0 4228 dp--;
michael@0 4229 }
michael@0 4230 break;
michael@0 4231 }
michael@0 4232
michael@0 4233 case 2:
michael@0 4234 {
michael@0 4235 sp = row + (png_size_t)((row_width - 1) >> 2);
michael@0 4236 dp = row + (png_size_t)row_width - 1;
michael@0 4237 shift = (int)((3 - ((row_width + 3) & 0x03)) << 1);
michael@0 4238 for (i = 0; i < row_width; i++)
michael@0 4239 {
michael@0 4240 value = (*sp >> shift) & 0x03;
michael@0 4241 *dp = (png_byte)value;
michael@0 4242 if (shift == 6)
michael@0 4243 {
michael@0 4244 shift = 0;
michael@0 4245 sp--;
michael@0 4246 }
michael@0 4247
michael@0 4248 else
michael@0 4249 shift += 2;
michael@0 4250
michael@0 4251 dp--;
michael@0 4252 }
michael@0 4253 break;
michael@0 4254 }
michael@0 4255
michael@0 4256 case 4:
michael@0 4257 {
michael@0 4258 sp = row + (png_size_t)((row_width - 1) >> 1);
michael@0 4259 dp = row + (png_size_t)row_width - 1;
michael@0 4260 shift = (int)((row_width & 0x01) << 2);
michael@0 4261 for (i = 0; i < row_width; i++)
michael@0 4262 {
michael@0 4263 value = (*sp >> shift) & 0x0f;
michael@0 4264 *dp = (png_byte)value;
michael@0 4265 if (shift == 4)
michael@0 4266 {
michael@0 4267 shift = 0;
michael@0 4268 sp--;
michael@0 4269 }
michael@0 4270
michael@0 4271 else
michael@0 4272 shift += 4;
michael@0 4273
michael@0 4274 dp--;
michael@0 4275 }
michael@0 4276 break;
michael@0 4277 }
michael@0 4278
michael@0 4279 default:
michael@0 4280 break;
michael@0 4281 }
michael@0 4282 row_info->bit_depth = 8;
michael@0 4283 row_info->pixel_depth = 8;
michael@0 4284 row_info->rowbytes = row_width;
michael@0 4285 }
michael@0 4286
michael@0 4287 if (row_info->bit_depth == 8)
michael@0 4288 {
michael@0 4289 {
michael@0 4290 if (num_trans > 0)
michael@0 4291 {
michael@0 4292 sp = row + (png_size_t)row_width - 1;
michael@0 4293 dp = row + (png_size_t)(row_width << 2) - 1;
michael@0 4294
michael@0 4295 for (i = 0; i < row_width; i++)
michael@0 4296 {
michael@0 4297 if ((int)(*sp) >= num_trans)
michael@0 4298 *dp-- = 0xff;
michael@0 4299
michael@0 4300 else
michael@0 4301 *dp-- = trans_alpha[*sp];
michael@0 4302
michael@0 4303 *dp-- = palette[*sp].blue;
michael@0 4304 *dp-- = palette[*sp].green;
michael@0 4305 *dp-- = palette[*sp].red;
michael@0 4306 sp--;
michael@0 4307 }
michael@0 4308 row_info->bit_depth = 8;
michael@0 4309 row_info->pixel_depth = 32;
michael@0 4310 row_info->rowbytes = row_width * 4;
michael@0 4311 row_info->color_type = 6;
michael@0 4312 row_info->channels = 4;
michael@0 4313 }
michael@0 4314
michael@0 4315 else
michael@0 4316 {
michael@0 4317 sp = row + (png_size_t)row_width - 1;
michael@0 4318 dp = row + (png_size_t)(row_width * 3) - 1;
michael@0 4319
michael@0 4320 for (i = 0; i < row_width; i++)
michael@0 4321 {
michael@0 4322 *dp-- = palette[*sp].blue;
michael@0 4323 *dp-- = palette[*sp].green;
michael@0 4324 *dp-- = palette[*sp].red;
michael@0 4325 sp--;
michael@0 4326 }
michael@0 4327
michael@0 4328 row_info->bit_depth = 8;
michael@0 4329 row_info->pixel_depth = 24;
michael@0 4330 row_info->rowbytes = row_width * 3;
michael@0 4331 row_info->color_type = 2;
michael@0 4332 row_info->channels = 3;
michael@0 4333 }
michael@0 4334 }
michael@0 4335 }
michael@0 4336 }
michael@0 4337 }
michael@0 4338
michael@0 4339 /* If the bit depth < 8, it is expanded to 8. Also, if the already
michael@0 4340 * expanded transparency value is supplied, an alpha channel is built.
michael@0 4341 */
michael@0 4342 static void
michael@0 4343 png_do_expand(png_row_infop row_info, png_bytep row,
michael@0 4344 png_const_color_16p trans_color)
michael@0 4345 {
michael@0 4346 int shift, value;
michael@0 4347 png_bytep sp, dp;
michael@0 4348 png_uint_32 i;
michael@0 4349 png_uint_32 row_width=row_info->width;
michael@0 4350
michael@0 4351 png_debug(1, "in png_do_expand");
michael@0 4352
michael@0 4353 {
michael@0 4354 if (row_info->color_type == PNG_COLOR_TYPE_GRAY)
michael@0 4355 {
michael@0 4356 unsigned int gray = trans_color ? trans_color->gray : 0;
michael@0 4357
michael@0 4358 if (row_info->bit_depth < 8)
michael@0 4359 {
michael@0 4360 switch (row_info->bit_depth)
michael@0 4361 {
michael@0 4362 case 1:
michael@0 4363 {
michael@0 4364 gray = (gray & 0x01) * 0xff;
michael@0 4365 sp = row + (png_size_t)((row_width - 1) >> 3);
michael@0 4366 dp = row + (png_size_t)row_width - 1;
michael@0 4367 shift = 7 - (int)((row_width + 7) & 0x07);
michael@0 4368 for (i = 0; i < row_width; i++)
michael@0 4369 {
michael@0 4370 if ((*sp >> shift) & 0x01)
michael@0 4371 *dp = 0xff;
michael@0 4372
michael@0 4373 else
michael@0 4374 *dp = 0;
michael@0 4375
michael@0 4376 if (shift == 7)
michael@0 4377 {
michael@0 4378 shift = 0;
michael@0 4379 sp--;
michael@0 4380 }
michael@0 4381
michael@0 4382 else
michael@0 4383 shift++;
michael@0 4384
michael@0 4385 dp--;
michael@0 4386 }
michael@0 4387 break;
michael@0 4388 }
michael@0 4389
michael@0 4390 case 2:
michael@0 4391 {
michael@0 4392 gray = (gray & 0x03) * 0x55;
michael@0 4393 sp = row + (png_size_t)((row_width - 1) >> 2);
michael@0 4394 dp = row + (png_size_t)row_width - 1;
michael@0 4395 shift = (int)((3 - ((row_width + 3) & 0x03)) << 1);
michael@0 4396 for (i = 0; i < row_width; i++)
michael@0 4397 {
michael@0 4398 value = (*sp >> shift) & 0x03;
michael@0 4399 *dp = (png_byte)(value | (value << 2) | (value << 4) |
michael@0 4400 (value << 6));
michael@0 4401 if (shift == 6)
michael@0 4402 {
michael@0 4403 shift = 0;
michael@0 4404 sp--;
michael@0 4405 }
michael@0 4406
michael@0 4407 else
michael@0 4408 shift += 2;
michael@0 4409
michael@0 4410 dp--;
michael@0 4411 }
michael@0 4412 break;
michael@0 4413 }
michael@0 4414
michael@0 4415 case 4:
michael@0 4416 {
michael@0 4417 gray = (gray & 0x0f) * 0x11;
michael@0 4418 sp = row + (png_size_t)((row_width - 1) >> 1);
michael@0 4419 dp = row + (png_size_t)row_width - 1;
michael@0 4420 shift = (int)((1 - ((row_width + 1) & 0x01)) << 2);
michael@0 4421 for (i = 0; i < row_width; i++)
michael@0 4422 {
michael@0 4423 value = (*sp >> shift) & 0x0f;
michael@0 4424 *dp = (png_byte)(value | (value << 4));
michael@0 4425 if (shift == 4)
michael@0 4426 {
michael@0 4427 shift = 0;
michael@0 4428 sp--;
michael@0 4429 }
michael@0 4430
michael@0 4431 else
michael@0 4432 shift = 4;
michael@0 4433
michael@0 4434 dp--;
michael@0 4435 }
michael@0 4436 break;
michael@0 4437 }
michael@0 4438
michael@0 4439 default:
michael@0 4440 break;
michael@0 4441 }
michael@0 4442
michael@0 4443 row_info->bit_depth = 8;
michael@0 4444 row_info->pixel_depth = 8;
michael@0 4445 row_info->rowbytes = row_width;
michael@0 4446 }
michael@0 4447
michael@0 4448 if (trans_color != NULL)
michael@0 4449 {
michael@0 4450 if (row_info->bit_depth == 8)
michael@0 4451 {
michael@0 4452 gray = gray & 0xff;
michael@0 4453 sp = row + (png_size_t)row_width - 1;
michael@0 4454 dp = row + (png_size_t)(row_width << 1) - 1;
michael@0 4455
michael@0 4456 for (i = 0; i < row_width; i++)
michael@0 4457 {
michael@0 4458 if (*sp == gray)
michael@0 4459 *dp-- = 0;
michael@0 4460
michael@0 4461 else
michael@0 4462 *dp-- = 0xff;
michael@0 4463
michael@0 4464 *dp-- = *sp--;
michael@0 4465 }
michael@0 4466 }
michael@0 4467
michael@0 4468 else if (row_info->bit_depth == 16)
michael@0 4469 {
michael@0 4470 unsigned int gray_high = (gray >> 8) & 0xff;
michael@0 4471 unsigned int gray_low = gray & 0xff;
michael@0 4472 sp = row + row_info->rowbytes - 1;
michael@0 4473 dp = row + (row_info->rowbytes << 1) - 1;
michael@0 4474 for (i = 0; i < row_width; i++)
michael@0 4475 {
michael@0 4476 if (*(sp - 1) == gray_high && *(sp) == gray_low)
michael@0 4477 {
michael@0 4478 *dp-- = 0;
michael@0 4479 *dp-- = 0;
michael@0 4480 }
michael@0 4481
michael@0 4482 else
michael@0 4483 {
michael@0 4484 *dp-- = 0xff;
michael@0 4485 *dp-- = 0xff;
michael@0 4486 }
michael@0 4487
michael@0 4488 *dp-- = *sp--;
michael@0 4489 *dp-- = *sp--;
michael@0 4490 }
michael@0 4491 }
michael@0 4492
michael@0 4493 row_info->color_type = PNG_COLOR_TYPE_GRAY_ALPHA;
michael@0 4494 row_info->channels = 2;
michael@0 4495 row_info->pixel_depth = (png_byte)(row_info->bit_depth << 1);
michael@0 4496 row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth,
michael@0 4497 row_width);
michael@0 4498 }
michael@0 4499 }
michael@0 4500 else if (row_info->color_type == PNG_COLOR_TYPE_RGB && trans_color)
michael@0 4501 {
michael@0 4502 if (row_info->bit_depth == 8)
michael@0 4503 {
michael@0 4504 png_byte red = (png_byte)(trans_color->red & 0xff);
michael@0 4505 png_byte green = (png_byte)(trans_color->green & 0xff);
michael@0 4506 png_byte blue = (png_byte)(trans_color->blue & 0xff);
michael@0 4507 sp = row + (png_size_t)row_info->rowbytes - 1;
michael@0 4508 dp = row + (png_size_t)(row_width << 2) - 1;
michael@0 4509 for (i = 0; i < row_width; i++)
michael@0 4510 {
michael@0 4511 if (*(sp - 2) == red && *(sp - 1) == green && *(sp) == blue)
michael@0 4512 *dp-- = 0;
michael@0 4513
michael@0 4514 else
michael@0 4515 *dp-- = 0xff;
michael@0 4516
michael@0 4517 *dp-- = *sp--;
michael@0 4518 *dp-- = *sp--;
michael@0 4519 *dp-- = *sp--;
michael@0 4520 }
michael@0 4521 }
michael@0 4522 else if (row_info->bit_depth == 16)
michael@0 4523 {
michael@0 4524 png_byte red_high = (png_byte)((trans_color->red >> 8) & 0xff);
michael@0 4525 png_byte green_high = (png_byte)((trans_color->green >> 8) & 0xff);
michael@0 4526 png_byte blue_high = (png_byte)((trans_color->blue >> 8) & 0xff);
michael@0 4527 png_byte red_low = (png_byte)(trans_color->red & 0xff);
michael@0 4528 png_byte green_low = (png_byte)(trans_color->green & 0xff);
michael@0 4529 png_byte blue_low = (png_byte)(trans_color->blue & 0xff);
michael@0 4530 sp = row + row_info->rowbytes - 1;
michael@0 4531 dp = row + (png_size_t)(row_width << 3) - 1;
michael@0 4532 for (i = 0; i < row_width; i++)
michael@0 4533 {
michael@0 4534 if (*(sp - 5) == red_high &&
michael@0 4535 *(sp - 4) == red_low &&
michael@0 4536 *(sp - 3) == green_high &&
michael@0 4537 *(sp - 2) == green_low &&
michael@0 4538 *(sp - 1) == blue_high &&
michael@0 4539 *(sp ) == blue_low)
michael@0 4540 {
michael@0 4541 *dp-- = 0;
michael@0 4542 *dp-- = 0;
michael@0 4543 }
michael@0 4544
michael@0 4545 else
michael@0 4546 {
michael@0 4547 *dp-- = 0xff;
michael@0 4548 *dp-- = 0xff;
michael@0 4549 }
michael@0 4550
michael@0 4551 *dp-- = *sp--;
michael@0 4552 *dp-- = *sp--;
michael@0 4553 *dp-- = *sp--;
michael@0 4554 *dp-- = *sp--;
michael@0 4555 *dp-- = *sp--;
michael@0 4556 *dp-- = *sp--;
michael@0 4557 }
michael@0 4558 }
michael@0 4559 row_info->color_type = PNG_COLOR_TYPE_RGB_ALPHA;
michael@0 4560 row_info->channels = 4;
michael@0 4561 row_info->pixel_depth = (png_byte)(row_info->bit_depth << 2);
michael@0 4562 row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width);
michael@0 4563 }
michael@0 4564 }
michael@0 4565 }
michael@0 4566 #endif
michael@0 4567
michael@0 4568 #ifdef PNG_READ_EXPAND_16_SUPPORTED
michael@0 4569 /* If the bit depth is 8 and the color type is not a palette type expand the
michael@0 4570 * whole row to 16 bits. Has no effect otherwise.
michael@0 4571 */
michael@0 4572 static void
michael@0 4573 png_do_expand_16(png_row_infop row_info, png_bytep row)
michael@0 4574 {
michael@0 4575 if (row_info->bit_depth == 8 &&
michael@0 4576 row_info->color_type != PNG_COLOR_TYPE_PALETTE)
michael@0 4577 {
michael@0 4578 /* The row have a sequence of bytes containing [0..255] and we need
michael@0 4579 * to turn it into another row containing [0..65535], to do this we
michael@0 4580 * calculate:
michael@0 4581 *
michael@0 4582 * (input / 255) * 65535
michael@0 4583 *
michael@0 4584 * Which happens to be exactly input * 257 and this can be achieved
michael@0 4585 * simply by byte replication in place (copying backwards).
michael@0 4586 */
michael@0 4587 png_byte *sp = row + row_info->rowbytes; /* source, last byte + 1 */
michael@0 4588 png_byte *dp = sp + row_info->rowbytes; /* destination, end + 1 */
michael@0 4589 while (dp > sp)
michael@0 4590 dp[-2] = dp[-1] = *--sp, dp -= 2;
michael@0 4591
michael@0 4592 row_info->rowbytes *= 2;
michael@0 4593 row_info->bit_depth = 16;
michael@0 4594 row_info->pixel_depth = (png_byte)(row_info->channels * 16);
michael@0 4595 }
michael@0 4596 }
michael@0 4597 #endif
michael@0 4598
michael@0 4599 #ifdef PNG_READ_QUANTIZE_SUPPORTED
michael@0 4600 static void
michael@0 4601 png_do_quantize(png_row_infop row_info, png_bytep row,
michael@0 4602 png_const_bytep palette_lookup, png_const_bytep quantize_lookup)
michael@0 4603 {
michael@0 4604 png_bytep sp, dp;
michael@0 4605 png_uint_32 i;
michael@0 4606 png_uint_32 row_width=row_info->width;
michael@0 4607
michael@0 4608 png_debug(1, "in png_do_quantize");
michael@0 4609
michael@0 4610 if (row_info->bit_depth == 8)
michael@0 4611 {
michael@0 4612 if (row_info->color_type == PNG_COLOR_TYPE_RGB && palette_lookup)
michael@0 4613 {
michael@0 4614 int r, g, b, p;
michael@0 4615 sp = row;
michael@0 4616 dp = row;
michael@0 4617 for (i = 0; i < row_width; i++)
michael@0 4618 {
michael@0 4619 r = *sp++;
michael@0 4620 g = *sp++;
michael@0 4621 b = *sp++;
michael@0 4622
michael@0 4623 /* This looks real messy, but the compiler will reduce
michael@0 4624 * it down to a reasonable formula. For example, with
michael@0 4625 * 5 bits per color, we get:
michael@0 4626 * p = (((r >> 3) & 0x1f) << 10) |
michael@0 4627 * (((g >> 3) & 0x1f) << 5) |
michael@0 4628 * ((b >> 3) & 0x1f);
michael@0 4629 */
michael@0 4630 p = (((r >> (8 - PNG_QUANTIZE_RED_BITS)) &
michael@0 4631 ((1 << PNG_QUANTIZE_RED_BITS) - 1)) <<
michael@0 4632 (PNG_QUANTIZE_GREEN_BITS + PNG_QUANTIZE_BLUE_BITS)) |
michael@0 4633 (((g >> (8 - PNG_QUANTIZE_GREEN_BITS)) &
michael@0 4634 ((1 << PNG_QUANTIZE_GREEN_BITS) - 1)) <<
michael@0 4635 (PNG_QUANTIZE_BLUE_BITS)) |
michael@0 4636 ((b >> (8 - PNG_QUANTIZE_BLUE_BITS)) &
michael@0 4637 ((1 << PNG_QUANTIZE_BLUE_BITS) - 1));
michael@0 4638
michael@0 4639 *dp++ = palette_lookup[p];
michael@0 4640 }
michael@0 4641
michael@0 4642 row_info->color_type = PNG_COLOR_TYPE_PALETTE;
michael@0 4643 row_info->channels = 1;
michael@0 4644 row_info->pixel_depth = row_info->bit_depth;
michael@0 4645 row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width);
michael@0 4646 }
michael@0 4647
michael@0 4648 else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA &&
michael@0 4649 palette_lookup != NULL)
michael@0 4650 {
michael@0 4651 int r, g, b, p;
michael@0 4652 sp = row;
michael@0 4653 dp = row;
michael@0 4654 for (i = 0; i < row_width; i++)
michael@0 4655 {
michael@0 4656 r = *sp++;
michael@0 4657 g = *sp++;
michael@0 4658 b = *sp++;
michael@0 4659 sp++;
michael@0 4660
michael@0 4661 p = (((r >> (8 - PNG_QUANTIZE_RED_BITS)) &
michael@0 4662 ((1 << PNG_QUANTIZE_RED_BITS) - 1)) <<
michael@0 4663 (PNG_QUANTIZE_GREEN_BITS + PNG_QUANTIZE_BLUE_BITS)) |
michael@0 4664 (((g >> (8 - PNG_QUANTIZE_GREEN_BITS)) &
michael@0 4665 ((1 << PNG_QUANTIZE_GREEN_BITS) - 1)) <<
michael@0 4666 (PNG_QUANTIZE_BLUE_BITS)) |
michael@0 4667 ((b >> (8 - PNG_QUANTIZE_BLUE_BITS)) &
michael@0 4668 ((1 << PNG_QUANTIZE_BLUE_BITS) - 1));
michael@0 4669
michael@0 4670 *dp++ = palette_lookup[p];
michael@0 4671 }
michael@0 4672
michael@0 4673 row_info->color_type = PNG_COLOR_TYPE_PALETTE;
michael@0 4674 row_info->channels = 1;
michael@0 4675 row_info->pixel_depth = row_info->bit_depth;
michael@0 4676 row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width);
michael@0 4677 }
michael@0 4678
michael@0 4679 else if (row_info->color_type == PNG_COLOR_TYPE_PALETTE &&
michael@0 4680 quantize_lookup)
michael@0 4681 {
michael@0 4682 sp = row;
michael@0 4683
michael@0 4684 for (i = 0; i < row_width; i++, sp++)
michael@0 4685 {
michael@0 4686 *sp = quantize_lookup[*sp];
michael@0 4687 }
michael@0 4688 }
michael@0 4689 }
michael@0 4690 }
michael@0 4691 #endif /* PNG_READ_QUANTIZE_SUPPORTED */
michael@0 4692
michael@0 4693 /* Transform the row. The order of transformations is significant,
michael@0 4694 * and is very touchy. If you add a transformation, take care to
michael@0 4695 * decide how it fits in with the other transformations here.
michael@0 4696 */
michael@0 4697 void /* PRIVATE */
michael@0 4698 png_do_read_transformations(png_structrp png_ptr, png_row_infop row_info)
michael@0 4699 {
michael@0 4700 png_debug(1, "in png_do_read_transformations");
michael@0 4701
michael@0 4702 if (png_ptr->row_buf == NULL)
michael@0 4703 {
michael@0 4704 /* Prior to 1.5.4 this output row/pass where the NULL pointer is, but this
michael@0 4705 * error is incredibly rare and incredibly easy to debug without this
michael@0 4706 * information.
michael@0 4707 */
michael@0 4708 png_error(png_ptr, "NULL row buffer");
michael@0 4709 }
michael@0 4710
michael@0 4711 /* The following is debugging; prior to 1.5.4 the code was never compiled in;
michael@0 4712 * in 1.5.4 PNG_FLAG_DETECT_UNINITIALIZED was added and the macro
michael@0 4713 * PNG_WARN_UNINITIALIZED_ROW removed. In 1.6 the new flag is set only for
michael@0 4714 * all transformations, however in practice the ROW_INIT always gets done on
michael@0 4715 * demand, if necessary.
michael@0 4716 */
michael@0 4717 if ((png_ptr->flags & PNG_FLAG_DETECT_UNINITIALIZED) != 0 &&
michael@0 4718 !(png_ptr->flags & PNG_FLAG_ROW_INIT))
michael@0 4719 {
michael@0 4720 /* Application has failed to call either png_read_start_image() or
michael@0 4721 * png_read_update_info() after setting transforms that expand pixels.
michael@0 4722 * This check added to libpng-1.2.19 (but not enabled until 1.5.4).
michael@0 4723 */
michael@0 4724 png_error(png_ptr, "Uninitialized row");
michael@0 4725 }
michael@0 4726
michael@0 4727 #ifdef PNG_READ_EXPAND_SUPPORTED
michael@0 4728 if (png_ptr->transformations & PNG_EXPAND)
michael@0 4729 {
michael@0 4730 if (row_info->color_type == PNG_COLOR_TYPE_PALETTE)
michael@0 4731 {
michael@0 4732 png_do_expand_palette(row_info, png_ptr->row_buf + 1,
michael@0 4733 png_ptr->palette, png_ptr->trans_alpha, png_ptr->num_trans);
michael@0 4734 }
michael@0 4735
michael@0 4736 else
michael@0 4737 {
michael@0 4738 if (png_ptr->num_trans &&
michael@0 4739 (png_ptr->transformations & PNG_EXPAND_tRNS))
michael@0 4740 png_do_expand(row_info, png_ptr->row_buf + 1,
michael@0 4741 &(png_ptr->trans_color));
michael@0 4742
michael@0 4743 else
michael@0 4744 png_do_expand(row_info, png_ptr->row_buf + 1,
michael@0 4745 NULL);
michael@0 4746 }
michael@0 4747 }
michael@0 4748 #endif
michael@0 4749
michael@0 4750 #ifdef PNG_READ_STRIP_ALPHA_SUPPORTED
michael@0 4751 if ((png_ptr->transformations & PNG_STRIP_ALPHA) &&
michael@0 4752 !(png_ptr->transformations & PNG_COMPOSE) &&
michael@0 4753 (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA ||
michael@0 4754 row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA))
michael@0 4755 png_do_strip_channel(row_info, png_ptr->row_buf + 1,
michael@0 4756 0 /* at_start == false, because SWAP_ALPHA happens later */);
michael@0 4757 #endif
michael@0 4758
michael@0 4759 #ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED
michael@0 4760 if (png_ptr->transformations & PNG_RGB_TO_GRAY)
michael@0 4761 {
michael@0 4762 int rgb_error =
michael@0 4763 png_do_rgb_to_gray(png_ptr, row_info,
michael@0 4764 png_ptr->row_buf + 1);
michael@0 4765
michael@0 4766 if (rgb_error)
michael@0 4767 {
michael@0 4768 png_ptr->rgb_to_gray_status=1;
michael@0 4769 if ((png_ptr->transformations & PNG_RGB_TO_GRAY) ==
michael@0 4770 PNG_RGB_TO_GRAY_WARN)
michael@0 4771 png_warning(png_ptr, "png_do_rgb_to_gray found nongray pixel");
michael@0 4772
michael@0 4773 if ((png_ptr->transformations & PNG_RGB_TO_GRAY) ==
michael@0 4774 PNG_RGB_TO_GRAY_ERR)
michael@0 4775 png_error(png_ptr, "png_do_rgb_to_gray found nongray pixel");
michael@0 4776 }
michael@0 4777 }
michael@0 4778 #endif
michael@0 4779
michael@0 4780 /* From Andreas Dilger e-mail to png-implement, 26 March 1998:
michael@0 4781 *
michael@0 4782 * In most cases, the "simple transparency" should be done prior to doing
michael@0 4783 * gray-to-RGB, or you will have to test 3x as many bytes to check if a
michael@0 4784 * pixel is transparent. You would also need to make sure that the
michael@0 4785 * transparency information is upgraded to RGB.
michael@0 4786 *
michael@0 4787 * To summarize, the current flow is:
michael@0 4788 * - Gray + simple transparency -> compare 1 or 2 gray bytes and composite
michael@0 4789 * with background "in place" if transparent,
michael@0 4790 * convert to RGB if necessary
michael@0 4791 * - Gray + alpha -> composite with gray background and remove alpha bytes,
michael@0 4792 * convert to RGB if necessary
michael@0 4793 *
michael@0 4794 * To support RGB backgrounds for gray images we need:
michael@0 4795 * - Gray + simple transparency -> convert to RGB + simple transparency,
michael@0 4796 * compare 3 or 6 bytes and composite with
michael@0 4797 * background "in place" if transparent
michael@0 4798 * (3x compare/pixel compared to doing
michael@0 4799 * composite with gray bkgrnd)
michael@0 4800 * - Gray + alpha -> convert to RGB + alpha, composite with background and
michael@0 4801 * remove alpha bytes (3x float
michael@0 4802 * operations/pixel compared with composite
michael@0 4803 * on gray background)
michael@0 4804 *
michael@0 4805 * Greg's change will do this. The reason it wasn't done before is for
michael@0 4806 * performance, as this increases the per-pixel operations. If we would check
michael@0 4807 * in advance if the background was gray or RGB, and position the gray-to-RGB
michael@0 4808 * transform appropriately, then it would save a lot of work/time.
michael@0 4809 */
michael@0 4810
michael@0 4811 #ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED
michael@0 4812 /* If gray -> RGB, do so now only if background is non-gray; else do later
michael@0 4813 * for performance reasons
michael@0 4814 */
michael@0 4815 if ((png_ptr->transformations & PNG_GRAY_TO_RGB) &&
michael@0 4816 !(png_ptr->mode & PNG_BACKGROUND_IS_GRAY))
michael@0 4817 png_do_gray_to_rgb(row_info, png_ptr->row_buf + 1);
michael@0 4818 #endif
michael@0 4819
michael@0 4820 #if defined(PNG_READ_BACKGROUND_SUPPORTED) ||\
michael@0 4821 defined(PNG_READ_ALPHA_MODE_SUPPORTED)
michael@0 4822 if (png_ptr->transformations & PNG_COMPOSE)
michael@0 4823 png_do_compose(row_info, png_ptr->row_buf + 1, png_ptr);
michael@0 4824 #endif
michael@0 4825
michael@0 4826 #ifdef PNG_READ_GAMMA_SUPPORTED
michael@0 4827 if ((png_ptr->transformations & PNG_GAMMA) &&
michael@0 4828 #ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED
michael@0 4829 /* Because RGB_TO_GRAY does the gamma transform. */
michael@0 4830 !(png_ptr->transformations & PNG_RGB_TO_GRAY) &&
michael@0 4831 #endif
michael@0 4832 #if defined(PNG_READ_BACKGROUND_SUPPORTED) ||\
michael@0 4833 defined(PNG_READ_ALPHA_MODE_SUPPORTED)
michael@0 4834 /* Because PNG_COMPOSE does the gamma transform if there is something to
michael@0 4835 * do (if there is an alpha channel or transparency.)
michael@0 4836 */
michael@0 4837 !((png_ptr->transformations & PNG_COMPOSE) &&
michael@0 4838 ((png_ptr->num_trans != 0) ||
michael@0 4839 (png_ptr->color_type & PNG_COLOR_MASK_ALPHA))) &&
michael@0 4840 #endif
michael@0 4841 /* Because png_init_read_transformations transforms the palette, unless
michael@0 4842 * RGB_TO_GRAY will do the transform.
michael@0 4843 */
michael@0 4844 (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE))
michael@0 4845 png_do_gamma(row_info, png_ptr->row_buf + 1, png_ptr);
michael@0 4846 #endif
michael@0 4847
michael@0 4848 #ifdef PNG_READ_STRIP_ALPHA_SUPPORTED
michael@0 4849 if ((png_ptr->transformations & PNG_STRIP_ALPHA) &&
michael@0 4850 (png_ptr->transformations & PNG_COMPOSE) &&
michael@0 4851 (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA ||
michael@0 4852 row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA))
michael@0 4853 png_do_strip_channel(row_info, png_ptr->row_buf + 1,
michael@0 4854 0 /* at_start == false, because SWAP_ALPHA happens later */);
michael@0 4855 #endif
michael@0 4856
michael@0 4857 #ifdef PNG_READ_ALPHA_MODE_SUPPORTED
michael@0 4858 if ((png_ptr->transformations & PNG_ENCODE_ALPHA) &&
michael@0 4859 (row_info->color_type & PNG_COLOR_MASK_ALPHA))
michael@0 4860 png_do_encode_alpha(row_info, png_ptr->row_buf + 1, png_ptr);
michael@0 4861 #endif
michael@0 4862
michael@0 4863 #ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED
michael@0 4864 if (png_ptr->transformations & PNG_SCALE_16_TO_8)
michael@0 4865 png_do_scale_16_to_8(row_info, png_ptr->row_buf + 1);
michael@0 4866 #endif
michael@0 4867
michael@0 4868 #ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED
michael@0 4869 /* There is no harm in doing both of these because only one has any effect,
michael@0 4870 * by putting the 'scale' option first if the app asks for scale (either by
michael@0 4871 * calling the API or in a TRANSFORM flag) this is what happens.
michael@0 4872 */
michael@0 4873 if (png_ptr->transformations & PNG_16_TO_8)
michael@0 4874 png_do_chop(row_info, png_ptr->row_buf + 1);
michael@0 4875 #endif
michael@0 4876
michael@0 4877 #ifdef PNG_READ_QUANTIZE_SUPPORTED
michael@0 4878 if (png_ptr->transformations & PNG_QUANTIZE)
michael@0 4879 {
michael@0 4880 png_do_quantize(row_info, png_ptr->row_buf + 1,
michael@0 4881 png_ptr->palette_lookup, png_ptr->quantize_index);
michael@0 4882
michael@0 4883 if (row_info->rowbytes == 0)
michael@0 4884 png_error(png_ptr, "png_do_quantize returned rowbytes=0");
michael@0 4885 }
michael@0 4886 #endif /* PNG_READ_QUANTIZE_SUPPORTED */
michael@0 4887
michael@0 4888 #ifdef PNG_READ_EXPAND_16_SUPPORTED
michael@0 4889 /* Do the expansion now, after all the arithmetic has been done. Notice
michael@0 4890 * that previous transformations can handle the PNG_EXPAND_16 flag if this
michael@0 4891 * is efficient (particularly true in the case of gamma correction, where
michael@0 4892 * better accuracy results faster!)
michael@0 4893 */
michael@0 4894 if (png_ptr->transformations & PNG_EXPAND_16)
michael@0 4895 png_do_expand_16(row_info, png_ptr->row_buf + 1);
michael@0 4896 #endif
michael@0 4897
michael@0 4898 #ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED
michael@0 4899 /* NOTE: moved here in 1.5.4 (from much later in this list.) */
michael@0 4900 if ((png_ptr->transformations & PNG_GRAY_TO_RGB) &&
michael@0 4901 (png_ptr->mode & PNG_BACKGROUND_IS_GRAY))
michael@0 4902 png_do_gray_to_rgb(row_info, png_ptr->row_buf + 1);
michael@0 4903 #endif
michael@0 4904
michael@0 4905 #ifdef PNG_READ_INVERT_SUPPORTED
michael@0 4906 if (png_ptr->transformations & PNG_INVERT_MONO)
michael@0 4907 png_do_invert(row_info, png_ptr->row_buf + 1);
michael@0 4908 #endif
michael@0 4909
michael@0 4910 #ifdef PNG_READ_INVERT_ALPHA_SUPPORTED
michael@0 4911 if (png_ptr->transformations & PNG_INVERT_ALPHA)
michael@0 4912 png_do_read_invert_alpha(row_info, png_ptr->row_buf + 1);
michael@0 4913 #endif
michael@0 4914
michael@0 4915 #ifdef PNG_READ_SHIFT_SUPPORTED
michael@0 4916 if (png_ptr->transformations & PNG_SHIFT)
michael@0 4917 png_do_unshift(row_info, png_ptr->row_buf + 1,
michael@0 4918 &(png_ptr->shift));
michael@0 4919 #endif
michael@0 4920
michael@0 4921 #ifdef PNG_READ_PACK_SUPPORTED
michael@0 4922 if (png_ptr->transformations & PNG_PACK)
michael@0 4923 png_do_unpack(row_info, png_ptr->row_buf + 1);
michael@0 4924 #endif
michael@0 4925
michael@0 4926 #ifdef PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED
michael@0 4927 /* Added at libpng-1.5.10 */
michael@0 4928 if (row_info->color_type == PNG_COLOR_TYPE_PALETTE &&
michael@0 4929 png_ptr->num_palette_max >= 0)
michael@0 4930 png_do_check_palette_indexes(png_ptr, row_info);
michael@0 4931 #endif
michael@0 4932
michael@0 4933 #ifdef PNG_READ_BGR_SUPPORTED
michael@0 4934 if (png_ptr->transformations & PNG_BGR)
michael@0 4935 png_do_bgr(row_info, png_ptr->row_buf + 1);
michael@0 4936 #endif
michael@0 4937
michael@0 4938 #ifdef PNG_READ_PACKSWAP_SUPPORTED
michael@0 4939 if (png_ptr->transformations & PNG_PACKSWAP)
michael@0 4940 png_do_packswap(row_info, png_ptr->row_buf + 1);
michael@0 4941 #endif
michael@0 4942
michael@0 4943 #ifdef PNG_READ_FILLER_SUPPORTED
michael@0 4944 if (png_ptr->transformations & PNG_FILLER)
michael@0 4945 png_do_read_filler(row_info, png_ptr->row_buf + 1,
michael@0 4946 (png_uint_32)png_ptr->filler, png_ptr->flags);
michael@0 4947 #endif
michael@0 4948
michael@0 4949 #ifdef PNG_READ_SWAP_ALPHA_SUPPORTED
michael@0 4950 if (png_ptr->transformations & PNG_SWAP_ALPHA)
michael@0 4951 png_do_read_swap_alpha(row_info, png_ptr->row_buf + 1);
michael@0 4952 #endif
michael@0 4953
michael@0 4954 #ifdef PNG_READ_16BIT_SUPPORTED
michael@0 4955 #ifdef PNG_READ_SWAP_SUPPORTED
michael@0 4956 if (png_ptr->transformations & PNG_SWAP_BYTES)
michael@0 4957 png_do_swap(row_info, png_ptr->row_buf + 1);
michael@0 4958 #endif
michael@0 4959 #endif
michael@0 4960
michael@0 4961 #ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
michael@0 4962 if (png_ptr->transformations & PNG_USER_TRANSFORM)
michael@0 4963 {
michael@0 4964 if (png_ptr->read_user_transform_fn != NULL)
michael@0 4965 (*(png_ptr->read_user_transform_fn)) /* User read transform function */
michael@0 4966 (png_ptr, /* png_ptr */
michael@0 4967 row_info, /* row_info: */
michael@0 4968 /* png_uint_32 width; width of row */
michael@0 4969 /* png_size_t rowbytes; number of bytes in row */
michael@0 4970 /* png_byte color_type; color type of pixels */
michael@0 4971 /* png_byte bit_depth; bit depth of samples */
michael@0 4972 /* png_byte channels; number of channels (1-4) */
michael@0 4973 /* png_byte pixel_depth; bits per pixel (depth*channels) */
michael@0 4974 png_ptr->row_buf + 1); /* start of pixel data for row */
michael@0 4975 #ifdef PNG_USER_TRANSFORM_PTR_SUPPORTED
michael@0 4976 if (png_ptr->user_transform_depth)
michael@0 4977 row_info->bit_depth = png_ptr->user_transform_depth;
michael@0 4978
michael@0 4979 if (png_ptr->user_transform_channels)
michael@0 4980 row_info->channels = png_ptr->user_transform_channels;
michael@0 4981 #endif
michael@0 4982 row_info->pixel_depth = (png_byte)(row_info->bit_depth *
michael@0 4983 row_info->channels);
michael@0 4984
michael@0 4985 row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_info->width);
michael@0 4986 }
michael@0 4987 #endif
michael@0 4988 }
michael@0 4989
michael@0 4990 #endif /* PNG_READ_TRANSFORMS_SUPPORTED */
michael@0 4991 #endif /* PNG_READ_SUPPORTED */

mercurial