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 */
22void /* PRIVATE */
23png_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 */
91void /* PRIVATE */
92png_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 */
218void /* PRIVATE */
219png_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
343void /* PRIVATE */
344png_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
432void /* PRIVATE */
433png_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  */
523void /* PRIVATE */
524png_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