added a bunch of libraries
[vrlugburz] / libs / imago / src / imago2.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
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include "imago2.h"
23 #include "ftmodule.h"
24
25 static int pixel_size(enum img_fmt fmt);
26 static size_t def_read(void *buf, size_t bytes, void *uptr);
27 static size_t def_write(void *buf, size_t bytes, void *uptr);
28 static long def_seek(long offset, int whence, void *uptr);
29
30
31 void img_init(struct img_pixmap *img)
32 {
33         img->pixels = 0;
34         img->width = img->height = 0;
35         img->fmt = IMG_FMT_RGBA32;
36         img->pixelsz = pixel_size(img->fmt);
37         img->name = 0;
38 }
39
40
41 void img_destroy(struct img_pixmap *img)
42 {
43         free(img->pixels);
44         img->pixels = 0;        /* just in case... */
45         img->width = img->height = 0xbadbeef;
46         free(img->name);
47 }
48
49 struct img_pixmap *img_create(void)
50 {
51         struct img_pixmap *p;
52
53         if(!(p = malloc(sizeof *p))) {
54                 return 0;
55         }
56         img_init(p);
57         return p;
58 }
59
60 void img_free(struct img_pixmap *img)
61 {
62         img_destroy(img);
63         free(img);
64 }
65
66 int img_set_name(struct img_pixmap *img, const char *name)
67 {
68         char *tmp;
69
70         if(!(tmp = malloc(strlen(name) + 1))) {
71                 return -1;
72         }
73         strcpy(tmp, name);
74         img->name = tmp;
75         return 0;
76 }
77
78 int img_set_format(struct img_pixmap *img, enum img_fmt fmt)
79 {
80         if(img->pixels) {
81                 return img_convert(img, fmt);
82         }
83         img->fmt = fmt;
84         return 0;
85 }
86
87 int img_copy(struct img_pixmap *dest, struct img_pixmap *src)
88 {
89         return img_set_pixels(dest, src->width, src->height, src->fmt, src->pixels);
90 }
91
92 int img_set_pixels(struct img_pixmap *img, int w, int h, enum img_fmt fmt, void *pix)
93 {
94         void *newpix;
95         int pixsz = pixel_size(fmt);
96
97         if(!(newpix = malloc(w * h * pixsz))) {
98                 return -1;
99         }
100
101         if(pix) {
102                 memcpy(newpix, pix, w * h * pixsz);
103         } else {
104                 memset(newpix, 0, w * h * pixsz);
105         }
106
107         free(img->pixels);
108         img->pixels = newpix;
109         img->width = w;
110         img->height = h;
111         img->pixelsz = pixsz;
112         img->fmt = fmt;
113         return 0;
114 }
115
116 void *img_load_pixels(const char *fname, int *xsz, int *ysz, enum img_fmt fmt)
117 {
118         struct img_pixmap img;
119
120         img_init(&img);
121
122         if(img_load(&img, fname) == -1) {
123                 return 0;
124         }
125         if(img.fmt != fmt) {
126                 if(img_convert(&img, fmt) == -1) {
127                         img_destroy(&img);
128                         return 0;
129                 }
130         }
131
132         *xsz = img.width;
133         *ysz = img.height;
134         return img.pixels;
135 }
136
137 int img_save_pixels(const char *fname, void *pix, int xsz, int ysz, enum img_fmt fmt)
138 {
139         int res;
140         struct img_pixmap img;
141
142         img_init(&img);
143         img.fmt = fmt;
144         img.pixelsz = pixel_size(fmt);
145         img.width = xsz;
146         img.height = ysz;
147         img.pixels = pix;
148
149         res = img_save(&img, fname);
150         img.pixels = 0;
151         img_destroy(&img);
152         return res;
153 }
154
155 void img_free_pixels(void *pix)
156 {
157         free(pix);
158 }
159
160 int img_load(struct img_pixmap *img, const char *fname)
161 {
162         int res;
163         FILE *fp;
164
165         if(!(fp = fopen(fname, "rb"))) {
166                 return -1;
167         }
168         res = img_read_file(img, fp);
169         fclose(fp);
170         return res;
171 }
172
173 /* TODO implement filetype selection */
174 int img_save(struct img_pixmap *img, const char *fname)
175 {
176         int res;
177         FILE *fp;
178
179         img_set_name(img, fname);
180
181         if(!(fp = fopen(fname, "wb"))) {
182                 return -1;
183         }
184         res = img_write_file(img, fp);
185         fclose(fp);
186         return res;
187 }
188
189 int img_read_file(struct img_pixmap *img, FILE *fp)
190 {
191         struct img_io io = {0, def_read, def_write, def_seek};
192
193         io.uptr = fp;
194         return img_read(img, &io);
195 }
196
197 int img_write_file(struct img_pixmap *img, FILE *fp)
198 {
199         struct img_io io = {0, def_read, def_write, def_seek};
200
201         io.uptr = fp;
202         return img_write(img, &io);
203 }
204
205 int img_read(struct img_pixmap *img, struct img_io *io)
206 {
207         struct ftype_module *mod;
208
209         if((mod = img_find_format_module(io))) {
210                 return mod->read(img, io);
211         }
212         return -1;
213 }
214
215 int img_write(struct img_pixmap *img, struct img_io *io)
216 {
217         struct ftype_module *mod;
218
219         if(!img->name || !(mod = img_guess_format(img->name))) {
220                 /* TODO throw some sort of warning? */
221                 /* TODO implement some sort of module priority or let the user specify? */
222                 if(!(mod = img_get_module(0))) {
223                         return -1;
224                 }
225         }
226
227         return mod->write(img, io);
228 }
229
230 int img_to_float(struct img_pixmap *img)
231 {
232         enum img_fmt targ_fmt;
233
234         switch(img->fmt) {
235         case IMG_FMT_GREY8:
236                 targ_fmt = IMG_FMT_GREYF;
237                 break;
238
239         case IMG_FMT_RGB24:
240                 targ_fmt = IMG_FMT_RGBF;
241                 break;
242
243         case IMG_FMT_RGBA32:
244                 targ_fmt = IMG_FMT_RGBAF;
245                 break;
246
247         default:
248                 return 0;       /* already float */
249         }
250
251         return img_convert(img, targ_fmt);
252 }
253
254 int img_to_integer(struct img_pixmap *img)
255 {
256         enum img_fmt targ_fmt;
257
258         switch(img->fmt) {
259         case IMG_FMT_GREYF:
260                 targ_fmt = IMG_FMT_GREY8;
261                 break;
262
263         case IMG_FMT_RGBF:
264                 targ_fmt = IMG_FMT_RGB24;
265                 break;
266
267         case IMG_FMT_RGBAF:
268                 targ_fmt = IMG_FMT_RGBA32;
269                 break;
270
271         default:
272                 return 0;       /* already integer */
273         }
274
275         return img_convert(img, targ_fmt);
276 }
277
278 int img_is_float(struct img_pixmap *img)
279 {
280         return img->fmt >= IMG_FMT_GREYF && img->fmt <= IMG_FMT_RGBAF;
281 }
282
283 int img_has_alpha(struct img_pixmap *img)
284 {
285         if(img->fmt == IMG_FMT_RGBA32 || img->fmt == IMG_FMT_RGBAF) {
286                 return 1;
287         }
288         return 0;
289 }
290
291 int img_is_greyscale(struct img_pixmap *img)
292 {
293         return img->fmt == IMG_FMT_GREY8 || img->fmt == IMG_FMT_GREYF;
294 }
295
296
297 void img_setpixel(struct img_pixmap *img, int x, int y, void *pixel)
298 {
299         char *dest = (char*)img->pixels + (y * img->width + x) * img->pixelsz;
300         memcpy(dest, pixel, img->pixelsz);
301 }
302
303 void img_getpixel(struct img_pixmap *img, int x, int y, void *pixel)
304 {
305         char *dest = (char*)img->pixels + (y * img->width + x) * img->pixelsz;
306         memcpy(pixel, dest, img->pixelsz);
307 }
308
309 void img_setpixel1i(struct img_pixmap *img, int x, int y, int pix)
310 {
311         img_setpixel4i(img, x, y, pix, pix, pix, pix);
312 }
313
314 void img_setpixel1f(struct img_pixmap *img, int x, int y, float pix)
315 {
316         img_setpixel4f(img, x, y, pix, pix, pix, pix);
317 }
318
319 void img_setpixel4i(struct img_pixmap *img, int x, int y, int r, int g, int b, int a)
320 {
321         if(img_is_float(img)) {
322                 img_setpixel4f(img, x, y, r / 255.0, g / 255.0, b / 255.0, a / 255.0);
323         } else {
324                 unsigned char pixel[4];
325                 pixel[0] = r;
326                 pixel[1] = g;
327                 pixel[2] = b;
328                 pixel[3] = a;
329
330                 img_setpixel(img, x, y, pixel);
331         }
332 }
333
334 void img_setpixel4f(struct img_pixmap *img, int x, int y, float r, float g, float b, float a)
335 {
336         if(img_is_float(img)) {
337                 float pixel[4];
338                 pixel[0] = r;
339                 pixel[1] = g;
340                 pixel[2] = b;
341                 pixel[3] = a;
342
343                 img_setpixel(img, x, y, pixel);
344         } else {
345                 img_setpixel4i(img, x, y, (int)(r * 255.0), (int)(g * 255.0), (int)(b * 255.0), (int)(a * 255.0));
346         }
347 }
348
349 void img_getpixel1i(struct img_pixmap *img, int x, int y, int *pix)
350 {
351         int junk[3];
352         img_getpixel4i(img, x, y, pix, junk, junk + 1, junk + 2);
353 }
354
355 void img_getpixel1f(struct img_pixmap *img, int x, int y, float *pix)
356 {
357         float junk[3];
358         img_getpixel4f(img, x, y, pix, junk, junk + 1, junk + 2);
359 }
360
361 void img_getpixel4i(struct img_pixmap *img, int x, int y, int *r, int *g, int *b, int *a)
362 {
363         if(img_is_float(img)) {
364                 float pixel[4] = {0, 0, 0, 0};
365                 img_getpixel(img, x, y, pixel);
366                 *r = pixel[0] * 255.0;
367                 *g = pixel[1] * 255.0;
368                 *b = pixel[2] * 255.0;
369                 *a = pixel[3] * 255.0;
370         } else {
371                 unsigned char pixel[4];
372                 img_getpixel(img, x, y, pixel);
373                 *r = pixel[0];
374                 *g = pixel[1];
375                 *b = pixel[2];
376                 *a = pixel[3];
377         }
378 }
379
380 void img_getpixel4f(struct img_pixmap *img, int x, int y, float *r, float *g, float *b, float *a)
381 {
382         if(img_is_float(img)) {
383                 float pixel[4] = {0, 0, 0, 0};
384                 img_getpixel(img, x, y, pixel);
385                 *r = pixel[0];
386                 *g = pixel[1];
387                 *b = pixel[2];
388                 *a = pixel[3];
389         } else {
390                 unsigned char pixel[4];
391                 img_getpixel(img, x, y, pixel);
392                 *r = pixel[0] / 255.0;
393                 *g = pixel[1] / 255.0;
394                 *b = pixel[2] / 255.0;
395                 *a = pixel[3] / 255.0;
396         }
397 }
398
399 void img_io_set_user_data(struct img_io *io, void *uptr)
400 {
401         io->uptr = uptr;
402 }
403
404 void img_io_set_read_func(struct img_io *io, size_t (*read)(void*, size_t, void*))
405 {
406         io->read = read;
407 }
408
409 void img_io_set_write_func(struct img_io *io, size_t (*write)(void*, size_t, void*))
410 {
411         io->write = write;
412 }
413
414 void img_io_set_seek_func(struct img_io *io, long (*seek)(long, int, void*))
415 {
416         io->seek = seek;
417 }
418
419
420 static int pixel_size(enum img_fmt fmt)
421 {
422         switch(fmt) {
423         case IMG_FMT_GREY8:
424                 return 1;
425         case IMG_FMT_RGB24:
426                 return 3;
427         case IMG_FMT_RGBA32:
428         case IMG_FMT_BGRA32:
429                 return 4;
430         case IMG_FMT_GREYF:
431                 return sizeof(float);
432         case IMG_FMT_RGBF:
433                 return 3 * sizeof(float);
434         case IMG_FMT_RGBAF:
435                 return 4 * sizeof(float);
436         case IMG_FMT_RGB565:
437                 return 2;
438         default:
439                 break;
440         }
441         return 0;
442 }
443
444 static size_t def_read(void *buf, size_t bytes, void *uptr)
445 {
446         return uptr ? fread(buf, 1, bytes, uptr) : 0;
447 }
448
449 static size_t def_write(void *buf, size_t bytes, void *uptr)
450 {
451         return uptr ? fwrite(buf, 1, bytes, uptr) : 0;
452 }
453
454 static long def_seek(long offset, int whence, void *uptr)
455 {
456         if(!uptr || fseek(uptr, offset, whence) == -1) {
457                 return -1;
458         }
459         return ftell(uptr);
460 }
461