1 2 /* pngwtran.c - transforms the data in a row for PNG writers 3 * 4 * Last changed in libpng 1.4.1 [February 25, 2010] 5 * Copyright (c) 1998-2010 Glenn Randers-Pehrson 6 * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) 7 * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) 8 * 9 * This code is released under the libpng license. 10 * For conditions of distribution and use, see the disclaimer 11 * and license in png.h 12 */ 13 14 #define PNG_NO_PEDANTIC_WARNINGS 15 #include "png.h" 16 #ifdef PNG_WRITE_SUPPORTED 17 #include "pngpriv.h" 18 19 /* Transform the data according to the user's wishes. The order of 20 * transformations is significant. 21 */ 22 void /* PRIVATE */ 23 png_do_write_transformations(png_structp png_ptr) 24 { 25 png_debug(1, "in png_do_write_transformations"); 26 27 if (png_ptr == NULL) 28 return; 29 30 #ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED 31 if (png_ptr->transformations & PNG_USER_TRANSFORM) 32 if (png_ptr->write_user_transform_fn != NULL) 33 (*(png_ptr->write_user_transform_fn)) /* User write transform 34 function */ 35 (png_ptr, /* png_ptr */ 36 &(png_ptr->row_info), /* row_info: */ 37 /* png_uint_32 width; width of row */ 38 /* png_uint_32 rowbytes; number of bytes in row */ 39 /* png_byte color_type; color type of pixels */ 40 /* png_byte bit_depth; bit depth of samples */ 41 /* png_byte channels; number of channels (1-4) */ 42 /* png_byte pixel_depth; bits per pixel (depth*channels) */ 43 png_ptr->row_buf + 1); /* start of pixel data for row */ 44 #endif 45 #ifdef PNG_WRITE_FILLER_SUPPORTED 46 if (png_ptr->transformations & PNG_FILLER) 47 png_do_strip_filler(&(png_ptr->row_info), png_ptr->row_buf + 1, 48 png_ptr->flags); 49 #endif 50 #ifdef PNG_WRITE_PACKSWAP_SUPPORTED 51 if (png_ptr->transformations & PNG_PACKSWAP) 52 png_do_packswap(&(png_ptr->row_info), png_ptr->row_buf + 1); 53 #endif 54 #ifdef PNG_WRITE_PACK_SUPPORTED 55 if (png_ptr->transformations & PNG_PACK) 56 png_do_pack(&(png_ptr->row_info), png_ptr->row_buf + 1, 57 (png_uint_32)png_ptr->bit_depth); 58 #endif 59 #ifdef PNG_WRITE_SWAP_SUPPORTED 60 if (png_ptr->transformations & PNG_SWAP_BYTES) 61 png_do_swap(&(png_ptr->row_info), png_ptr->row_buf + 1); 62 #endif 63 #ifdef PNG_WRITE_SHIFT_SUPPORTED 64 if (png_ptr->transformations & PNG_SHIFT) 65 png_do_shift(&(png_ptr->row_info), png_ptr->row_buf + 1, 66 &(png_ptr->shift)); 67 #endif 68 #ifdef PNG_WRITE_SWAP_ALPHA_SUPPORTED 69 if (png_ptr->transformations & PNG_SWAP_ALPHA) 70 png_do_write_swap_alpha(&(png_ptr->row_info), png_ptr->row_buf + 1); 71 #endif 72 #ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED 73 if (png_ptr->transformations & PNG_INVERT_ALPHA) 74 png_do_write_invert_alpha(&(png_ptr->row_info), png_ptr->row_buf + 1); 75 #endif 76 #ifdef PNG_WRITE_BGR_SUPPORTED 77 if (png_ptr->transformations & PNG_BGR) 78 png_do_bgr(&(png_ptr->row_info), png_ptr->row_buf + 1); 79 #endif 80 #ifdef PNG_WRITE_INVERT_SUPPORTED 81 if (png_ptr->transformations & PNG_INVERT_MONO) 82 png_do_invert(&(png_ptr->row_info), png_ptr->row_buf + 1); 83 #endif 84 } 85 86 #ifdef PNG_WRITE_PACK_SUPPORTED 87 /* Pack pixels into bytes. Pass the true bit depth in bit_depth. The 88 * row_info bit depth should be 8 (one pixel per byte). The channels 89 * should be 1 (this only happens on grayscale and paletted images). 90 */ 91 void /* PRIVATE */ 92 png_do_pack(png_row_infop row_info, png_bytep row, png_uint_32 bit_depth) 93 { 94 png_debug(1, "in png_do_pack"); 95 96 if (row_info->bit_depth == 8 && 97 row_info->channels == 1) 98 { 99 switch ((int)bit_depth) 100 { 101 case 1: 102 { 103 png_bytep sp, dp; 104 int mask, v; 105 png_uint_32 i; 106 png_uint_32 row_width = row_info->width; 107 108 sp = row; 109 dp = row; 110 mask = 0x80; 111 v = 0; 112 113 for (i = 0; i < row_width; i++) 114 { 115 if (*sp != 0) 116 v |= mask; 117 sp++; 118 if (mask > 1) 119 mask >>= 1; 120 else 121 { 122 mask = 0x80; 123 *dp = (png_byte)v; 124 dp++; 125 v = 0; 126 } 127 } 128 if (mask != 0x80) 129 *dp = (png_byte)v; 130 break; 131 } 132 case 2: 133 { 134 png_bytep sp, dp; 135 int shift, v; 136 png_uint_32 i; 137 png_uint_32 row_width = row_info->width; 138 139 sp = row; 140 dp = row; 141 shift = 6; 142 v = 0; 143 for (i = 0; i < row_width; i++) 144 { 145 png_byte value; 146 147 value = (png_byte)(*sp & 0x03); 148 v |= (value << shift); 149 if (shift == 0) 150 { 151 shift = 6; 152 *dp = (png_byte)v; 153 dp++; 154 v = 0; 155 } 156 else 157 shift -= 2; 158 sp++; 159 } 160 if (shift != 6) 161 *dp = (png_byte)v; 162 break; 163 } 164 case 4: 165 { 166 png_bytep sp, dp; 167 int shift, v; 168 png_uint_32 i; 169 png_uint_32 row_width = row_info->width; 170 171 sp = row; 172 dp = row; 173 shift = 4; 174 v = 0; 175 for (i = 0; i < row_width; i++) 176 { 177 png_byte value; 178 179 value = (png_byte)(*sp & 0x0f); 180 v |= (value << shift); 181 182 if (shift == 0) 183 { 184 shift = 4; 185 *dp = (png_byte)v; 186 dp++; 187 v = 0; 188 } 189 else 190 shift -= 4; 191 192 sp++; 193 } 194 if (shift != 4) 195 *dp = (png_byte)v; 196 break; 197 } 198 } 199 row_info->bit_depth = (png_byte)bit_depth; 200 row_info->pixel_depth = (png_byte)(bit_depth * row_info->channels); 201 row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, 202 row_info->width); 203 } 204 } 205 #endif 206 207 #ifdef PNG_WRITE_SHIFT_SUPPORTED 208 /* Shift pixel values to take advantage of whole range. Pass the 209 * true number of bits in bit_depth. The row should be packed 210 * according to row_info->bit_depth. Thus, if you had a row of 211 * bit depth 4, but the pixels only had values from 0 to 7, you 212 * would pass 3 as bit_depth, and this routine would translate the 213 * data to 0 to 15. 214 */ 215 void /* PRIVATE */ 216 png_do_shift(png_row_infop row_info, png_bytep row, png_color_8p bit_depth) 217 { 218 png_debug(1, "in png_do_shift"); 219 220 if ( 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 #ifdef 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"); 340 341 { 342 if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) 343 { 344 /* This converts from ARGB to RGBA */ 345 if (row_info->bit_depth == 8) 346 { 347 png_bytep sp, dp; 348 png_uint_32 i; 349 png_uint_32 row_width = row_info->width; 350 for (i = 0, sp = dp = row; i < row_width; i++) 351 { 352 png_byte save = *(sp++); 353 *(dp++) = *(sp++); 354 *(dp++) = *(sp++); 355 *(dp++) = *(sp++); 356 *(dp++) = save; 357 } 358 } 359 /* This converts from AARRGGBB to RRGGBBAA */ 360 else 361 { 362 png_bytep sp, dp; 363 png_uint_32 i; 364 png_uint_32 row_width = row_info->width; 365 366 for (i = 0, sp = dp = row; i < row_width; i++) 367 { 368 png_byte save[2]; 369 save[0] = *(sp++); 370 save[1] = *(sp++); 371 *(dp++) = *(sp++); 372 *(dp++) = *(sp++); 373 *(dp++) = *(sp++); 374 *(dp++) = *(sp++); 375 *(dp++) = *(sp++); 376 *(dp++) = *(sp++); 377 *(dp++) = save[0]; 378 *(dp++) = save[1]; 379 } 380 } 381 } 382 else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) 383 { 384 /* This converts from AG to GA */ 385 if (row_info->bit_depth == 8) 386 { 387 png_bytep sp, dp; 388 png_uint_32 i; 389 png_uint_32 row_width = row_info->width; 390 391 for (i = 0, sp = dp = row; i < row_width; i++) 392 { 393 png_byte save = *(sp++); 394 *(dp++) = *(sp++); 395 *(dp++) = save; 396 } 397 } 398 /* This converts from AAGG to GGAA */ 399 else 400 { 401 png_bytep sp, dp; 402 png_uint_32 i; 403 png_uint_32 row_width = row_info->width; 404 405 for (i = 0, sp = dp = row; i < row_width; i++) 406 { 407 png_byte save[2]; 408 save[0] = *(sp++); 409 save[1] = *(sp++); 410 *(dp++) = *(sp++); 411 *(dp++) = *(sp++); 412 *(dp++) = save[0]; 413 *(dp++) = save[1]; 414 } 415 } 416 } 417 } 418 } 419 #endif 420 421 #ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED 422 void /* PRIVATE */ 423 png_do_write_invert_alpha(png_row_infop row_info, png_bytep row) 424 { 425 png_debug(1, "in png_do_write_invert_alpha"); 426 427 { 428 if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) 429 { 430 /* This inverts the alpha channel in RGBA */ 431 if (row_info->bit_depth == 8) 432 { 433 png_bytep sp, dp; 434 png_uint_32 i; 435 png_uint_32 row_width = row_info->width; 436 for (i = 0, sp = dp = row; i < row_width; i++) 437 { 438 /* Does nothing 439 *(dp++) = *(sp++); 440 *(dp++) = *(sp++); 441 *(dp++) = *(sp++); 442 */ 443 sp+=3; dp = sp; 444 *(dp++) = (png_byte)(255 - *(sp++)); 445 } 446 } 447 /* This inverts the alpha channel in RRGGBBAA */ 448 else 449 { 450 png_bytep sp, dp; 451 png_uint_32 i; 452 png_uint_32 row_width = row_info->width; 453 454 for (i = 0, sp = dp = row; i < row_width; i++) 455 { 456 /* Does nothing 457 *(dp++) = *(sp++); 458 *(dp++) = *(sp++); 459 *(dp++) = *(sp++); 460 *(dp++) = *(sp++); 461 *(dp++) = *(sp++); 462 *(dp++) = *(sp++); 463 */ 464 sp+=6; dp = sp; 465 *(dp++) = (png_byte)(255 - *(sp++)); 466 *(dp++) = (png_byte)(255 - *(sp++)); 467 } 468 } 469 } 470 else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) 471 { 472 /* This inverts the alpha channel in GA */ 473 if (row_info->bit_depth == 8) 474 { 475 png_bytep sp, dp; 476 png_uint_32 i; 477 png_uint_32 row_width = row_info->width; 478 479 for (i = 0, sp = dp = row; i < row_width; i++) 480 { 481 *(dp++) = *(sp++); 482 *(dp++) = (png_byte)(255 - *(sp++)); 483 } 484 } 485 /* This inverts the alpha channel in GGAA */ 486 else 487 { 488 png_bytep sp, dp; 489 png_uint_32 i; 490 png_uint_32 row_width = row_info->width; 491 492 for (i = 0, sp = dp = row; i < row_width; i++) 493 { 494 /* Does nothing 495 *(dp++) = *(sp++); 496 *(dp++) = *(sp++); 497 */ 498 sp+=2; dp = sp; 499 *(dp++) = (png_byte)(255 - *(sp++)); 500 *(dp++) = (png_byte)(255 - *(sp++)); 501 } 502 } 503 } 504 } 505 } 506 #endif 507 508 #ifdef PNG_MNG_FEATURES_SUPPORTED 509 /* Undoes intrapixel differencing */ 510 void /* PRIVATE */ 511 png_do_write_intrapixel(png_row_infop row_info, png_bytep row) 512 { 513 png_debug(1, "in png_do_write_intrapixel"); 514 515 if ( 516 (row_info->color_type & PNG_COLOR_MASK_COLOR)) 517 { 518 int bytes_per_pixel; 519 png_uint_32 row_width = row_info->width; 520 if (row_info->bit_depth == 8) 521 { 522 png_bytep rp; 523 png_uint_32 i; 524 525 if (row_info->color_type == PNG_COLOR_TYPE_RGB) 526 bytes_per_pixel = 3; 527 else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) 528 bytes_per_pixel = 4; 529 else 530 return; 531 532 for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel) 533 { 534 *(rp) = (png_byte)((*rp - *(rp+1))&0xff); 535 *(rp+2) = (png_byte)((*(rp+2) - *(rp+1))&0xff); 536 } 537 } 538 else if (row_info->bit_depth == 16) 539 { 540 png_bytep rp; 541 png_uint_32 i; 542 543 if (row_info->color_type == PNG_COLOR_TYPE_RGB) 544 bytes_per_pixel = 6; 545 else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) 546 bytes_per_pixel = 8; 547 else 548 return; 549 550 for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel) 551 { 552 png_uint_32 s0 = (*(rp ) << 8) | *(rp+1); 553 png_uint_32 s1 = (*(rp+2) << 8) | *(rp+3); 554 png_uint_32 s2 = (*(rp+4) << 8) | *(rp+5); 555 png_uint_32 red = (png_uint_32)((s0 - s1) & 0xffffL); 556 png_uint_32 blue = (png_uint_32)((s2 - s1) & 0xffffL); 557 *(rp ) = (png_byte)((red >> 8) & 0xff); 558 *(rp+1) = (png_byte)(red & 0xff); 559 *(rp+4) = (png_byte)((blue >> 8) & 0xff); 560 *(rp+5) = (png_byte)(blue & 0xff); 561 } 562 } 563 } 564 } 565 #endif /* PNG_MNG_FEATURES_SUPPORTED */ 566 #endif /* PNG_WRITE_SUPPORTED */ 567