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