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