merge of wxMac into main repository
[wxWidgets.git] / src / png / pngwtran.c
1
2 /* pngwtran.c - transforms the data in a row for PNG writers
3 *
4 * libpng 1.0.3 - January 14, 1999
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
8 * Copyright (c) 1998, 1999 Glenn Randers-Pehrson
9 */
10
11 #define PNG_INTERNAL
12 #include "png.h"
13
14 /* Transform the data according to the user's wishes. The order of
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
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
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
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;
99 png_uint_32 row_width = row_info->width;
100
101 sp = row;
102 dp = row;
103 mask = 0x80;
104 v = 0;
105
106 for (i = 0; i < row_width; i++)
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;
130 png_uint_32 row_width = row_info->width;
131
132 sp = row;
133 dp = row;
134 shift = 6;
135 v = 0;
136 for (i = 0; i < row_width; i++)
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;
162 png_uint_32 row_width = row_info->width;
163
164 sp = row;
165 dp = row;
166 shift = 4;
167 v = 0;
168 for (i = 0; i < row_width; i++)
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];
220 int channels = 0;
221
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 {
250 png_bytep bp = row;
251 png_uint_32 i;
252 png_byte mask;
253 png_uint_32 row_bytes = row_info->rowbytes;
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
262 for (i = 0; i < row_bytes; i++, bp++)
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 {
280 png_bytep bp = row;
281 png_uint_32 i;
282 png_uint_32 istop = channels * row_info->width;
283
284 for (i = 0; i < istop; i++, bp++)
285 {
286
287 png_uint_16 v;
288 int j;
289 int c = (int)(i%channels);
290
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);
299 }
300 }
301 }
302 else
303 {
304 png_bytep bp;
305 png_uint_32 i;
306 png_uint_32 istop = channels * row_info->width;
307
308 for (bp = row, i = 0; i < istop; i++)
309 {
310 int c = (int)(i%channels);
311 png_uint_16 value, v;
312 int j;
313
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])
317 {
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);
322 }
323 *bp++ = (png_byte)(value >> 8);
324 *bp++ = (png_byte)(value & 0xff);
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;
346 png_uint_32 i;
347 png_uint_32 row_width = row_info->width;
348 for (i = 0, sp = dp = row; i < row_width; i++)
349 {
350 png_byte save = *(sp++);
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;
361 png_uint_32 i;
362 png_uint_32 row_width = row_info->width;
363
364 for (i = 0, sp = dp = row; i < row_width; i++)
365 {
366 png_byte save[2];
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;
386 png_uint_32 i;
387 png_uint_32 row_width = row_info->width;
388
389 for (i = 0, sp = dp = row; i < row_width; i++)
390 {
391 png_byte save = *(sp++);
392 *(dp++) = *(sp++);
393 *(dp++) = save;
394 }
395 }
396 /* This converts from AAGG to GGAA */
397 else
398 {
399 png_bytep sp, dp;
400 png_uint_32 i;
401 png_uint_32 row_width = row_info->width;
402
403 for (i = 0, sp = dp = row; i < row_width; i++)
404 {
405 png_byte save[2];
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;
435 png_uint_32 row_width = row_info->width;
436 for (i = 0, sp = dp = row; i < row_width; i++)
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;
449 png_uint_32 row_width = row_info->width;
450
451 for (i = 0, sp = dp = row; i < row_width; i++)
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;
471 png_uint_32 row_width = row_info->width;
472
473 for (i = 0, sp = dp = row; i < row_width; i++)
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;
484 png_uint_32 row_width = row_info->width;
485
486 for (i = 0, sp = dp = row; i < row_width; i++)
487 {
488 *(dp++) = *(sp++);
489 *(dp++) = *(sp++);
490 *(dp++) = 255 - *(sp++);
491 *(dp++) = 255 - *(sp++);
492 }
493 }
494 }
495 }
496 }
497 #endif