334fe356df107f6f0602bbc300b51fd48549059a
[dosdemo] / libs / imago / src / conv.c
1 /*
2 libimago - a multi-format image file input/output library.
3 Copyright (C) 2010 John Tsiombikas <nuclear@member.fsf.org>
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published
7 by the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License
16 along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 */
18 #include <string.h>
19 #include "imago2.h"
20
21 /* pixel-format conversions are sub-optimal at the moment to avoid
22  * writing a lot of code. optimize at some point ?
23  */
24
25 #define CLAMP(x, a, b)  ((x) < (a) ? (a) : ((x) > (b) ? (b) : (x)))
26
27 struct pixel {
28         float r, g, b, a;
29 };
30
31 static void unpack_grey8(struct pixel *unp, void *pptr, int count);
32 static void unpack_rgb24(struct pixel *unp, void *pptr, int count);
33 static void unpack_rgba32(struct pixel *unp, void *pptr, int count);
34 static void unpack_greyf(struct pixel *unp, void *pptr, int count);
35 static void unpack_rgbf(struct pixel *unp, void *pptr, int count);
36 static void unpack_rgbaf(struct pixel *unp, void *pptr, int count);
37
38 static void pack_grey8(void *pptr, struct pixel *unp, int count);
39 static void pack_rgb24(void *pptr, struct pixel *unp, int count);
40 static void pack_rgba32(void *pptr, struct pixel *unp, int count);
41 static void pack_greyf(void *pptr, struct pixel *unp, int count);
42 static void pack_rgbf(void *pptr, struct pixel *unp, int count);
43 static void pack_rgbaf(void *pptr, struct pixel *unp, int count);
44
45 /* XXX keep in sync with enum img_fmt at imago2.h */
46 static void (*unpack[])(struct pixel*, void*, int) = {
47         unpack_grey8,
48         unpack_rgb24,
49         unpack_rgba32,
50         unpack_greyf,
51         unpack_rgbf,
52         unpack_rgbaf
53 };
54
55 /* XXX keep in sync with enum img_fmt at imago2.h */
56 static void (*pack[])(void*, struct pixel*, int) = {
57         pack_grey8,
58         pack_rgb24,
59         pack_rgba32,
60         pack_greyf,
61         pack_rgbf,
62         pack_rgbaf
63 };
64
65
66 int img_convert(struct img_pixmap *img, enum img_fmt tofmt)
67 {
68         struct pixel pbuf[8];
69         int bufsz = (img->width & 7) == 0 ? 8 : ((img->width & 3) == 0 ? 4 : 1);
70         int i, num_pix = img->width * img->height;
71         int num_iter = num_pix / bufsz;
72         char *sptr, *dptr;
73         struct img_pixmap nimg;
74
75         if(img->fmt == tofmt) {
76                 return 0;       /* nothing to do */
77         }
78
79         img_init(&nimg);
80         if(img_set_pixels(&nimg, img->width, img->height, tofmt, 0) == -1) {
81                 img_destroy(&nimg);
82                 return -1;
83         }
84
85         sptr = img->pixels;
86         dptr = nimg.pixels;
87
88         for(i=0; i<num_iter; i++) {
89                 unpack[img->fmt](pbuf, sptr, bufsz);
90                 pack[tofmt](dptr, pbuf, bufsz);
91
92                 sptr += bufsz * img->pixelsz;
93                 dptr += bufsz * nimg.pixelsz;
94         }
95
96         img_copy(img, &nimg);
97         img_destroy(&nimg);
98         return 0;
99 }
100
101 /* the following functions *could* benefit from SIMD */
102
103 static void unpack_grey8(struct pixel *unp, void *pptr, int count)
104 {
105         int i;
106         unsigned char *pix = pptr;
107
108         for(i=0; i<count; i++) {
109                 unp->r = unp->g = unp->b = (float)*pix++ / 255.0;
110                 unp->a = 1.0;
111                 unp++;
112         }
113 }
114
115 static void unpack_rgb24(struct pixel *unp, void *pptr, int count)
116 {
117         int i;
118         unsigned char *pix = pptr;
119
120         for(i=0; i<count; i++) {
121                 unp->r = (float)*pix++ / 255.0;
122                 unp->g = (float)*pix++ / 255.0;
123                 unp->b = (float)*pix++ / 255.0;
124                 unp->a = 1.0;
125                 unp++;
126         }
127 }
128
129 static void unpack_rgba32(struct pixel *unp, void *pptr, int count)
130 {
131         int i;
132         unsigned char *pix = pptr;
133
134         for(i=0; i<count; i++) {
135                 unp->r = (float)*pix++ / 255.0;
136                 unp->g = (float)*pix++ / 255.0;
137                 unp->b = (float)*pix++ / 255.0;
138                 unp->a = (float)*pix++ / 255.0;
139                 unp++;
140         }
141 }
142
143 static void unpack_greyf(struct pixel *unp, void *pptr, int count)
144 {
145         int i;
146         float *pix = pptr;
147
148         for(i=0; i<count; i++) {
149                 unp->r = unp->g = unp->b = *pix++;
150                 unp->a = 1.0;
151                 unp++;
152         }
153 }
154
155 static void unpack_rgbf(struct pixel *unp, void *pptr, int count)
156 {
157         int i;
158         float *pix = pptr;
159
160         for(i=0; i<count; i++) {
161                 unp->r = *pix++;
162                 unp->g = *pix++;
163                 unp->b = *pix++;
164                 unp->a = 1.0;
165                 unp++;
166         }
167 }
168
169 static void unpack_rgbaf(struct pixel *unp, void *pptr, int count)
170 {
171         int i;
172         float *pix = pptr;
173
174         for(i=0; i<count; i++) {
175                 unp->r = *pix++;
176                 unp->g = *pix++;
177                 unp->b = *pix++;
178                 unp->a = *pix++;
179                 unp++;
180         }
181 }
182
183
184 static void pack_grey8(void *pptr, struct pixel *unp, int count)
185 {
186         int i;
187         unsigned char *pix = pptr;
188
189         for(i=0; i<count; i++) {
190                 int lum = (int)(255.0 * (unp->r + unp->g + unp->b) / 3.0);
191                 *pix++ = CLAMP(lum, 0, 255);
192                 unp++;
193         }
194 }
195
196 static void pack_rgb24(void *pptr, struct pixel *unp, int count)
197 {
198         int i;
199         unsigned char *pix = pptr;
200
201         for(i=0; i<count; i++) {
202                 int r = (int)(unp->r * 255.0);
203                 int g = (int)(unp->g * 255.0);
204                 int b = (int)(unp->b * 255.0);
205
206                 *pix++ = CLAMP(r, 0, 255);
207                 *pix++ = CLAMP(g, 0, 255);
208                 *pix++ = CLAMP(b, 0, 255);
209                 unp++;
210         }
211 }
212
213 static void pack_rgba32(void *pptr, struct pixel *unp, int count)
214 {
215         int i;
216         unsigned char *pix = pptr;
217
218         for(i=0; i<count; i++) {
219                 int r = (int)(unp->r * 255.0);
220                 int g = (int)(unp->g * 255.0);
221                 int b = (int)(unp->b * 255.0);
222                 int a = (int)(unp->a * 255.0);
223
224                 *pix++ = CLAMP(r, 0, 255);
225                 *pix++ = CLAMP(g, 0, 255);
226                 *pix++ = CLAMP(b, 0, 255);
227                 *pix++ = CLAMP(a, 0, 255);
228                 unp++;
229         }
230 }
231
232 static void pack_greyf(void *pptr, struct pixel *unp, int count)
233 {
234         int i;
235         float *pix = pptr;
236
237         for(i=0; i<count; i++) {
238                 *pix++ = (unp->r + unp->g + unp->b) / 3.0;
239                 unp++;
240         }
241 }
242
243 static void pack_rgbf(void *pptr, struct pixel *unp, int count)
244 {
245         int i;
246         float *pix = pptr;
247
248         for(i=0; i<count; i++) {
249                 *pix++ = unp->r;
250                 *pix++ = unp->g;
251                 *pix++ = unp->b;
252                 unp++;
253         }
254 }
255
256 static void pack_rgbaf(void *pptr, struct pixel *unp, int count)
257 {
258         memcpy(pptr, unp, count * sizeof *unp);
259 }
260