2 libimago - a multi-format image file input/output library.
3 Copyright (C) 2010-2021 John Tsiombikas <nuclear@member.fsf.org>
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.
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.
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/>.
26 /* calculate int-aligned offset to colormap, right after the end of the pixel data */
27 #define CMAPPTR(fb, fbsz) \
28 (struct img_colormap*)((((uintptr_t)fb) + (fbsz) + sizeof(int) - 1) & ~(sizeof(int) - 1))
30 static int pixel_size(enum img_fmt fmt);
31 static size_t def_read(void *buf, size_t bytes, void *uptr);
32 static size_t def_write(void *buf, size_t bytes, void *uptr);
33 static long def_seek(long offset, int whence, void *uptr);
36 void img_init(struct img_pixmap *img)
39 img->width = img->height = 0;
40 img->fmt = IMG_FMT_RGBA32;
41 img->pixelsz = pixel_size(img->fmt);
46 void img_destroy(struct img_pixmap *img)
49 img->pixels = 0; /* just in case... */
50 img->width = img->height = 0xbadbeef;
54 struct img_pixmap *img_create(void)
58 if(!(p = malloc(sizeof *p))) {
65 void img_free(struct img_pixmap *img)
71 int img_set_name(struct img_pixmap *img, const char *name)
75 if(!(tmp = malloc(strlen(name) + 1))) {
83 int img_set_format(struct img_pixmap *img, enum img_fmt fmt)
86 return img_convert(img, fmt);
92 int img_copy(struct img_pixmap *dest, struct img_pixmap *src)
94 if(img_set_pixels(dest, src->width, src->height, src->fmt, src->pixels) == -1) {
98 if(src->fmt == IMG_FMT_IDX8) {
99 *img_colormap(dest) = *img_colormap(src);
104 int img_set_pixels(struct img_pixmap *img, int w, int h, enum img_fmt fmt, void *pix)
107 int pixsz = pixel_size(fmt);
108 int bsz = w * h * pixsz;
110 if(fmt == IMG_FMT_IDX8) {
111 /* add space for the colormap, and space to align it to sizeof(int) */
112 bsz += sizeof(struct img_colormap) + sizeof(int) - 1;
115 if(!(newpix = malloc(bsz))) {
120 memcpy(newpix, pix, w * h * pixsz);
122 memset(newpix, 0, bsz);
126 img->pixels = newpix;
129 img->pixelsz = pixsz;
134 void *img_load_pixels(const char *fname, int *xsz, int *ysz, enum img_fmt fmt)
136 struct img_pixmap img;
140 if(img_load(&img, fname) == -1) {
144 if(img_convert(&img, fmt) == -1) {
155 int img_save_pixels(const char *fname, void *pix, int xsz, int ysz, enum img_fmt fmt)
158 struct img_pixmap img;
162 img.pixelsz = pixel_size(fmt);
167 res = img_save(&img, fname);
173 void img_free_pixels(void *pix)
178 int img_load(struct img_pixmap *img, const char *fname)
183 if(!(fp = fopen(fname, "rb"))) {
186 img_set_name(img, fname);
187 res = img_read_file(img, fp);
192 /* TODO implement filetype selection */
193 int img_save(struct img_pixmap *img, const char *fname)
198 img_set_name(img, fname);
200 if(!(fp = fopen(fname, "wb"))) {
203 res = img_write_file(img, fp);
208 int img_read_file(struct img_pixmap *img, FILE *fp)
210 struct img_io io = {0, def_read, def_write, def_seek};
213 return img_read(img, &io);
216 int img_write_file(struct img_pixmap *img, FILE *fp)
218 struct img_io io = {0, def_read, def_write, def_seek};
221 return img_write(img, &io);
224 int img_read(struct img_pixmap *img, struct img_io *io)
226 struct ftype_module *mod;
228 if((mod = img_find_format_module(io, img->name))) {
229 return mod->read(img, io);
234 int img_write(struct img_pixmap *img, struct img_io *io)
236 struct ftype_module *mod;
238 if(!img->name || !(mod = img_guess_format(img->name))) {
239 /* TODO throw some sort of warning? */
240 /* TODO implement some sort of module priority or let the user specify? */
241 if(!(mod = img_get_module(0))) {
246 return mod->write(img, io);
249 int img_to_float(struct img_pixmap *img)
251 enum img_fmt targ_fmt;
255 targ_fmt = IMG_FMT_GREYF;
259 targ_fmt = IMG_FMT_RGBF;
263 targ_fmt = IMG_FMT_RGBAF;
267 return 0; /* already float */
270 return img_convert(img, targ_fmt);
273 int img_to_integer(struct img_pixmap *img)
275 enum img_fmt targ_fmt;
279 targ_fmt = IMG_FMT_GREY8;
283 targ_fmt = IMG_FMT_RGB24;
287 targ_fmt = IMG_FMT_RGBA32;
291 return 0; /* already integer */
294 return img_convert(img, targ_fmt);
297 int img_is_float(struct img_pixmap *img)
299 return img->fmt >= IMG_FMT_GREYF && img->fmt <= IMG_FMT_RGBAF;
302 int img_has_alpha(struct img_pixmap *img)
304 if(img->fmt == IMG_FMT_RGBA32 || img->fmt == IMG_FMT_RGBAF) {
310 int img_is_greyscale(struct img_pixmap *img)
312 return img->fmt == IMG_FMT_GREY8 || img->fmt == IMG_FMT_GREYF;
316 void img_setpixel(struct img_pixmap *img, int x, int y, void *pixel)
318 char *dest = (char*)img->pixels + (y * img->width + x) * img->pixelsz;
319 memcpy(dest, pixel, img->pixelsz);
322 void img_getpixel(struct img_pixmap *img, int x, int y, void *pixel)
324 char *dest = (char*)img->pixels + (y * img->width + x) * img->pixelsz;
325 memcpy(pixel, dest, img->pixelsz);
328 void img_setpixel1i(struct img_pixmap *img, int x, int y, int pix)
330 img_setpixel4i(img, x, y, pix, pix, pix, pix);
333 void img_setpixel1f(struct img_pixmap *img, int x, int y, float pix)
335 img_setpixel4f(img, x, y, pix, pix, pix, pix);
338 void img_setpixel4i(struct img_pixmap *img, int x, int y, int r, int g, int b, int a)
340 if(img_is_float(img)) {
341 img_setpixel4f(img, x, y, r / 255.0, g / 255.0, b / 255.0, a / 255.0);
343 unsigned char pixel[4];
349 img_setpixel(img, x, y, pixel);
353 void img_setpixel4f(struct img_pixmap *img, int x, int y, float r, float g, float b, float a)
355 if(img_is_float(img)) {
362 img_setpixel(img, x, y, pixel);
364 img_setpixel4i(img, x, y, (int)(r * 255.0), (int)(g * 255.0), (int)(b * 255.0), (int)(a * 255.0));
368 void img_getpixel1i(struct img_pixmap *img, int x, int y, int *pix)
371 img_getpixel4i(img, x, y, pix, junk, junk + 1, junk + 2);
374 void img_getpixel1f(struct img_pixmap *img, int x, int y, float *pix)
377 img_getpixel4f(img, x, y, pix, junk, junk + 1, junk + 2);
380 void img_getpixel4i(struct img_pixmap *img, int x, int y, int *r, int *g, int *b, int *a)
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] * 255.0;
386 *g = pixel[1] * 255.0;
387 *b = pixel[2] * 255.0;
388 *a = pixel[3] * 255.0;
390 unsigned char pixel[4];
391 img_getpixel(img, x, y, pixel);
399 void img_getpixel4f(struct img_pixmap *img, int x, int y, float *r, float *g, float *b, float *a)
401 if(img_is_float(img)) {
402 float pixel[4] = {0, 0, 0, 0};
403 img_getpixel(img, x, y, pixel);
409 unsigned char pixel[4];
410 img_getpixel(img, x, y, pixel);
411 *r = pixel[0] / 255.0;
412 *g = pixel[1] / 255.0;
413 *b = pixel[2] / 255.0;
414 *a = pixel[3] / 255.0;
418 struct img_colormap *img_colormap(struct img_pixmap *img)
420 if(img->fmt != IMG_FMT_IDX8 || !img->pixels) {
424 return CMAPPTR(img->pixels, img->width * img->height * img->pixelsz);
427 void img_io_set_user_data(struct img_io *io, void *uptr)
432 void img_io_set_read_func(struct img_io *io, size_t (*read)(void*, size_t, void*))
437 void img_io_set_write_func(struct img_io *io, size_t (*write)(void*, size_t, void*))
442 void img_io_set_seek_func(struct img_io *io, long (*seek)(long, int, void*))
448 static int pixel_size(enum img_fmt fmt)
460 return sizeof(float);
462 return 3 * sizeof(float);
464 return 4 * sizeof(float);
473 static size_t def_read(void *buf, size_t bytes, void *uptr)
475 return uptr ? fread(buf, 1, bytes, uptr) : 0;
478 static size_t def_write(void *buf, size_t bytes, void *uptr)
480 return uptr ? fwrite(buf, 1, bytes, uptr) : 0;
483 static long def_seek(long offset, int whence, void *uptr)
485 if(!uptr || fseek(uptr, offset, whence) == -1) {