nuclear@1: /* nuclear@1: libimago - a multi-format image file input/output library. nuclear@1: Copyright (C) 2010 John Tsiombikas nuclear@1: nuclear@1: This program is free software: you can redistribute it and/or modify nuclear@1: it under the terms of the GNU Lesser General Public License as published nuclear@1: by the Free Software Foundation, either version 3 of the License, or nuclear@1: (at your option) any later version. nuclear@1: nuclear@1: This program is distributed in the hope that it will be useful, nuclear@1: but WITHOUT ANY WARRANTY; without even the implied warranty of nuclear@1: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the nuclear@1: GNU Lesser General Public License for more details. nuclear@1: nuclear@1: You should have received a copy of the GNU Lesser General Public License nuclear@1: along with this program. If not, see . nuclear@1: */ nuclear@1: nuclear@1: #include nuclear@1: #include nuclear@1: #include nuclear@1: #include "imago2.h" nuclear@1: #include "ftype_module.h" nuclear@1: nuclear@1: static int pixel_size(enum img_fmt fmt); nuclear@1: static size_t def_read(void *buf, size_t bytes, void *uptr); nuclear@1: static size_t def_write(void *buf, size_t bytes, void *uptr); nuclear@1: static long def_seek(long offset, int whence, void *uptr); nuclear@1: nuclear@1: nuclear@1: void img_init(struct img_pixmap *img) nuclear@1: { nuclear@1: img->pixels = 0; nuclear@1: img->width = img->height = 0; nuclear@1: img->fmt = IMG_FMT_RGBA32; nuclear@1: img->pixelsz = pixel_size(img->fmt); nuclear@1: img->name = 0; nuclear@1: } nuclear@1: nuclear@1: nuclear@1: void img_destroy(struct img_pixmap *img) nuclear@1: { nuclear@1: free(img->pixels); nuclear@1: img->pixels = 0; /* just in case... */ nuclear@1: img->width = img->height = 0xbadbeef; nuclear@1: free(img->name); nuclear@1: } nuclear@1: nuclear@1: struct img_pixmap *img_create(void) nuclear@1: { nuclear@1: struct img_pixmap *p; nuclear@1: nuclear@1: if(!(p = malloc(sizeof *p))) { nuclear@1: return 0; nuclear@1: } nuclear@1: img_init(p); nuclear@1: return p; nuclear@1: } nuclear@1: nuclear@1: void img_free(struct img_pixmap *img) nuclear@1: { nuclear@1: img_destroy(img); nuclear@1: free(img); nuclear@1: } nuclear@1: nuclear@1: int img_set_name(struct img_pixmap *img, const char *name) nuclear@1: { nuclear@1: char *tmp; nuclear@1: nuclear@1: if(!(tmp = malloc(strlen(name) + 1))) { nuclear@1: return -1; nuclear@1: } nuclear@1: strcpy(tmp, name); nuclear@1: img->name = tmp; nuclear@1: return 0; nuclear@1: } nuclear@1: nuclear@1: int img_set_format(struct img_pixmap *img, enum img_fmt fmt) nuclear@1: { nuclear@1: if(img->pixels) { nuclear@1: return img_convert(img, fmt); nuclear@1: } nuclear@1: img->fmt = fmt; nuclear@1: return 0; nuclear@1: } nuclear@1: nuclear@1: int img_copy(struct img_pixmap *dest, struct img_pixmap *src) nuclear@1: { nuclear@1: return img_set_pixels(dest, src->width, src->height, src->fmt, src->pixels); nuclear@1: } nuclear@1: nuclear@1: int img_set_pixels(struct img_pixmap *img, int w, int h, enum img_fmt fmt, void *pix) nuclear@1: { nuclear@1: void *newpix; nuclear@1: int pixsz = pixel_size(fmt); nuclear@1: nuclear@1: if(!(newpix = malloc(w * h * pixsz))) { nuclear@1: return -1; nuclear@1: } nuclear@1: nuclear@1: if(pix) { nuclear@1: memcpy(newpix, pix, w * h * pixsz); nuclear@1: } else { nuclear@1: memset(newpix, 0, w * h * pixsz); nuclear@1: } nuclear@1: nuclear@1: free(img->pixels); nuclear@1: img->pixels = newpix; nuclear@1: img->width = w; nuclear@1: img->height = h; nuclear@1: img->pixelsz = pixsz; nuclear@1: img->fmt = fmt; nuclear@1: return 0; nuclear@1: } nuclear@1: nuclear@1: void *img_load_pixels(const char *fname, int *xsz, int *ysz, enum img_fmt fmt) nuclear@1: { nuclear@1: struct img_pixmap img; nuclear@1: nuclear@1: img_init(&img); nuclear@1: nuclear@1: if(img_load(&img, fname) == -1) { nuclear@1: return 0; nuclear@1: } nuclear@1: if(img.fmt != fmt) { nuclear@1: if(img_convert(&img, fmt) == -1) { nuclear@1: img_destroy(&img); nuclear@1: return 0; nuclear@1: } nuclear@1: } nuclear@1: nuclear@1: *xsz = img.width; nuclear@1: *ysz = img.height; nuclear@1: return img.pixels; nuclear@1: } nuclear@1: nuclear@1: int img_save_pixels(const char *fname, void *pix, int xsz, int ysz, enum img_fmt fmt) nuclear@1: { nuclear@1: struct img_pixmap img; nuclear@1: nuclear@1: img_init(&img); nuclear@1: img.fmt = fmt; nuclear@1: img.name = (char*)fname; nuclear@1: img.width = xsz; nuclear@1: img.height = ysz; nuclear@1: img.pixels = pix; nuclear@1: nuclear@1: return img_save(&img, fname); nuclear@1: } nuclear@1: nuclear@1: void img_free_pixels(void *pix) nuclear@1: { nuclear@1: free(pix); nuclear@1: } nuclear@1: nuclear@1: int img_load(struct img_pixmap *img, const char *fname) nuclear@1: { nuclear@1: int res; nuclear@1: FILE *fp; nuclear@1: nuclear@1: if(!(fp = fopen(fname, "rb"))) { nuclear@1: return -1; nuclear@1: } nuclear@1: res = img_read_file(img, fp); nuclear@1: fclose(fp); nuclear@1: return res; nuclear@1: } nuclear@1: nuclear@1: /* TODO implement filetype selection */ nuclear@1: int img_save(struct img_pixmap *img, const char *fname) nuclear@1: { nuclear@1: int res; nuclear@1: FILE *fp; nuclear@1: nuclear@1: img_set_name(img, fname); nuclear@1: nuclear@1: if(!(fp = fopen(fname, "wb"))) { nuclear@1: return -1; nuclear@1: } nuclear@1: res = img_write_file(img, fp); nuclear@1: fclose(fp); nuclear@1: return res; nuclear@1: } nuclear@1: nuclear@1: int img_read_file(struct img_pixmap *img, FILE *fp) nuclear@1: { nuclear@1: struct img_io io = {0, def_read, def_write, def_seek}; nuclear@1: nuclear@1: io.uptr = fp; nuclear@1: return img_read(img, &io); nuclear@1: } nuclear@1: nuclear@1: int img_write_file(struct img_pixmap *img, FILE *fp) nuclear@1: { nuclear@1: struct img_io io = {0, def_read, def_write, def_seek}; nuclear@1: nuclear@1: io.uptr = fp; nuclear@1: return img_write(img, &io); nuclear@1: } nuclear@1: nuclear@1: int img_read(struct img_pixmap *img, struct img_io *io) nuclear@1: { nuclear@1: struct ftype_module *mod; nuclear@1: nuclear@1: if((mod = img_find_format_module(io))) { nuclear@1: return mod->read(img, io); nuclear@1: } nuclear@1: return -1; nuclear@1: } nuclear@1: nuclear@1: int img_write(struct img_pixmap *img, struct img_io *io) nuclear@1: { nuclear@1: struct ftype_module *mod; nuclear@1: nuclear@1: if(!img->name || !(mod = img_guess_format(img->name))) { nuclear@1: /* TODO throw some sort of warning? */ nuclear@1: /* TODO implement some sort of module priority or let the user specify? */ nuclear@1: if(!(mod = img_get_module(0))) { nuclear@1: return -1; nuclear@1: } nuclear@1: } nuclear@1: nuclear@1: return mod->write(img, io); nuclear@1: } nuclear@1: nuclear@1: int img_to_float(struct img_pixmap *img) nuclear@1: { nuclear@1: enum img_fmt targ_fmt; nuclear@1: nuclear@1: switch(img->fmt) { nuclear@1: case IMG_FMT_GREY8: nuclear@1: targ_fmt = IMG_FMT_GREYF; nuclear@1: break; nuclear@1: nuclear@1: case IMG_FMT_RGB24: nuclear@1: targ_fmt = IMG_FMT_RGBF; nuclear@1: break; nuclear@1: nuclear@1: case IMG_FMT_RGBA32: nuclear@1: targ_fmt = IMG_FMT_RGBAF; nuclear@1: break; nuclear@1: nuclear@1: default: nuclear@1: return 0; /* already float */ nuclear@1: } nuclear@1: nuclear@1: return img_convert(img, targ_fmt); nuclear@1: } nuclear@1: nuclear@1: int img_to_integer(struct img_pixmap *img) nuclear@1: { nuclear@1: enum img_fmt targ_fmt; nuclear@1: nuclear@1: switch(img->fmt) { nuclear@1: case IMG_FMT_GREYF: nuclear@1: targ_fmt = IMG_FMT_GREY8; nuclear@1: break; nuclear@1: nuclear@1: case IMG_FMT_RGBF: nuclear@1: targ_fmt = IMG_FMT_RGB24; nuclear@1: break; nuclear@1: nuclear@1: case IMG_FMT_RGBAF: nuclear@1: targ_fmt = IMG_FMT_RGBA32; nuclear@1: break; nuclear@1: nuclear@1: default: nuclear@1: return 0; /* already integer */ nuclear@1: } nuclear@1: nuclear@1: return img_convert(img, targ_fmt); nuclear@1: } nuclear@1: nuclear@1: int img_is_float(struct img_pixmap *img) nuclear@1: { nuclear@1: return img->fmt >= IMG_FMT_GREYF && img->fmt <= IMG_FMT_RGBAF; nuclear@1: } nuclear@1: nuclear@1: int img_has_alpha(struct img_pixmap *img) nuclear@1: { nuclear@1: if(img->fmt == IMG_FMT_RGBA32 || img->fmt == IMG_FMT_RGBAF) { nuclear@1: return 1; nuclear@1: } nuclear@1: return 0; nuclear@1: } nuclear@1: nuclear@1: nuclear@1: void img_setpixel(struct img_pixmap *img, int x, int y, void *pixel) nuclear@1: { nuclear@1: char *dest = (char*)img->pixels + (y * img->width + x) * img->pixelsz; nuclear@1: memcpy(dest, pixel, img->pixelsz); nuclear@1: } nuclear@1: nuclear@1: void img_getpixel(struct img_pixmap *img, int x, int y, void *pixel) nuclear@1: { nuclear@1: char *dest = (char*)img->pixels + (y * img->width + x) * img->pixelsz; nuclear@1: memcpy(pixel, dest, img->pixelsz); nuclear@1: } nuclear@1: nuclear@1: void img_setpixel1i(struct img_pixmap *img, int x, int y, int pix) nuclear@1: { nuclear@1: img_setpixel4i(img, x, y, pix, pix, pix, pix); nuclear@1: } nuclear@1: nuclear@1: void img_setpixel1f(struct img_pixmap *img, int x, int y, float pix) nuclear@1: { nuclear@1: img_setpixel4f(img, x, y, pix, pix, pix, pix); nuclear@1: } nuclear@1: nuclear@1: void img_setpixel4i(struct img_pixmap *img, int x, int y, int r, int g, int b, int a) nuclear@1: { nuclear@1: if(img_is_float(img)) { nuclear@1: img_setpixel4f(img, x, y, r / 255.0, g / 255.0, b / 255.0, a / 255.0); nuclear@1: } else { nuclear@1: unsigned char pixel[4]; nuclear@1: pixel[0] = r; nuclear@1: pixel[1] = g; nuclear@1: pixel[2] = b; nuclear@1: pixel[3] = a; nuclear@1: nuclear@1: img_setpixel(img, x, y, pixel); nuclear@1: } nuclear@1: } nuclear@1: nuclear@1: void img_setpixel4f(struct img_pixmap *img, int x, int y, float r, float g, float b, float a) nuclear@1: { nuclear@1: if(img_is_float(img)) { nuclear@1: float pixel[4]; nuclear@1: pixel[0] = r; nuclear@1: pixel[1] = g; nuclear@1: pixel[2] = b; nuclear@1: pixel[3] = a; nuclear@1: nuclear@1: img_setpixel(img, x, y, pixel); nuclear@1: } else { nuclear@1: img_setpixel4i(img, x, y, (int)(r * 255.0), (int)(g * 255.0), (int)(b * 255.0), (int)(a * 255.0)); nuclear@1: } nuclear@1: } nuclear@1: nuclear@1: void img_getpixel1i(struct img_pixmap *img, int x, int y, int *pix) nuclear@1: { nuclear@1: int junk[3]; nuclear@1: img_getpixel4i(img, x, y, pix, junk, junk + 1, junk + 2); nuclear@1: } nuclear@1: nuclear@1: void img_getpixel1f(struct img_pixmap *img, int x, int y, float *pix) nuclear@1: { nuclear@1: float junk[3]; nuclear@1: img_getpixel4f(img, x, y, pix, junk, junk + 1, junk + 2); nuclear@1: } nuclear@1: nuclear@1: void img_getpixel4i(struct img_pixmap *img, int x, int y, int *r, int *g, int *b, int *a) nuclear@1: { nuclear@1: if(img_is_float(img)) { nuclear@1: float pixel[4] = {0, 0, 0, 0}; nuclear@1: img_getpixel(img, x, y, pixel); nuclear@1: *r = pixel[0] * 255.0; nuclear@1: *g = pixel[1] * 255.0; nuclear@1: *b = pixel[2] * 255.0; nuclear@1: *a = pixel[3] * 255.0; nuclear@1: } else { nuclear@1: unsigned char pixel[4]; nuclear@1: img_getpixel(img, x, y, pixel); nuclear@1: *r = pixel[0]; nuclear@1: *g = pixel[1]; nuclear@1: *b = pixel[2]; nuclear@1: *a = pixel[3]; nuclear@1: } nuclear@1: } nuclear@1: nuclear@1: void img_getpixel4f(struct img_pixmap *img, int x, int y, float *r, float *g, float *b, float *a) nuclear@1: { nuclear@1: if(img_is_float(img)) { nuclear@1: float pixel[4] = {0, 0, 0, 0}; nuclear@1: img_getpixel(img, x, y, pixel); nuclear@1: *r = pixel[0]; nuclear@1: *g = pixel[1]; nuclear@1: *b = pixel[2]; nuclear@1: *a = pixel[3]; nuclear@1: } else { nuclear@1: unsigned char pixel[4]; nuclear@1: img_getpixel(img, x, y, pixel); nuclear@1: *r = pixel[0] / 255.0; nuclear@1: *g = pixel[1] / 255.0; nuclear@1: *b = pixel[2] / 255.0; nuclear@1: *a = pixel[3] / 255.0; nuclear@1: } nuclear@1: } nuclear@1: nuclear@1: void img_io_set_user_data(struct img_io *io, void *uptr) nuclear@1: { nuclear@1: io->uptr = uptr; nuclear@1: } nuclear@1: nuclear@1: void img_io_set_read_func(struct img_io *io, size_t (*read)(void*, size_t, void*)) nuclear@1: { nuclear@1: io->read = read; nuclear@1: } nuclear@1: nuclear@1: void img_io_set_write_func(struct img_io *io, size_t (*write)(void*, size_t, void*)) nuclear@1: { nuclear@1: io->write = write; nuclear@1: } nuclear@1: nuclear@1: void img_io_set_seek_func(struct img_io *io, long (*seek)(long, int, void*)) nuclear@1: { nuclear@1: io->seek = seek; nuclear@1: } nuclear@1: nuclear@1: nuclear@1: static int pixel_size(enum img_fmt fmt) nuclear@1: { nuclear@1: switch(fmt) { nuclear@1: case IMG_FMT_GREY8: nuclear@1: return 1; nuclear@1: case IMG_FMT_RGB24: nuclear@1: return 3; nuclear@1: case IMG_FMT_RGBA32: nuclear@1: return 4; nuclear@1: case IMG_FMT_GREYF: nuclear@1: return sizeof(float); nuclear@1: case IMG_FMT_RGBF: nuclear@1: return 3 * sizeof(float); nuclear@1: case IMG_FMT_RGBAF: nuclear@1: return 4 * sizeof(float); nuclear@1: default: nuclear@1: break; nuclear@1: } nuclear@1: return 0; nuclear@1: } nuclear@1: nuclear@1: static size_t def_read(void *buf, size_t bytes, void *uptr) nuclear@1: { nuclear@1: return uptr ? fread(buf, 1, bytes, uptr) : 0; nuclear@1: } nuclear@1: nuclear@1: static size_t def_write(void *buf, size_t bytes, void *uptr) nuclear@1: { nuclear@1: return uptr ? fwrite(buf, 1, bytes, uptr) : 0; nuclear@1: } nuclear@1: nuclear@1: static long def_seek(long offset, int whence, void *uptr) nuclear@1: { nuclear@1: if(!uptr || fseek(uptr, offset, whence) == -1) { nuclear@1: return -1; nuclear@1: } nuclear@1: return ftell(uptr); nuclear@1: } nuclear@1: