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