blob: 99d32a442ab6b89e94bc7df8304e87ea6e591387 [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
Guy Schalnat0d580581995-07-20 02:43:20 -05003
Andreas Dilger47a0c421997-05-16 02:46:07 -05004 libpng 1.0 beta 6 - version 0.96
Guy Schalnat0d580581995-07-20 02:43:20 -05005 For conditions of distribution and use, see copyright notice in png.h
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06006 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
Andreas Dilger47a0c421997-05-16 02:46:07 -05007 Copyright (c) 1996, 1997 Andreas Dilger
8 May 12, 1997
Guy Schalnat0d580581995-07-20 02:43:20 -05009 */
10
11#define PNG_INTERNAL
12#include "png.h"
13
14/* transform the data according to the users wishes. The order of
15 transformations is significant. */
16void
Guy Schalnat6d764711995-12-19 03:22:19 -060017png_do_write_transformations(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -050018{
Andreas Dilger47a0c421997-05-16 02:46:07 -050019 png_debug(1, "in png_do_write_transformations\n");
Guy Schalnat51f0eb41995-09-26 05:22:39 -050020#if defined(PNG_WRITE_FILLER_SUPPORTED)
Guy Schalnat6d764711995-12-19 03:22:19 -060021 if (png_ptr->transformations & PNG_FILLER)
Andreas Dilger47a0c421997-05-16 02:46:07 -050022 png_do_strip_filler(&(png_ptr->row_info), png_ptr->row_buf + 1,
Guy Schalnate5a37791996-06-05 15:50:50 -050023 png_ptr->flags);
Guy Schalnat51f0eb41995-09-26 05:22:39 -050024#endif
25#if defined(PNG_WRITE_PACK_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -050026 if (png_ptr->transformations & PNG_PACK)
27 png_do_pack(&(png_ptr->row_info), png_ptr->row_buf + 1,
Andreas Dilger47a0c421997-05-16 02:46:07 -050028 (png_uint_32)png_ptr->bit_depth);
Guy Schalnat51f0eb41995-09-26 05:22:39 -050029#endif
30#if defined(PNG_WRITE_SHIFT_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -050031 if (png_ptr->transformations & PNG_SHIFT)
32 png_do_shift(&(png_ptr->row_info), png_ptr->row_buf + 1,
33 &(png_ptr->shift));
Guy Schalnat51f0eb41995-09-26 05:22:39 -050034#endif
35#if defined(PNG_WRITE_SWAP_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -050036 if (png_ptr->transformations & PNG_SWAP_BYTES)
37 png_do_swap(&(png_ptr->row_info), png_ptr->row_buf + 1);
Guy Schalnat51f0eb41995-09-26 05:22:39 -050038#endif
Andreas Dilger47a0c421997-05-16 02:46:07 -050039#if defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED)
40 if (png_ptr->transformations & PNG_SWAP_ALPHA)
41 png_do_write_swap_alpha(&(png_ptr->row_info), png_ptr->row_buf + 1);
42#endif
Guy Schalnat51f0eb41995-09-26 05:22:39 -050043#if defined(PNG_WRITE_BGR_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -050044 if (png_ptr->transformations & PNG_BGR)
45 png_do_bgr(&(png_ptr->row_info), png_ptr->row_buf + 1);
Guy Schalnat51f0eb41995-09-26 05:22:39 -050046#endif
47#if defined(PNG_WRITE_INVERT_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -050048 if (png_ptr->transformations & PNG_INVERT_MONO)
49 png_do_invert(&(png_ptr->row_info), png_ptr->row_buf + 1);
Guy Schalnat51f0eb41995-09-26 05:22:39 -050050#endif
Guy Schalnat0d580581995-07-20 02:43:20 -050051}
52
Guy Schalnat51f0eb41995-09-26 05:22:39 -050053#if defined(PNG_WRITE_PACK_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -050054/* pack pixels into bytes. Pass the true bit depth in bit_depth. The
55 row_info bit depth should be 8 (one pixel per byte). The channels
56 should be 1 (this only happens on grayscale and paletted images) */
57void
Andreas Dilger47a0c421997-05-16 02:46:07 -050058png_do_pack(png_row_infop row_info, png_bytep row, png_uint_32 bit_depth)
Guy Schalnat0d580581995-07-20 02:43:20 -050059{
Andreas Dilger47a0c421997-05-16 02:46:07 -050060 png_debug(1, "in png_do_pack\n");
61 if (row_info->bit_depth == 8 &&
62#if defined(PNG_USELESS_TESTS_SUPPORTED)
63 row != NULL && row_info != NULL &&
64#endif
Guy Schalnat0d580581995-07-20 02:43:20 -050065 row_info->channels == 1)
66 {
Andreas Dilger47a0c421997-05-16 02:46:07 -050067 switch ((int)bit_depth)
Guy Schalnat0d580581995-07-20 02:43:20 -050068 {
69 case 1:
70 {
Andreas Dilger47a0c421997-05-16 02:46:07 -050071 png_bytep sp, dp;
72 int mask, v;
73 png_uint_32 i;
Guy Schalnat0d580581995-07-20 02:43:20 -050074
75 sp = row;
76 dp = row;
77 mask = 0x80;
78 v = 0;
79 for (i = 0; i < row_info->width; i++)
80 {
Andreas Dilger47a0c421997-05-16 02:46:07 -050081 if (*sp != 0)
Guy Schalnat0d580581995-07-20 02:43:20 -050082 v |= mask;
83 sp++;
84 if (mask > 1)
85 mask >>= 1;
86 else
87 {
88 mask = 0x80;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -060089 *dp = (png_byte)v;
90 dp++;
Guy Schalnat0d580581995-07-20 02:43:20 -050091 v = 0;
92 }
93 }
94 if (mask != 0x80)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -060095 *dp = (png_byte)v;
Guy Schalnat0d580581995-07-20 02:43:20 -050096 break;
97 }
98 case 2:
99 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500100 png_bytep sp, dp;
101 int shift, v;
102 png_uint_32 i;
Guy Schalnat0d580581995-07-20 02:43:20 -0500103
104 sp = row;
105 dp = row;
106 shift = 6;
107 v = 0;
108 for (i = 0; i < row_info->width; i++)
109 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500110 png_byte value;
111
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600112 value = (png_byte)(*sp & 0x3);
Guy Schalnat0d580581995-07-20 02:43:20 -0500113 v |= (value << shift);
114 if (shift == 0)
115 {
116 shift = 6;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600117 *dp = (png_byte)v;
Guy Schalnat0d580581995-07-20 02:43:20 -0500118 dp++;
119 v = 0;
120 }
121 else
122 shift -= 2;
123 sp++;
124 }
125 if (shift != 6)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600126 *dp = (png_byte)v;
Guy Schalnat0d580581995-07-20 02:43:20 -0500127 break;
128 }
129 case 4:
130 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500131 png_bytep sp, dp;
132 int shift, v;
133 png_uint_32 i;
Guy Schalnat0d580581995-07-20 02:43:20 -0500134
135 sp = row;
136 dp = row;
137 shift = 4;
138 v = 0;
139 for (i = 0; i < row_info->width; i++)
140 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500141 png_byte value;
142
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600143 value = (png_byte)(*sp & 0xf);
Guy Schalnat0d580581995-07-20 02:43:20 -0500144 v |= (value << shift);
145
146 if (shift == 0)
147 {
148 shift = 4;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600149 *dp = (png_byte)v;
Guy Schalnat0d580581995-07-20 02:43:20 -0500150 dp++;
151 v = 0;
152 }
153 else
154 shift -= 4;
155
156 sp++;
157 }
158 if (shift != 4)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600159 *dp = (png_byte)v;
Guy Schalnat0d580581995-07-20 02:43:20 -0500160 break;
161 }
162 }
Andreas Dilger47a0c421997-05-16 02:46:07 -0500163 row_info->bit_depth = (png_byte)bit_depth;
164 row_info->pixel_depth = (png_byte)(bit_depth * row_info->channels);
Guy Schalnat0d580581995-07-20 02:43:20 -0500165 row_info->rowbytes =
166 ((row_info->width * row_info->pixel_depth + 7) >> 3);
167 }
168}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500169#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500170
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500171#if defined(PNG_WRITE_SHIFT_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500172/* shift pixel values to take advantage of whole range. Pass the
173 true number of bits in bit_depth. The row should be packed
174 according to row_info->bit_depth. Thus, if you had a row of
175 bit depth 4, but the pixels only had values from 0 to 7, you
176 would pass 3 as bit_depth, and this routine would translate the
177 data to 0 to 15. */
178void
Guy Schalnat6d764711995-12-19 03:22:19 -0600179png_do_shift(png_row_infop row_info, png_bytep row, png_color_8p bit_depth)
Guy Schalnat0d580581995-07-20 02:43:20 -0500180{
Andreas Dilger47a0c421997-05-16 02:46:07 -0500181 png_debug(1, "in png_do_shift\n");
182#if defined(PNG_USELESS_TESTS_SUPPORTED)
183 if (row != NULL && row_info != NULL &&
184#else
185 if (
186#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500187 row_info->color_type != PNG_COLOR_TYPE_PALETTE)
188 {
189 int shift_start[4], shift_dec[4];
Andreas Dilger47a0c421997-05-16 02:46:07 -0500190 png_uint_32 channels;
Guy Schalnat0d580581995-07-20 02:43:20 -0500191
192 channels = 0;
193 if (row_info->color_type & PNG_COLOR_MASK_COLOR)
194 {
195 shift_start[channels] = row_info->bit_depth - bit_depth->red;
196 shift_dec[channels] = bit_depth->red;
197 channels++;
198 shift_start[channels] = row_info->bit_depth - bit_depth->green;
199 shift_dec[channels] = bit_depth->green;
200 channels++;
201 shift_start[channels] = row_info->bit_depth - bit_depth->blue;
202 shift_dec[channels] = bit_depth->blue;
203 channels++;
204 }
205 else
206 {
207 shift_start[channels] = row_info->bit_depth - bit_depth->gray;
208 shift_dec[channels] = bit_depth->gray;
209 channels++;
210 }
211 if (row_info->color_type & PNG_COLOR_MASK_ALPHA)
212 {
213 shift_start[channels] = row_info->bit_depth - bit_depth->alpha;
214 shift_dec[channels] = bit_depth->alpha;
215 channels++;
216 }
217
218 /* with low row dephts, could only be grayscale, so one channel */
219 if (row_info->bit_depth < 8)
220 {
Guy Schalnat6d764711995-12-19 03:22:19 -0600221 png_bytep bp;
Guy Schalnat0d580581995-07-20 02:43:20 -0500222 png_uint_32 i;
Guy Schalnat0d580581995-07-20 02:43:20 -0500223 png_byte mask;
224
225 if (bit_depth->gray == 1 && row_info->bit_depth == 2)
226 mask = 0x55;
227 else if (row_info->bit_depth == 4 && bit_depth->gray == 3)
228 mask = 0x11;
229 else
230 mask = 0xff;
231
232 for (bp = row, i = 0; i < row_info->rowbytes; i++, bp++)
233 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500234 png_uint_16 v;
235 int j;
Guy Schalnat0d580581995-07-20 02:43:20 -0500236
237 v = *bp;
238 *bp = 0;
239 for (j = shift_start[0]; j > -shift_dec[0]; j -= shift_dec[0])
240 {
241 if (j > 0)
242 *bp |= (png_byte)((v << j) & 0xff);
243 else
244 *bp |= (png_byte)((v >> (-j)) & mask);
245 }
246 }
247 }
248 else if (row_info->bit_depth == 8)
249 {
Guy Schalnat6d764711995-12-19 03:22:19 -0600250 png_bytep bp;
Guy Schalnat0d580581995-07-20 02:43:20 -0500251 png_uint_32 i;
Guy Schalnat0d580581995-07-20 02:43:20 -0500252
253 for (bp = row, i = 0; i < row_info->width; i++)
254 {
255 int c;
256
257 for (c = 0; c < channels; c++, bp++)
258 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500259 png_uint_16 v;
260 int j;
Guy Schalnat0d580581995-07-20 02:43:20 -0500261
262 v = *bp;
263 *bp = 0;
264 for (j = shift_start[c]; j > -shift_dec[c]; j -= shift_dec[c])
265 {
266 if (j > 0)
267 *bp |= (png_byte)((v << j) & 0xff);
268 else
269 *bp |= (png_byte)((v >> (-j)) & 0xff);
270 }
271 }
272 }
273 }
274 else
275 {
Guy Schalnat6d764711995-12-19 03:22:19 -0600276 png_bytep bp;
Guy Schalnat0d580581995-07-20 02:43:20 -0500277 png_uint_32 i;
Guy Schalnat0d580581995-07-20 02:43:20 -0500278
Andreas Dilger47a0c421997-05-16 02:46:07 -0500279 for (bp = row, i = 0; i < row_info->width * row_info->channels; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -0500280 {
281 int c;
282
283 for (c = 0; c < channels; c++, bp += 2)
284 {
285 png_uint_16 value, v;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500286 int j;
Guy Schalnat0d580581995-07-20 02:43:20 -0500287
Andreas Dilger47a0c421997-05-16 02:46:07 -0500288 v = ((png_uint_16)(*bp) << 8) + *(bp + 1);
Guy Schalnat0d580581995-07-20 02:43:20 -0500289 value = 0;
290 for (j = shift_start[c]; j > -shift_dec[c]; j -= shift_dec[c])
291 {
292 if (j > 0)
293 value |= (png_uint_16)((v << j) & (png_uint_16)0xffff);
294 else
295 value |= (png_uint_16)((v >> (-j)) & (png_uint_16)0xffff);
296 }
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600297 *bp = (png_byte)(value >> 8);
Guy Schalnat4ee97b01996-01-16 01:51:56 -0600298 *(bp + 1) = (png_byte)(value & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -0500299 }
300 }
301 }
302 }
303}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500304#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500305
Andreas Dilger47a0c421997-05-16 02:46:07 -0500306#if defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500307void
Andreas Dilger47a0c421997-05-16 02:46:07 -0500308png_do_write_swap_alpha(png_row_infop row_info, png_bytep row)
Guy Schalnat0d580581995-07-20 02:43:20 -0500309{
Andreas Dilger47a0c421997-05-16 02:46:07 -0500310 png_debug(1, "in png_do_write_swap_alpha\n");
311#if defined(PNG_USELESS_TESTS_SUPPORTED)
312 if (row != NULL && row_info != NULL)
313#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500314 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500315 if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
Guy Schalnat0d580581995-07-20 02:43:20 -0500316 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500317 /* This converts from ARGB to RGBA */
318 if (row_info->bit_depth == 8)
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500319 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500320 png_bytep sp, dp;
321 png_byte save;
322 png_uint_32 i;
323
324 for (i = 0, sp = dp = row; i < row_info->width; i++)
325 {
326 save = *(sp++);
327 *(dp++) = *(sp++);
328 *(dp++) = *(sp++);
329 *(dp++) = *(sp++);
330 *(dp++) = save;
331 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500332 }
Andreas Dilger47a0c421997-05-16 02:46:07 -0500333 /* This converts from AARRGGBB to RRGGBBAA */
334 else
335 {
336 png_bytep sp, dp;
337 png_byte save[2];
338 png_uint_32 i;
339
340 for (i = 0, sp = dp = row; i < row_info->width; i++)
341 {
342 save[0] = *(sp++);
343 save[1] = *(sp++);
344 *(dp++) = *(sp++);
345 *(dp++) = *(sp++);
346 *(dp++) = *(sp++);
347 *(dp++) = *(sp++);
348 *(dp++) = *(sp++);
349 *(dp++) = *(sp++);
350 *(dp++) = save[0];
351 *(dp++) = save[1];
352 }
353 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500354 }
Andreas Dilger47a0c421997-05-16 02:46:07 -0500355 else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500356 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500357 /* This converts from AG to GA */
358 if (row_info->bit_depth == 8)
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500359 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500360 png_bytep sp, dp;
361 png_byte save;
362 png_uint_32 i;
363
364 for (i = 0, sp = dp = row; i < row_info->width; i++)
365 {
366 save = *(sp++);
367 *(dp++) = *(sp++);
368 *(dp++) = save;
369 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500370 }
Andreas Dilger47a0c421997-05-16 02:46:07 -0500371 /* This converts from AAGG to GGAA */
372 else
373 {
374 png_bytep sp, dp;
375 png_byte save[2];
376 png_uint_32 i;
377
378 for (i = 0, sp = dp = row; i < row_info->width; i++)
379 {
380 save[0] = *(sp++);
381 save[1] = *(sp++);
382 *(dp++) = *(sp++);
383 *(dp++) = *(sp++);
384 *(dp++) = save[0];
385 *(dp++) = save[1];
386 }
387 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500388 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500389 }
390}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500391#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500392