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