MMX
[eradicate] / libs / imago / src / conv.c
1 /*
2 libimago - a multi-format image file input/output library.
3 Copyright (C) 2010-2020 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 #include "inttypes.h"
21
22 /* pixel-format conversions are sub-optimal at the moment to avoid
23  * writing a lot of code. optimize at some point ?
24  */
25
26 #define CLAMP(x, a, b)  ((x) < (a) ? (a) : ((x) > (b) ? (b) : (x)))
27
28 struct pixel {
29         float r, g, b, a;
30 };
31
32 static void unpack_grey8(struct pixel *unp, void *pptr, int count);
33 static void unpack_rgb24(struct pixel *unp, void *pptr, int count);
34 static void unpack_rgba32(struct pixel *unp, void *pptr, int count);
35 static void unpack_bgra32(struct pixel *unp, void *pptr, int count);
36 static void unpack_greyf(struct pixel *unp, void *pptr, int count);
37 static void unpack_rgbf(struct pixel *unp, void *pptr, int count);
38 static void unpack_rgbaf(struct pixel *unp, void *pptr, int count);
39 static void unpack_rgb565(struct pixel *unp, void *pptr, int count);
40
41 static void pack_grey8(void *pptr, struct pixel *unp, int count);
42 static void pack_rgb24(void *pptr, struct pixel *unp, int count);
43 static void pack_rgba32(void *pptr, struct pixel *unp, int count);
44 static void pack_bgra32(void *pptr, struct pixel *unp, int count);
45 static void pack_greyf(void *pptr, struct pixel *unp, int count);
46 static void pack_rgbf(void *pptr, struct pixel *unp, int count);
47 static void pack_rgbaf(void *pptr, struct pixel *unp, int count);
48 static void pack_rgb565(void *pptr, struct pixel *unp, int count);
49
50 /* XXX keep in sync with enum img_fmt at imago2.h */
51 static void (*unpack[])(struct pixel*, void*, int) = {
52         unpack_grey8,
53         unpack_rgb24,
54         unpack_rgba32,
55         unpack_bgra32,
56         unpack_greyf,
57         unpack_rgbf,
58         unpack_rgbaf,
59         unpack_rgb565
60 };
61
62 /* XXX keep in sync with enum img_fmt at imago2.h */
63 static void (*pack[])(void*, struct pixel*, int) = {
64         pack_grey8,
65         pack_rgb24,
66         pack_rgba32,
67         pack_bgra32,
68         pack_greyf,
69         pack_rgbf,
70         pack_rgbaf,
71         pack_rgb565
72 };
73
74
75 int img_convert(struct img_pixmap *img, enum img_fmt tofmt)
76 {
77         struct pixel pbuf[8];
78         int bufsz = (img->width & 7) == 0 ? 8 : ((img->width & 3) == 0 ? 4 : 1);
79         int i, num_pix = img->width * img->height;
80         int num_iter = num_pix / bufsz;
81         char *sptr, *dptr;
82         struct img_pixmap nimg;
83
84         if(img->fmt == tofmt) {
85                 return 0;       /* nothing to do */
86         }
87
88         img_init(&nimg);
89         if(img_set_pixels(&nimg, img->width, img->height, tofmt, 0) == -1) {
90                 img_destroy(&nimg);
91                 return -1;
92         }
93
94         sptr = img->pixels;
95         dptr = nimg.pixels;
96
97         for(i=0; i<num_iter; i++) {
98                 unpack[img->fmt](pbuf, sptr, bufsz);
99                 pack[tofmt](dptr, pbuf, bufsz);
100
101                 sptr += bufsz * img->pixelsz;
102                 dptr += bufsz * nimg.pixelsz;
103         }
104
105         img_copy(img, &nimg);
106         img_destroy(&nimg);
107         return 0;
108 }
109
110 /* the following functions *could* benefit from SIMD */
111
112 static void unpack_grey8(struct pixel *unp, void *pptr, int count)
113 {
114         int i;
115         unsigned char *pix = pptr;
116
117         for(i=0; i<count; i++) {
118                 unp->r = unp->g = unp->b = (float)*pix++ / 255.0;
119                 unp->a = 1.0;
120                 unp++;
121         }
122 }
123
124 static void unpack_rgb24(struct pixel *unp, void *pptr, int count)
125 {
126         int i;
127         unsigned char *pix = pptr;
128
129         for(i=0; i<count; i++) {
130                 unp->r = (float)*pix++ / 255.0;
131                 unp->g = (float)*pix++ / 255.0;
132                 unp->b = (float)*pix++ / 255.0;
133                 unp->a = 1.0;
134                 unp++;
135         }
136 }
137
138 static void unpack_rgba32(struct pixel *unp, void *pptr, int count)
139 {
140         int i;
141         unsigned char *pix = pptr;
142
143         for(i=0; i<count; i++) {
144                 unp->r = (float)*pix++ / 255.0;
145                 unp->g = (float)*pix++ / 255.0;
146                 unp->b = (float)*pix++ / 255.0;
147                 unp->a = (float)*pix++ / 255.0;
148                 unp++;
149         }
150 }
151
152 static void unpack_bgra32(struct pixel *unp, void *pptr, int count)
153 {
154         int i;
155         unsigned char *pix = pptr;
156
157         for(i=0; i<count; i++) {
158                 unp->b = (float)*pix++ / 255.0;
159                 unp->g = (float)*pix++ / 255.0;
160                 unp->r = (float)*pix++ / 255.0;
161                 unp->a = (float)*pix++ / 255.0;
162                 unp++;
163         }
164 }
165
166 static void unpack_greyf(struct pixel *unp, void *pptr, int count)
167 {
168         int i;
169         float *pix = pptr;
170
171         for(i=0; i<count; i++) {
172                 unp->r = unp->g = unp->b = *pix++;
173                 unp->a = 1.0;
174                 unp++;
175         }
176 }
177
178 static void unpack_rgbf(struct pixel *unp, void *pptr, int count)
179 {
180         int i;
181         float *pix = pptr;
182
183         for(i=0; i<count; i++) {
184                 unp->r = *pix++;
185                 unp->g = *pix++;
186                 unp->b = *pix++;
187                 unp->a = 1.0;
188                 unp++;
189         }
190 }
191
192 static void unpack_rgbaf(struct pixel *unp, void *pptr, int count)
193 {
194         int i;
195         float *pix = pptr;
196
197         for(i=0; i<count; i++) {
198                 unp->r = *pix++;
199                 unp->g = *pix++;
200                 unp->b = *pix++;
201                 unp->a = *pix++;
202                 unp++;
203         }
204 }
205
206 static void unpack_rgb565(struct pixel *unp, void *pptr, int count)
207 {
208         int i;
209         uint16_t *pix = pptr;
210
211         for(i=0; i<count; i++) {
212                 uint16_t r, g, b, p = *pix++;
213                 b = (p & 0x1f) << 3;
214                 if(b & 8) b |= 7;       /* fill LSbits with whatever bit 0 was */
215                 g = (p >> 2) & 0xfc;
216                 if(g & 4) g |= 3;       /* ditto */
217                 r = (p >> 8) & 0xf8;
218                 if(r & 8) r |= 7;       /* same */
219
220                 unp->r = (float)r / 255.0f;
221                 unp->g = (float)g / 255.0f;
222                 unp->b = (float)b / 255.0f;
223                 unp->a = 1.0f;
224                 unp++;
225         }
226 }
227
228
229 static void pack_grey8(void *pptr, struct pixel *unp, int count)
230 {
231         int i;
232         unsigned char *pix = pptr;
233
234         for(i=0; i<count; i++) {
235                 int lum = (int)(255.0 * (unp->r + unp->g + unp->b) / 3.0);
236                 *pix++ = CLAMP(lum, 0, 255);
237                 unp++;
238         }
239 }
240
241 static void pack_rgb24(void *pptr, struct pixel *unp, int count)
242 {
243         int i;
244         unsigned char *pix = pptr;
245
246         for(i=0; i<count; i++) {
247                 int r = (int)(unp->r * 255.0);
248                 int g = (int)(unp->g * 255.0);
249                 int b = (int)(unp->b * 255.0);
250
251                 *pix++ = CLAMP(r, 0, 255);
252                 *pix++ = CLAMP(g, 0, 255);
253                 *pix++ = CLAMP(b, 0, 255);
254                 unp++;
255         }
256 }
257
258 static void pack_rgba32(void *pptr, struct pixel *unp, int count)
259 {
260         int i;
261         unsigned char *pix = pptr;
262
263         for(i=0; i<count; i++) {
264                 int r = (int)(unp->r * 255.0);
265                 int g = (int)(unp->g * 255.0);
266                 int b = (int)(unp->b * 255.0);
267                 int a = (int)(unp->a * 255.0);
268
269                 *pix++ = CLAMP(r, 0, 255);
270                 *pix++ = CLAMP(g, 0, 255);
271                 *pix++ = CLAMP(b, 0, 255);
272                 *pix++ = CLAMP(a, 0, 255);
273                 unp++;
274         }
275 }
276
277 static void pack_bgra32(void *pptr, struct pixel *unp, int count)
278 {
279         int i;
280         unsigned char *pix = pptr;
281
282         for(i=0; i<count; i++) {
283                 int r = (int)(unp->r * 255.0);
284                 int g = (int)(unp->g * 255.0);
285                 int b = (int)(unp->b * 255.0);
286                 int a = (int)(unp->a * 255.0);
287
288                 *pix++ = CLAMP(b, 0, 255);
289                 *pix++ = CLAMP(g, 0, 255);
290                 *pix++ = CLAMP(r, 0, 255);
291                 *pix++ = CLAMP(a, 0, 255);
292                 unp++;
293         }
294 }
295
296 static void pack_greyf(void *pptr, struct pixel *unp, int count)
297 {
298         int i;
299         float *pix = pptr;
300
301         for(i=0; i<count; i++) {
302                 *pix++ = (unp->r + unp->g + unp->b) / 3.0;
303                 unp++;
304         }
305 }
306
307 static void pack_rgbf(void *pptr, struct pixel *unp, int count)
308 {
309         int i;
310         float *pix = pptr;
311
312         for(i=0; i<count; i++) {
313                 *pix++ = unp->r;
314                 *pix++ = unp->g;
315                 *pix++ = unp->b;
316                 unp++;
317         }
318 }
319
320 static void pack_rgbaf(void *pptr, struct pixel *unp, int count)
321 {
322         memcpy(pptr, unp, count * sizeof *unp);
323 }
324
325
326 static void pack_rgb565(void *pptr, struct pixel *unp, int count)
327 {
328         int i;
329         uint16_t *pix = pptr;
330
331         for(i=0; i<count; i++) {
332                 uint16_t r = (uint16_t)(unp->r * 31.0f);
333                 uint16_t g = (uint16_t)(unp->g * 63.0f);
334                 uint16_t b = (uint16_t)(unp->b * 31.0f);
335                 if(r > 31) r = 31;
336                 if(g > 63) g = 63;
337                 if(b > 31) b = 31;
338                 *pix++ = (r << 11) | (g << 5) | b;
339                 unp++;
340         }
341 }