--- /dev/null
+#include <string.h>
+#include "assman.h"
+#include "imago2.h"
+#include "image.h"
+
+
+static int pixel_elements(Image::Format fmt);
+static int elem_size(Image::Format fmt);
+static int pixel_size(Image::Format fmt);
+
+Image::Image()
+{
+ fmt = FMT_RGBA;
+ width = height = 0;
+ pixels = 0;
+}
+
+Image::~Image()
+{
+ delete [] (char*)pixels;
+}
+
+Image::Image(const Image &img)
+{
+ pixels = 0;
+ set_pixels(img.width, img.height, img.pixels, img.fmt);
+}
+
+Image &Image::operator =(const Image &img)
+{
+ if(&img != this) {
+ delete [] (char*)pixels;
+ pixels = 0;
+ set_pixels(img.width, img.height, img.pixels, img.fmt);
+ }
+ return *this;
+}
+
+Image::Image(Image &&img)
+{
+ width = img.width;
+ height = img.height;
+ pixels = img.pixels;
+ fmt = img.fmt;
+
+ img.pixels = 0;
+}
+
+Image &Image::operator =(Image &&img)
+{
+ if(&img != this) {
+ width = img.width;
+ height = img.height;
+ pixels = img.pixels;
+ fmt = img.fmt;
+
+ img.pixels = 0;
+ }
+ return *this;
+}
+
+int Image::get_width() const
+{
+ return width;
+}
+
+int Image::get_height() const
+{
+ return height;
+}
+
+Image::Format Image::get_format() const
+{
+ return fmt;
+}
+
+bool Image::create(int x, int y, Format fmt)
+{
+ width = x;
+ height = y;
+ this->fmt = fmt;
+
+ try {
+ pixels = new char[x * y * pixel_size(fmt)];
+ }
+ catch(...) {
+ return false;
+ }
+ return true;
+}
+
+bool Image::set_pixels(int x, int y, void *pixels, Format fmt)
+{
+ if(!create(x, y, fmt)) {
+ return false;
+ }
+ memcpy(this->pixels, pixels, x * y * pixel_size(fmt));
+ return true;
+}
+
+void *Image::get_pixels() const
+{
+ return pixels;
+}
+
+static size_t io_read(void *buf, size_t bytes, void *uptr)
+{
+ return ass_fread(buf, 1, bytes, uptr);
+}
+
+static long io_seek(long offs, int whence, void *uptr)
+{
+ return ass_fseek(uptr, offs, whence);
+}
+
+bool Image::load(const char *fname)
+{
+ struct img_pixmap pixmap;
+ struct img_io io;
+
+ if(!(io.uptr = ass_fopen(fname, "rb"))) {
+ fprintf(stderr, "failed to open image: %s\n", fname);
+ return false;
+ }
+ io.read = io_read;
+ io.write = 0;
+ io.seek = io_seek;
+
+ img_init(&pixmap);
+ if(img_read(&pixmap, &io) == -1) {
+ return false;
+ }
+ ass_fclose(io.uptr);
+
+ Format fmt;
+ switch(pixmap.fmt) {
+ case IMG_FMT_GREY8:
+ fmt = FMT_GREY;
+ break;
+ case IMG_FMT_RGB24:
+ fmt = FMT_RGB;
+ break;
+ case IMG_FMT_RGBA32:
+ fmt = FMT_RGBA;
+ break;
+ case IMG_FMT_GREYF:
+ fmt = FMT_GREY_FLOAT;
+ break;
+ case IMG_FMT_RGBF:
+ fmt = FMT_RGB_FLOAT;
+ break;
+ case IMG_FMT_RGBAF:
+ fmt = FMT_RGBA_FLOAT;
+ break;
+ default:
+ img_destroy(&pixmap);
+ return false;
+ }
+
+ if(!set_pixels(pixmap.width, pixmap.height, pixmap.pixels, fmt)) {
+ img_destroy(&pixmap);
+ return false;
+ }
+ img_destroy(&pixmap);
+ return true;
+}
+
+bool Image::save(const char *fname) const
+{
+ struct img_pixmap pixmap;
+
+ img_init(&pixmap);
+
+ switch(fmt) {
+ case FMT_GREY:
+ pixmap.fmt = IMG_FMT_GREY8;
+ break;
+ case FMT_GREY_FLOAT:
+ pixmap.fmt = IMG_FMT_GREYF;
+ break;
+ case FMT_RGB:
+ pixmap.fmt = IMG_FMT_RGB24;
+ break;
+ case FMT_RGB_FLOAT:
+ pixmap.fmt = IMG_FMT_RGBF;
+ break;
+ case FMT_RGBA:
+ pixmap.fmt = IMG_FMT_RGBA32;
+ break;
+ case FMT_RGBA_FLOAT:
+ pixmap.fmt = IMG_FMT_RGBAF;
+ break;
+ default:
+ return false;
+ }
+
+ pixmap.width = width;
+ pixmap.height = height;
+ pixmap.pixels = pixels;
+ pixmap.pixelsz = pixel_size(fmt);
+
+ if(img_save(&pixmap, fname) == -1) {
+ return false;
+ }
+ return true;
+}
+
+static int pixel_elements(Image::Format fmt)
+{
+ switch(fmt) {
+ case Image::FMT_GREY:
+ case Image::FMT_GREY_FLOAT:
+ return 1;
+
+ case Image::FMT_RGB:
+ case Image::FMT_RGB_FLOAT:
+ return 3;
+
+ case Image::FMT_RGBA:
+ case Image::FMT_RGBA_FLOAT:
+ return 4;
+
+ default:
+ break;
+ }
+ return 0;
+}
+
+static int elem_size(Image::Format fmt)
+{
+ switch(fmt) {
+ case Image::FMT_GREY:
+ case Image::FMT_RGB:
+ case Image::FMT_RGBA:
+ return 1;
+
+ case Image::FMT_GREY_FLOAT:
+ case Image::FMT_RGB_FLOAT:
+ case Image::FMT_RGBA_FLOAT:
+ return sizeof(float);
+
+ default:
+ break;
+ }
+ return 0;
+}
+
+static int pixel_size(Image::Format fmt)
+{
+ return elem_size(fmt) * pixel_elements(fmt);
+}