diff --git a/pipi/codec.c b/pipi/codec.c
index 2b31d31..c1683d1 100644
--- a/pipi/codec.c
+++ b/pipi/codec.c
@@ -38,32 +38,23 @@ pipi_image_t *pipi_load(const char *name)
 #endif
 }
 
-pipi_image_t *pipi_new(int width, int height)
-{
-#if USE_SDL
-    return pipi_new_sdl(width, height);
-#elif USE_IMLIB2
-    return pipi_new_imlib2(width, height);
-#elif USE_OPENCV
-    return pipi_new_opencv(width, height);
-#endif
-}
-
 void pipi_free(pipi_image_t *img)
 {
-    unsigned int i;
+    int i;
 
     for(i = 0; i < PIPI_PIXELS_MAX; i++)
         if(i != img->codec_format && img->p[i].pixels)
             free(img->p[i].pixels);
 
 #if USE_SDL
-    return pipi_free_sdl(img);
+    pipi_free_sdl(img);
 #elif USE_IMLIB2
-    return pipi_free_imlib2(img);
+    pipi_free_imlib2(img);
 #elif USE_OPENCV
-    return pipi_free_opencv(img);
+    pipi_free_opencv(img);
 #endif
+
+    free(img);
 }
 
 void pipi_save(pipi_image_t *img, const char *name)
diff --git a/pipi/codec/imlib.c b/pipi/codec/imlib.c
index 49bf476..0288825 100644
--- a/pipi/codec/imlib.c
+++ b/pipi/codec/imlib.c
@@ -36,44 +36,13 @@ pipi_image_t *pipi_load_imlib2(const char *name)
     if(!priv)
         return NULL;
 
-    img = (pipi_image_t *)malloc(sizeof(pipi_image_t));
-    memset(img, 0, sizeof(pipi_image_t));
-
     imlib_context_set_image(priv);
-    img->w = imlib_image_get_width();
-    img->h = imlib_image_get_height();
+    img = pipi_new(imlib_image_get_width(), imlib_image_get_height());
 
     img->p[PIPI_PIXELS_RGBA32].pixels = imlib_image_get_data();
-    img->p[PIPI_PIXELS_RGBA32].w = imlib_image_get_width();
-    img->p[PIPI_PIXELS_RGBA32].h = imlib_image_get_height();
-    img->p[PIPI_PIXELS_RGBA32].pitch = 4 * imlib_image_get_width();
-    img->last_modified = PIPI_PIXELS_RGBA32;
-
-    img->codec_priv = (void *)priv;
-    img->codec_format = PIPI_PIXELS_RGBA32;
-
-    return img;
-}
-
-pipi_image_t *pipi_new_imlib2(int width, int height)
-{
-    pipi_image_t *img;
-    Imlib_Image priv = imlib_create_image(width, height);
-
-    if(!priv)
-        return NULL;
-
-    img = (pipi_image_t *)malloc(sizeof(pipi_image_t));
-    memset(img, 0, sizeof(pipi_image_t));
-
-    imlib_context_set_image(priv);
-    img->w = imlib_image_get_width();
-    img->h = imlib_image_get_height();
-
-    img->p[PIPI_PIXELS_RGBA32].pixels = imlib_image_get_data();
-    img->p[PIPI_PIXELS_RGBA32].w = imlib_image_get_width();
-    img->p[PIPI_PIXELS_RGBA32].h = imlib_image_get_height();
-    img->p[PIPI_PIXELS_RGBA32].pitch = 4 * imlib_image_get_width();
+    img->p[PIPI_PIXELS_RGBA32].w = img->w;
+    img->p[PIPI_PIXELS_RGBA32].h = img->h;
+    img->p[PIPI_PIXELS_RGBA32].pitch = 4 * img->w;
     img->last_modified = PIPI_PIXELS_RGBA32;
 
     img->codec_priv = (void *)priv;
@@ -86,12 +55,35 @@ void pipi_free_imlib2(pipi_image_t *img)
 {
     imlib_context_set_image(img->codec_priv);
     imlib_free_image();
-
-    free(img);
 }
 
 void pipi_save_imlib2(pipi_image_t *img, const char *name)
 {
+    if(!img->codec_priv)
+    {
+        Imlib_Image priv = imlib_create_image(img->w, img->h);
+        void *data;
+
+        imlib_context_set_image(priv);
+        data = imlib_image_get_data();
+
+        /* FIXME: check pitch differences here */
+        if(img->last_modified == PIPI_PIXELS_RGBA32)
+        {
+            memcpy(data, img->p[PIPI_PIXELS_RGBA32].pixels,
+                   4 * img->w * img->h);
+            free(img->p[PIPI_PIXELS_RGBA32].pixels);
+        }
+
+        img->p[PIPI_PIXELS_RGBA32].pixels = data;
+        img->p[PIPI_PIXELS_RGBA32].w = imlib_image_get_width();
+        img->p[PIPI_PIXELS_RGBA32].h = imlib_image_get_height();
+        img->p[PIPI_PIXELS_RGBA32].pitch = 4 * imlib_image_get_width();
+
+        img->codec_priv = (void *)priv;
+        img->codec_format = PIPI_PIXELS_RGBA32;
+    }
+
     pipi_getpixels(img, img->codec_format);
     imlib_context_set_image(img->codec_priv);
     imlib_save_image(name);
diff --git a/pipi/codec/opencv.c b/pipi/codec/opencv.c
index e061dd0..c1a8284 100644
--- a/pipi/codec/opencv.c
+++ b/pipi/codec/opencv.c
@@ -29,6 +29,8 @@
 #include "pipi.h"
 #include "pipi_internals.h"
 
+/* FIXME: this whole file is broken until we support BGR24 images */
+
 pipi_image_t *pipi_load_opencv(const char *name)
 {
     pipi_image_t *img;
@@ -58,7 +60,7 @@ pipi_image_t *pipi_load_opencv(const char *name)
 pipi_image_t *pipi_new_opencv(int width, int height)
 {
     pipi_image_t *img;
-    IplImage *priv = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 3);
+    IplImage *priv = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 4);
 
     if(!priv)
         return NULL;
diff --git a/pipi/codec/sdl.c b/pipi/codec/sdl.c
index 010affe..6cf97c3 100644
--- a/pipi/codec/sdl.c
+++ b/pipi/codec/sdl.c
@@ -28,6 +28,8 @@
 #include "pipi.h"
 #include "pipi_internals.h"
 
+static SDL_Surface *create_32bpp_surface(int w, int h);
+
 pipi_image_t *pipi_load_sdl(const char *name)
 {
     pipi_image_t *img;
@@ -38,17 +40,13 @@ pipi_image_t *pipi_load_sdl(const char *name)
 
     if(priv->format->BytesPerPixel != 4)
     {
-        img = pipi_new(priv->w, priv->h);
-        SDL_BlitSurface(priv, NULL, img->codec_priv, NULL);
+        SDL_Surface *tmp = create_32bpp_surface(priv->w, priv->h);
+        SDL_BlitSurface(priv, NULL, tmp, NULL);
         SDL_FreeSurface(priv);
-        return img;
+        priv = tmp;
     }
 
-    img = (pipi_image_t *)malloc(sizeof(pipi_image_t));
-    memset(img, 0, sizeof(pipi_image_t));
-
-    img->w = priv->w;
-    img->h = priv->h;
+    img = pipi_new(priv->w, priv->h);
 
     img->p[PIPI_PIXELS_RGBA32].pixels = priv->pixels;
     img->p[PIPI_PIXELS_RGBA32].w = priv->w;
@@ -62,10 +60,44 @@ pipi_image_t *pipi_load_sdl(const char *name)
     return img;
 }
 
-pipi_image_t *pipi_new_sdl(int width, int height)
+void pipi_free_sdl(pipi_image_t *img)
+{
+    SDL_FreeSurface(img->codec_priv);
+}
+
+void pipi_save_sdl(pipi_image_t *img, const char *name)
+{
+    if(!img->codec_priv)
+    {
+        SDL_Surface *priv = create_32bpp_surface(img->w, img->h);
+
+        /* FIXME: check pitch differences here */
+        if(img->last_modified == PIPI_PIXELS_RGBA32)
+        {
+            memcpy(priv->pixels, img->p[PIPI_PIXELS_RGBA32].pixels,
+                   priv->pitch * priv->h);
+            free(img->p[PIPI_PIXELS_RGBA32].pixels);
+        }
+
+        img->p[PIPI_PIXELS_RGBA32].pixels = priv->pixels;
+        img->p[PIPI_PIXELS_RGBA32].w = priv->w;
+        img->p[PIPI_PIXELS_RGBA32].h = priv->h;
+        img->p[PIPI_PIXELS_RGBA32].pitch = priv->pitch;
+
+        img->codec_priv = (void *)priv;
+        img->codec_format = PIPI_PIXELS_RGBA32;
+    }
+
+    pipi_getpixels(img, img->codec_format);
+    SDL_SaveBMP(img->codec_priv, name);
+}
+
+/*
+ * The following functions are local.
+ */
+
+static SDL_Surface *create_32bpp_surface(int w, int h)
 {
-    pipi_image_t *img;
-    SDL_Surface *priv;
     Uint32 rmask, gmask, bmask, amask;
 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
     rmask = 0xff000000;
@@ -78,40 +110,8 @@ pipi_image_t *pipi_new_sdl(int width, int height)
     bmask = 0x00ff0000;
     amask = 0x00000000;
 #endif
-    priv = SDL_CreateRGBSurface(SDL_SWSURFACE, width, height, 32,
-                                rmask, gmask, bmask, amask);
-
-    if(!priv)
-        return NULL;
-
-    img = (pipi_image_t *)malloc(sizeof(pipi_image_t));
-    memset(img, 0, sizeof(pipi_image_t));
 
-    img->w = priv->w;
-    img->h = priv->h;
-
-    img->p[PIPI_PIXELS_RGBA32].pixels = priv->pixels;
-    img->p[PIPI_PIXELS_RGBA32].w = priv->w;
-    img->p[PIPI_PIXELS_RGBA32].h = priv->h;
-    img->p[PIPI_PIXELS_RGBA32].pitch = priv->pitch;
-    img->last_modified = PIPI_PIXELS_RGBA32;
-
-    img->codec_priv = (void *)priv;
-    img->codec_format = PIPI_PIXELS_RGBA32;
-
-    return img;
-}
-
-void pipi_free_sdl(pipi_image_t *img)
-{
-    SDL_FreeSurface(img->codec_priv);
-
-    free(img);
-}
-
-void pipi_save_sdl(pipi_image_t *img, const char *name)
-{
-    pipi_getpixels(img, img->codec_format);
-    SDL_SaveBMP(img->codec_priv, name);
+    return SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, 32,
+                                rmask, gmask, bmask, amask);
 }
 
diff --git a/pipi/pipi.c b/pipi/pipi.c
index 24d1aa8..0c45ee2 100644
--- a/pipi/pipi.c
+++ b/pipi/pipi.c
@@ -38,3 +38,17 @@ void _pipi_init(void)
 }
 */
 
+pipi_image_t *pipi_new(int w, int h)
+{
+    pipi_image_t *img;
+
+    img = malloc(sizeof(pipi_image_t));
+    memset(img, 0, sizeof(pipi_image_t));
+
+    img->w = w;
+    img->h = h;
+    img->last_modified = PIPI_PIXELS_UNINITIALISED;
+
+    return img;
+}
+
diff --git a/pipi/pipi.h b/pipi/pipi.h
index 83fb0a4..ce52e60 100644
--- a/pipi/pipi.h
+++ b/pipi/pipi.h
@@ -29,6 +29,8 @@ extern "C"
  * just been loaded, but RGBA_F is a lot better for complex operations. */
 typedef enum
 {
+    PIPI_PIXELS_UNINITIALISED = -1,
+
     PIPI_PIXELS_RGBA32 = 0,
     PIPI_PIXELS_RGBA_F = 1,