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