pngwtran.c 14.6 KB
Newer Older
G
Guy Schalnat 已提交
1

A
Andreas Dilger 已提交
2
/* pngwtran.c - transforms the data in a row for PNG writers
3
 *
4
 * libpng 1.0.6i - May 1, 2000
5 6 7
 * For conditions of distribution and use, see copyright notice in png.h
 * Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
 * Copyright (c) 1996, 1997 Andreas Dilger
8
 * Copyright (c) 1998, 1999, 2000 Glenn Randers-Pehrson
9
 */
G
Guy Schalnat 已提交
10 11 12 13

#define PNG_INTERNAL
#include "png.h"

14
/* Transform the data according to the user's wishes.  The order of
15 16
 * transformations is significant.
 */
G
Guy Schalnat 已提交
17
void
G
Guy Schalnat 已提交
18
png_do_write_transformations(png_structp png_ptr)
G
Guy Schalnat 已提交
19
{
A
Andreas Dilger 已提交
20
   png_debug(1, "in png_do_write_transformations\n");
21

22 23 24
   if (png_ptr == NULL)
      return;

25 26 27 28 29 30 31 32 33 34 35 36 37 38
#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
G
Guy Schalnat 已提交
39
#if defined(PNG_WRITE_FILLER_SUPPORTED)
G
Guy Schalnat 已提交
40
   if (png_ptr->transformations & PNG_FILLER)
A
Andreas Dilger 已提交
41
      png_do_strip_filler(&(png_ptr->row_info), png_ptr->row_buf + 1,
G
Guy Schalnat 已提交
42
         png_ptr->flags);
G
Guy Schalnat 已提交
43
#endif
44 45 46 47
#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
G
Guy Schalnat 已提交
48
#if defined(PNG_WRITE_PACK_SUPPORTED)
G
Guy Schalnat 已提交
49 50
   if (png_ptr->transformations & PNG_PACK)
      png_do_pack(&(png_ptr->row_info), png_ptr->row_buf + 1,
A
Andreas Dilger 已提交
51
         (png_uint_32)png_ptr->bit_depth);
G
Guy Schalnat 已提交
52
#endif
53 54 55 56
#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
G
Guy Schalnat 已提交
57
#if defined(PNG_WRITE_SHIFT_SUPPORTED)
G
Guy Schalnat 已提交
58 59 60
   if (png_ptr->transformations & PNG_SHIFT)
      png_do_shift(&(png_ptr->row_info), png_ptr->row_buf + 1,
         &(png_ptr->shift));
G
Guy Schalnat 已提交
61
#endif
62 63 64 65
#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
66 67 68 69
#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
G
Guy Schalnat 已提交
70
#if defined(PNG_WRITE_BGR_SUPPORTED)
G
Guy Schalnat 已提交
71 72
   if (png_ptr->transformations & PNG_BGR)
      png_do_bgr(&(png_ptr->row_info), png_ptr->row_buf + 1);
G
Guy Schalnat 已提交
73 74
#endif
#if defined(PNG_WRITE_INVERT_SUPPORTED)
G
Guy Schalnat 已提交
75 76
   if (png_ptr->transformations & PNG_INVERT_MONO)
      png_do_invert(&(png_ptr->row_info), png_ptr->row_buf + 1);
G
Guy Schalnat 已提交
77
#endif
G
Guy Schalnat 已提交
78 79
}

G
Guy Schalnat 已提交
80
#if defined(PNG_WRITE_PACK_SUPPORTED)
81 82 83 84
/* 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).
 */
G
Guy Schalnat 已提交
85
void
A
Andreas Dilger 已提交
86
png_do_pack(png_row_infop row_info, png_bytep row, png_uint_32 bit_depth)
G
Guy Schalnat 已提交
87
{
A
Andreas Dilger 已提交
88 89 90 91 92
   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
G
Guy Schalnat 已提交
93 94
      row_info->channels == 1)
   {
A
Andreas Dilger 已提交
95
      switch ((int)bit_depth)
G
Guy Schalnat 已提交
96 97 98
      {
         case 1:
         {
A
Andreas Dilger 已提交
99 100
            png_bytep sp, dp;
            int mask, v;
101 102
            png_uint_32 i;
            png_uint_32 row_width = row_info->width;
G
Guy Schalnat 已提交
103 104 105 106 107

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

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

            sp = row;
            dp = row;
            shift = 6;
            v = 0;
139
            for (i = 0; i < row_width; i++)
G
Guy Schalnat 已提交
140
            {
A
Andreas Dilger 已提交
141 142
               png_byte value;

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

            sp = row;
            dp = row;
            shift = 4;
            v = 0;
171
            for (i = 0; i < row_width; i++)
G
Guy Schalnat 已提交
172
            {
A
Andreas Dilger 已提交
173 174
               png_byte value;

175
               value = (png_byte)(*sp & 0x0f);
G
Guy Schalnat 已提交
176 177 178 179 180
               v |= (value << shift);

               if (shift == 0)
               {
                  shift = 4;
G
Guy Schalnat 已提交
181
                  *dp = (png_byte)v;
G
Guy Schalnat 已提交
182 183 184 185 186 187 188 189 190
                  dp++;
                  v = 0;
               }
               else
                  shift -= 4;

               sp++;
            }
            if (shift != 4)
G
Guy Schalnat 已提交
191
               *dp = (png_byte)v;
G
Guy Schalnat 已提交
192 193 194
            break;
         }
      }
A
Andreas Dilger 已提交
195 196
      row_info->bit_depth = (png_byte)bit_depth;
      row_info->pixel_depth = (png_byte)(bit_depth * row_info->channels);
G
Guy Schalnat 已提交
197 198 199 200
      row_info->rowbytes =
         ((row_info->width * row_info->pixel_depth + 7) >> 3);
   }
}
G
Guy Schalnat 已提交
201
#endif
G
Guy Schalnat 已提交
202

G
Guy Schalnat 已提交
203
#if defined(PNG_WRITE_SHIFT_SUPPORTED)
204 205 206 207 208 209 210
/* 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.
 */
G
Guy Schalnat 已提交
211
void
G
Guy Schalnat 已提交
212
png_do_shift(png_row_infop row_info, png_bytep row, png_color_8p bit_depth)
G
Guy Schalnat 已提交
213
{
A
Andreas Dilger 已提交
214 215 216 217 218 219
   png_debug(1, "in png_do_shift\n");
#if defined(PNG_USELESS_TESTS_SUPPORTED)
   if (row != NULL && row_info != NULL &&
#else
   if (
#endif
G
Guy Schalnat 已提交
220 221 222
      row_info->color_type != PNG_COLOR_TYPE_PALETTE)
   {
      int shift_start[4], shift_dec[4];
223
      int channels = 0;
G
Guy Schalnat 已提交
224 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

      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++;
      }

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

         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;

265
         for (i = 0; i < row_bytes; i++, bp++)
G
Guy Schalnat 已提交
266
         {
A
Andreas Dilger 已提交
267 268
            png_uint_16 v;
            int j;
G
Guy Schalnat 已提交
269 270 271 272 273 274 275 276 277 278 279 280 281 282

            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)
      {
283 284
         png_bytep bp = row;
         png_uint_32 i;
285
         png_uint_32 istop = channels * row_info->width;
G
Guy Schalnat 已提交
286

287
         for (i = 0; i < istop; i++, bp++)
G
Guy Schalnat 已提交
288 289
         {

290 291 292
            png_uint_16 v;
            int j;
            int c = (int)(i%channels);
G
Guy Schalnat 已提交
293

294 295 296 297 298 299 300 301
            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);
G
Guy Schalnat 已提交
302 303 304 305 306
            }
         }
      }
      else
      {
G
Guy Schalnat 已提交
307
         png_bytep bp;
308
         png_uint_32 i;
309
         png_uint_32 istop = channels * row_info->width;
G
Guy Schalnat 已提交
310

311
         for (bp = row, i = 0; i < istop; i++)
G
Guy Schalnat 已提交
312
         {
313 314 315
            int c = (int)(i%channels);
            png_uint_16 value, v;
            int j;
G
Guy Schalnat 已提交
316

317
            v = (png_uint_16)(((png_uint_16)(*bp) << 8) + *(bp + 1));
318 319
            value = 0;
            for (j = shift_start[c]; j > -shift_dec[c]; j -= shift_dec[c])
G
Guy Schalnat 已提交
320
            {
321 322 323 324
               if (j > 0)
                  value |= (png_uint_16)((v << j) & (png_uint_16)0xffff);
               else
                  value |= (png_uint_16)((v >> (-j)) & (png_uint_16)0xffff);
G
Guy Schalnat 已提交
325
            }
326 327
            *bp++ = (png_byte)(value >> 8);
            *bp++ = (png_byte)(value & 0xff);
G
Guy Schalnat 已提交
328 329 330 331
         }
      }
   }
}
G
Guy Schalnat 已提交
332
#endif
G
Guy Schalnat 已提交
333

A
Andreas Dilger 已提交
334
#if defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED)
G
Guy Schalnat 已提交
335
void
A
Andreas Dilger 已提交
336
png_do_write_swap_alpha(png_row_infop row_info, png_bytep row)
G
Guy Schalnat 已提交
337
{
A
Andreas Dilger 已提交
338 339 340 341
   png_debug(1, "in png_do_write_swap_alpha\n");
#if defined(PNG_USELESS_TESTS_SUPPORTED)
   if (row != NULL && row_info != NULL)
#endif
G
Guy Schalnat 已提交
342
   {
A
Andreas Dilger 已提交
343
      if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
G
Guy Schalnat 已提交
344
      {
A
Andreas Dilger 已提交
345 346 347 348
         /* This converts from ARGB to RGBA */
         if (row_info->bit_depth == 8)
         {
            png_bytep sp, dp;
349 350 351
            png_uint_32 i;
            png_uint_32 row_width = row_info->width;
            for (i = 0, sp = dp = row; i < row_width; i++)
A
Andreas Dilger 已提交
352
            {
353
               png_byte save = *(sp++);
A
Andreas Dilger 已提交
354 355 356 357 358 359 360 361
               *(dp++) = *(sp++);
               *(dp++) = *(sp++);
               *(dp++) = *(sp++);
               *(dp++) = save;
            }
         }
         /* This converts from AARRGGBB to RRGGBBAA */
         else
G
Guy Schalnat 已提交
362
         {
A
Andreas Dilger 已提交
363
            png_bytep sp, dp;
364 365
            png_uint_32 i;
            png_uint_32 row_width = row_info->width;
A
Andreas Dilger 已提交
366

367
            for (i = 0, sp = dp = row; i < row_width; i++)
A
Andreas Dilger 已提交
368
            {
369
               png_byte save[2];
A
Andreas Dilger 已提交
370 371 372 373 374 375 376 377 378 379 380
               save[0] = *(sp++);
               save[1] = *(sp++);
               *(dp++) = *(sp++);
               *(dp++) = *(sp++);
               *(dp++) = *(sp++);
               *(dp++) = *(sp++);
               *(dp++) = *(sp++);
               *(dp++) = *(sp++);
               *(dp++) = save[0];
               *(dp++) = save[1];
            }
G
Guy Schalnat 已提交
381 382
         }
      }
A
Andreas Dilger 已提交
383
      else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
G
Guy Schalnat 已提交
384
      {
A
Andreas Dilger 已提交
385 386 387 388 389
         /* This converts from AG to GA */
         if (row_info->bit_depth == 8)
         {
            png_bytep sp, dp;
            png_uint_32 i;
390
            png_uint_32 row_width = row_info->width;
G
Guy Schalnat 已提交
391

392
            for (i = 0, sp = dp = row; i < row_width; i++)
A
Andreas Dilger 已提交
393
            {
394
               png_byte save = *(sp++);
A
Andreas Dilger 已提交
395 396 397 398 399 400
               *(dp++) = *(sp++);
               *(dp++) = save;
            }
         }
         /* This converts from AAGG to GGAA */
         else
G
Guy Schalnat 已提交
401
         {
A
Andreas Dilger 已提交
402 403
            png_bytep sp, dp;
            png_uint_32 i;
404
            png_uint_32 row_width = row_info->width;
A
Andreas Dilger 已提交
405

406
            for (i = 0, sp = dp = row; i < row_width; i++)
A
Andreas Dilger 已提交
407
            {
408
               png_byte save[2];
A
Andreas Dilger 已提交
409 410 411 412 413 414 415
               save[0] = *(sp++);
               save[1] = *(sp++);
               *(dp++) = *(sp++);
               *(dp++) = *(sp++);
               *(dp++) = save[0];
               *(dp++) = save[1];
            }
G
Guy Schalnat 已提交
416
         }
G
Guy Schalnat 已提交
417 418 419
      }
   }
}
G
Guy Schalnat 已提交
420
#endif
G
Guy Schalnat 已提交
421

422 423 424 425 426 427 428 429 430 431 432 433 434 435 436
#if defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED)
void
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;
437 438 439
            png_uint_32 i;
            png_uint_32 row_width = row_info->width;
            for (i = 0, sp = dp = row; i < row_width; i++)
440 441 442 443
            {
               *(dp++) = *(sp++);
               *(dp++) = *(sp++);
               *(dp++) = *(sp++);
444
               *(dp++) = (png_byte)(255 - *(sp++));
445 446 447 448 449 450
            }
         }
         /* This inverts the alpha channel in RRGGBBAA */
         else
         {
            png_bytep sp, dp;
451 452
            png_uint_32 i;
            png_uint_32 row_width = row_info->width;
453

454
            for (i = 0, sp = dp = row; i < row_width; i++)
455 456 457 458 459 460 461
            {
               *(dp++) = *(sp++);
               *(dp++) = *(sp++);
               *(dp++) = *(sp++);
               *(dp++) = *(sp++);
               *(dp++) = *(sp++);
               *(dp++) = *(sp++);
462 463
               *(dp++) = (png_byte)(255 - *(sp++));
               *(dp++) = (png_byte)(255 - *(sp++));
464 465 466 467 468 469 470 471 472
            }
         }
      }
      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;
473 474
            png_uint_32 i;
            png_uint_32 row_width = row_info->width;
475

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

489
            for (i = 0, sp = dp = row; i < row_width; i++)
490 491 492
            {
               *(dp++) = *(sp++);
               *(dp++) = *(sp++);
493 494
               *(dp++) = (png_byte)(255 - *(sp++));
               *(dp++) = (png_byte)(255 - *(sp++));
495 496 497 498 499 500
            }
         }
      }
   }
}
#endif