Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/thirdparty/libpng/pngwtran.c
9833 views
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
{
26
png_debug(1, "in png_do_pack");
27
28
if (row_info->bit_depth == 8 &&
29
row_info->channels == 1)
30
{
31
switch ((int)bit_depth)
32
{
33
case 1:
34
{
35
png_bytep sp, dp;
36
int mask, v;
37
png_uint_32 i;
38
png_uint_32 row_width = row_info->width;
39
40
sp = row;
41
dp = row;
42
mask = 0x80;
43
v = 0;
44
45
for (i = 0; i < row_width; i++)
46
{
47
if (*sp != 0)
48
v |= mask;
49
50
sp++;
51
52
if (mask > 1)
53
mask >>= 1;
54
55
else
56
{
57
mask = 0x80;
58
*dp = (png_byte)v;
59
dp++;
60
v = 0;
61
}
62
}
63
64
if (mask != 0x80)
65
*dp = (png_byte)v;
66
67
break;
68
}
69
70
case 2:
71
{
72
png_bytep sp, dp;
73
unsigned int shift;
74
int 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
unsigned int shift;
114
int v;
115
png_uint_32 i;
116
png_uint_32 row_width = row_info->width;
117
118
sp = row;
119
dp = row;
120
shift = 4;
121
v = 0;
122
123
for (i = 0; i < row_width; i++)
124
{
125
png_byte value;
126
127
value = (png_byte)(*sp & 0x0f);
128
v |= (value << shift);
129
130
if (shift == 0)
131
{
132
shift = 4;
133
*dp = (png_byte)v;
134
dp++;
135
v = 0;
136
}
137
138
else
139
shift -= 4;
140
141
sp++;
142
}
143
144
if (shift != 4)
145
*dp = (png_byte)v;
146
147
break;
148
}
149
150
default:
151
break;
152
}
153
154
row_info->bit_depth = (png_byte)bit_depth;
155
row_info->pixel_depth = (png_byte)(bit_depth * row_info->channels);
156
row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth,
157
row_info->width);
158
}
159
}
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
{
174
png_debug(1, "in png_do_shift");
175
176
if (row_info->color_type != PNG_COLOR_TYPE_PALETTE)
177
{
178
int shift_start[4], shift_dec[4];
179
unsigned int channels = 0;
180
181
if ((row_info->color_type & PNG_COLOR_MASK_COLOR) != 0)
182
{
183
shift_start[channels] = row_info->bit_depth - bit_depth->red;
184
shift_dec[channels] = bit_depth->red;
185
channels++;
186
187
shift_start[channels] = row_info->bit_depth - bit_depth->green;
188
shift_dec[channels] = bit_depth->green;
189
channels++;
190
191
shift_start[channels] = row_info->bit_depth - bit_depth->blue;
192
shift_dec[channels] = bit_depth->blue;
193
channels++;
194
}
195
196
else
197
{
198
shift_start[channels] = row_info->bit_depth - bit_depth->gray;
199
shift_dec[channels] = bit_depth->gray;
200
channels++;
201
}
202
203
if ((row_info->color_type & PNG_COLOR_MASK_ALPHA) != 0)
204
{
205
shift_start[channels] = row_info->bit_depth - bit_depth->alpha;
206
shift_dec[channels] = bit_depth->alpha;
207
channels++;
208
}
209
210
/* With low row depths, could only be grayscale, so one channel */
211
if (row_info->bit_depth < 8)
212
{
213
png_bytep bp = row;
214
size_t i;
215
unsigned int mask;
216
size_t row_bytes = row_info->rowbytes;
217
218
if (bit_depth->gray == 1 && row_info->bit_depth == 2)
219
mask = 0x55;
220
221
else if (row_info->bit_depth == 4 && bit_depth->gray == 3)
222
mask = 0x11;
223
224
else
225
mask = 0xff;
226
227
for (i = 0; i < row_bytes; i++, bp++)
228
{
229
int j;
230
unsigned int v, out;
231
232
v = *bp;
233
out = 0;
234
235
for (j = shift_start[0]; j > -shift_dec[0]; j -= shift_dec[0])
236
{
237
if (j > 0)
238
out |= v << j;
239
240
else
241
out |= (v >> (-j)) & mask;
242
}
243
244
*bp = (png_byte)(out & 0xff);
245
}
246
}
247
248
else if (row_info->bit_depth == 8)
249
{
250
png_bytep bp = row;
251
png_uint_32 i;
252
png_uint_32 istop = channels * row_info->width;
253
254
for (i = 0; i < istop; i++, bp++)
255
{
256
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
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
308
static void
309
png_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 /* WRITE_16BIT */
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 /* WRITE_16BIT */
396
}
397
}
398
}
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
{
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 /* WRITE_16BIT */
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 /* WRITE_16BIT */
491
}
492
}
493
}
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
{
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) != 0)
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
/* 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) != 0)
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) != 0)
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) != 0)
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
# ifdef PNG_16BIT_SUPPORTED
542
if ((png_ptr->transformations & PNG_SWAP_BYTES) != 0)
543
png_do_swap(row_info, png_ptr->row_buf + 1);
544
# endif
545
#endif
546
547
#ifdef PNG_WRITE_SHIFT_SUPPORTED
548
if ((png_ptr->transformations & PNG_SHIFT) != 0)
549
png_do_shift(row_info, png_ptr->row_buf + 1,
550
&(png_ptr->shift));
551
#endif
552
553
#ifdef PNG_WRITE_SWAP_ALPHA_SUPPORTED
554
if ((png_ptr->transformations & PNG_SWAP_ALPHA) != 0)
555
png_do_write_swap_alpha(row_info, png_ptr->row_buf + 1);
556
#endif
557
558
#ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED
559
if ((png_ptr->transformations & PNG_INVERT_ALPHA) != 0)
560
png_do_write_invert_alpha(row_info, png_ptr->row_buf + 1);
561
#endif
562
563
#ifdef PNG_WRITE_BGR_SUPPORTED
564
if ((png_ptr->transformations & PNG_BGR) != 0)
565
png_do_bgr(row_info, png_ptr->row_buf + 1);
566
#endif
567
568
#ifdef PNG_WRITE_INVERT_SUPPORTED
569
if ((png_ptr->transformations & PNG_INVERT_MONO) != 0)
570
png_do_invert(row_info, png_ptr->row_buf + 1);
571
#endif
572
}
573
#endif /* WRITE_TRANSFORMS */
574
#endif /* WRITE */
575
576