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