Coverage Report

Created: 2024-06-18 06:05

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