blob: 7423ade340fce2d923dece16f29495d5bd49255d [file] [log] [blame]
Guy Schalnat0d580581995-07-20 02:43:20 -05001
2/* pngwtran.c - transforms the data in a row for png writers
3
4 libpng 1.0 beta 1 - version 0.71
5 For conditions of distribution and use, see copyright notice in png.h
6 Copyright (c) 1995 Guy Eric Schalnat, Group 42, Inc.
7 June 26, 1995
8 */
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{
18 if (png_ptr->transformations & PNG_RGBA)
19 png_do_write_rgbx(&(png_ptr->row_info), png_ptr->row_buf + 1);
20 if (png_ptr->transformations & PNG_XRGB)
21 png_do_write_xrgb(&(png_ptr->row_info), png_ptr->row_buf + 1);
22 if (png_ptr->transformations & PNG_PACK)
23 png_do_pack(&(png_ptr->row_info), png_ptr->row_buf + 1,
24 png_ptr->bit_depth);
25 if (png_ptr->transformations & PNG_SHIFT)
26 png_do_shift(&(png_ptr->row_info), png_ptr->row_buf + 1,
27 &(png_ptr->shift));
28 if (png_ptr->transformations & PNG_SWAP_BYTES)
29 png_do_swap(&(png_ptr->row_info), png_ptr->row_buf + 1);
30 if (png_ptr->transformations & PNG_BGR)
31 png_do_bgr(&(png_ptr->row_info), png_ptr->row_buf + 1);
32 if (png_ptr->transformations & PNG_INVERT_MONO)
33 png_do_invert(&(png_ptr->row_info), png_ptr->row_buf + 1);
34}
35
36/* pack pixels into bytes. Pass the true bit depth in bit_depth. The
37 row_info bit depth should be 8 (one pixel per byte). The channels
38 should be 1 (this only happens on grayscale and paletted images) */
39void
40png_do_pack(png_row_info *row_info, png_byte *row, png_byte bit_depth)
41{
42 if (row_info && row && row_info->bit_depth == 8 &&
43 row_info->channels == 1)
44 {
45 switch (bit_depth)
46 {
47 case 1:
48 {
49 png_byte *sp;
50 png_byte *dp;
51 int mask;
52 png_int_32 i;
53 int v;
54
55 sp = row;
56 dp = row;
57 mask = 0x80;
58 v = 0;
59 for (i = 0; i < row_info->width; i++)
60 {
61 if (*sp)
62 v |= mask;
63 sp++;
64 if (mask > 1)
65 mask >>= 1;
66 else
67 {
68 mask = 0x80;
69 *dp = v;
70 dp++;
71 v = 0;
72 }
73 }
74 if (mask != 0x80)
75 *dp = v;
76 break;
77 }
78 case 2:
79 {
80 png_byte *sp;
81 png_byte *dp;
82 int shift;
83 png_int_32 i;
84 int v;
85 png_byte value;
86
87 sp = row;
88 dp = row;
89 shift = 6;
90 v = 0;
91 for (i = 0; i < row_info->width; i++)
92 {
93 value = *sp & 0x3;
94 v |= (value << shift);
95 if (shift == 0)
96 {
97 shift = 6;
98 *dp = v;
99 dp++;
100 v = 0;
101 }
102 else
103 shift -= 2;
104 sp++;
105 }
106 if (shift != 6)
107 *dp = v;
108 break;
109 }
110 case 4:
111 {
112 png_byte *sp;
113 png_byte *dp;
114 int shift;
115 png_int_32 i;
116 int v;
117 png_byte value;
118
119 sp = row;
120 dp = row;
121 shift = 4;
122 v = 0;
123 for (i = 0; i < row_info->width; i++)
124 {
125 value = *sp & 0xf;
126 v |= (value << shift);
127
128 if (shift == 0)
129 {
130 shift = 4;
131 *dp = v;
132 dp++;
133 v = 0;
134 }
135 else
136 shift -= 4;
137
138 sp++;
139 }
140 if (shift != 4)
141 *dp = v;
142 break;
143 }
144 }
145 row_info->bit_depth = bit_depth;
146 row_info->pixel_depth = bit_depth * row_info->channels;
147 row_info->rowbytes =
148 ((row_info->width * row_info->pixel_depth + 7) >> 3);
149 }
150}
151
152/* shift pixel values to take advantage of whole range. Pass the
153 true number of bits in bit_depth. The row should be packed
154 according to row_info->bit_depth. Thus, if you had a row of
155 bit depth 4, but the pixels only had values from 0 to 7, you
156 would pass 3 as bit_depth, and this routine would translate the
157 data to 0 to 15. */
158void
159png_do_shift(png_row_info *row_info, png_byte *row, png_color_8 *bit_depth)
160{
161 if (row && row_info &&
162 row_info->color_type != PNG_COLOR_TYPE_PALETTE)
163 {
164 int shift_start[4], shift_dec[4];
165 int channels;
166
167 channels = 0;
168 if (row_info->color_type & PNG_COLOR_MASK_COLOR)
169 {
170 shift_start[channels] = row_info->bit_depth - bit_depth->red;
171 shift_dec[channels] = bit_depth->red;
172 channels++;
173 shift_start[channels] = row_info->bit_depth - bit_depth->green;
174 shift_dec[channels] = bit_depth->green;
175 channels++;
176 shift_start[channels] = row_info->bit_depth - bit_depth->blue;
177 shift_dec[channels] = bit_depth->blue;
178 channels++;
179 }
180 else
181 {
182 shift_start[channels] = row_info->bit_depth - bit_depth->gray;
183 shift_dec[channels] = bit_depth->gray;
184 channels++;
185 }
186 if (row_info->color_type & PNG_COLOR_MASK_ALPHA)
187 {
188 shift_start[channels] = row_info->bit_depth - bit_depth->alpha;
189 shift_dec[channels] = bit_depth->alpha;
190 channels++;
191 }
192
193 /* with low row dephts, could only be grayscale, so one channel */
194 if (row_info->bit_depth < 8)
195 {
196 png_byte *bp;
197 png_uint_32 i;
198 int j;
199 png_byte mask;
200
201 if (bit_depth->gray == 1 && row_info->bit_depth == 2)
202 mask = 0x55;
203 else if (row_info->bit_depth == 4 && bit_depth->gray == 3)
204 mask = 0x11;
205 else
206 mask = 0xff;
207
208 for (bp = row, i = 0; i < row_info->rowbytes; i++, bp++)
209 {
210 int v;
211
212 v = *bp;
213 *bp = 0;
214 for (j = shift_start[0]; j > -shift_dec[0]; j -= shift_dec[0])
215 {
216 if (j > 0)
217 *bp |= (png_byte)((v << j) & 0xff);
218 else
219 *bp |= (png_byte)((v >> (-j)) & mask);
220 }
221 }
222 }
223 else if (row_info->bit_depth == 8)
224 {
225 png_byte *bp;
226 png_uint_32 i;
227 int j;
228
229 for (bp = row, i = 0; i < row_info->width; i++)
230 {
231 int c;
232
233 for (c = 0; c < channels; c++, bp++)
234 {
235 int v;
236
237 v = *bp;
238 *bp = 0;
239 for (j = shift_start[c]; j > -shift_dec[c]; j -= shift_dec[c])
240 {
241 if (j > 0)
242 *bp |= (png_byte)((v << j) & 0xff);
243 else
244 *bp |= (png_byte)((v >> (-j)) & 0xff);
245 }
246 }
247 }
248 }
249 else
250 {
251 png_byte *bp;
252 png_uint_32 i;
253 int j;
254
255 for (bp = row, i = 0;
256 i < row_info->width * row_info->channels;
257 i++)
258 {
259 int c;
260
261 for (c = 0; c < channels; c++, bp += 2)
262 {
263 png_uint_16 value, v;
264
265 v = ((png_uint_16)(*bp) << 8) + (png_uint_16)(*(bp + 1));
266 value = 0;
267 for (j = shift_start[c]; j > -shift_dec[c]; j -= shift_dec[c])
268 {
269 if (j > 0)
270 value |= (png_uint_16)((v << j) & (png_uint_16)0xffff);
271 else
272 value |= (png_uint_16)((v >> (-j)) & (png_uint_16)0xffff);
273 }
274 *bp = value >> 8;
275 *(bp + 1) = value & 0xff;
276 }
277 }
278 }
279 }
280}
281
282/* remove filler byte after rgb */
283void
284png_do_write_rgbx(png_row_info *row_info, png_byte *row)
285{
286 if (row && row_info && row_info->color_type == PNG_COLOR_TYPE_RGB &&
287 row_info->bit_depth == 8)
288 {
289 png_byte *sp, *dp;
290 png_uint_32 i;
291
292 for (i = 1, sp = row + 4, dp = row + 3;
293 i < row_info->width;
294 i++)
295 {
296 *dp++ = *sp++;
297 *dp++ = *sp++;
298 *dp++ = *sp++;
299 sp++;
300 }
301 row_info->channels = 3;
302 row_info->pixel_depth = 24;
303 row_info->rowbytes = row_info->width * 3;
304 }
305}
306
307/* remove filler byte before rgb */
308void
309png_do_write_xrgb(png_row_info *row_info, png_byte *row)
310{
311 if (row && row_info && row_info->color_type == PNG_COLOR_TYPE_RGB &&
312 row_info->bit_depth == 8)
313 {
314 png_byte *sp, *dp;
315 png_uint_32 i;
316
317 for (i = 0, sp = row, dp = row;
318 i < row_info->width;
319 i++)
320 {
321 sp++;
322 *dp++ = *sp++;
323 *dp++ = *sp++;
324 *dp++ = *sp++;
325 }
326 row_info->channels = 3;
327 row_info->pixel_depth = 24;
328 row_info->rowbytes = row_info->width * 3;
329 }
330}
331