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