blob: fc7d56c1232f2407ad652c7dbdd33cd749545c76 [file] [log] [blame]
Guy Schalnat0d580581995-07-20 02:43:20 -05001
Andreas Dilger47a0c421997-05-16 02:46:07 -05002/* pngwtran.c - transforms the data in a row for PNG writers
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06003 *
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06004 * libpng 0.98
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06005 * 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
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -06008 * Copyright (c) 1998, Glenn Randers-Pehrson
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06009 * January 16, 1998
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -060010 */
Guy Schalnat0d580581995-07-20 02:43:20 -050011
12#define PNG_INTERNAL
13#include "png.h"
14
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -060015/* Transform the data according to the users wishes. The order of
16 * transformations is significant.
17 */
Guy Schalnat0d580581995-07-20 02:43:20 -050018void
Guy Schalnat6d764711995-12-19 03:22:19 -060019png_do_write_transformations(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -050020{
Andreas Dilger47a0c421997-05-16 02:46:07 -050021 png_debug(1, "in png_do_write_transformations\n");
Guy Schalnat51f0eb41995-09-26 05:22:39 -050022#if defined(PNG_WRITE_FILLER_SUPPORTED)
Guy Schalnat6d764711995-12-19 03:22:19 -060023 if (png_ptr->transformations & PNG_FILLER)
Andreas Dilger47a0c421997-05-16 02:46:07 -050024 png_do_strip_filler(&(png_ptr->row_info), png_ptr->row_buf + 1,
Guy Schalnate5a37791996-06-05 15:50:50 -050025 png_ptr->flags);
Guy Schalnat51f0eb41995-09-26 05:22:39 -050026#endif
27#if defined(PNG_WRITE_PACK_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -050028 if (png_ptr->transformations & PNG_PACK)
29 png_do_pack(&(png_ptr->row_info), png_ptr->row_buf + 1,
Andreas Dilger47a0c421997-05-16 02:46:07 -050030 (png_uint_32)png_ptr->bit_depth);
Guy Schalnat51f0eb41995-09-26 05:22:39 -050031#endif
32#if defined(PNG_WRITE_SHIFT_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -050033 if (png_ptr->transformations & PNG_SHIFT)
34 png_do_shift(&(png_ptr->row_info), png_ptr->row_buf + 1,
35 &(png_ptr->shift));
Guy Schalnat51f0eb41995-09-26 05:22:39 -050036#endif
37#if defined(PNG_WRITE_SWAP_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -050038 if (png_ptr->transformations & PNG_SWAP_BYTES)
39 png_do_swap(&(png_ptr->row_info), png_ptr->row_buf + 1);
Guy Schalnat51f0eb41995-09-26 05:22:39 -050040#endif
Andreas Dilger47a0c421997-05-16 02:46:07 -050041#if defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED)
42 if (png_ptr->transformations & PNG_SWAP_ALPHA)
43 png_do_write_swap_alpha(&(png_ptr->row_info), png_ptr->row_buf + 1);
44#endif
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -060045#if defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED)
46 if (png_ptr->transformations & PNG_INVERT_ALPHA)
47 png_do_write_invert_alpha(&(png_ptr->row_info), png_ptr->row_buf + 1);
48#endif
Guy Schalnat51f0eb41995-09-26 05:22:39 -050049#if defined(PNG_WRITE_BGR_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -050050 if (png_ptr->transformations & PNG_BGR)
51 png_do_bgr(&(png_ptr->row_info), png_ptr->row_buf + 1);
Guy Schalnat51f0eb41995-09-26 05:22:39 -050052#endif
53#if defined(PNG_WRITE_INVERT_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -050054 if (png_ptr->transformations & PNG_INVERT_MONO)
55 png_do_invert(&(png_ptr->row_info), png_ptr->row_buf + 1);
Guy Schalnat51f0eb41995-09-26 05:22:39 -050056#endif
Guy Schalnat0d580581995-07-20 02:43:20 -050057}
58
Guy Schalnat51f0eb41995-09-26 05:22:39 -050059#if defined(PNG_WRITE_PACK_SUPPORTED)
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -060060/* Pack pixels into bytes. Pass the true bit depth in bit_depth. The
61 * row_info bit depth should be 8 (one pixel per byte). The channels
62 * should be 1 (this only happens on grayscale and paletted images).
63 */
Guy Schalnat0d580581995-07-20 02:43:20 -050064void
Andreas Dilger47a0c421997-05-16 02:46:07 -050065png_do_pack(png_row_infop row_info, png_bytep row, png_uint_32 bit_depth)
Guy Schalnat0d580581995-07-20 02:43:20 -050066{
Andreas Dilger47a0c421997-05-16 02:46:07 -050067 png_debug(1, "in png_do_pack\n");
68 if (row_info->bit_depth == 8 &&
69#if defined(PNG_USELESS_TESTS_SUPPORTED)
70 row != NULL && row_info != NULL &&
71#endif
Guy Schalnat0d580581995-07-20 02:43:20 -050072 row_info->channels == 1)
73 {
Andreas Dilger47a0c421997-05-16 02:46:07 -050074 switch ((int)bit_depth)
Guy Schalnat0d580581995-07-20 02:43:20 -050075 {
76 case 1:
77 {
Andreas Dilger47a0c421997-05-16 02:46:07 -050078 png_bytep sp, dp;
79 int mask, v;
80 png_uint_32 i;
Guy Schalnat0d580581995-07-20 02:43:20 -050081
82 sp = row;
83 dp = row;
84 mask = 0x80;
85 v = 0;
86 for (i = 0; i < row_info->width; i++)
87 {
Andreas Dilger47a0c421997-05-16 02:46:07 -050088 if (*sp != 0)
Guy Schalnat0d580581995-07-20 02:43:20 -050089 v |= mask;
90 sp++;
91 if (mask > 1)
92 mask >>= 1;
93 else
94 {
95 mask = 0x80;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -060096 *dp = (png_byte)v;
97 dp++;
Guy Schalnat0d580581995-07-20 02:43:20 -050098 v = 0;
99 }
100 }
101 if (mask != 0x80)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600102 *dp = (png_byte)v;
Guy Schalnat0d580581995-07-20 02:43:20 -0500103 break;
104 }
105 case 2:
106 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500107 png_bytep sp, dp;
108 int shift, v;
109 png_uint_32 i;
Guy Schalnat0d580581995-07-20 02:43:20 -0500110
111 sp = row;
112 dp = row;
113 shift = 6;
114 v = 0;
115 for (i = 0; i < row_info->width; i++)
116 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500117 png_byte value;
118
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600119 value = (png_byte)(*sp & 0x3);
Guy Schalnat0d580581995-07-20 02:43:20 -0500120 v |= (value << shift);
121 if (shift == 0)
122 {
123 shift = 6;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600124 *dp = (png_byte)v;
Guy Schalnat0d580581995-07-20 02:43:20 -0500125 dp++;
126 v = 0;
127 }
128 else
129 shift -= 2;
130 sp++;
131 }
132 if (shift != 6)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600133 *dp = (png_byte)v;
Guy Schalnat0d580581995-07-20 02:43:20 -0500134 break;
135 }
136 case 4:
137 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500138 png_bytep sp, dp;
139 int shift, v;
140 png_uint_32 i;
Guy Schalnat0d580581995-07-20 02:43:20 -0500141
142 sp = row;
143 dp = row;
144 shift = 4;
145 v = 0;
146 for (i = 0; i < row_info->width; i++)
147 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500148 png_byte value;
149
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600150 value = (png_byte)(*sp & 0xf);
Guy Schalnat0d580581995-07-20 02:43:20 -0500151 v |= (value << shift);
152
153 if (shift == 0)
154 {
155 shift = 4;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600156 *dp = (png_byte)v;
Guy Schalnat0d580581995-07-20 02:43:20 -0500157 dp++;
158 v = 0;
159 }
160 else
161 shift -= 4;
162
163 sp++;
164 }
165 if (shift != 4)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600166 *dp = (png_byte)v;
Guy Schalnat0d580581995-07-20 02:43:20 -0500167 break;
168 }
169 }
Andreas Dilger47a0c421997-05-16 02:46:07 -0500170 row_info->bit_depth = (png_byte)bit_depth;
171 row_info->pixel_depth = (png_byte)(bit_depth * row_info->channels);
Guy Schalnat0d580581995-07-20 02:43:20 -0500172 row_info->rowbytes =
173 ((row_info->width * row_info->pixel_depth + 7) >> 3);
174 }
175}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500176#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500177
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500178#if defined(PNG_WRITE_SHIFT_SUPPORTED)
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600179/* Shift pixel values to take advantage of whole range. Pass the
180 * true number of bits in bit_depth. The row should be packed
181 * according to row_info->bit_depth. Thus, if you had a row of
182 * bit depth 4, but the pixels only had values from 0 to 7, you
183 * would pass 3 as bit_depth, and this routine would translate the
184 * data to 0 to 15.
185 */
Guy Schalnat0d580581995-07-20 02:43:20 -0500186void
Guy Schalnat6d764711995-12-19 03:22:19 -0600187png_do_shift(png_row_infop row_info, png_bytep row, png_color_8p bit_depth)
Guy Schalnat0d580581995-07-20 02:43:20 -0500188{
Andreas Dilger47a0c421997-05-16 02:46:07 -0500189 png_debug(1, "in png_do_shift\n");
190#if defined(PNG_USELESS_TESTS_SUPPORTED)
191 if (row != NULL && row_info != NULL &&
192#else
193 if (
194#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500195 row_info->color_type != PNG_COLOR_TYPE_PALETTE)
196 {
197 int shift_start[4], shift_dec[4];
Andreas Dilger47a0c421997-05-16 02:46:07 -0500198 png_uint_32 channels;
Guy Schalnat0d580581995-07-20 02:43:20 -0500199
200 channels = 0;
201 if (row_info->color_type & PNG_COLOR_MASK_COLOR)
202 {
203 shift_start[channels] = row_info->bit_depth - bit_depth->red;
204 shift_dec[channels] = bit_depth->red;
205 channels++;
206 shift_start[channels] = row_info->bit_depth - bit_depth->green;
207 shift_dec[channels] = bit_depth->green;
208 channels++;
209 shift_start[channels] = row_info->bit_depth - bit_depth->blue;
210 shift_dec[channels] = bit_depth->blue;
211 channels++;
212 }
213 else
214 {
215 shift_start[channels] = row_info->bit_depth - bit_depth->gray;
216 shift_dec[channels] = bit_depth->gray;
217 channels++;
218 }
219 if (row_info->color_type & PNG_COLOR_MASK_ALPHA)
220 {
221 shift_start[channels] = row_info->bit_depth - bit_depth->alpha;
222 shift_dec[channels] = bit_depth->alpha;
223 channels++;
224 }
225
226 /* with low row dephts, could only be grayscale, so one channel */
227 if (row_info->bit_depth < 8)
228 {
Guy Schalnat6d764711995-12-19 03:22:19 -0600229 png_bytep bp;
Guy Schalnat0d580581995-07-20 02:43:20 -0500230 png_uint_32 i;
Guy Schalnat0d580581995-07-20 02:43:20 -0500231 png_byte mask;
232
233 if (bit_depth->gray == 1 && row_info->bit_depth == 2)
234 mask = 0x55;
235 else if (row_info->bit_depth == 4 && bit_depth->gray == 3)
236 mask = 0x11;
237 else
238 mask = 0xff;
239
240 for (bp = row, i = 0; i < row_info->rowbytes; i++, bp++)
241 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500242 png_uint_16 v;
243 int j;
Guy Schalnat0d580581995-07-20 02:43:20 -0500244
245 v = *bp;
246 *bp = 0;
247 for (j = shift_start[0]; j > -shift_dec[0]; j -= shift_dec[0])
248 {
249 if (j > 0)
250 *bp |= (png_byte)((v << j) & 0xff);
251 else
252 *bp |= (png_byte)((v >> (-j)) & mask);
253 }
254 }
255 }
256 else if (row_info->bit_depth == 8)
257 {
Guy Schalnat6d764711995-12-19 03:22:19 -0600258 png_bytep bp;
Guy Schalnat0d580581995-07-20 02:43:20 -0500259 png_uint_32 i;
Guy Schalnat0d580581995-07-20 02:43:20 -0500260
261 for (bp = row, i = 0; i < row_info->width; i++)
262 {
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600263 png_uint_32 c;
Guy Schalnat0d580581995-07-20 02:43:20 -0500264
265 for (c = 0; c < channels; c++, bp++)
266 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500267 png_uint_16 v;
268 int j;
Guy Schalnat0d580581995-07-20 02:43:20 -0500269
270 v = *bp;
271 *bp = 0;
272 for (j = shift_start[c]; j > -shift_dec[c]; j -= shift_dec[c])
273 {
274 if (j > 0)
275 *bp |= (png_byte)((v << j) & 0xff);
276 else
277 *bp |= (png_byte)((v >> (-j)) & 0xff);
278 }
279 }
280 }
281 }
282 else
283 {
Guy Schalnat6d764711995-12-19 03:22:19 -0600284 png_bytep bp;
Guy Schalnat0d580581995-07-20 02:43:20 -0500285 png_uint_32 i;
Guy Schalnat0d580581995-07-20 02:43:20 -0500286
Andreas Dilger47a0c421997-05-16 02:46:07 -0500287 for (bp = row, i = 0; i < row_info->width * row_info->channels; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -0500288 {
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600289 png_uint_32 c;
Guy Schalnat0d580581995-07-20 02:43:20 -0500290
291 for (c = 0; c < channels; c++, bp += 2)
292 {
293 png_uint_16 value, v;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500294 int j;
Guy Schalnat0d580581995-07-20 02:43:20 -0500295
Andreas Dilger47a0c421997-05-16 02:46:07 -0500296 v = ((png_uint_16)(*bp) << 8) + *(bp + 1);
Guy Schalnat0d580581995-07-20 02:43:20 -0500297 value = 0;
298 for (j = shift_start[c]; j > -shift_dec[c]; j -= shift_dec[c])
299 {
300 if (j > 0)
301 value |= (png_uint_16)((v << j) & (png_uint_16)0xffff);
302 else
303 value |= (png_uint_16)((v >> (-j)) & (png_uint_16)0xffff);
304 }
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600305 *bp = (png_byte)(value >> 8);
Guy Schalnat4ee97b01996-01-16 01:51:56 -0600306 *(bp + 1) = (png_byte)(value & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -0500307 }
308 }
309 }
310 }
311}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500312#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500313
Andreas Dilger47a0c421997-05-16 02:46:07 -0500314#if defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500315void
Andreas Dilger47a0c421997-05-16 02:46:07 -0500316png_do_write_swap_alpha(png_row_infop row_info, png_bytep row)
Guy Schalnat0d580581995-07-20 02:43:20 -0500317{
Andreas Dilger47a0c421997-05-16 02:46:07 -0500318 png_debug(1, "in png_do_write_swap_alpha\n");
319#if defined(PNG_USELESS_TESTS_SUPPORTED)
320 if (row != NULL && row_info != NULL)
321#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500322 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500323 if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
Guy Schalnat0d580581995-07-20 02:43:20 -0500324 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500325 /* This converts from ARGB to RGBA */
326 if (row_info->bit_depth == 8)
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500327 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500328 png_bytep sp, dp;
329 png_byte save;
330 png_uint_32 i;
331
332 for (i = 0, sp = dp = row; i < row_info->width; i++)
333 {
334 save = *(sp++);
335 *(dp++) = *(sp++);
336 *(dp++) = *(sp++);
337 *(dp++) = *(sp++);
338 *(dp++) = save;
339 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500340 }
Andreas Dilger47a0c421997-05-16 02:46:07 -0500341 /* This converts from AARRGGBB to RRGGBBAA */
342 else
343 {
344 png_bytep sp, dp;
345 png_byte save[2];
346 png_uint_32 i;
347
348 for (i = 0, sp = dp = row; i < row_info->width; i++)
349 {
350 save[0] = *(sp++);
351 save[1] = *(sp++);
352 *(dp++) = *(sp++);
353 *(dp++) = *(sp++);
354 *(dp++) = *(sp++);
355 *(dp++) = *(sp++);
356 *(dp++) = *(sp++);
357 *(dp++) = *(sp++);
358 *(dp++) = save[0];
359 *(dp++) = save[1];
360 }
361 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500362 }
Andreas Dilger47a0c421997-05-16 02:46:07 -0500363 else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500364 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500365 /* This converts from AG to GA */
366 if (row_info->bit_depth == 8)
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500367 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500368 png_bytep sp, dp;
369 png_byte save;
370 png_uint_32 i;
371
372 for (i = 0, sp = dp = row; i < row_info->width; i++)
373 {
374 save = *(sp++);
375 *(dp++) = *(sp++);
376 *(dp++) = save;
377 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500378 }
Andreas Dilger47a0c421997-05-16 02:46:07 -0500379 /* This converts from AAGG to GGAA */
380 else
381 {
382 png_bytep sp, dp;
383 png_byte save[2];
384 png_uint_32 i;
385
386 for (i = 0, sp = dp = row; i < row_info->width; i++)
387 {
388 save[0] = *(sp++);
389 save[1] = *(sp++);
390 *(dp++) = *(sp++);
391 *(dp++) = *(sp++);
392 *(dp++) = save[0];
393 *(dp++) = save[1];
394 }
395 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500396 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500397 }
398}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500399#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500400
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600401#if defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED)
402void
403png_do_write_invert_alpha(png_row_infop row_info, png_bytep row)
404{
405 png_debug(1, "in png_do_write_invert_alpha\n");
406#if defined(PNG_USELESS_TESTS_SUPPORTED)
407 if (row != NULL && row_info != NULL)
408#endif
409 {
410 if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
411 {
412 /* This inverts the alpha channel in RGBA */
413 if (row_info->bit_depth == 8)
414 {
415 png_bytep sp, dp;
416 png_uint_32 i;
417
418 for (i = 0, sp = dp = row; i < row_info->width; i++)
419 {
420 *(dp++) = *(sp++);
421 *(dp++) = *(sp++);
422 *(dp++) = *(sp++);
423 *(dp++) = 255 - *(sp++);
424 }
425 }
426 /* This inverts the alpha channel in RRGGBBAA */
427 else
428 {
429 png_bytep sp, dp;
430 png_uint_32 i;
431
432 for (i = 0, sp = dp = row; i < row_info->width; i++)
433 {
434 *(dp++) = *(sp++);
435 *(dp++) = *(sp++);
436 *(dp++) = *(sp++);
437 *(dp++) = *(sp++);
438 *(dp++) = *(sp++);
439 *(dp++) = *(sp++);
440 *(dp++) = 255 - *(sp++);
441 *(dp++) = 255 - *(sp++);
442 }
443 }
444 }
445 else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
446 {
447 /* This inverts the alpha channel in GA */
448 if (row_info->bit_depth == 8)
449 {
450 png_bytep sp, dp;
451 png_uint_32 i;
452
453 for (i = 0, sp = dp = row; i < row_info->width; i++)
454 {
455 *(dp++) = *(sp++);
456 *(dp++) = 255 - *(sp++);
457 }
458 }
459 /* This inverts the alpha channel in GGAA */
460 else
461 {
462 png_bytep sp, dp;
463 png_uint_32 i;
464
465 for (i = 0, sp = dp = row; i < row_info->width; i++)
466 {
467 *(dp++) = *(sp++);
468 *(dp++) = *(sp++);
469 *(dp++) = 255 - *(sp++);
470 *(dp++) = 255 - *(sp++);
471 }
472 }
473 }
474 }
475}
476#endif