• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 
2 /* pngwtran.c - transforms the data in a row for PNG writers
3  *
4  * Last changed in libpng 1.2.43 [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_INTERNAL
15 #define PNG_NO_PEDANTIC_WARNINGS
16 #include "png.h"
17 #ifdef PNG_WRITE_SUPPORTED
18 
19 /* Transform the data according to the user's wishes.  The order of
20  * transformations is significant.
21  */
22 void /* PRIVATE */
png_do_write_transformations(png_structp png_ptr)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 */
png_do_pack(png_row_infop row_info,png_bytep row,png_uint_32 bit_depth)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 #ifdef PNG_USELESS_TESTS_SUPPORTED
98        row != NULL && row_info != NULL &&
99 #endif
100       row_info->channels == 1)
101    {
102       switch ((int)bit_depth)
103       {
104          case 1:
105          {
106             png_bytep sp, dp;
107             int mask, v;
108             png_uint_32 i;
109             png_uint_32 row_width = row_info->width;
110 
111             sp = row;
112             dp = row;
113             mask = 0x80;
114             v = 0;
115 
116             for (i = 0; i < row_width; i++)
117             {
118                if (*sp != 0)
119                   v |= mask;
120                sp++;
121                if (mask > 1)
122                   mask >>= 1;
123                else
124                {
125                   mask = 0x80;
126                   *dp = (png_byte)v;
127                   dp++;
128                   v = 0;
129                }
130             }
131             if (mask != 0x80)
132                *dp = (png_byte)v;
133             break;
134          }
135          case 2:
136          {
137             png_bytep sp, dp;
138             int shift, v;
139             png_uint_32 i;
140             png_uint_32 row_width = row_info->width;
141 
142             sp = row;
143             dp = row;
144             shift = 6;
145             v = 0;
146             for (i = 0; i < row_width; i++)
147             {
148                png_byte value;
149 
150                value = (png_byte)(*sp & 0x03);
151                v |= (value << shift);
152                if (shift == 0)
153                {
154                   shift = 6;
155                   *dp = (png_byte)v;
156                   dp++;
157                   v = 0;
158                }
159                else
160                   shift -= 2;
161                sp++;
162             }
163             if (shift != 6)
164                *dp = (png_byte)v;
165             break;
166          }
167          case 4:
168          {
169             png_bytep sp, dp;
170             int shift, v;
171             png_uint_32 i;
172             png_uint_32 row_width = row_info->width;
173 
174             sp = row;
175             dp = row;
176             shift = 4;
177             v = 0;
178             for (i = 0; i < row_width; i++)
179             {
180                png_byte value;
181 
182                value = (png_byte)(*sp & 0x0f);
183                v |= (value << shift);
184 
185                if (shift == 0)
186                {
187                   shift = 4;
188                   *dp = (png_byte)v;
189                   dp++;
190                   v = 0;
191                }
192                else
193                   shift -= 4;
194 
195                sp++;
196             }
197             if (shift != 4)
198                *dp = (png_byte)v;
199             break;
200          }
201       }
202       row_info->bit_depth = (png_byte)bit_depth;
203       row_info->pixel_depth = (png_byte)(bit_depth * row_info->channels);
204       row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth,
205          row_info->width);
206    }
207 }
208 #endif
209 
210 #ifdef PNG_WRITE_SHIFT_SUPPORTED
211 /* Shift pixel values to take advantage of whole range.  Pass the
212  * true number of bits in bit_depth.  The row should be packed
213  * according to row_info->bit_depth.  Thus, if you had a row of
214  * bit depth 4, but the pixels only had values from 0 to 7, you
215  * would pass 3 as bit_depth, and this routine would translate the
216  * data to 0 to 15.
217  */
218 void /* PRIVATE */
png_do_shift(png_row_infop row_info,png_bytep row,png_color_8p bit_depth)219 png_do_shift(png_row_infop row_info, png_bytep row, png_color_8p bit_depth)
220 {
221    png_debug(1, "in png_do_shift");
222 
223 #ifdef PNG_USELESS_TESTS_SUPPORTED
224    if (row != NULL && row_info != NULL &&
225 #else
226    if (
227 #endif
228       row_info->color_type != PNG_COLOR_TYPE_PALETTE)
229    {
230       int shift_start[4], shift_dec[4];
231       int channels = 0;
232 
233       if (row_info->color_type & PNG_COLOR_MASK_COLOR)
234       {
235          shift_start[channels] = row_info->bit_depth - bit_depth->red;
236          shift_dec[channels] = bit_depth->red;
237          channels++;
238          shift_start[channels] = row_info->bit_depth - bit_depth->green;
239          shift_dec[channels] = bit_depth->green;
240          channels++;
241          shift_start[channels] = row_info->bit_depth - bit_depth->blue;
242          shift_dec[channels] = bit_depth->blue;
243          channels++;
244       }
245       else
246       {
247          shift_start[channels] = row_info->bit_depth - bit_depth->gray;
248          shift_dec[channels] = bit_depth->gray;
249          channels++;
250       }
251       if (row_info->color_type & PNG_COLOR_MASK_ALPHA)
252       {
253          shift_start[channels] = row_info->bit_depth - bit_depth->alpha;
254          shift_dec[channels] = bit_depth->alpha;
255          channels++;
256       }
257 
258       /* With low row depths, could only be grayscale, so one channel */
259       if (row_info->bit_depth < 8)
260       {
261          png_bytep bp = row;
262          png_uint_32 i;
263          png_byte mask;
264          png_uint_32 row_bytes = row_info->rowbytes;
265 
266          if (bit_depth->gray == 1 && row_info->bit_depth == 2)
267             mask = 0x55;
268          else if (row_info->bit_depth == 4 && bit_depth->gray == 3)
269             mask = 0x11;
270          else
271             mask = 0xff;
272 
273          for (i = 0; i < row_bytes; i++, bp++)
274          {
275             png_uint_16 v;
276             int j;
277 
278             v = *bp;
279             *bp = 0;
280             for (j = shift_start[0]; j > -shift_dec[0]; j -= shift_dec[0])
281             {
282                if (j > 0)
283                   *bp |= (png_byte)((v << j) & 0xff);
284                else
285                   *bp |= (png_byte)((v >> (-j)) & mask);
286             }
287          }
288       }
289       else if (row_info->bit_depth == 8)
290       {
291          png_bytep bp = row;
292          png_uint_32 i;
293          png_uint_32 istop = channels * row_info->width;
294 
295          for (i = 0; i < istop; i++, bp++)
296          {
297 
298             png_uint_16 v;
299             int j;
300             int c = (int)(i%channels);
301 
302             v = *bp;
303             *bp = 0;
304             for (j = shift_start[c]; j > -shift_dec[c]; j -= shift_dec[c])
305             {
306                if (j > 0)
307                   *bp |= (png_byte)((v << j) & 0xff);
308                else
309                   *bp |= (png_byte)((v >> (-j)) & 0xff);
310             }
311          }
312       }
313       else
314       {
315          png_bytep bp;
316          png_uint_32 i;
317          png_uint_32 istop = channels * row_info->width;
318 
319          for (bp = row, i = 0; i < istop; i++)
320          {
321             int c = (int)(i%channels);
322             png_uint_16 value, v;
323             int j;
324 
325             v = (png_uint_16)(((png_uint_16)(*bp) << 8) + *(bp + 1));
326             value = 0;
327             for (j = shift_start[c]; j > -shift_dec[c]; j -= shift_dec[c])
328             {
329                if (j > 0)
330                   value |= (png_uint_16)((v << j) & (png_uint_16)0xffff);
331                else
332                   value |= (png_uint_16)((v >> (-j)) & (png_uint_16)0xffff);
333             }
334             *bp++ = (png_byte)(value >> 8);
335             *bp++ = (png_byte)(value & 0xff);
336          }
337       }
338    }
339 }
340 #endif
341 
342 #ifdef PNG_WRITE_SWAP_ALPHA_SUPPORTED
343 void /* PRIVATE */
png_do_write_swap_alpha(png_row_infop row_info,png_bytep row)344 png_do_write_swap_alpha(png_row_infop row_info, png_bytep row)
345 {
346    png_debug(1, "in png_do_write_swap_alpha");
347 
348 #ifdef PNG_USELESS_TESTS_SUPPORTED
349    if (row != NULL && row_info != NULL)
350 #endif
351    {
352       if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
353       {
354          /* This converts from ARGB to RGBA */
355          if (row_info->bit_depth == 8)
356          {
357             png_bytep sp, dp;
358             png_uint_32 i;
359             png_uint_32 row_width = row_info->width;
360             for (i = 0, sp = dp = row; i < row_width; i++)
361             {
362                png_byte save = *(sp++);
363                *(dp++) = *(sp++);
364                *(dp++) = *(sp++);
365                *(dp++) = *(sp++);
366                *(dp++) = save;
367             }
368          }
369          /* This converts from AARRGGBB to RRGGBBAA */
370          else
371          {
372             png_bytep sp, dp;
373             png_uint_32 i;
374             png_uint_32 row_width = row_info->width;
375 
376             for (i = 0, sp = dp = row; i < row_width; i++)
377             {
378                png_byte save[2];
379                save[0] = *(sp++);
380                save[1] = *(sp++);
381                *(dp++) = *(sp++);
382                *(dp++) = *(sp++);
383                *(dp++) = *(sp++);
384                *(dp++) = *(sp++);
385                *(dp++) = *(sp++);
386                *(dp++) = *(sp++);
387                *(dp++) = save[0];
388                *(dp++) = save[1];
389             }
390          }
391       }
392       else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
393       {
394          /* This converts from AG to GA */
395          if (row_info->bit_depth == 8)
396          {
397             png_bytep sp, dp;
398             png_uint_32 i;
399             png_uint_32 row_width = row_info->width;
400 
401             for (i = 0, sp = dp = row; i < row_width; i++)
402             {
403                png_byte save = *(sp++);
404                *(dp++) = *(sp++);
405                *(dp++) = save;
406             }
407          }
408          /* This converts from AAGG to GGAA */
409          else
410          {
411             png_bytep sp, dp;
412             png_uint_32 i;
413             png_uint_32 row_width = row_info->width;
414 
415             for (i = 0, sp = dp = row; i < row_width; i++)
416             {
417                png_byte save[2];
418                save[0] = *(sp++);
419                save[1] = *(sp++);
420                *(dp++) = *(sp++);
421                *(dp++) = *(sp++);
422                *(dp++) = save[0];
423                *(dp++) = save[1];
424             }
425          }
426       }
427    }
428 }
429 #endif
430 
431 #ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED
432 void /* PRIVATE */
png_do_write_invert_alpha(png_row_infop row_info,png_bytep row)433 png_do_write_invert_alpha(png_row_infop row_info, png_bytep row)
434 {
435    png_debug(1, "in png_do_write_invert_alpha");
436 
437 #ifdef PNG_USELESS_TESTS_SUPPORTED
438    if (row != NULL && row_info != NULL)
439 #endif
440    {
441       if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
442       {
443          /* This inverts the alpha channel in RGBA */
444          if (row_info->bit_depth == 8)
445          {
446             png_bytep sp, dp;
447             png_uint_32 i;
448             png_uint_32 row_width = row_info->width;
449             for (i = 0, sp = dp = row; i < row_width; i++)
450             {
451                /* Does nothing
452                *(dp++) = *(sp++);
453                *(dp++) = *(sp++);
454                *(dp++) = *(sp++);
455                */
456                sp+=3; dp = sp;
457                *(dp++) = (png_byte)(255 - *(sp++));
458             }
459          }
460          /* This inverts the alpha channel in RRGGBBAA */
461          else
462          {
463             png_bytep sp, dp;
464             png_uint_32 i;
465             png_uint_32 row_width = row_info->width;
466 
467             for (i = 0, sp = dp = row; i < row_width; i++)
468             {
469                /* Does nothing
470                *(dp++) = *(sp++);
471                *(dp++) = *(sp++);
472                *(dp++) = *(sp++);
473                *(dp++) = *(sp++);
474                *(dp++) = *(sp++);
475                *(dp++) = *(sp++);
476                */
477                sp+=6; dp = sp;
478                *(dp++) = (png_byte)(255 - *(sp++));
479                *(dp++) = (png_byte)(255 - *(sp++));
480             }
481          }
482       }
483       else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
484       {
485          /* This inverts the alpha channel in GA */
486          if (row_info->bit_depth == 8)
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                *(dp++) = *(sp++);
495                *(dp++) = (png_byte)(255 - *(sp++));
496             }
497          }
498          /* This inverts the alpha channel in GGAA */
499          else
500          {
501             png_bytep sp, dp;
502             png_uint_32 i;
503             png_uint_32 row_width = row_info->width;
504 
505             for (i = 0, sp = dp = row; i < row_width; i++)
506             {
507                /* Does nothing
508                *(dp++) = *(sp++);
509                *(dp++) = *(sp++);
510                */
511                sp+=2; dp = sp;
512                *(dp++) = (png_byte)(255 - *(sp++));
513                *(dp++) = (png_byte)(255 - *(sp++));
514             }
515          }
516       }
517    }
518 }
519 #endif
520 
521 #ifdef PNG_MNG_FEATURES_SUPPORTED
522 /* Undoes intrapixel differencing  */
523 void /* PRIVATE */
png_do_write_intrapixel(png_row_infop row_info,png_bytep row)524 png_do_write_intrapixel(png_row_infop row_info, png_bytep row)
525 {
526    png_debug(1, "in png_do_write_intrapixel");
527 
528    if (
529 #ifdef PNG_USELESS_TESTS_SUPPORTED
530        row != NULL && row_info != NULL &&
531 #endif
532        (row_info->color_type & PNG_COLOR_MASK_COLOR))
533    {
534       int bytes_per_pixel;
535       png_uint_32 row_width = row_info->width;
536       if (row_info->bit_depth == 8)
537       {
538          png_bytep rp;
539          png_uint_32 i;
540 
541          if (row_info->color_type == PNG_COLOR_TYPE_RGB)
542             bytes_per_pixel = 3;
543          else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
544             bytes_per_pixel = 4;
545          else
546             return;
547 
548          for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel)
549          {
550             *(rp)   = (png_byte)((*rp     - *(rp+1))&0xff);
551             *(rp+2) = (png_byte)((*(rp+2) - *(rp+1))&0xff);
552          }
553       }
554       else if (row_info->bit_depth == 16)
555       {
556          png_bytep rp;
557          png_uint_32 i;
558 
559          if (row_info->color_type == PNG_COLOR_TYPE_RGB)
560             bytes_per_pixel = 6;
561          else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
562             bytes_per_pixel = 8;
563          else
564             return;
565 
566          for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel)
567          {
568             png_uint_32 s0   = (*(rp  ) << 8) | *(rp+1);
569             png_uint_32 s1   = (*(rp+2) << 8) | *(rp+3);
570             png_uint_32 s2   = (*(rp+4) << 8) | *(rp+5);
571             png_uint_32 red  = (png_uint_32)((s0 - s1) & 0xffffL);
572             png_uint_32 blue = (png_uint_32)((s2 - s1) & 0xffffL);
573             *(rp  ) = (png_byte)((red >> 8) & 0xff);
574             *(rp+1) = (png_byte)(red & 0xff);
575             *(rp+4) = (png_byte)((blue >> 8) & 0xff);
576             *(rp+5) = (png_byte)(blue & 0xff);
577          }
578       }
579    }
580 }
581 #endif /* PNG_MNG_FEATURES_SUPPORTED */
582 #endif /* PNG_WRITE_SUPPORTED */
583