pngwtran.c 16.6 KB
Newer Older
1

2
/* pngwtran.c - transforms the data in a row for PNG writers
3
 *
4
 * libpng 1.2.3 - May 21, 2002
5
 * For conditions of distribution and use, see copyright notice in png.h
6
 * Copyright (c) 1998-2002 Glenn Randers-Pehrson
7 8
 * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
 * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
9
 */
10 11 12

#define PNG_INTERNAL
#include "png.h"
13
#ifdef PNG_WRITE_SUPPORTED
14

15
/* Transform the data according to the user's wishes.  The order of
16 17
 * transformations is significant.
 */
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 24 25
   if (png_ptr == NULL)
      return;

26 27 28 29 30 31 32 33 34 35 36 37 38 39
#if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
   if (png_ptr->transformations & PNG_USER_TRANSFORM)
      if(png_ptr->write_user_transform_fn != NULL)
        (*(png_ptr->write_user_transform_fn)) /* user write transform function */
          (png_ptr,                    /* png_ptr */
           &(png_ptr->row_info),       /* row_info:     */
             /*  png_uint_32 width;          width of row */
             /*  png_uint_32 rowbytes;       number of bytes in row */
             /*  png_byte color_type;        color type of pixels */
             /*  png_byte bit_depth;         bit depth of samples */
             /*  png_byte channels;          number of channels (1-4) */
             /*  png_byte pixel_depth;       bits per pixel (depth*channels) */
           png_ptr->row_buf + 1);      /* start of pixel data for row */
#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 46 47 48
#if defined(PNG_WRITE_PACKSWAP_SUPPORTED)
   if (png_ptr->transformations & PNG_PACKSWAP)
      png_do_packswap(&(png_ptr->row_info), png_ptr->row_buf + 1);
#endif
49
#if defined(PNG_WRITE_PACK_SUPPORTED)
50 51
   if (png_ptr->transformations & PNG_PACK)
      png_do_pack(&(png_ptr->row_info), png_ptr->row_buf + 1,
52
         (png_uint_32)png_ptr->bit_depth);
53
#endif
54 55 56 57
#if defined(PNG_WRITE_SWAP_SUPPORTED)
   if (png_ptr->transformations & PNG_SWAP_BYTES)
      png_do_swap(&(png_ptr->row_info), png_ptr->row_buf + 1);
#endif
58
#if defined(PNG_WRITE_SHIFT_SUPPORTED)
59 60 61
   if (png_ptr->transformations & PNG_SHIFT)
      png_do_shift(&(png_ptr->row_info), png_ptr->row_buf + 1,
         &(png_ptr->shift));
62
#endif
63 64 65 66
#if defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED)
   if (png_ptr->transformations & PNG_INVERT_ALPHA)
      png_do_write_invert_alpha(&(png_ptr->row_info), png_ptr->row_buf + 1);
#endif
67 68 69 70
#if defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED)
   if (png_ptr->transformations & PNG_SWAP_ALPHA)
      png_do_write_swap_alpha(&(png_ptr->row_info), png_ptr->row_buf + 1);
#endif
71
#if defined(PNG_WRITE_BGR_SUPPORTED)
72 73
   if (png_ptr->transformations & PNG_BGR)
      png_do_bgr(&(png_ptr->row_info), png_ptr->row_buf + 1);
74 75
#endif
#if defined(PNG_WRITE_INVERT_SUPPORTED)
76 77
   if (png_ptr->transformations & PNG_INVERT_MONO)
      png_do_invert(&(png_ptr->row_info), png_ptr->row_buf + 1);
78
#endif
79 80
}

81
#if defined(PNG_WRITE_PACK_SUPPORTED)
82 83 84 85
/* Pack pixels into bytes.  Pass the true bit depth in bit_depth.  The
 * row_info bit depth should be 8 (one pixel per byte).  The channels
 * should be 1 (this only happens on grayscale and paletted images).
 */
86
void /* PRIVATE */
87
png_do_pack(png_row_infop row_info, png_bytep row, png_uint_32 bit_depth)
88
{
89 90 91 92 93
   png_debug(1, "in png_do_pack\n");
   if (row_info->bit_depth == 8 &&
#if defined(PNG_USELESS_TESTS_SUPPORTED)
       row != NULL && row_info != NULL &&
#endif
94 95
      row_info->channels == 1)
   {
96
      switch ((int)bit_depth)
97 98 99
      {
         case 1:
         {
100 101
            png_bytep sp, dp;
            int mask, v;
102 103
            png_uint_32 i;
            png_uint_32 row_width = row_info->width;
104 105 106 107 108

            sp = row;
            dp = row;
            mask = 0x80;
            v = 0;
109

110
            for (i = 0; i < row_width; i++)
111
            {
112
               if (*sp != 0)
113 114 115 116 117 118 119
                  v |= mask;
               sp++;
               if (mask > 1)
                  mask >>= 1;
               else
               {
                  mask = 0x80;
120 121
                  *dp = (png_byte)v;
                  dp++;
122 123 124 125
                  v = 0;
               }
            }
            if (mask != 0x80)
126
               *dp = (png_byte)v;
127 128 129 130
            break;
         }
         case 2:
         {
131 132
            png_bytep sp, dp;
            int shift, v;
133 134
            png_uint_32 i;
            png_uint_32 row_width = row_info->width;
135 136 137 138 139

            sp = row;
            dp = row;
            shift = 6;
            v = 0;
140
            for (i = 0; i < row_width; i++)
141
            {
142 143
               png_byte value;

144
               value = (png_byte)(*sp & 0x03);
145 146 147 148
               v |= (value << shift);
               if (shift == 0)
               {
                  shift = 6;
149
                  *dp = (png_byte)v;
150 151 152 153 154 155 156 157
                  dp++;
                  v = 0;
               }
               else
                  shift -= 2;
               sp++;
            }
            if (shift != 6)
158
               *dp = (png_byte)v;
159 160 161 162
            break;
         }
         case 4:
         {
163 164
            png_bytep sp, dp;
            int shift, v;
165 166
            png_uint_32 i;
            png_uint_32 row_width = row_info->width;
167 168 169 170 171

            sp = row;
            dp = row;
            shift = 4;
            v = 0;
172
            for (i = 0; i < row_width; i++)
173
            {
174 175
               png_byte value;

176
               value = (png_byte)(*sp & 0x0f);
177 178 179 180 181
               v |= (value << shift);

               if (shift == 0)
               {
                  shift = 4;
182
                  *dp = (png_byte)v;
183 184 185 186 187 188 189 190 191
                  dp++;
                  v = 0;
               }
               else
                  shift -= 4;

               sp++;
            }
            if (shift != 4)
192
               *dp = (png_byte)v;
193 194 195
            break;
         }
      }
196 197
      row_info->bit_depth = (png_byte)bit_depth;
      row_info->pixel_depth = (png_byte)(bit_depth * row_info->channels);
198 199 200 201
      row_info->rowbytes =
         ((row_info->width * row_info->pixel_depth + 7) >> 3);
   }
}
202
#endif
203

204
#if defined(PNG_WRITE_SHIFT_SUPPORTED)
205 206 207 208 209 210 211
/* Shift pixel values to take advantage of whole range.  Pass the
 * true number of bits in bit_depth.  The row should be packed
 * according to row_info->bit_depth.  Thus, if you had a row of
 * bit depth 4, but the pixels only had values from 0 to 7, you
 * would pass 3 as bit_depth, and this routine would translate the
 * data to 0 to 15.
 */
212
void /* PRIVATE */
213
png_do_shift(png_row_infop row_info, png_bytep row, png_color_8p bit_depth)
214
{
215 216 217 218 219 220
   png_debug(1, "in png_do_shift\n");
#if defined(PNG_USELESS_TESTS_SUPPORTED)
   if (row != NULL && row_info != NULL &&
#else
   if (
#endif
221 222 223
      row_info->color_type != PNG_COLOR_TYPE_PALETTE)
   {
      int shift_start[4], shift_dec[4];
224
      int channels = 0;
225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250

      if (row_info->color_type & PNG_COLOR_MASK_COLOR)
      {
         shift_start[channels] = row_info->bit_depth - bit_depth->red;
         shift_dec[channels] = bit_depth->red;
         channels++;
         shift_start[channels] = row_info->bit_depth - bit_depth->green;
         shift_dec[channels] = bit_depth->green;
         channels++;
         shift_start[channels] = row_info->bit_depth - bit_depth->blue;
         shift_dec[channels] = bit_depth->blue;
         channels++;
      }
      else
      {
         shift_start[channels] = row_info->bit_depth - bit_depth->gray;
         shift_dec[channels] = bit_depth->gray;
         channels++;
      }
      if (row_info->color_type & PNG_COLOR_MASK_ALPHA)
      {
         shift_start[channels] = row_info->bit_depth - bit_depth->alpha;
         shift_dec[channels] = bit_depth->alpha;
         channels++;
      }

251
      /* with low row depths, could only be grayscale, so one channel */
252 253
      if (row_info->bit_depth < 8)
      {
254 255
         png_bytep bp = row;
         png_uint_32 i;
256
         png_byte mask;
257
         png_uint_32 row_bytes = row_info->rowbytes;
258 259 260 261 262 263 264 265

         if (bit_depth->gray == 1 && row_info->bit_depth == 2)
            mask = 0x55;
         else if (row_info->bit_depth == 4 && bit_depth->gray == 3)
            mask = 0x11;
         else
            mask = 0xff;

266
         for (i = 0; i < row_bytes; i++, bp++)
267
         {
268 269
            png_uint_16 v;
            int j;
270 271 272 273 274 275 276 277 278 279 280 281 282 283

            v = *bp;
            *bp = 0;
            for (j = shift_start[0]; j > -shift_dec[0]; j -= shift_dec[0])
            {
               if (j > 0)
                  *bp |= (png_byte)((v << j) & 0xff);
               else
                  *bp |= (png_byte)((v >> (-j)) & mask);
            }
         }
      }
      else if (row_info->bit_depth == 8)
      {
284 285
         png_bytep bp = row;
         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 292 293
            png_uint_16 v;
            int j;
            int c = (int)(i%channels);
294

295 296 297 298 299 300 301 302
            v = *bp;
            *bp = 0;
            for (j = shift_start[c]; j > -shift_dec[c]; j -= shift_dec[c])
            {
               if (j > 0)
                  *bp |= (png_byte)((v << j) & 0xff);
               else
                  *bp |= (png_byte)((v >> (-j)) & 0xff);
303 304 305 306 307
            }
         }
      }
      else
      {
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 315 316
            int c = (int)(i%channels);
            png_uint_16 value, v;
            int j;
317

318
            v = (png_uint_16)(((png_uint_16)(*bp) << 8) + *(bp + 1));
319 320
            value = 0;
            for (j = shift_start[c]; j > -shift_dec[c]; j -= shift_dec[c])
321
            {
322 323 324 325
               if (j > 0)
                  value |= (png_uint_16)((v << j) & (png_uint_16)0xffff);
               else
                  value |= (png_uint_16)((v >> (-j)) & (png_uint_16)0xffff);
326
            }
327 328
            *bp++ = (png_byte)(value >> 8);
            *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 340 341 342
   png_debug(1, "in png_do_write_swap_alpha\n");
#if defined(PNG_USELESS_TESTS_SUPPORTED)
   if (row != NULL && row_info != NULL)
#endif
343
   {
344
      if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
345
      {
346 347 348 349
         /* This converts from ARGB to RGBA */
         if (row_info->bit_depth == 8)
         {
            png_bytep sp, dp;
350 351 352
            png_uint_32 i;
            png_uint_32 row_width = row_info->width;
            for (i = 0, sp = dp = row; i < row_width; i++)
353
            {
354
               png_byte save = *(sp++);
355 356 357 358 359 360 361 362
               *(dp++) = *(sp++);
               *(dp++) = *(sp++);
               *(dp++) = *(sp++);
               *(dp++) = save;
            }
         }
         /* This converts from AARRGGBB to RRGGBBAA */
         else
363
         {
364
            png_bytep sp, dp;
365 366
            png_uint_32 i;
            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 372 373 374 375 376 377 378 379 380 381
               save[0] = *(sp++);
               save[1] = *(sp++);
               *(dp++) = *(sp++);
               *(dp++) = *(sp++);
               *(dp++) = *(sp++);
               *(dp++) = *(sp++);
               *(dp++) = *(sp++);
               *(dp++) = *(sp++);
               *(dp++) = save[0];
               *(dp++) = save[1];
            }
382 383
         }
      }
384
      else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
385
      {
386 387 388 389 390
         /* This converts from AG to GA */
         if (row_info->bit_depth == 8)
         {
            png_bytep sp, dp;
            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 397 398 399 400 401
               *(dp++) = *(sp++);
               *(dp++) = save;
            }
         }
         /* This converts from AAGG to GGAA */
         else
402
         {
403 404
            png_bytep sp, dp;
            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 411 412 413 414 415 416
               save[0] = *(sp++);
               save[1] = *(sp++);
               *(dp++) = *(sp++);
               *(dp++) = *(sp++);
               *(dp++) = save[0];
               *(dp++) = save[1];
            }
417
         }
418 419 420
      }
   }
}
421
#endif
422

423
#if defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED)
424
void /* PRIVATE */
425 426 427 428 429 430 431 432 433 434 435 436 437
png_do_write_invert_alpha(png_row_infop row_info, png_bytep row)
{
   png_debug(1, "in png_do_write_invert_alpha\n");
#if defined(PNG_USELESS_TESTS_SUPPORTED)
   if (row != NULL && row_info != NULL)
#endif
   {
      if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
      {
         /* This inverts the alpha channel in RGBA */
         if (row_info->bit_depth == 8)
         {
            png_bytep sp, dp;
438 439 440
            png_uint_32 i;
            png_uint_32 row_width = row_info->width;
            for (i = 0, sp = dp = row; i < row_width; i++)
441 442 443 444
            {
               *(dp++) = *(sp++);
               *(dp++) = *(sp++);
               *(dp++) = *(sp++);
445
               *(dp++) = (png_byte)(255 - *(sp++));
446 447 448 449 450 451
            }
         }
         /* This inverts the alpha channel in RRGGBBAA */
         else
         {
            png_bytep sp, dp;
452 453
            png_uint_32 i;
            png_uint_32 row_width = row_info->width;
454

455
            for (i = 0, sp = dp = row; i < row_width; i++)
456 457 458 459 460 461 462
            {
               *(dp++) = *(sp++);
               *(dp++) = *(sp++);
               *(dp++) = *(sp++);
               *(dp++) = *(sp++);
               *(dp++) = *(sp++);
               *(dp++) = *(sp++);
463 464
               *(dp++) = (png_byte)(255 - *(sp++));
               *(dp++) = (png_byte)(255 - *(sp++));
465 466 467 468 469 470 471 472 473
            }
         }
      }
      else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
      {
         /* This inverts the alpha channel in GA */
         if (row_info->bit_depth == 8)
         {
            png_bytep sp, dp;
474 475
            png_uint_32 i;
            png_uint_32 row_width = row_info->width;
476

477
            for (i = 0, sp = dp = row; i < row_width; i++)
478 479
            {
               *(dp++) = *(sp++);
480
               *(dp++) = (png_byte)(255 - *(sp++));
481 482 483 484 485 486
            }
         }
         /* This inverts the alpha channel in GGAA */
         else
         {
            png_bytep sp, dp;
487 488
            png_uint_32 i;
            png_uint_32 row_width = row_info->width;
489

490
            for (i = 0, sp = dp = row; i < row_width; i++)
491 492 493
            {
               *(dp++) = *(sp++);
               *(dp++) = *(sp++);
494 495
               *(dp++) = (png_byte)(255 - *(sp++));
               *(dp++) = (png_byte)(255 - *(sp++));
496 497 498 499 500 501
            }
         }
      }
   }
}
#endif
502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562

#if defined(PNG_MNG_FEATURES_SUPPORTED)
/* undoes intrapixel differencing  */
void /* PRIVATE */
png_do_write_intrapixel(png_row_infop row_info, png_bytep row)
{
   png_debug(1, "in png_do_write_intrapixel\n");
   if (
#if defined(PNG_USELESS_TESTS_SUPPORTED)
       row != NULL && row_info != NULL &&
#endif
       (row_info->color_type & PNG_COLOR_MASK_COLOR))
   {
      int bytes_per_pixel;
      png_uint_32 row_width = row_info->width;
      if (row_info->bit_depth == 8)
      {
         png_bytep rp;
         png_uint_32 i;

         if (row_info->color_type == PNG_COLOR_TYPE_RGB)
            bytes_per_pixel = 3;
         else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
            bytes_per_pixel = 4;
         else
            return;

         for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel)
         {
            *(rp)   = (png_byte)((*rp     - *(rp+1))&0xff);
            *(rp+2) = (png_byte)((*(rp+2) - *(rp+1))&0xff);
         }
      }
      else if (row_info->bit_depth == 16)
      {
         png_bytep rp;
         png_uint_32 i;

         if (row_info->color_type == PNG_COLOR_TYPE_RGB)
            bytes_per_pixel = 6;
         else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
            bytes_per_pixel = 8;
         else
            return;

         for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel)
         {
            png_uint_32 s0=*(rp  )<<8 | *(rp+1);
            png_uint_32 s1=*(rp+2)<<8 | *(rp+3);
            png_uint_32 s2=*(rp+4)<<8 | *(rp+5);
            png_uint_32 red=(s0-s1)&0xffff;
            png_uint_32 blue=(s2-s1)&0xffff;
            *(rp  ) = (png_byte)((red>>8)&0xff);
            *(rp+1) = (png_byte)(red&0xff);
            *(rp+4) = (png_byte)((blue>>8)&0xff);
            *(rp+5) = (png_byte)(blue&0xff);
         }
      }
   }
}
#endif /* PNG_MNG_FEATURES_SUPPORTED */
563
#endif /* PNG_WRITE_SUPPORTED */
新手
引导
客服 返回
顶部