blob: 078b9f86dc7bd7bc4a35c1f5ff926d3f706dfac9 [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 *
4 * libpng 1.00.97
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 * May 28, 1997
9 */
Guy Schalnat0d580581995-07-20 02:43:20 -050010
11#define PNG_INTERNAL
12#include "png.h"
13
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -060014/* Transform the data according to the users wishes. The order of
15 * transformations is significant.
16 */
Guy Schalnat0d580581995-07-20 02:43:20 -050017void
Guy Schalnat6d764711995-12-19 03:22:19 -060018png_do_write_transformations(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -050019{
Andreas Dilger47a0c421997-05-16 02:46:07 -050020 png_debug(1, "in png_do_write_transformations\n");
Guy Schalnat51f0eb41995-09-26 05:22:39 -050021#if defined(PNG_WRITE_FILLER_SUPPORTED)
Guy Schalnat6d764711995-12-19 03:22:19 -060022 if (png_ptr->transformations & PNG_FILLER)
Andreas Dilger47a0c421997-05-16 02:46:07 -050023 png_do_strip_filler(&(png_ptr->row_info), png_ptr->row_buf + 1,
Guy Schalnate5a37791996-06-05 15:50:50 -050024 png_ptr->flags);
Guy Schalnat51f0eb41995-09-26 05:22:39 -050025#endif
26#if defined(PNG_WRITE_PACK_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -050027 if (png_ptr->transformations & PNG_PACK)
28 png_do_pack(&(png_ptr->row_info), png_ptr->row_buf + 1,
Andreas Dilger47a0c421997-05-16 02:46:07 -050029 (png_uint_32)png_ptr->bit_depth);
Guy Schalnat51f0eb41995-09-26 05:22:39 -050030#endif
31#if defined(PNG_WRITE_SHIFT_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -050032 if (png_ptr->transformations & PNG_SHIFT)
33 png_do_shift(&(png_ptr->row_info), png_ptr->row_buf + 1,
34 &(png_ptr->shift));
Guy Schalnat51f0eb41995-09-26 05:22:39 -050035#endif
36#if defined(PNG_WRITE_SWAP_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -050037 if (png_ptr->transformations & PNG_SWAP_BYTES)
38 png_do_swap(&(png_ptr->row_info), png_ptr->row_buf + 1);
Guy Schalnat51f0eb41995-09-26 05:22:39 -050039#endif
Andreas Dilger47a0c421997-05-16 02:46:07 -050040#if defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED)
41 if (png_ptr->transformations & PNG_SWAP_ALPHA)
42 png_do_write_swap_alpha(&(png_ptr->row_info), png_ptr->row_buf + 1);
43#endif
Guy Schalnat51f0eb41995-09-26 05:22:39 -050044#if defined(PNG_WRITE_BGR_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -050045 if (png_ptr->transformations & PNG_BGR)
46 png_do_bgr(&(png_ptr->row_info), png_ptr->row_buf + 1);
Guy Schalnat51f0eb41995-09-26 05:22:39 -050047#endif
48#if defined(PNG_WRITE_INVERT_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -050049 if (png_ptr->transformations & PNG_INVERT_MONO)
50 png_do_invert(&(png_ptr->row_info), png_ptr->row_buf + 1);
Guy Schalnat51f0eb41995-09-26 05:22:39 -050051#endif
Guy Schalnat0d580581995-07-20 02:43:20 -050052}
53
Guy Schalnat51f0eb41995-09-26 05:22:39 -050054#if defined(PNG_WRITE_PACK_SUPPORTED)
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -060055/* Pack pixels into bytes. Pass the true bit depth in bit_depth. The
56 * row_info bit depth should be 8 (one pixel per byte). The channels
57 * should be 1 (this only happens on grayscale and paletted images).
58 */
Guy Schalnat0d580581995-07-20 02:43:20 -050059void
Andreas Dilger47a0c421997-05-16 02:46:07 -050060png_do_pack(png_row_infop row_info, png_bytep row, png_uint_32 bit_depth)
Guy Schalnat0d580581995-07-20 02:43:20 -050061{
Andreas Dilger47a0c421997-05-16 02:46:07 -050062 png_debug(1, "in png_do_pack\n");
63 if (row_info->bit_depth == 8 &&
64#if defined(PNG_USELESS_TESTS_SUPPORTED)
65 row != NULL && row_info != NULL &&
66#endif
Guy Schalnat0d580581995-07-20 02:43:20 -050067 row_info->channels == 1)
68 {
Andreas Dilger47a0c421997-05-16 02:46:07 -050069 switch ((int)bit_depth)
Guy Schalnat0d580581995-07-20 02:43:20 -050070 {
71 case 1:
72 {
Andreas Dilger47a0c421997-05-16 02:46:07 -050073 png_bytep sp, dp;
74 int mask, v;
75 png_uint_32 i;
Guy Schalnat0d580581995-07-20 02:43:20 -050076
77 sp = row;
78 dp = row;
79 mask = 0x80;
80 v = 0;
81 for (i = 0; i < row_info->width; i++)
82 {
Andreas Dilger47a0c421997-05-16 02:46:07 -050083 if (*sp != 0)
Guy Schalnat0d580581995-07-20 02:43:20 -050084 v |= mask;
85 sp++;
86 if (mask > 1)
87 mask >>= 1;
88 else
89 {
90 mask = 0x80;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -060091 *dp = (png_byte)v;
92 dp++;
Guy Schalnat0d580581995-07-20 02:43:20 -050093 v = 0;
94 }
95 }
96 if (mask != 0x80)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -060097 *dp = (png_byte)v;
Guy Schalnat0d580581995-07-20 02:43:20 -050098 break;
99 }
100 case 2:
101 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500102 png_bytep sp, dp;
103 int shift, v;
104 png_uint_32 i;
Guy Schalnat0d580581995-07-20 02:43:20 -0500105
106 sp = row;
107 dp = row;
108 shift = 6;
109 v = 0;
110 for (i = 0; i < row_info->width; i++)
111 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500112 png_byte value;
113
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600114 value = (png_byte)(*sp & 0x3);
Guy Schalnat0d580581995-07-20 02:43:20 -0500115 v |= (value << shift);
116 if (shift == 0)
117 {
118 shift = 6;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600119 *dp = (png_byte)v;
Guy Schalnat0d580581995-07-20 02:43:20 -0500120 dp++;
121 v = 0;
122 }
123 else
124 shift -= 2;
125 sp++;
126 }
127 if (shift != 6)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600128 *dp = (png_byte)v;
Guy Schalnat0d580581995-07-20 02:43:20 -0500129 break;
130 }
131 case 4:
132 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500133 png_bytep sp, dp;
134 int shift, v;
135 png_uint_32 i;
Guy Schalnat0d580581995-07-20 02:43:20 -0500136
137 sp = row;
138 dp = row;
139 shift = 4;
140 v = 0;
141 for (i = 0; i < row_info->width; i++)
142 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500143 png_byte value;
144
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600145 value = (png_byte)(*sp & 0xf);
Guy Schalnat0d580581995-07-20 02:43:20 -0500146 v |= (value << shift);
147
148 if (shift == 0)
149 {
150 shift = 4;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600151 *dp = (png_byte)v;
Guy Schalnat0d580581995-07-20 02:43:20 -0500152 dp++;
153 v = 0;
154 }
155 else
156 shift -= 4;
157
158 sp++;
159 }
160 if (shift != 4)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600161 *dp = (png_byte)v;
Guy Schalnat0d580581995-07-20 02:43:20 -0500162 break;
163 }
164 }
Andreas Dilger47a0c421997-05-16 02:46:07 -0500165 row_info->bit_depth = (png_byte)bit_depth;
166 row_info->pixel_depth = (png_byte)(bit_depth * row_info->channels);
Guy Schalnat0d580581995-07-20 02:43:20 -0500167 row_info->rowbytes =
168 ((row_info->width * row_info->pixel_depth + 7) >> 3);
169 }
170}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500171#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500172
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500173#if defined(PNG_WRITE_SHIFT_SUPPORTED)
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600174/* Shift pixel values to take advantage of whole range. Pass the
175 * true number of bits in bit_depth. The row should be packed
176 * according to row_info->bit_depth. Thus, if you had a row of
177 * bit depth 4, but the pixels only had values from 0 to 7, you
178 * would pass 3 as bit_depth, and this routine would translate the
179 * data to 0 to 15.
180 */
Guy Schalnat0d580581995-07-20 02:43:20 -0500181void
Guy Schalnat6d764711995-12-19 03:22:19 -0600182png_do_shift(png_row_infop row_info, png_bytep row, png_color_8p bit_depth)
Guy Schalnat0d580581995-07-20 02:43:20 -0500183{
Andreas Dilger47a0c421997-05-16 02:46:07 -0500184 png_debug(1, "in png_do_shift\n");
185#if defined(PNG_USELESS_TESTS_SUPPORTED)
186 if (row != NULL && row_info != NULL &&
187#else
188 if (
189#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500190 row_info->color_type != PNG_COLOR_TYPE_PALETTE)
191 {
192 int shift_start[4], shift_dec[4];
Andreas Dilger47a0c421997-05-16 02:46:07 -0500193 png_uint_32 channels;
Guy Schalnat0d580581995-07-20 02:43:20 -0500194
195 channels = 0;
196 if (row_info->color_type & PNG_COLOR_MASK_COLOR)
197 {
198 shift_start[channels] = row_info->bit_depth - bit_depth->red;
199 shift_dec[channels] = bit_depth->red;
200 channels++;
201 shift_start[channels] = row_info->bit_depth - bit_depth->green;
202 shift_dec[channels] = bit_depth->green;
203 channels++;
204 shift_start[channels] = row_info->bit_depth - bit_depth->blue;
205 shift_dec[channels] = bit_depth->blue;
206 channels++;
207 }
208 else
209 {
210 shift_start[channels] = row_info->bit_depth - bit_depth->gray;
211 shift_dec[channels] = bit_depth->gray;
212 channels++;
213 }
214 if (row_info->color_type & PNG_COLOR_MASK_ALPHA)
215 {
216 shift_start[channels] = row_info->bit_depth - bit_depth->alpha;
217 shift_dec[channels] = bit_depth->alpha;
218 channels++;
219 }
220
221 /* with low row dephts, could only be grayscale, so one channel */
222 if (row_info->bit_depth < 8)
223 {
Guy Schalnat6d764711995-12-19 03:22:19 -0600224 png_bytep bp;
Guy Schalnat0d580581995-07-20 02:43:20 -0500225 png_uint_32 i;
Guy Schalnat0d580581995-07-20 02:43:20 -0500226 png_byte mask;
227
228 if (bit_depth->gray == 1 && row_info->bit_depth == 2)
229 mask = 0x55;
230 else if (row_info->bit_depth == 4 && bit_depth->gray == 3)
231 mask = 0x11;
232 else
233 mask = 0xff;
234
235 for (bp = row, i = 0; i < row_info->rowbytes; i++, bp++)
236 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500237 png_uint_16 v;
238 int j;
Guy Schalnat0d580581995-07-20 02:43:20 -0500239
240 v = *bp;
241 *bp = 0;
242 for (j = shift_start[0]; j > -shift_dec[0]; j -= shift_dec[0])
243 {
244 if (j > 0)
245 *bp |= (png_byte)((v << j) & 0xff);
246 else
247 *bp |= (png_byte)((v >> (-j)) & mask);
248 }
249 }
250 }
251 else if (row_info->bit_depth == 8)
252 {
Guy Schalnat6d764711995-12-19 03:22:19 -0600253 png_bytep bp;
Guy Schalnat0d580581995-07-20 02:43:20 -0500254 png_uint_32 i;
Guy Schalnat0d580581995-07-20 02:43:20 -0500255
256 for (bp = row, i = 0; i < row_info->width; i++)
257 {
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600258 png_uint_32 c;
Guy Schalnat0d580581995-07-20 02:43:20 -0500259
260 for (c = 0; c < channels; c++, bp++)
261 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500262 png_uint_16 v;
263 int j;
Guy Schalnat0d580581995-07-20 02:43:20 -0500264
265 v = *bp;
266 *bp = 0;
267 for (j = shift_start[c]; j > -shift_dec[c]; j -= shift_dec[c])
268 {
269 if (j > 0)
270 *bp |= (png_byte)((v << j) & 0xff);
271 else
272 *bp |= (png_byte)((v >> (-j)) & 0xff);
273 }
274 }
275 }
276 }
277 else
278 {
Guy Schalnat6d764711995-12-19 03:22:19 -0600279 png_bytep bp;
Guy Schalnat0d580581995-07-20 02:43:20 -0500280 png_uint_32 i;
Guy Schalnat0d580581995-07-20 02:43:20 -0500281
Andreas Dilger47a0c421997-05-16 02:46:07 -0500282 for (bp = row, i = 0; i < row_info->width * row_info->channels; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -0500283 {
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600284 png_uint_32 c;
Guy Schalnat0d580581995-07-20 02:43:20 -0500285
286 for (c = 0; c < channels; c++, bp += 2)
287 {
288 png_uint_16 value, v;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500289 int j;
Guy Schalnat0d580581995-07-20 02:43:20 -0500290
Andreas Dilger47a0c421997-05-16 02:46:07 -0500291 v = ((png_uint_16)(*bp) << 8) + *(bp + 1);
Guy Schalnat0d580581995-07-20 02:43:20 -0500292 value = 0;
293 for (j = shift_start[c]; j > -shift_dec[c]; j -= shift_dec[c])
294 {
295 if (j > 0)
296 value |= (png_uint_16)((v << j) & (png_uint_16)0xffff);
297 else
298 value |= (png_uint_16)((v >> (-j)) & (png_uint_16)0xffff);
299 }
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600300 *bp = (png_byte)(value >> 8);
Guy Schalnat4ee97b01996-01-16 01:51:56 -0600301 *(bp + 1) = (png_byte)(value & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -0500302 }
303 }
304 }
305 }
306}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500307#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500308
Andreas Dilger47a0c421997-05-16 02:46:07 -0500309#if defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500310void
Andreas Dilger47a0c421997-05-16 02:46:07 -0500311png_do_write_swap_alpha(png_row_infop row_info, png_bytep row)
Guy Schalnat0d580581995-07-20 02:43:20 -0500312{
Andreas Dilger47a0c421997-05-16 02:46:07 -0500313 png_debug(1, "in png_do_write_swap_alpha\n");
314#if defined(PNG_USELESS_TESTS_SUPPORTED)
315 if (row != NULL && row_info != NULL)
316#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500317 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500318 if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
Guy Schalnat0d580581995-07-20 02:43:20 -0500319 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500320 /* This converts from ARGB to RGBA */
321 if (row_info->bit_depth == 8)
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500322 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500323 png_bytep sp, dp;
324 png_byte save;
325 png_uint_32 i;
326
327 for (i = 0, sp = dp = row; i < row_info->width; i++)
328 {
329 save = *(sp++);
330 *(dp++) = *(sp++);
331 *(dp++) = *(sp++);
332 *(dp++) = *(sp++);
333 *(dp++) = save;
334 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500335 }
Andreas Dilger47a0c421997-05-16 02:46:07 -0500336 /* This converts from AARRGGBB to RRGGBBAA */
337 else
338 {
339 png_bytep sp, dp;
340 png_byte save[2];
341 png_uint_32 i;
342
343 for (i = 0, sp = dp = row; i < row_info->width; i++)
344 {
345 save[0] = *(sp++);
346 save[1] = *(sp++);
347 *(dp++) = *(sp++);
348 *(dp++) = *(sp++);
349 *(dp++) = *(sp++);
350 *(dp++) = *(sp++);
351 *(dp++) = *(sp++);
352 *(dp++) = *(sp++);
353 *(dp++) = save[0];
354 *(dp++) = save[1];
355 }
356 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500357 }
Andreas Dilger47a0c421997-05-16 02:46:07 -0500358 else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500359 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500360 /* This converts from AG to GA */
361 if (row_info->bit_depth == 8)
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500362 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500363 png_bytep sp, dp;
364 png_byte save;
365 png_uint_32 i;
366
367 for (i = 0, sp = dp = row; i < row_info->width; i++)
368 {
369 save = *(sp++);
370 *(dp++) = *(sp++);
371 *(dp++) = save;
372 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500373 }
Andreas Dilger47a0c421997-05-16 02:46:07 -0500374 /* This converts from AAGG to GGAA */
375 else
376 {
377 png_bytep sp, dp;
378 png_byte save[2];
379 png_uint_32 i;
380
381 for (i = 0, sp = dp = row; i < row_info->width; i++)
382 {
383 save[0] = *(sp++);
384 save[1] = *(sp++);
385 *(dp++) = *(sp++);
386 *(dp++) = *(sp++);
387 *(dp++) = save[0];
388 *(dp++) = save[1];
389 }
390 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500391 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500392 }
393}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500394#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500395