intro screen
[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_greyf(struct pixel *unp, void *pptr, int count);
36 static void unpack_rgbf(struct pixel *unp, void *pptr, int count);
37 static void unpack_rgbaf(struct pixel *unp, void *pptr, int count);
38 static void unpack_rgb565(struct pixel *unp, void *pptr, int count);
39
40 static void pack_grey8(void *pptr, struct pixel *unp, int count);
41 static void pack_rgb24(void *pptr, struct pixel *unp, int count);
42 static void pack_rgba32(void *pptr, struct pixel *unp, int count);
43 static void pack_greyf(void *pptr, struct pixel *unp, int count);
44 static void pack_rgbf(void *pptr, struct pixel *unp, int count);
45 static void pack_rgbaf(void *pptr, struct pixel *unp, int count);
46 static void pack_rgb565(void *pptr, struct pixel *unp, int count);
47
48 /* XXX keep in sync with enum img_fmt at imago2.h */
49 static void (*unpack[])(struct pixel*, void*, int) = {
50         unpack_grey8,
51         unpack_rgb24,
52         unpack_rgba32,
53         unpack_greyf,
54         unpack_rgbf,
55         unpack_rgbaf,
56         unpack_rgb565
57 };
58
59 /* XXX keep in sync with enum img_fmt at imago2.h */
60 static void (*pack[])(void*, struct pixel*, int) = {
61         pack_grey8,
62         pack_rgb24,
63         pack_rgba32,
64         pack_greyf,
65         pack_rgbf,
66         pack_rgbaf,
67         pack_rgb565
68 };
69
70
71 int img_convert(struct img_pixmap *img, enum img_fmt tofmt)
72 {
73         struct pixel pbuf[8];
74         int bufsz = (img->width & 7) == 0 ? 8 : ((img->width & 3) == 0 ? 4 : 1);
75         int i, num_pix = img->width * img->height;
76         int num_iter = num_pix / bufsz;
77         char *sptr, *dptr;
78         struct img_pixmap nimg;
79
80         if(img->fmt == tofmt) {
81                 return 0;       /* nothing to do */
82         }
83
84         img_init(&nimg);
85         if(img_set_pixels(&nimg, img->width, img->height, tofmt, 0) == -1) {
86                 img_destroy(&nimg);
87                 return -1;
88         }
89
90         sptr = img->pixels;
91         dptr = nimg.pixels;
92
93         for(i=0; i<num_iter; i++) {
94                 unpack[img->fmt](pbuf, sptr, bufsz);
95                 pack[tofmt](dptr, pbuf, bufsz);
96
97                 sptr += bufsz * img->pixelsz;
98                 dptr += bufsz * nimg.pixelsz;
99         }
100
101         img_copy(img, &nimg);
102         img_destroy(&nimg);
103         return 0;
104 }
105
106 /* the following functions *could* benefit from SIMD */
107
108 static void unpack_grey8(struct pixel *unp, void *pptr, int count)
109 {
110         int i;
111         unsigned char *pix = pptr;
112
113         for(i=0; i<count; i++) {
114                 unp->r = unp->g = unp->b = (float)*pix++ / 255.0;
115                 unp->a = 1.0;
116                 unp++;
117         }
118 }
119
120 static void unpack_rgb24(struct pixel *unp, void *pptr, int count)
121 {
122         int i;
123         unsigned char *pix = pptr;
124
125         for(i=0; i<count; i++) {
126                 unp->r = (float)*pix++ / 255.0;
127                 unp->g = (float)*pix++ / 255.0;
128                 unp->b = (float)*pix++ / 255.0;
129                 unp->a = 1.0;
130                 unp++;
131         }
132 }
133
134 static void unpack_rgba32(struct pixel *unp, void *pptr, int count)
135 {
136         int i;
137         unsigned char *pix = pptr;
138
139         for(i=0; i<count; i++) {
140                 unp->r = (float)*pix++ / 255.0;
141                 unp->g = (float)*pix++ / 255.0;
142                 unp->b = (float)*pix++ / 255.0;
143                 unp->a = (float)*pix++ / 255.0;
144                 unp++;
145         }
146 }
147
148 static void unpack_greyf(struct pixel *unp, void *pptr, int count)
149 {
150         int i;
151         float *pix = pptr;
152
153         for(i=0; i<count; i++) {
154                 unp->r = unp->g = unp->b = *pix++;
155                 unp->a = 1.0;
156                 unp++;
157         }
158 }
159
160 static void unpack_rgbf(struct pixel *unp, void *pptr, int count)
161 {
162         int i;
163         float *pix = pptr;
164
165         for(i=0; i<count; i++) {
166                 unp->r = *pix++;
167                 unp->g = *pix++;
168                 unp->b = *pix++;
169                 unp->a = 1.0;
170                 unp++;
171         }
172 }
173
174 static void unpack_rgbaf(struct pixel *unp, void *pptr, int count)
175 {
176         int i;
177         float *pix = pptr;
178
179         for(i=0; i<count; i++) {
180                 unp->r = *pix++;
181                 unp->g = *pix++;
182                 unp->b = *pix++;
183                 unp->a = *pix++;
184                 unp++;
185         }
186 }
187
188 static void unpack_rgb565(struct pixel *unp, void *pptr, int count)
189 {
190         int i;
191         uint16_t *pix = pptr;
192
193         for(i=0; i<count; i++) {
194                 uint16_t r, g, b, p = *pix++;
195                 r = (p & 0x1f) << 3;
196                 if(r & 8) r |= 7;       /* fill LSbits with whatever bit 0 was */
197                 g = (p >> 2) & 0xfc;
198                 if(g & 4) g |= 3;       /* ditto */
199                 b = (p >> 8) & 0xf8;
200                 if(b & 8) r |= 7;       /* same */
201
202                 unp->r = (float)r / 255.0f;
203                 unp->g = (float)g / 255.0f;
204                 unp->b = (float)b / 255.0f;
205                 unp->a = 1.0f;
206                 unp++;
207         }
208 }
209
210
211 static void pack_grey8(void *pptr, struct pixel *unp, int count)
212 {
213         int i;
214         unsigned char *pix = pptr;
215
216         for(i=0; i<count; i++) {
217                 int lum = (int)(255.0 * (unp->r + unp->g + unp->b) / 3.0);
218                 *pix++ = CLAMP(lum, 0, 255);
219                 unp++;
220         }
221 }
222
223 static void pack_rgb24(void *pptr, struct pixel *unp, int count)
224 {
225         int i;
226         unsigned char *pix = pptr;
227
228         for(i=0; i<count; i++) {
229                 int r = (int)(unp->r * 255.0);
230                 int g = (int)(unp->g * 255.0);
231                 int b = (int)(unp->b * 255.0);
232
233                 *pix++ = CLAMP(r, 0, 255);
234                 *pix++ = CLAMP(g, 0, 255);
235                 *pix++ = CLAMP(b, 0, 255);
236                 unp++;
237         }
238 }
239
240 static void pack_rgba32(void *pptr, struct pixel *unp, int count)
241 {
242         int i;
243         unsigned char *pix = pptr;
244
245         for(i=0; i<count; i++) {
246                 int r = (int)(unp->r * 255.0);
247                 int g = (int)(unp->g * 255.0);
248                 int b = (int)(unp->b * 255.0);
249                 int a = (int)(unp->a * 255.0);
250
251                 *pix++ = CLAMP(r, 0, 255);
252                 *pix++ = CLAMP(g, 0, 255);
253                 *pix++ = CLAMP(b, 0, 255);
254                 *pix++ = CLAMP(a, 0, 255);
255                 unp++;
256         }
257 }
258
259 static void pack_greyf(void *pptr, struct pixel *unp, int count)
260 {
261         int i;
262         float *pix = pptr;
263
264         for(i=0; i<count; i++) {
265                 *pix++ = (unp->r + unp->g + unp->b) / 3.0;
266                 unp++;
267         }
268 }
269
270 static void pack_rgbf(void *pptr, struct pixel *unp, int count)
271 {
272         int i;
273         float *pix = pptr;
274
275         for(i=0; i<count; i++) {
276                 *pix++ = unp->r;
277                 *pix++ = unp->g;
278                 *pix++ = unp->b;
279                 unp++;
280         }
281 }
282
283 static void pack_rgbaf(void *pptr, struct pixel *unp, int count)
284 {
285         memcpy(pptr, unp, count * sizeof *unp);
286 }
287
288
289 static void pack_rgb565(void *pptr, struct pixel *unp, int count)
290 {
291         int i;
292         uint16_t *pix = pptr;
293
294         for(i=0; i<count; i++) {
295                 uint16_t r = (uint16_t)(unp->r * 255.0f);
296                 uint16_t g = (uint16_t)(unp->g * 255.0f);
297                 uint16_t b = (uint16_t)(unp->b * 255.0f);
298                 if(r > 255) r = 255;
299                 if(g > 255) g = 255;
300                 if(b > 255) b = 255;
301                 *pix++ = (r >> 3) | ((g & 0x3f) << 2) | ((b & 0x1f) << 8);
302                 unp++;
303         }
304 }