blob: a07b00c48e3bc9903d1a79c16545f1bc590f4677 [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-Pehrson4bb4d012009-05-20 12:45:29 -05004 * Last changed in libpng 1.4.0 [May 20, 2009]
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06005 * For conditions of distribution and use, see copyright notice in png.h
Glenn Randers-Pehrson79134c62009-02-14 10:32:18 -06006 * Copyright (c) 1998-2009 Glenn Randers-Pehrson
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -05007 * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
8 * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06009 */
Guy Schalnat0d580581995-07-20 02:43:20 -050010
Guy Schalnat0d580581995-07-20 02:43:20 -050011#include "png.h"
Glenn Randers-Pehrson3097f612001-05-07 14:52:45 -050012#ifdef PNG_WRITE_SUPPORTED
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -050013#include "pngpriv.h"
Guy Schalnat0d580581995-07-20 02:43:20 -050014
Glenn Randers-Pehrson345bc271998-06-14 14:43:31 -050015/* Transform the data according to the user's wishes. The order of
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -060016 * transformations is significant.
17 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -050018void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -060019png_do_write_transformations(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -050020{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -050021 png_debug(1, "in png_do_write_transformations");
Glenn Randers-Pehrson08a33431998-03-07 06:06:55 -060022
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -060023 if (png_ptr == NULL)
24 return;
25
Glenn Randers-Pehrson08a33431998-03-07 06:06:55 -060026#if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
27 if (png_ptr->transformations & PNG_USER_TRANSFORM)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -050028 if (png_ptr->write_user_transform_fn != NULL)
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -050029 (*(png_ptr->write_user_transform_fn)) /* User write transform function */
Glenn Randers-Pehrson08a33431998-03-07 06:06:55 -060030 (png_ptr, /* png_ptr */
31 &(png_ptr->row_info), /* row_info: */
32 /* png_uint_32 width; width of row */
33 /* png_uint_32 rowbytes; number of bytes in row */
34 /* png_byte color_type; color type of pixels */
35 /* png_byte bit_depth; bit depth of samples */
36 /* png_byte channels; number of channels (1-4) */
37 /* png_byte pixel_depth; bits per pixel (depth*channels) */
38 png_ptr->row_buf + 1); /* start of pixel data for row */
39#endif
Guy Schalnat51f0eb41995-09-26 05:22:39 -050040#if defined(PNG_WRITE_FILLER_SUPPORTED)
Glenn Randers-Pehrson73b029f2004-11-26 17:28:09 -060041 if (png_ptr->transformations & PNG_FILLER)
Andreas Dilger47a0c421997-05-16 02:46:07 -050042 png_do_strip_filler(&(png_ptr->row_info), png_ptr->row_buf + 1,
Glenn Randers-Pehrson40936072004-11-20 11:18:40 -060043 png_ptr->flags);
Guy Schalnat51f0eb41995-09-26 05:22:39 -050044#endif
Glenn Randers-Pehrson46f61e21998-01-30 21:45:12 -060045#if defined(PNG_WRITE_PACKSWAP_SUPPORTED)
46 if (png_ptr->transformations & PNG_PACKSWAP)
47 png_do_packswap(&(png_ptr->row_info), png_ptr->row_buf + 1);
48#endif
Guy Schalnat51f0eb41995-09-26 05:22:39 -050049#if defined(PNG_WRITE_PACK_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -050050 if (png_ptr->transformations & PNG_PACK)
51 png_do_pack(&(png_ptr->row_info), png_ptr->row_buf + 1,
Andreas Dilger47a0c421997-05-16 02:46:07 -050052 (png_uint_32)png_ptr->bit_depth);
Guy Schalnat51f0eb41995-09-26 05:22:39 -050053#endif
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -060054#if defined(PNG_WRITE_SWAP_SUPPORTED)
55 if (png_ptr->transformations & PNG_SWAP_BYTES)
56 png_do_swap(&(png_ptr->row_info), png_ptr->row_buf + 1);
57#endif
Guy Schalnat51f0eb41995-09-26 05:22:39 -050058#if defined(PNG_WRITE_SHIFT_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -050059 if (png_ptr->transformations & PNG_SHIFT)
60 png_do_shift(&(png_ptr->row_info), png_ptr->row_buf + 1,
61 &(png_ptr->shift));
Guy Schalnat51f0eb41995-09-26 05:22:39 -050062#endif
Glenn Randers-Pehrsoncbe52d81998-02-28 07:00:24 -060063#if defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED)
64 if (png_ptr->transformations & PNG_SWAP_ALPHA)
65 png_do_write_swap_alpha(&(png_ptr->row_info), png_ptr->row_buf + 1);
66#endif
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -060067#if defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED)
68 if (png_ptr->transformations & PNG_INVERT_ALPHA)
69 png_do_write_invert_alpha(&(png_ptr->row_info), png_ptr->row_buf + 1);
70#endif
Guy Schalnat51f0eb41995-09-26 05:22:39 -050071#if defined(PNG_WRITE_BGR_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -050072 if (png_ptr->transformations & PNG_BGR)
73 png_do_bgr(&(png_ptr->row_info), png_ptr->row_buf + 1);
Guy Schalnat51f0eb41995-09-26 05:22:39 -050074#endif
75#if defined(PNG_WRITE_INVERT_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -050076 if (png_ptr->transformations & PNG_INVERT_MONO)
77 png_do_invert(&(png_ptr->row_info), png_ptr->row_buf + 1);
Guy Schalnat51f0eb41995-09-26 05:22:39 -050078#endif
Guy Schalnat0d580581995-07-20 02:43:20 -050079}
80
Guy Schalnat51f0eb41995-09-26 05:22:39 -050081#if defined(PNG_WRITE_PACK_SUPPORTED)
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -060082/* Pack pixels into bytes. Pass the true bit depth in bit_depth. The
83 * row_info bit depth should be 8 (one pixel per byte). The channels
84 * should be 1 (this only happens on grayscale and paletted images).
85 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -050086void /* PRIVATE */
Andreas Dilger47a0c421997-05-16 02:46:07 -050087png_do_pack(png_row_infop row_info, png_bytep row, png_uint_32 bit_depth)
Guy Schalnat0d580581995-07-20 02:43:20 -050088{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -050089 png_debug(1, "in png_do_pack");
Andreas Dilger47a0c421997-05-16 02:46:07 -050090 if (row_info->bit_depth == 8 &&
Guy Schalnat0d580581995-07-20 02:43:20 -050091 row_info->channels == 1)
92 {
Andreas Dilger47a0c421997-05-16 02:46:07 -050093 switch ((int)bit_depth)
Guy Schalnat0d580581995-07-20 02:43:20 -050094 {
95 case 1:
96 {
Andreas Dilger47a0c421997-05-16 02:46:07 -050097 png_bytep sp, dp;
98 int mask, v;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -050099 png_uint_32 i;
100 png_uint_32 row_width = row_info->width;
Guy Schalnat0d580581995-07-20 02:43:20 -0500101
102 sp = row;
103 dp = row;
104 mask = 0x80;
105 v = 0;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600106
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500107 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -0500108 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500109 if (*sp != 0)
Guy Schalnat0d580581995-07-20 02:43:20 -0500110 v |= mask;
111 sp++;
112 if (mask > 1)
113 mask >>= 1;
114 else
115 {
116 mask = 0x80;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600117 *dp = (png_byte)v;
118 dp++;
Guy Schalnat0d580581995-07-20 02:43:20 -0500119 v = 0;
120 }
121 }
122 if (mask != 0x80)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600123 *dp = (png_byte)v;
Guy Schalnat0d580581995-07-20 02:43:20 -0500124 break;
125 }
126 case 2:
127 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500128 png_bytep sp, dp;
129 int shift, v;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500130 png_uint_32 i;
131 png_uint_32 row_width = row_info->width;
Guy Schalnat0d580581995-07-20 02:43:20 -0500132
133 sp = row;
134 dp = row;
135 shift = 6;
136 v = 0;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500137 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -0500138 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500139 png_byte value;
140
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600141 value = (png_byte)(*sp & 0x03);
Guy Schalnat0d580581995-07-20 02:43:20 -0500142 v |= (value << shift);
143 if (shift == 0)
144 {
145 shift = 6;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600146 *dp = (png_byte)v;
Guy Schalnat0d580581995-07-20 02:43:20 -0500147 dp++;
148 v = 0;
149 }
150 else
151 shift -= 2;
152 sp++;
153 }
154 if (shift != 6)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600155 *dp = (png_byte)v;
Guy Schalnat0d580581995-07-20 02:43:20 -0500156 break;
157 }
158 case 4:
159 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500160 png_bytep sp, dp;
161 int shift, v;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500162 png_uint_32 i;
163 png_uint_32 row_width = row_info->width;
Guy Schalnat0d580581995-07-20 02:43:20 -0500164
165 sp = row;
166 dp = row;
167 shift = 4;
168 v = 0;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500169 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -0500170 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500171 png_byte value;
172
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600173 value = (png_byte)(*sp & 0x0f);
Guy Schalnat0d580581995-07-20 02:43:20 -0500174 v |= (value << shift);
175
176 if (shift == 0)
177 {
178 shift = 4;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600179 *dp = (png_byte)v;
Guy Schalnat0d580581995-07-20 02:43:20 -0500180 dp++;
181 v = 0;
182 }
183 else
184 shift -= 4;
185
186 sp++;
187 }
188 if (shift != 4)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600189 *dp = (png_byte)v;
Guy Schalnat0d580581995-07-20 02:43:20 -0500190 break;
191 }
192 }
Andreas Dilger47a0c421997-05-16 02:46:07 -0500193 row_info->bit_depth = (png_byte)bit_depth;
194 row_info->pixel_depth = (png_byte)(bit_depth * row_info->channels);
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -0500195 row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth,
196 row_info->width);
Guy Schalnat0d580581995-07-20 02:43:20 -0500197 }
198}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500199#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500200
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500201#if defined(PNG_WRITE_SHIFT_SUPPORTED)
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600202/* Shift pixel values to take advantage of whole range. Pass the
203 * true number of bits in bit_depth. The row should be packed
204 * according to row_info->bit_depth. Thus, if you had a row of
205 * bit depth 4, but the pixels only had values from 0 to 7, you
206 * would pass 3 as bit_depth, and this routine would translate the
207 * data to 0 to 15.
208 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500209void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -0600210png_do_shift(png_row_infop row_info, png_bytep row, png_color_8p bit_depth)
Guy Schalnat0d580581995-07-20 02:43:20 -0500211{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500212 png_debug(1, "in png_do_shift");
Andreas Dilger47a0c421997-05-16 02:46:07 -0500213 if (
Guy Schalnat0d580581995-07-20 02:43:20 -0500214 row_info->color_type != PNG_COLOR_TYPE_PALETTE)
215 {
216 int shift_start[4], shift_dec[4];
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -0500217 int channels = 0;
Guy Schalnat0d580581995-07-20 02:43:20 -0500218
Guy Schalnat0d580581995-07-20 02:43:20 -0500219 if (row_info->color_type & PNG_COLOR_MASK_COLOR)
220 {
221 shift_start[channels] = row_info->bit_depth - bit_depth->red;
222 shift_dec[channels] = bit_depth->red;
223 channels++;
224 shift_start[channels] = row_info->bit_depth - bit_depth->green;
225 shift_dec[channels] = bit_depth->green;
226 channels++;
227 shift_start[channels] = row_info->bit_depth - bit_depth->blue;
228 shift_dec[channels] = bit_depth->blue;
229 channels++;
230 }
231 else
232 {
233 shift_start[channels] = row_info->bit_depth - bit_depth->gray;
234 shift_dec[channels] = bit_depth->gray;
235 channels++;
236 }
237 if (row_info->color_type & PNG_COLOR_MASK_ALPHA)
238 {
239 shift_start[channels] = row_info->bit_depth - bit_depth->alpha;
240 shift_dec[channels] = bit_depth->alpha;
241 channels++;
242 }
243
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -0500244 /* With low row depths, could only be grayscale, so one channel */
Guy Schalnat0d580581995-07-20 02:43:20 -0500245 if (row_info->bit_depth < 8)
246 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500247 png_bytep bp = row;
248 png_uint_32 i;
Guy Schalnat0d580581995-07-20 02:43:20 -0500249 png_byte mask;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500250 png_uint_32 row_bytes = row_info->rowbytes;
Guy Schalnat0d580581995-07-20 02:43:20 -0500251
252 if (bit_depth->gray == 1 && row_info->bit_depth == 2)
253 mask = 0x55;
254 else if (row_info->bit_depth == 4 && bit_depth->gray == 3)
255 mask = 0x11;
256 else
257 mask = 0xff;
258
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500259 for (i = 0; i < row_bytes; i++, bp++)
Guy Schalnat0d580581995-07-20 02:43:20 -0500260 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500261 png_uint_16 v;
262 int j;
Guy Schalnat0d580581995-07-20 02:43:20 -0500263
264 v = *bp;
265 *bp = 0;
266 for (j = shift_start[0]; j > -shift_dec[0]; j -= shift_dec[0])
267 {
268 if (j > 0)
269 *bp |= (png_byte)((v << j) & 0xff);
270 else
271 *bp |= (png_byte)((v >> (-j)) & mask);
272 }
273 }
274 }
275 else if (row_info->bit_depth == 8)
276 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500277 png_bytep bp = row;
278 png_uint_32 i;
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -0500279 png_uint_32 istop = channels * row_info->width;
Guy Schalnat0d580581995-07-20 02:43:20 -0500280
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -0500281 for (i = 0; i < istop; i++, bp++)
Guy Schalnat0d580581995-07-20 02:43:20 -0500282 {
Guy Schalnat0d580581995-07-20 02:43:20 -0500283
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -0500284 png_uint_16 v;
285 int j;
286 int c = (int)(i%channels);
287
288 v = *bp;
289 *bp = 0;
290 for (j = shift_start[c]; j > -shift_dec[c]; j -= shift_dec[c])
Guy Schalnat0d580581995-07-20 02:43:20 -0500291 {
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -0500292 if (j > 0)
293 *bp |= (png_byte)((v << j) & 0xff);
294 else
295 *bp |= (png_byte)((v >> (-j)) & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -0500296 }
297 }
298 }
299 else
300 {
Guy Schalnat6d764711995-12-19 03:22:19 -0600301 png_bytep bp;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500302 png_uint_32 i;
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -0500303 png_uint_32 istop = channels * row_info->width;
Guy Schalnat0d580581995-07-20 02:43:20 -0500304
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -0500305 for (bp = row, i = 0; i < istop; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -0500306 {
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -0500307 int c = (int)(i%channels);
308 png_uint_16 value, v;
309 int j;
Guy Schalnat0d580581995-07-20 02:43:20 -0500310
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -0500311 v = (png_uint_16)(((png_uint_16)(*bp) << 8) + *(bp + 1));
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -0500312 value = 0;
313 for (j = shift_start[c]; j > -shift_dec[c]; j -= shift_dec[c])
Guy Schalnat0d580581995-07-20 02:43:20 -0500314 {
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -0500315 if (j > 0)
316 value |= (png_uint_16)((v << j) & (png_uint_16)0xffff);
317 else
318 value |= (png_uint_16)((v >> (-j)) & (png_uint_16)0xffff);
Guy Schalnat0d580581995-07-20 02:43:20 -0500319 }
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -0500320 *bp++ = (png_byte)(value >> 8);
321 *bp++ = (png_byte)(value & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -0500322 }
323 }
324 }
325}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500326#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500327
Andreas Dilger47a0c421997-05-16 02:46:07 -0500328#if defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500329void /* PRIVATE */
Andreas Dilger47a0c421997-05-16 02:46:07 -0500330png_do_write_swap_alpha(png_row_infop row_info, png_bytep row)
Guy Schalnat0d580581995-07-20 02:43:20 -0500331{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500332 png_debug(1, "in png_do_write_swap_alpha");
Guy Schalnat0d580581995-07-20 02:43:20 -0500333 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500334 if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
Guy Schalnat0d580581995-07-20 02:43:20 -0500335 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500336 /* This converts from ARGB to RGBA */
337 if (row_info->bit_depth == 8)
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500338 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500339 png_bytep sp, dp;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500340 png_uint_32 i;
341 png_uint_32 row_width = row_info->width;
342 for (i = 0, sp = dp = row; i < row_width; i++)
Andreas Dilger47a0c421997-05-16 02:46:07 -0500343 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -0500344 png_byte save = *(sp++);
Andreas Dilger47a0c421997-05-16 02:46:07 -0500345 *(dp++) = *(sp++);
346 *(dp++) = *(sp++);
347 *(dp++) = *(sp++);
348 *(dp++) = save;
349 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500350 }
Andreas Dilger47a0c421997-05-16 02:46:07 -0500351 /* This converts from AARRGGBB to RRGGBBAA */
352 else
353 {
354 png_bytep sp, dp;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500355 png_uint_32 i;
356 png_uint_32 row_width = row_info->width;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500357
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500358 for (i = 0, sp = dp = row; i < row_width; i++)
Andreas Dilger47a0c421997-05-16 02:46:07 -0500359 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -0500360 png_byte save[2];
Andreas Dilger47a0c421997-05-16 02:46:07 -0500361 save[0] = *(sp++);
362 save[1] = *(sp++);
363 *(dp++) = *(sp++);
364 *(dp++) = *(sp++);
365 *(dp++) = *(sp++);
366 *(dp++) = *(sp++);
367 *(dp++) = *(sp++);
368 *(dp++) = *(sp++);
369 *(dp++) = save[0];
370 *(dp++) = save[1];
371 }
372 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500373 }
Andreas Dilger47a0c421997-05-16 02:46:07 -0500374 else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500375 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500376 /* This converts from AG to GA */
377 if (row_info->bit_depth == 8)
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500378 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500379 png_bytep sp, dp;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500380 png_uint_32 i;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500381 png_uint_32 row_width = row_info->width;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500382
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500383 for (i = 0, sp = dp = row; i < row_width; i++)
Andreas Dilger47a0c421997-05-16 02:46:07 -0500384 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -0500385 png_byte save = *(sp++);
Andreas Dilger47a0c421997-05-16 02:46:07 -0500386 *(dp++) = *(sp++);
387 *(dp++) = save;
388 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500389 }
Andreas Dilger47a0c421997-05-16 02:46:07 -0500390 /* This converts from AAGG to GGAA */
391 else
392 {
393 png_bytep sp, dp;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500394 png_uint_32 i;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500395 png_uint_32 row_width = row_info->width;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500396
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500397 for (i = 0, sp = dp = row; i < row_width; i++)
Andreas Dilger47a0c421997-05-16 02:46:07 -0500398 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -0500399 png_byte save[2];
Andreas Dilger47a0c421997-05-16 02:46:07 -0500400 save[0] = *(sp++);
401 save[1] = *(sp++);
402 *(dp++) = *(sp++);
403 *(dp++) = *(sp++);
404 *(dp++) = save[0];
405 *(dp++) = save[1];
406 }
407 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500408 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500409 }
410}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500411#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500412
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600413#if defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500414void /* PRIVATE */
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600415png_do_write_invert_alpha(png_row_infop row_info, png_bytep row)
416{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500417 png_debug(1, "in png_do_write_invert_alpha");
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600418 {
419 if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
420 {
421 /* This inverts the alpha channel in RGBA */
422 if (row_info->bit_depth == 8)
423 {
424 png_bytep sp, dp;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500425 png_uint_32 i;
426 png_uint_32 row_width = row_info->width;
427 for (i = 0, sp = dp = row; i < row_width; i++)
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600428 {
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -0500429 /* Does nothing
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600430 *(dp++) = *(sp++);
431 *(dp++) = *(sp++);
432 *(dp++) = *(sp++);
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -0600433 */
434 sp+=3; dp = sp;
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -0500435 *(dp++) = (png_byte)(255 - *(sp++));
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600436 }
437 }
438 /* This inverts the alpha channel in RRGGBBAA */
439 else
440 {
441 png_bytep sp, dp;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500442 png_uint_32 i;
443 png_uint_32 row_width = row_info->width;
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600444
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500445 for (i = 0, sp = dp = row; i < row_width; i++)
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600446 {
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -0500447 /* Does nothing
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600448 *(dp++) = *(sp++);
449 *(dp++) = *(sp++);
450 *(dp++) = *(sp++);
451 *(dp++) = *(sp++);
452 *(dp++) = *(sp++);
453 *(dp++) = *(sp++);
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -0600454 */
455 sp+=6; dp = sp;
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -0500456 *(dp++) = (png_byte)(255 - *(sp++));
457 *(dp++) = (png_byte)(255 - *(sp++));
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600458 }
459 }
460 }
461 else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
462 {
463 /* This inverts the alpha channel in GA */
464 if (row_info->bit_depth == 8)
465 {
466 png_bytep sp, dp;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500467 png_uint_32 i;
468 png_uint_32 row_width = row_info->width;
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600469
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500470 for (i = 0, sp = dp = row; i < row_width; i++)
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600471 {
472 *(dp++) = *(sp++);
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -0500473 *(dp++) = (png_byte)(255 - *(sp++));
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600474 }
475 }
476 /* This inverts the alpha channel in GGAA */
477 else
478 {
479 png_bytep sp, dp;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500480 png_uint_32 i;
481 png_uint_32 row_width = row_info->width;
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600482
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500483 for (i = 0, sp = dp = row; i < row_width; i++)
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600484 {
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -0500485 /* Does nothing
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600486 *(dp++) = *(sp++);
487 *(dp++) = *(sp++);
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -0600488 */
489 sp+=2; dp = sp;
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -0500490 *(dp++) = (png_byte)(255 - *(sp++));
491 *(dp++) = (png_byte)(255 - *(sp++));
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600492 }
493 }
494 }
495 }
496}
497#endif
Glenn Randers-Pehrson2ad31ae2000-12-15 08:54:42 -0600498
499#if defined(PNG_MNG_FEATURES_SUPPORTED)
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -0500500/* Undoes intrapixel differencing */
Glenn Randers-Pehrson2ad31ae2000-12-15 08:54:42 -0600501void /* PRIVATE */
502png_do_write_intrapixel(png_row_infop row_info, png_bytep row)
503{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500504 png_debug(1, "in png_do_write_intrapixel");
Glenn Randers-Pehrson2ad31ae2000-12-15 08:54:42 -0600505 if (
Glenn Randers-Pehrson2ad31ae2000-12-15 08:54:42 -0600506 (row_info->color_type & PNG_COLOR_MASK_COLOR))
507 {
508 int bytes_per_pixel;
509 png_uint_32 row_width = row_info->width;
510 if (row_info->bit_depth == 8)
511 {
512 png_bytep rp;
513 png_uint_32 i;
514
515 if (row_info->color_type == PNG_COLOR_TYPE_RGB)
516 bytes_per_pixel = 3;
517 else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
518 bytes_per_pixel = 4;
519 else
520 return;
521
522 for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel)
523 {
524 *(rp) = (png_byte)((*rp - *(rp+1))&0xff);
525 *(rp+2) = (png_byte)((*(rp+2) - *(rp+1))&0xff);
526 }
527 }
528 else if (row_info->bit_depth == 16)
529 {
530 png_bytep rp;
531 png_uint_32 i;
532
533 if (row_info->color_type == PNG_COLOR_TYPE_RGB)
534 bytes_per_pixel = 6;
535 else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
536 bytes_per_pixel = 8;
537 else
538 return;
539
540 for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel)
541 {
Glenn Randers-Pehrson5b5dcf82004-07-17 22:45:44 -0500542 png_uint_32 s0 = (*(rp ) << 8) | *(rp+1);
543 png_uint_32 s1 = (*(rp+2) << 8) | *(rp+3);
544 png_uint_32 s2 = (*(rp+4) << 8) | *(rp+5);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500545 png_uint_32 red = (png_uint_32)((s0 - s1) & 0xffffL);
546 png_uint_32 blue = (png_uint_32)((s2 - s1) & 0xffffL);
Glenn Randers-Pehrson5b5dcf82004-07-17 22:45:44 -0500547 *(rp ) = (png_byte)((red >> 8) & 0xff);
548 *(rp+1) = (png_byte)(red & 0xff);
549 *(rp+4) = (png_byte)((blue >> 8) & 0xff);
550 *(rp+5) = (png_byte)(blue & 0xff);
Glenn Randers-Pehrson2ad31ae2000-12-15 08:54:42 -0600551 }
552 }
553 }
554}
555#endif /* PNG_MNG_FEATURES_SUPPORTED */
Glenn Randers-Pehrson3097f612001-05-07 14:52:45 -0500556#endif /* PNG_WRITE_SUPPORTED */