blob: acbd0c219efd8f873de7dd957ceb4e4f2eda2fbf [file] [log] [blame]
Guy Schalnat0d580581995-07-20 02:43:20 -05001
2/* pngwtran.c - transforms the data in a row for png writers
3
Guy Schalnat51f0eb41995-09-26 05:22:39 -05004 libpng 1.0 beta 2 - version 0.81
Guy Schalnat0d580581995-07-20 02:43:20 -05005 For conditions of distribution and use, see copyright notice in png.h
6 Copyright (c) 1995 Guy Eric Schalnat, Group 42, Inc.
Guy Schalnat51f0eb41995-09-26 05:22:39 -05007 August 24, 1995
Guy Schalnat0d580581995-07-20 02:43:20 -05008 */
9
10#define PNG_INTERNAL
11#include "png.h"
12
13/* transform the data according to the users wishes. The order of
14 transformations is significant. */
15void
16png_do_write_transformations(png_struct *png_ptr)
17{
Guy Schalnat51f0eb41995-09-26 05:22:39 -050018#if defined(PNG_WRITE_FILLER_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -050019 if (png_ptr->transformations & PNG_RGBA)
Guy Schalnat51f0eb41995-09-26 05:22:39 -050020 png_do_write_filler(&(png_ptr->row_info), png_ptr->row_buf + 1,
21 png_ptr->filler_loc);
22#endif
23#if defined(PNG_WRITE_PACK_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -050024 if (png_ptr->transformations & PNG_PACK)
25 png_do_pack(&(png_ptr->row_info), png_ptr->row_buf + 1,
26 png_ptr->bit_depth);
Guy Schalnat51f0eb41995-09-26 05:22:39 -050027#endif
28#if defined(PNG_WRITE_SHIFT_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -050029 if (png_ptr->transformations & PNG_SHIFT)
30 png_do_shift(&(png_ptr->row_info), png_ptr->row_buf + 1,
31 &(png_ptr->shift));
Guy Schalnat51f0eb41995-09-26 05:22:39 -050032#endif
33#if defined(PNG_WRITE_SWAP_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -050034 if (png_ptr->transformations & PNG_SWAP_BYTES)
35 png_do_swap(&(png_ptr->row_info), png_ptr->row_buf + 1);
Guy Schalnat51f0eb41995-09-26 05:22:39 -050036#endif
37#if defined(PNG_WRITE_BGR_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -050038 if (png_ptr->transformations & PNG_BGR)
39 png_do_bgr(&(png_ptr->row_info), png_ptr->row_buf + 1);
Guy Schalnat51f0eb41995-09-26 05:22:39 -050040#endif
41#if defined(PNG_WRITE_INVERT_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -050042 if (png_ptr->transformations & PNG_INVERT_MONO)
43 png_do_invert(&(png_ptr->row_info), png_ptr->row_buf + 1);
Guy Schalnat51f0eb41995-09-26 05:22:39 -050044#endif
Guy Schalnat0d580581995-07-20 02:43:20 -050045}
46
Guy Schalnat51f0eb41995-09-26 05:22:39 -050047#if defined(PNG_WRITE_PACK_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -050048/* pack pixels into bytes. Pass the true bit depth in bit_depth. The
49 row_info bit depth should be 8 (one pixel per byte). The channels
50 should be 1 (this only happens on grayscale and paletted images) */
51void
Guy Schalnat51f0eb41995-09-26 05:22:39 -050052png_do_pack(png_row_info *row_info, png_bytef *row, png_byte bit_depth)
Guy Schalnat0d580581995-07-20 02:43:20 -050053{
54 if (row_info && row && row_info->bit_depth == 8 &&
55 row_info->channels == 1)
56 {
57 switch (bit_depth)
58 {
59 case 1:
60 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -050061 png_bytef *sp;
62 png_bytef *dp;
Guy Schalnat0d580581995-07-20 02:43:20 -050063 int mask;
64 png_int_32 i;
65 int v;
66
67 sp = row;
68 dp = row;
69 mask = 0x80;
70 v = 0;
71 for (i = 0; i < row_info->width; i++)
72 {
73 if (*sp)
74 v |= mask;
75 sp++;
76 if (mask > 1)
77 mask >>= 1;
78 else
79 {
80 mask = 0x80;
81 *dp = v;
82 dp++;
83 v = 0;
84 }
85 }
86 if (mask != 0x80)
87 *dp = v;
88 break;
89 }
90 case 2:
91 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -050092 png_bytef *sp;
93 png_bytef *dp;
Guy Schalnat0d580581995-07-20 02:43:20 -050094 int shift;
95 png_int_32 i;
96 int v;
97 png_byte value;
98
99 sp = row;
100 dp = row;
101 shift = 6;
102 v = 0;
103 for (i = 0; i < row_info->width; i++)
104 {
105 value = *sp & 0x3;
106 v |= (value << shift);
107 if (shift == 0)
108 {
109 shift = 6;
110 *dp = v;
111 dp++;
112 v = 0;
113 }
114 else
115 shift -= 2;
116 sp++;
117 }
118 if (shift != 6)
119 *dp = v;
120 break;
121 }
122 case 4:
123 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500124 png_bytef *sp;
125 png_bytef *dp;
Guy Schalnat0d580581995-07-20 02:43:20 -0500126 int shift;
127 png_int_32 i;
128 int v;
129 png_byte value;
130
131 sp = row;
132 dp = row;
133 shift = 4;
134 v = 0;
135 for (i = 0; i < row_info->width; i++)
136 {
137 value = *sp & 0xf;
138 v |= (value << shift);
139
140 if (shift == 0)
141 {
142 shift = 4;
143 *dp = v;
144 dp++;
145 v = 0;
146 }
147 else
148 shift -= 4;
149
150 sp++;
151 }
152 if (shift != 4)
153 *dp = v;
154 break;
155 }
156 }
157 row_info->bit_depth = bit_depth;
158 row_info->pixel_depth = bit_depth * row_info->channels;
159 row_info->rowbytes =
160 ((row_info->width * row_info->pixel_depth + 7) >> 3);
161 }
162}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500163#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500164
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500165#if defined(PNG_WRITE_SHIFT_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500166/* shift pixel values to take advantage of whole range. Pass the
167 true number of bits in bit_depth. The row should be packed
168 according to row_info->bit_depth. Thus, if you had a row of
169 bit depth 4, but the pixels only had values from 0 to 7, you
170 would pass 3 as bit_depth, and this routine would translate the
171 data to 0 to 15. */
172void
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500173png_do_shift(png_row_info *row_info, png_bytef *row, png_color_8 *bit_depth)
Guy Schalnat0d580581995-07-20 02:43:20 -0500174{
175 if (row && row_info &&
176 row_info->color_type != PNG_COLOR_TYPE_PALETTE)
177 {
178 int shift_start[4], shift_dec[4];
179 int channels;
180
181 channels = 0;
182 if (row_info->color_type & PNG_COLOR_MASK_COLOR)
183 {
184 shift_start[channels] = row_info->bit_depth - bit_depth->red;
185 shift_dec[channels] = bit_depth->red;
186 channels++;
187 shift_start[channels] = row_info->bit_depth - bit_depth->green;
188 shift_dec[channels] = bit_depth->green;
189 channels++;
190 shift_start[channels] = row_info->bit_depth - bit_depth->blue;
191 shift_dec[channels] = bit_depth->blue;
192 channels++;
193 }
194 else
195 {
196 shift_start[channels] = row_info->bit_depth - bit_depth->gray;
197 shift_dec[channels] = bit_depth->gray;
198 channels++;
199 }
200 if (row_info->color_type & PNG_COLOR_MASK_ALPHA)
201 {
202 shift_start[channels] = row_info->bit_depth - bit_depth->alpha;
203 shift_dec[channels] = bit_depth->alpha;
204 channels++;
205 }
206
207 /* with low row dephts, could only be grayscale, so one channel */
208 if (row_info->bit_depth < 8)
209 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500210 png_bytef *bp;
Guy Schalnat0d580581995-07-20 02:43:20 -0500211 png_uint_32 i;
212 int j;
213 png_byte mask;
214
215 if (bit_depth->gray == 1 && row_info->bit_depth == 2)
216 mask = 0x55;
217 else if (row_info->bit_depth == 4 && bit_depth->gray == 3)
218 mask = 0x11;
219 else
220 mask = 0xff;
221
222 for (bp = row, i = 0; i < row_info->rowbytes; i++, bp++)
223 {
224 int v;
225
226 v = *bp;
227 *bp = 0;
228 for (j = shift_start[0]; j > -shift_dec[0]; j -= shift_dec[0])
229 {
230 if (j > 0)
231 *bp |= (png_byte)((v << j) & 0xff);
232 else
233 *bp |= (png_byte)((v >> (-j)) & mask);
234 }
235 }
236 }
237 else if (row_info->bit_depth == 8)
238 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500239 png_bytef *bp;
Guy Schalnat0d580581995-07-20 02:43:20 -0500240 png_uint_32 i;
241 int j;
242
243 for (bp = row, i = 0; i < row_info->width; i++)
244 {
245 int c;
246
247 for (c = 0; c < channels; c++, bp++)
248 {
249 int v;
250
251 v = *bp;
252 *bp = 0;
253 for (j = shift_start[c]; j > -shift_dec[c]; j -= shift_dec[c])
254 {
255 if (j > 0)
256 *bp |= (png_byte)((v << j) & 0xff);
257 else
258 *bp |= (png_byte)((v >> (-j)) & 0xff);
259 }
260 }
261 }
262 }
263 else
264 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500265 png_bytef *bp;
Guy Schalnat0d580581995-07-20 02:43:20 -0500266 png_uint_32 i;
267 int j;
268
269 for (bp = row, i = 0;
270 i < row_info->width * row_info->channels;
271 i++)
272 {
273 int c;
274
275 for (c = 0; c < channels; c++, bp += 2)
276 {
277 png_uint_16 value, v;
278
279 v = ((png_uint_16)(*bp) << 8) + (png_uint_16)(*(bp + 1));
280 value = 0;
281 for (j = shift_start[c]; j > -shift_dec[c]; j -= shift_dec[c])
282 {
283 if (j > 0)
284 value |= (png_uint_16)((v << j) & (png_uint_16)0xffff);
285 else
286 value |= (png_uint_16)((v >> (-j)) & (png_uint_16)0xffff);
287 }
288 *bp = value >> 8;
289 *(bp + 1) = value & 0xff;
290 }
291 }
292 }
293 }
294}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500295#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500296
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500297#ifdef PNG_WRITE_FILLER_SUPPORTED
298/* remove filler byte */
Guy Schalnat0d580581995-07-20 02:43:20 -0500299void
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500300png_do_write_filler(png_row_info *row_info, png_bytef *row,
301 png_byte filler_loc)
Guy Schalnat0d580581995-07-20 02:43:20 -0500302{
303 if (row && row_info && row_info->color_type == PNG_COLOR_TYPE_RGB &&
304 row_info->bit_depth == 8)
305 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500306 if (filler_loc == PNG_FILLER_AFTER)
Guy Schalnat0d580581995-07-20 02:43:20 -0500307 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500308 png_bytef *sp, *dp;
309 png_uint_32 i;
310
311 for (i = 1, sp = row + 4, dp = row + 3;
312 i < row_info->width;
313 i++)
314 {
315 *dp++ = *sp++;
316 *dp++ = *sp++;
317 *dp++ = *sp++;
318 sp++;
319 }
320 row_info->channels = 3;
321 row_info->pixel_depth = 24;
322 row_info->rowbytes = row_info->width * 3;
Guy Schalnat0d580581995-07-20 02:43:20 -0500323 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500324 else
325 {
326 png_bytef *sp, *dp;
327 png_uint_32 i;
328
329 for (i = 1, sp = row + 4, dp = row + 3;
330 i < row_info->width;
331 i++)
332 {
333 sp++;
334 *dp++ = *sp++;
335 *dp++ = *sp++;
336 *dp++ = *sp++;
337 }
338 row_info->channels = 3;
339 row_info->pixel_depth = 24;
340 row_info->rowbytes = row_info->width * 3;
341 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500342 }
343}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500344#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500345