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