Coverage Report

Created: 2025-06-16 07:00

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