media/libpng/pngwtran.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 /* pngwtran.c - transforms the data in a row for PNG writers
michael@0 3 *
michael@0 4 * Last changed in libpng 1.6.9 [February 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
michael@0 14 #include "pngpriv.h"
michael@0 15
michael@0 16 #ifdef PNG_WRITE_SUPPORTED
michael@0 17 #ifdef PNG_WRITE_TRANSFORMS_SUPPORTED
michael@0 18
michael@0 19 #ifdef PNG_WRITE_PACK_SUPPORTED
michael@0 20 /* Pack pixels into bytes. Pass the true bit depth in bit_depth. The
michael@0 21 * row_info bit depth should be 8 (one pixel per byte). The channels
michael@0 22 * should be 1 (this only happens on grayscale and paletted images).
michael@0 23 */
michael@0 24 static void
michael@0 25 png_do_pack(png_row_infop row_info, png_bytep row, png_uint_32 bit_depth)
michael@0 26 {
michael@0 27 png_debug(1, "in png_do_pack");
michael@0 28
michael@0 29 if (row_info->bit_depth == 8 &&
michael@0 30 row_info->channels == 1)
michael@0 31 {
michael@0 32 switch ((int)bit_depth)
michael@0 33 {
michael@0 34 case 1:
michael@0 35 {
michael@0 36 png_bytep sp, dp;
michael@0 37 int mask, v;
michael@0 38 png_uint_32 i;
michael@0 39 png_uint_32 row_width = row_info->width;
michael@0 40
michael@0 41 sp = row;
michael@0 42 dp = row;
michael@0 43 mask = 0x80;
michael@0 44 v = 0;
michael@0 45
michael@0 46 for (i = 0; i < row_width; i++)
michael@0 47 {
michael@0 48 if (*sp != 0)
michael@0 49 v |= mask;
michael@0 50
michael@0 51 sp++;
michael@0 52
michael@0 53 if (mask > 1)
michael@0 54 mask >>= 1;
michael@0 55
michael@0 56 else
michael@0 57 {
michael@0 58 mask = 0x80;
michael@0 59 *dp = (png_byte)v;
michael@0 60 dp++;
michael@0 61 v = 0;
michael@0 62 }
michael@0 63 }
michael@0 64
michael@0 65 if (mask != 0x80)
michael@0 66 *dp = (png_byte)v;
michael@0 67
michael@0 68 break;
michael@0 69 }
michael@0 70
michael@0 71 case 2:
michael@0 72 {
michael@0 73 png_bytep sp, dp;
michael@0 74 int shift, v;
michael@0 75 png_uint_32 i;
michael@0 76 png_uint_32 row_width = row_info->width;
michael@0 77
michael@0 78 sp = row;
michael@0 79 dp = row;
michael@0 80 shift = 6;
michael@0 81 v = 0;
michael@0 82
michael@0 83 for (i = 0; i < row_width; i++)
michael@0 84 {
michael@0 85 png_byte value;
michael@0 86
michael@0 87 value = (png_byte)(*sp & 0x03);
michael@0 88 v |= (value << shift);
michael@0 89
michael@0 90 if (shift == 0)
michael@0 91 {
michael@0 92 shift = 6;
michael@0 93 *dp = (png_byte)v;
michael@0 94 dp++;
michael@0 95 v = 0;
michael@0 96 }
michael@0 97
michael@0 98 else
michael@0 99 shift -= 2;
michael@0 100
michael@0 101 sp++;
michael@0 102 }
michael@0 103
michael@0 104 if (shift != 6)
michael@0 105 *dp = (png_byte)v;
michael@0 106
michael@0 107 break;
michael@0 108 }
michael@0 109
michael@0 110 case 4:
michael@0 111 {
michael@0 112 png_bytep sp, dp;
michael@0 113 int shift, v;
michael@0 114 png_uint_32 i;
michael@0 115 png_uint_32 row_width = row_info->width;
michael@0 116
michael@0 117 sp = row;
michael@0 118 dp = row;
michael@0 119 shift = 4;
michael@0 120 v = 0;
michael@0 121
michael@0 122 for (i = 0; i < row_width; i++)
michael@0 123 {
michael@0 124 png_byte value;
michael@0 125
michael@0 126 value = (png_byte)(*sp & 0x0f);
michael@0 127 v |= (value << shift);
michael@0 128
michael@0 129 if (shift == 0)
michael@0 130 {
michael@0 131 shift = 4;
michael@0 132 *dp = (png_byte)v;
michael@0 133 dp++;
michael@0 134 v = 0;
michael@0 135 }
michael@0 136
michael@0 137 else
michael@0 138 shift -= 4;
michael@0 139
michael@0 140 sp++;
michael@0 141 }
michael@0 142
michael@0 143 if (shift != 4)
michael@0 144 *dp = (png_byte)v;
michael@0 145
michael@0 146 break;
michael@0 147 }
michael@0 148
michael@0 149 default:
michael@0 150 break;
michael@0 151 }
michael@0 152
michael@0 153 row_info->bit_depth = (png_byte)bit_depth;
michael@0 154 row_info->pixel_depth = (png_byte)(bit_depth * row_info->channels);
michael@0 155 row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth,
michael@0 156 row_info->width);
michael@0 157 }
michael@0 158 }
michael@0 159 #endif
michael@0 160
michael@0 161 #ifdef PNG_WRITE_SHIFT_SUPPORTED
michael@0 162 /* Shift pixel values to take advantage of whole range. Pass the
michael@0 163 * true number of bits in bit_depth. The row should be packed
michael@0 164 * according to row_info->bit_depth. Thus, if you had a row of
michael@0 165 * bit depth 4, but the pixels only had values from 0 to 7, you
michael@0 166 * would pass 3 as bit_depth, and this routine would translate the
michael@0 167 * data to 0 to 15.
michael@0 168 */
michael@0 169 static void
michael@0 170 png_do_shift(png_row_infop row_info, png_bytep row,
michael@0 171 png_const_color_8p bit_depth)
michael@0 172 {
michael@0 173 png_debug(1, "in png_do_shift");
michael@0 174
michael@0 175 if (row_info->color_type != PNG_COLOR_TYPE_PALETTE)
michael@0 176 {
michael@0 177 int shift_start[4], shift_dec[4];
michael@0 178 int channels = 0;
michael@0 179
michael@0 180 if (row_info->color_type & PNG_COLOR_MASK_COLOR)
michael@0 181 {
michael@0 182 shift_start[channels] = row_info->bit_depth - bit_depth->red;
michael@0 183 shift_dec[channels] = bit_depth->red;
michael@0 184 channels++;
michael@0 185
michael@0 186 shift_start[channels] = row_info->bit_depth - bit_depth->green;
michael@0 187 shift_dec[channels] = bit_depth->green;
michael@0 188 channels++;
michael@0 189
michael@0 190 shift_start[channels] = row_info->bit_depth - bit_depth->blue;
michael@0 191 shift_dec[channels] = bit_depth->blue;
michael@0 192 channels++;
michael@0 193 }
michael@0 194
michael@0 195 else
michael@0 196 {
michael@0 197 shift_start[channels] = row_info->bit_depth - bit_depth->gray;
michael@0 198 shift_dec[channels] = bit_depth->gray;
michael@0 199 channels++;
michael@0 200 }
michael@0 201
michael@0 202 if (row_info->color_type & PNG_COLOR_MASK_ALPHA)
michael@0 203 {
michael@0 204 shift_start[channels] = row_info->bit_depth - bit_depth->alpha;
michael@0 205 shift_dec[channels] = bit_depth->alpha;
michael@0 206 channels++;
michael@0 207 }
michael@0 208
michael@0 209 /* With low row depths, could only be grayscale, so one channel */
michael@0 210 if (row_info->bit_depth < 8)
michael@0 211 {
michael@0 212 png_bytep bp = row;
michael@0 213 png_size_t i;
michael@0 214 unsigned int mask;
michael@0 215 png_size_t row_bytes = row_info->rowbytes;
michael@0 216
michael@0 217 if (bit_depth->gray == 1 && row_info->bit_depth == 2)
michael@0 218 mask = 0x55;
michael@0 219
michael@0 220 else if (row_info->bit_depth == 4 && bit_depth->gray == 3)
michael@0 221 mask = 0x11;
michael@0 222
michael@0 223 else
michael@0 224 mask = 0xff;
michael@0 225
michael@0 226 for (i = 0; i < row_bytes; i++, bp++)
michael@0 227 {
michael@0 228 int j;
michael@0 229 unsigned int v, out;
michael@0 230
michael@0 231 v = *bp;
michael@0 232 out = 0;
michael@0 233
michael@0 234 for (j = shift_start[0]; j > -shift_dec[0]; j -= shift_dec[0])
michael@0 235 {
michael@0 236 if (j > 0)
michael@0 237 out |= v << j;
michael@0 238
michael@0 239 else
michael@0 240 out |= (v >> (-j)) & mask;
michael@0 241 }
michael@0 242
michael@0 243 *bp = (png_byte)(out & 0xff);
michael@0 244 }
michael@0 245 }
michael@0 246
michael@0 247 else if (row_info->bit_depth == 8)
michael@0 248 {
michael@0 249 png_bytep bp = row;
michael@0 250 png_uint_32 i;
michael@0 251 png_uint_32 istop = channels * row_info->width;
michael@0 252
michael@0 253 for (i = 0; i < istop; i++, bp++)
michael@0 254 {
michael@0 255
michael@0 256 const unsigned int c = i%channels;
michael@0 257 int j;
michael@0 258 unsigned int v, out;
michael@0 259
michael@0 260 v = *bp;
michael@0 261 out = 0;
michael@0 262
michael@0 263 for (j = shift_start[c]; j > -shift_dec[c]; j -= shift_dec[c])
michael@0 264 {
michael@0 265 if (j > 0)
michael@0 266 out |= v << j;
michael@0 267
michael@0 268 else
michael@0 269 out |= v >> (-j);
michael@0 270 }
michael@0 271
michael@0 272 *bp = (png_byte)(out & 0xff);
michael@0 273 }
michael@0 274 }
michael@0 275
michael@0 276 else
michael@0 277 {
michael@0 278 png_bytep bp;
michael@0 279 png_uint_32 i;
michael@0 280 png_uint_32 istop = channels * row_info->width;
michael@0 281
michael@0 282 for (bp = row, i = 0; i < istop; i++)
michael@0 283 {
michael@0 284 const unsigned int c = i%channels;
michael@0 285 int j;
michael@0 286 unsigned int value, v;
michael@0 287
michael@0 288 v = png_get_uint_16(bp);
michael@0 289 value = 0;
michael@0 290
michael@0 291 for (j = shift_start[c]; j > -shift_dec[c]; j -= shift_dec[c])
michael@0 292 {
michael@0 293 if (j > 0)
michael@0 294 value |= v << j;
michael@0 295
michael@0 296 else
michael@0 297 value |= v >> (-j);
michael@0 298 }
michael@0 299 *bp++ = (png_byte)((value >> 8) & 0xff);
michael@0 300 *bp++ = (png_byte)(value & 0xff);
michael@0 301 }
michael@0 302 }
michael@0 303 }
michael@0 304 }
michael@0 305 #endif
michael@0 306
michael@0 307 #ifdef PNG_WRITE_SWAP_ALPHA_SUPPORTED
michael@0 308 static void
michael@0 309 png_do_write_swap_alpha(png_row_infop row_info, png_bytep row)
michael@0 310 {
michael@0 311 png_debug(1, "in png_do_write_swap_alpha");
michael@0 312
michael@0 313 {
michael@0 314 if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
michael@0 315 {
michael@0 316 if (row_info->bit_depth == 8)
michael@0 317 {
michael@0 318 /* This converts from ARGB to RGBA */
michael@0 319 png_bytep sp, dp;
michael@0 320 png_uint_32 i;
michael@0 321 png_uint_32 row_width = row_info->width;
michael@0 322
michael@0 323 for (i = 0, sp = dp = row; i < row_width; i++)
michael@0 324 {
michael@0 325 png_byte save = *(sp++);
michael@0 326 *(dp++) = *(sp++);
michael@0 327 *(dp++) = *(sp++);
michael@0 328 *(dp++) = *(sp++);
michael@0 329 *(dp++) = save;
michael@0 330 }
michael@0 331 }
michael@0 332
michael@0 333 #ifdef PNG_WRITE_16BIT_SUPPORTED
michael@0 334 else
michael@0 335 {
michael@0 336 /* This converts from AARRGGBB to RRGGBBAA */
michael@0 337 png_bytep sp, dp;
michael@0 338 png_uint_32 i;
michael@0 339 png_uint_32 row_width = row_info->width;
michael@0 340
michael@0 341 for (i = 0, sp = dp = row; i < row_width; i++)
michael@0 342 {
michael@0 343 png_byte save[2];
michael@0 344 save[0] = *(sp++);
michael@0 345 save[1] = *(sp++);
michael@0 346 *(dp++) = *(sp++);
michael@0 347 *(dp++) = *(sp++);
michael@0 348 *(dp++) = *(sp++);
michael@0 349 *(dp++) = *(sp++);
michael@0 350 *(dp++) = *(sp++);
michael@0 351 *(dp++) = *(sp++);
michael@0 352 *(dp++) = save[0];
michael@0 353 *(dp++) = save[1];
michael@0 354 }
michael@0 355 }
michael@0 356 #endif /* PNG_WRITE_16BIT_SUPPORTED */
michael@0 357 }
michael@0 358
michael@0 359 else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
michael@0 360 {
michael@0 361 if (row_info->bit_depth == 8)
michael@0 362 {
michael@0 363 /* This converts from AG to GA */
michael@0 364 png_bytep sp, dp;
michael@0 365 png_uint_32 i;
michael@0 366 png_uint_32 row_width = row_info->width;
michael@0 367
michael@0 368 for (i = 0, sp = dp = row; i < row_width; i++)
michael@0 369 {
michael@0 370 png_byte save = *(sp++);
michael@0 371 *(dp++) = *(sp++);
michael@0 372 *(dp++) = save;
michael@0 373 }
michael@0 374 }
michael@0 375
michael@0 376 #ifdef PNG_WRITE_16BIT_SUPPORTED
michael@0 377 else
michael@0 378 {
michael@0 379 /* This converts from AAGG to GGAA */
michael@0 380 png_bytep sp, dp;
michael@0 381 png_uint_32 i;
michael@0 382 png_uint_32 row_width = row_info->width;
michael@0 383
michael@0 384 for (i = 0, sp = dp = row; i < row_width; i++)
michael@0 385 {
michael@0 386 png_byte save[2];
michael@0 387 save[0] = *(sp++);
michael@0 388 save[1] = *(sp++);
michael@0 389 *(dp++) = *(sp++);
michael@0 390 *(dp++) = *(sp++);
michael@0 391 *(dp++) = save[0];
michael@0 392 *(dp++) = save[1];
michael@0 393 }
michael@0 394 }
michael@0 395 #endif /* PNG_WRITE_16BIT_SUPPORTED */
michael@0 396 }
michael@0 397 }
michael@0 398 }
michael@0 399 #endif
michael@0 400
michael@0 401 #ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED
michael@0 402 static void
michael@0 403 png_do_write_invert_alpha(png_row_infop row_info, png_bytep row)
michael@0 404 {
michael@0 405 png_debug(1, "in png_do_write_invert_alpha");
michael@0 406
michael@0 407 {
michael@0 408 if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
michael@0 409 {
michael@0 410 if (row_info->bit_depth == 8)
michael@0 411 {
michael@0 412 /* This inverts the alpha channel in RGBA */
michael@0 413 png_bytep sp, dp;
michael@0 414 png_uint_32 i;
michael@0 415 png_uint_32 row_width = row_info->width;
michael@0 416
michael@0 417 for (i = 0, sp = dp = row; i < row_width; i++)
michael@0 418 {
michael@0 419 /* Does nothing
michael@0 420 *(dp++) = *(sp++);
michael@0 421 *(dp++) = *(sp++);
michael@0 422 *(dp++) = *(sp++);
michael@0 423 */
michael@0 424 sp+=3; dp = sp;
michael@0 425 *(dp++) = (png_byte)(255 - *(sp++));
michael@0 426 }
michael@0 427 }
michael@0 428
michael@0 429 #ifdef PNG_WRITE_16BIT_SUPPORTED
michael@0 430 else
michael@0 431 {
michael@0 432 /* This inverts the alpha channel in RRGGBBAA */
michael@0 433 png_bytep sp, dp;
michael@0 434 png_uint_32 i;
michael@0 435 png_uint_32 row_width = row_info->width;
michael@0 436
michael@0 437 for (i = 0, sp = dp = row; i < row_width; i++)
michael@0 438 {
michael@0 439 /* Does nothing
michael@0 440 *(dp++) = *(sp++);
michael@0 441 *(dp++) = *(sp++);
michael@0 442 *(dp++) = *(sp++);
michael@0 443 *(dp++) = *(sp++);
michael@0 444 *(dp++) = *(sp++);
michael@0 445 *(dp++) = *(sp++);
michael@0 446 */
michael@0 447 sp+=6; dp = sp;
michael@0 448 *(dp++) = (png_byte)(255 - *(sp++));
michael@0 449 *(dp++) = (png_byte)(255 - *(sp++));
michael@0 450 }
michael@0 451 }
michael@0 452 #endif /* PNG_WRITE_16BIT_SUPPORTED */
michael@0 453 }
michael@0 454
michael@0 455 else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
michael@0 456 {
michael@0 457 if (row_info->bit_depth == 8)
michael@0 458 {
michael@0 459 /* This inverts the alpha channel in GA */
michael@0 460 png_bytep sp, dp;
michael@0 461 png_uint_32 i;
michael@0 462 png_uint_32 row_width = row_info->width;
michael@0 463
michael@0 464 for (i = 0, sp = dp = row; i < row_width; i++)
michael@0 465 {
michael@0 466 *(dp++) = *(sp++);
michael@0 467 *(dp++) = (png_byte)(255 - *(sp++));
michael@0 468 }
michael@0 469 }
michael@0 470
michael@0 471 #ifdef PNG_WRITE_16BIT_SUPPORTED
michael@0 472 else
michael@0 473 {
michael@0 474 /* This inverts the alpha channel in GGAA */
michael@0 475 png_bytep sp, dp;
michael@0 476 png_uint_32 i;
michael@0 477 png_uint_32 row_width = row_info->width;
michael@0 478
michael@0 479 for (i = 0, sp = dp = row; i < row_width; i++)
michael@0 480 {
michael@0 481 /* Does nothing
michael@0 482 *(dp++) = *(sp++);
michael@0 483 *(dp++) = *(sp++);
michael@0 484 */
michael@0 485 sp+=2; dp = sp;
michael@0 486 *(dp++) = (png_byte)(255 - *(sp++));
michael@0 487 *(dp++) = (png_byte)(255 - *(sp++));
michael@0 488 }
michael@0 489 }
michael@0 490 #endif /* PNG_WRITE_16BIT_SUPPORTED */
michael@0 491 }
michael@0 492 }
michael@0 493 }
michael@0 494 #endif
michael@0 495
michael@0 496 /* Transform the data according to the user's wishes. The order of
michael@0 497 * transformations is significant.
michael@0 498 */
michael@0 499 void /* PRIVATE */
michael@0 500 png_do_write_transformations(png_structrp png_ptr, png_row_infop row_info)
michael@0 501 {
michael@0 502 png_debug(1, "in png_do_write_transformations");
michael@0 503
michael@0 504 if (png_ptr == NULL)
michael@0 505 return;
michael@0 506
michael@0 507 #ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED
michael@0 508 if (png_ptr->transformations & PNG_USER_TRANSFORM)
michael@0 509 if (png_ptr->write_user_transform_fn != NULL)
michael@0 510 (*(png_ptr->write_user_transform_fn)) /* User write transform
michael@0 511 function */
michael@0 512 (png_ptr, /* png_ptr */
michael@0 513 row_info, /* row_info: */
michael@0 514 /* png_uint_32 width; width of row */
michael@0 515 /* png_size_t rowbytes; number of bytes in row */
michael@0 516 /* png_byte color_type; color type of pixels */
michael@0 517 /* png_byte bit_depth; bit depth of samples */
michael@0 518 /* png_byte channels; number of channels (1-4) */
michael@0 519 /* png_byte pixel_depth; bits per pixel (depth*channels) */
michael@0 520 png_ptr->row_buf + 1); /* start of pixel data for row */
michael@0 521 #endif
michael@0 522
michael@0 523 #ifdef PNG_WRITE_FILLER_SUPPORTED
michael@0 524 if (png_ptr->transformations & PNG_FILLER)
michael@0 525 png_do_strip_channel(row_info, png_ptr->row_buf + 1,
michael@0 526 !(png_ptr->flags & PNG_FLAG_FILLER_AFTER));
michael@0 527 #endif
michael@0 528
michael@0 529 #ifdef PNG_WRITE_PACKSWAP_SUPPORTED
michael@0 530 if (png_ptr->transformations & PNG_PACKSWAP)
michael@0 531 png_do_packswap(row_info, png_ptr->row_buf + 1);
michael@0 532 #endif
michael@0 533
michael@0 534 #ifdef PNG_WRITE_PACK_SUPPORTED
michael@0 535 if (png_ptr->transformations & PNG_PACK)
michael@0 536 png_do_pack(row_info, png_ptr->row_buf + 1,
michael@0 537 (png_uint_32)png_ptr->bit_depth);
michael@0 538 #endif
michael@0 539
michael@0 540 #ifdef PNG_WRITE_SWAP_SUPPORTED
michael@0 541 if (png_ptr->transformations & PNG_SWAP_BYTES)
michael@0 542 png_do_swap(row_info, png_ptr->row_buf + 1);
michael@0 543 #endif
michael@0 544
michael@0 545 #ifdef PNG_WRITE_SHIFT_SUPPORTED
michael@0 546 if (png_ptr->transformations & PNG_SHIFT)
michael@0 547 png_do_shift(row_info, png_ptr->row_buf + 1,
michael@0 548 &(png_ptr->shift));
michael@0 549 #endif
michael@0 550
michael@0 551 #ifdef PNG_WRITE_SWAP_ALPHA_SUPPORTED
michael@0 552 if (png_ptr->transformations & PNG_SWAP_ALPHA)
michael@0 553 png_do_write_swap_alpha(row_info, png_ptr->row_buf + 1);
michael@0 554 #endif
michael@0 555
michael@0 556 #ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED
michael@0 557 if (png_ptr->transformations & PNG_INVERT_ALPHA)
michael@0 558 png_do_write_invert_alpha(row_info, png_ptr->row_buf + 1);
michael@0 559 #endif
michael@0 560
michael@0 561 #ifdef PNG_WRITE_BGR_SUPPORTED
michael@0 562 if (png_ptr->transformations & PNG_BGR)
michael@0 563 png_do_bgr(row_info, png_ptr->row_buf + 1);
michael@0 564 #endif
michael@0 565
michael@0 566 #ifdef PNG_WRITE_INVERT_SUPPORTED
michael@0 567 if (png_ptr->transformations & PNG_INVERT_MONO)
michael@0 568 png_do_invert(row_info, png_ptr->row_buf + 1);
michael@0 569 #endif
michael@0 570 }
michael@0 571 #endif /* PNG_WRITE_TRANSFORMS_SUPPORTED */
michael@0 572 #endif /* PNG_WRITE_SUPPORTED */

mercurial