changeset 435:e4a3f183e463

Modularize some more.
author Matti Hamalainen <ccr@tnsp.org>
date Sat, 03 Nov 2012 16:08:30 +0200
parents 380c226c75af
children 86f956e4580f
files Makefile.gen gfxconv.c lib64gfx.c lib64gfx.h libgfx.c libgfx.h
diffstat 6 files changed, 1192 insertions(+), 1035 deletions(-) [+]
line wrap: on
line diff
--- a/Makefile.gen	Sat Nov 03 14:52:52 2012 +0200
+++ b/Makefile.gen	Sat Nov 03 16:08:30 2012 +0200
@@ -189,7 +189,7 @@
 
 ### Dependancies
 ifeq ($(DM_BUILD_TOOLS),yes)
-DMLIB_OBJS += lib64gfx.o
+DMLIB_OBJS += libgfx.o lib64gfx.o
 ifeq ($(DM_USE_STDIO),yes)
 BINARIES+= objlink data2inc gfxconv
 ifeq ($(SUP_MODLOAD),yes)
@@ -310,6 +310,10 @@
 	@echo " CC $+"
 	@$(CC) $(CFLAGS) -c -o $@ $< $(DM_CFLAGS)
 
+$(OBJPATH)libgfx.o: $(DMLIB)libgfx.c $(DMLIB)libgfx.h
+	@echo " CC $+"
+	@$(CC) $(CFLAGS) -c -o $@ $< $(DM_CFLAGS) $(LIBPNG_CFLAGS)
+
 
 $(DMLIB_A): $(addprefix $(OBJPATH),$(DMLIB_OBJS)) $(DMLIB)Makefile.gen config.mak
 	@echo " AR $@ $(addprefix $(OBJPATH),$(DMLIB_OBJS))"
--- a/gfxconv.c	Sat Nov 03 14:52:52 2012 +0200
+++ b/gfxconv.c	Sat Nov 03 16:08:30 2012 +0200
@@ -9,34 +9,12 @@
 #include "dmlib.h"
 #include "dmargs.h"
 #include "dmfile.h"
-#include "dmbstr.h"
 #include "dmmutex.h"
+#include "libgfx.h"
 #include "lib64gfx.h"
 
 //#define UNFINISHED 1
 
-#ifdef DM_USE_LIBPNG
-#include <png.h>
-#endif
-
-enum
-{
-    IMGFMT_PNG,
-    IMGFMT_PPM,
-    IMGFMT_PCX,
-    IMGFMT_ARAW,
-
-    IMGFMT_LAST
-};
-
-static const char *imageFormatList[IMGFMT_LAST] =
-{
-    "PNG",
-    "PPM",
-    "PCX",
-    "ARAW",
-};
-
 enum
 {
     FFMT_AUTO = 0,
@@ -120,17 +98,21 @@
         optInSubFormat = IMGFMT_PNG,
         optOutSubFormat = IMGFMT_PNG,
         optItemCount = -1,
-        optScale = 2,
         optPlanedWidth = 1,
-        optForcedFormat = -1,
-        optBPP = 4;
+        optForcedFormat = -1;
 int     optInSkip = 0;
 BOOL    optInMulticolor = FALSE,
-        optSequential = FALSE,
-        optPaletted = FALSE,
-        optInterleave = FALSE;
+        optSequential = FALSE;
 int     optColors[C64_MAX_COLORS];
 
+DMImageSpec optSpec =
+{
+    .scale = 2,
+    .nplanes = 4,
+    .interleave = FALSE,
+    .paletted = FALSE,
+    .format = 0,
+};
 
 static DMOptArg optList[] =
 {
@@ -344,7 +326,7 @@
                     dmError("Invalid scale value '%s'.\n", optArg);
                     return FALSE;
                 }
-                optScale = tmp;
+                optSpec.scale = tmp;
             }
             break;
 
@@ -361,7 +343,7 @@
             break;
 
         case 12:
-            optPaletted = TRUE;
+            optSpec.paletted = TRUE;
             break;
 
         case 13:
@@ -372,12 +354,12 @@
                     dmError("Invalid bitplanes/bpp value '%s'.\n", optArg);
                     return FALSE;
                 }
-                optBPP = tmp;
+                optSpec.nplanes = tmp;
             }
             break;
 
         case 14:
-            optInterleave = TRUE;
+            optSpec.interleave = TRUE;
             break;
 
         default:
@@ -489,875 +471,6 @@
 }
 
 
-int dmWriteImageData(DMImage *img, void *cbdata, BOOL (*writeRowCB)(void *, Uint8 *, size_t), int scale, int format)
-{
-    int x, y, yscale, xscale, res = 0, rowSize, rowWidth;
-    Uint8 *row = NULL;
-
-    // Allocate memory for row buffer
-    rowWidth = img->width * scale;
-    rowSize = rowWidth * dmImageGetBytesPerPixel(format);
-
-    if ((row = dmMalloc(rowSize + 16)) == NULL)
-    {
-        res = DMERR_MALLOC;
-        goto done;
-    }
-
-    // Generate the image
-    for (y = 0; y < img->height; y++)
-    {
-        Uint8 *ptr = row,
-                *ptr1 = row,
-                *ptr2 = ptr1 + rowWidth,
-                *ptr3 = ptr2 + rowWidth;
-
-        for (x = 0; x < img->width; x++)
-        {
-            Uint8 c = img->data[(y * img->pitch) + x], qr, qg, qb, qa;
-            switch (format)
-            {
-                case DM_IFMT_PALETTE:
-                    for (xscale = 0; xscale < scale; xscale++)
-                        *ptr++ = c;
-                    break;
-
-                case DM_IFMT_RGBA:
-                    qr = img->pal[c].r;
-                    qg = img->pal[c].g;
-                    qb = img->pal[c].b;
-                    qa = (c == img->ctrans) ? 0 : 255;
-                
-                    for (xscale = 0; xscale < scale; xscale++)
-                    {
-                        *ptr++ = qr;
-                        *ptr++ = qg;
-                        *ptr++ = qb;
-                        *ptr++ = qa;
-                    }
-                    break;
-
-                case DM_IFMT_RGB:
-                    qr = img->pal[c].r;
-                    qg = img->pal[c].g;
-                    qb = img->pal[c].b;
-                
-                    for (xscale = 0; xscale < scale; xscale++)
-                    {
-                        *ptr++ = qr;
-                        *ptr++ = qg;
-                        *ptr++ = qb;
-                    }
-                    break;
-
-                case DM_IFMT_RGB_PLANE:
-                    qr = img->pal[c].r;
-                    qg = img->pal[c].g;
-                    qb = img->pal[c].b;
-                
-                    for (xscale = 0; xscale < scale; xscale++)
-                    {
-                        *ptr1++ = qr;
-                        *ptr2++ = qg;
-                        *ptr3++ = qb;
-                    }
-                    break;
-            }
-        }
-
-        for (yscale = 0; yscale < scale; yscale++)
-        {
-            if (!writeRowCB(cbdata, row, rowSize))
-            {
-                res = DMERR_FWRITE;
-                goto done;
-            }
-        }
-    }
-
-done:
-    dmFree(row);    
-    return res;
-}
-
-
-#define DMCOL(x) (((x) >> 4) & 0xf)
-
-int dmWriteIFFMasterRAWPalette(const char *filename, DMImage *img, int ncolors)
-{
-    FILE *fp;
-    int i;
-
-    if ((fp = fopen(filename, "w")) == NULL)
-    {
-        dmError("IFFMasterRAW: Could not open file '%s' for writing.\n", filename);
-        return -15;
-    }
-
-    for (i = 0; i < ncolors; i++)
-    {
-        int color;
-        if (i < img->ncolors)
-        {
-            color = (DMCOL(img->pal[i].r) << 8) |
-                    (DMCOL(img->pal[i].g) << 4) |
-                    (DMCOL(img->pal[i].b));
-        }
-        else
-            color = 0;
-
-        fprintf(fp, "\tdc.w $%04X\n", color);
-    }
-
-    return 0;    
-}
-
-
-int dmWriteIFFMasterRAWImageFILE(FILE *fp, DMImage *img, int scale, int nplanes, BOOL interleave)
-{
-    int xc, yc, plane, res;
-    DMBitStream bs;
-    
-    if ((res = dmInitBitStream(&bs, fp)) != DMERR_OK)
-        return res;
-
-    if (interleave)
-    {
-        // Output bitplanes in interleaved format (each plane of line sequentially)
-        for (yc = 0; yc < img->height; yc++)
-        {
-            for (plane = 0; plane < nplanes; plane++)
-            {
-                Uint8 *sp = img->data + yc * img->pitch;
-                for (xc = 0; xc < img->width; xc++)
-                {
-                    if (!dmPutBits(&bs, (sp[xc] & (1 << plane)) ? 1 : 0, 1))
-                        return DMERR_FWRITE;
-                }
-            }
-        }
-    }
-    else
-    {
-        // Output each bitplane in sequence
-        for (plane = 0; plane < nplanes; plane++)
-        {
-            for (yc = 0; yc < img->height; yc++)
-            {
-                Uint8 *sp = img->data + yc * img->pitch;
-                for (xc = 0; xc < img->width; xc++)
-                {
-                    if (!dmPutBits(&bs, (sp[xc] & (1 << plane)) ? 1 : 0, 1))
-                        return DMERR_FWRITE;
-                }
-            }
-        }
-    }
-    
-    return dmFlushBitStream(&bs);
-}
-
-int dmWriteIFFMasterRAWImage(const char *filename, DMImage *img, int scale, int nplanes, BOOL interleave)
-{
-    FILE *fp;
-    int res;
-
-    if ((fp = fopen(filename, "wb")) == NULL)
-    {
-        dmError("IFFMasterRAW: Could not open file '%s' for writing.\n", filename);
-        return DMERR_FOPEN;
-    }
-
-    res = dmWriteIFFMasterRAWImageFILE(fp, img, scale, nplanes, interleave);
-
-    fclose(fp);
-    return res;
-}
-
-
-static BOOL dmWritePPMRow(void *cbdata, Uint8 *row, size_t len)
-{
-    return fwrite(row, sizeof(Uint8), len, (FILE *) cbdata) == len;
-}
-
-
-int dmWritePPMImageFILE(FILE *fp, DMImage *img, int scale)
-{
-    // Write PPM header
-    fprintf(fp,
-        "P6\n%d %d\n255\n",
-        img->width * scale, img->height * scale);
-
-    // Write image data
-    return dmWriteImageData(img, (void *) fp, dmWritePPMRow, scale, DM_IFMT_RGB);
-}
-
-
-int dmWritePPMImage(const char *filename, DMImage *img, int scale)
-{
-    FILE *fp;
-    int res;
-
-    // Create output file
-    if ((fp = fopen(filename, "wb")) == NULL)
-    {
-        dmError("PPM: could not open file '%s' for writing.\n", filename);
-        return DMERR_FOPEN;
-    }
-
-    res = dmWritePPMImageFILE(fp, img, scale);
-
-    fclose(fp);
-    return res;
-}
-
-
-#ifdef DM_USE_LIBPNG
-static BOOL dmWritePNGRow(void *cbdata, Uint8 *row, size_t len)
-{
-    png_structp png_ptr = cbdata;
-    (void) len;
-
-    if (setjmp(png_jmpbuf(png_ptr)))
-        return FALSE;
-
-    png_write_row(png_ptr, row);
-
-    return TRUE;
-}
-
-
-int dmWritePNGImageFILE(FILE *fp, DMImage *img, int scale, int format)
-{
-    png_structp png_ptr = NULL;
-    png_infop info_ptr = NULL;
-    png_colorp palette = NULL;
-    int fmt, res = DMERR_OK;
-
-    // Create PNG structures
-    png_ptr = png_create_write_struct(
-        PNG_LIBPNG_VER_STRING,
-        NULL, NULL, NULL);
-
-    if (png_ptr == NULL)
-    {
-        dmError("PNG: png_create_write_struct() failed.\n");
-        res = DMERR_MALLOC;
-        goto error;
-    }
-    
-    info_ptr = png_create_info_struct(png_ptr);
-    if (info_ptr == NULL)
-    {
-        dmError("PNG: png_create_info_struct(%p) failed.\n", png_ptr);
-        res = DMERR_INIT_FAIL;
-        goto error;
-    }
-    
-    if (setjmp(png_jmpbuf(png_ptr)))
-    {
-        dmError("PNG: Error during image writing..\n");
-        res = DMERR_INIT_FAIL;
-        goto error;
-    }
-
-    png_init_io(png_ptr, fp);
-
-    // Write PNG header info
-    switch (format)
-    {
-        case DM_IFMT_PALETTE: fmt = PNG_COLOR_TYPE_PALETTE; break;
-        case DM_IFMT_RGB    : fmt = PNG_COLOR_TYPE_RGB; break;
-        case DM_IFMT_RGBA   : fmt = PNG_COLOR_TYPE_RGB_ALPHA; break;
-        default:
-            dmError("PNG: Internal error, unsupported image format %d.\n", format);
-            goto error;
-    }
- 
-    png_set_IHDR(png_ptr, info_ptr,
-        img->width * scale,
-        img->height * scale,
-        8,                    /* bits per component */
-        fmt,
-        PNG_INTERLACE_NONE,
-        PNG_COMPRESSION_TYPE_DEFAULT,
-        PNG_FILTER_TYPE_DEFAULT);
-
-    // Palette
-    if (format == DM_IFMT_PALETTE)
-    {
-        int i;
-
-        palette = png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH * sizeof(png_color));
-        if (palette == NULL)
-        {
-            dmError("PNG: Could not allocate palette structure.");
-            goto error;
-        }
-        
-        memset(palette, 0, PNG_MAX_PALETTE_LENGTH * sizeof(png_color));
-
-        for (i = 0; i < img->ncolors; i++)
-        {
-            palette[i].red   = img->pal[i].r;
-            palette[i].green = img->pal[i].g;
-            palette[i].blue  = img->pal[i].b;
-        }
-
-        png_set_PLTE(png_ptr, info_ptr, palette, PNG_MAX_PALETTE_LENGTH);
-    }
-
-//    png_set_gAMA(png_ptr, info_ptr, 2.2);
-
-    png_write_info(png_ptr, info_ptr);
-
-
-    // Write compressed image data
-    dmWriteImageData(img, (void *) png_ptr, dmWritePNGRow, scale, format);
-
-    // Write footer
-    png_write_end(png_ptr, NULL);
-
-error:
-    png_free(png_ptr, palette);
-    palette = NULL;
-
-    if (png_ptr && info_ptr)
-        png_destroy_write_struct(&png_ptr, &info_ptr);
-
-    return res;
-}
-
-
-int dmWritePNGImage(const char *filename, DMImage *img, int scale, int format)
-{
-    int res;
-    FILE *fp;
-
-    if ((fp = fopen(filename, "wb")) == NULL)
-    {
-        dmError("PNG: could not open file '%s' for writing.\n", filename);
-        return DMERR_FOPEN;
-    }
-
-    res = dmWritePNGImageFILE(fp, img, scale, format);
-
-    fclose(fp);
-    return res;
-}
-#endif
-
-
-typedef struct
-{
-    Uint8 r,g,b;
-} DMPCXColor;
-
-
-typedef struct
-{
-    Uint8 manufacturer,
-            version,
-            encoding,
-            bpp;
-    Uint16 xmin, ymin, xmax, ymax;
-    Uint16 hres, vres;
-    DMPCXColor colormap[16];
-    Uint8 reserved;
-    Uint8 nplanes;
-    Uint16 bpl;
-    Uint16 palinfo;
-    Uint8 filler[58];
-} DMPCXHeader;
-
-typedef struct
-{
-    DMPCXHeader *header;
-    Uint8 *buf;
-    size_t bufLen, bufOffs;
-    int format;
-    FILE *fp;
-} DMPCXData;
-
-
-static inline Uint8 dmPCXGetByte(Uint8 *row, const size_t len, const size_t soffs)
-{
-    return (soffs < len) ? row[soffs] : 0;
-}
-
-static BOOL dmPCXFlush(DMPCXData *pcx)
-{
-    BOOL ret = fwrite(pcx->buf, sizeof(Uint8), pcx->bufOffs, pcx->fp) == pcx->bufOffs;
-    pcx->bufOffs = 0;
-    return ret;
-}
-
-static inline BOOL dmPCXPutByte(DMPCXData *pcx, const Uint8 val)
-{
-    if (pcx->bufOffs < pcx->bufLen)
-    {
-        pcx->buf[pcx->bufOffs++] = val;
-        return TRUE;
-    }
-    else
-        return dmPCXFlush(pcx);
-}
-
-BOOL dmWritePCXRow(void *cbdata, Uint8 *row, size_t len)
-{
-    DMPCXData *pcx = (DMPCXData *) cbdata;
-    int plane;
-    
-    for (plane = 0; plane < pcx->header->nplanes; plane++)
-    {
-        size_t soffs = 0;
-        Uint8 data = dmPCXGetByte(row, len, soffs++),
-              count = 1;
-
-        pcx->bufOffs = 0;
-
-        while (soffs < pcx->header->bpl)
-        {
-            if (data == dmPCXGetByte(row, len, soffs) && count < 63)
-            {
-                count++;
-                soffs++;
-            }
-            else
-            {
-                if (count == 1 && (data & 0xC0) != 0xC0)
-                {
-                    if (!dmPCXPutByte(pcx, data))
-                        return FALSE;
-                }
-                else
-                {
-                    if (!dmPCXPutByte(pcx, 0xC0 | count) ||
-                        !dmPCXPutByte(pcx, data))
-                        return FALSE;
-                }
-
-                data = dmPCXGetByte(row, len, soffs++);
-                count = 1;
-            }
-        }
-        
-        if (count > 1)
-        {
-            if (!dmPCXPutByte(pcx, 0xC0 | count) ||
-                !dmPCXPutByte(pcx, data))
-                return FALSE;
-        }
-
-        if (!dmPCXFlush(pcx))
-            return FALSE;
-    }
-
-    return TRUE;
-}
-
-
-int dmWritePCXImageFILE(FILE *fp, DMImage *img, int scale, BOOL paletted)
-{
-    DMPCXData pcx;
-    DMPCXHeader hdr;
-    int res;
-
-    // Create output file
-    pcx.buf    = NULL;
-    pcx.format = paletted ? DM_IFMT_PALETTE : DM_IFMT_RGB_PLANE;
-    pcx.header = &hdr;
-    pcx.fp     = fp;
-
-    // Create PCX header
-    memset(&hdr, 0, sizeof(hdr));
-    if (paletted)
-    {
-        int i;
-        for (i = 0; i < (img->ncolors > 16 ? 16 : img->ncolors); i++)
-        {
-            hdr.colormap[i].r = img->pal[i].r;
-            hdr.colormap[i].g = img->pal[i].g;
-            hdr.colormap[i].b = img->pal[i].b;
-        }
-    }
-    hdr.manufacturer = 10;
-    hdr.version      = 5;
-    hdr.encoding     = 1;
-    hdr.bpp          = 8;
-    hdr.hres         = img->width * scale;
-    hdr.vres         = img->height * scale;
-    hdr.xmin         = hdr.ymin = 0;
-    hdr.xmax         = hdr.hres - 1;
-    hdr.ymax         = hdr.vres - 1;
-    hdr.nplanes      = dmImageGetBytesPerPixel(pcx.format);
-    hdr.palinfo      = 1;
-    res = (img->width * scale);
-    hdr.bpl = res / 2;
-    if (res % 2) hdr.bpl++;
-    hdr.bpl *= 2;
-
-    dmMsg(2, "PCX: paletted=%d, nplanes=%d, bpp=%d, bpl=%d\n",
-        paletted, hdr.nplanes, hdr.bpp, hdr.bpl);
-
-    pcx.bufLen       = hdr.bpl * 4;
-    if ((pcx.buf = dmMalloc(pcx.bufLen)) == NULL)
-    {
-        dmError("PCX: Could not allocate %d bytes for RLE compression buffer.\n",
-            pcx.bufLen);
-        res = DMERR_MALLOC;
-        goto error;
-    }
-
-    // Write PCX header
-    if (!dm_fwrite_byte(pcx.fp, hdr.manufacturer) ||
-        !dm_fwrite_byte(pcx.fp, hdr.version) ||
-        !dm_fwrite_byte(pcx.fp, hdr.encoding) ||
-        !dm_fwrite_byte(pcx.fp, hdr.bpp))
-    {
-        dmError("PCX: Could not write basic header data.\n");
-        res = DMERR_FWRITE;
-        goto error;
-    }
-    
-    if (!dm_fwrite_le16(pcx.fp, hdr.xmin) ||
-        !dm_fwrite_le16(pcx.fp, hdr.ymin) ||
-        !dm_fwrite_le16(pcx.fp, hdr.xmax) ||
-        !dm_fwrite_le16(pcx.fp, hdr.ymax) ||
-        !dm_fwrite_le16(pcx.fp, hdr.hres) ||
-        !dm_fwrite_le16(pcx.fp, hdr.vres))
-    {
-        dmError("PCX: Could not write image dimensions.\n");
-        res = DMERR_FWRITE;
-        goto error;
-    }
-
-    if (!dm_fwrite_str(pcx.fp, (Uint8 *) &hdr.colormap, sizeof(hdr.colormap)))
-    {
-        dmError("PCX: Could not write colormap.\n");
-        res = DMERR_FWRITE;
-        goto error;
-    }
-    
-    if (!dm_fwrite_byte(pcx.fp, hdr.reserved) ||
-        !dm_fwrite_byte(pcx.fp, hdr.nplanes) ||
-        !dm_fwrite_le16(pcx.fp, hdr.bpl) ||
-        !dm_fwrite_le16(pcx.fp, hdr.palinfo) ||
-        !dm_fwrite_str(pcx.fp, (Uint8 *) &hdr.filler, sizeof(hdr.filler)))
-    {
-        dmError("PCX: Could not write header remainder.\n");
-        res = DMERR_FWRITE;
-        goto error;
-    }
-
-    // Write image data
-    res = dmWriteImageData(img, (void *) &pcx, dmWritePCXRow, scale, pcx.format);
-
-    // Write VGA palette
-    if (paletted)
-    {
-        int i;
-        dm_fwrite_byte(pcx.fp, 0x0C);
-        dmMsg(2, "PCX: Writing palette of %d active entries.\n", img->ncolors);
-
-        for (i = 0; i < img->ncolors; i++)
-        {
-            dm_fwrite_byte(pcx.fp, img->pal[i].r);
-            dm_fwrite_byte(pcx.fp, img->pal[i].g);
-            dm_fwrite_byte(pcx.fp, img->pal[i].b);
-        }
-
-        // Pad the palette, if necessary        
-        for (; i < 256; i++)
-        {
-            dm_fwrite_byte(pcx.fp, 0);
-            dm_fwrite_byte(pcx.fp, 0);
-            dm_fwrite_byte(pcx.fp, 0);
-        }
-    }
-    
-error:
-    dmFree(pcx.buf);
-    return res;
-}
-
-
-int dmWritePCXImage(const char *filename, DMImage *img, int scale, BOOL paletted)
-{
-    FILE *fp;
-    int res;
-
-    if ((fp = fopen(filename, "wb")) == NULL)
-    {
-        dmError("PCX: Could not open file '%s' for writing.\n", filename);
-        return DMERR_FOPEN;
-    }
-    
-    res = dmWritePCXImageFILE(fp, img, scale, paletted);
-    
-    fclose(fp);
-    return res;
-}
-
-
-static BOOL dmPCXDecodeRLERow(FILE *fp, Uint8 *buf, const size_t bufLen)
-{
-    size_t offs = 0;
-    do
-    {
-        int count;
-        Uint8 data;
-
-        if (!dm_fread_byte(fp, &data))
-            return FALSE;
-        
-        if ((data & 0xC0) == 0xC0)
-        {
-            count = data & 0x3F;
-            if (!dm_fread_byte(fp, &data))
-                return FALSE;
-        }
-        else
-            count = 1;
-
-        while (count-- && offs < bufLen)
-            buf[offs++] = data;
-
-    } while (offs < bufLen);
-
-    return TRUE;
-}
-
-
-int dmReadPCXImageFILE(FILE *fp, DMImage **pimg)
-{
-    DMImage *img;
-    DMPCXData pcx;
-    DMPCXHeader hdr;
-    BOOL paletted;
-    int res = 0, yc, xc;
-    Uint8 *dp;
-
-    pcx.buf = NULL;
-
-    // Read PCX header
-    if (!dm_fread_byte(fp, &hdr.manufacturer) ||
-        !dm_fread_byte(fp, &hdr.version) ||
-        !dm_fread_byte(fp, &hdr.encoding) ||
-        !dm_fread_byte(fp, &hdr.bpp))
-    {
-        dmError("PCX: Could not read basic header data.\n");
-        res = DMERR_FREAD;
-        goto error;
-    }
-    
-    if (hdr.manufacturer != 10 ||
-        hdr.version != 5 ||
-        hdr.encoding != 1 ||
-        hdr.bpp != 8)
-    {
-        dmError("PCX: Not a PCX file, or unsupported variant.\n");
-        res = DMERR_FREAD;
-        goto error;
-    }
-    
-    if (!dm_fread_le16(fp, &hdr.xmin) ||
-        !dm_fread_le16(fp, &hdr.ymin) ||
-        !dm_fread_le16(fp, &hdr.xmax) ||
-        !dm_fread_le16(fp, &hdr.ymax) ||
-        !dm_fread_le16(fp, &hdr.hres) ||
-        !dm_fread_le16(fp, &hdr.vres))
-    {
-        dmError("PCX: Could not read image dimensions.\n");
-        res = DMERR_FREAD;
-        goto error;
-    }
-
-    if (!dm_fread_str(fp, (Uint8 *) &hdr.colormap, sizeof(hdr.colormap)))
-    {
-        dmError("PCX: Could not read colormap.\n");
-        res = DMERR_FREAD;
-        goto error;
-    }
-    
-    if (!dm_fread_byte(fp, &hdr.reserved) ||
-        !dm_fread_byte(fp, &hdr.nplanes) ||
-        !dm_fread_le16(fp, &hdr.bpl) ||
-        !dm_fread_le16(fp, &hdr.palinfo) ||
-        !dm_fread_str(fp, (Uint8 *) &hdr.filler, sizeof(hdr.filler)))
-    {
-        dmError("PCX: Could not read header remainder.\n");
-        res = DMERR_FREAD;
-        goto error;
-    }
-    
-    if (hdr.nplanes != 3 && hdr.nplanes != 1)
-    {
-        dmError("PCX: Unsupported number of bitplanes %d.\n", hdr.nplanes);
-        res = DMERR_FREAD;
-        goto error;
-    }
-
-    // Allocate image
-    if ((*pimg = img = dmImageAlloc(hdr.xmax - hdr.xmin + 1, hdr.ymax - hdr.ymin + 1)) == NULL)
-    {
-        dmError("PCX: Could not allocate image structure.\n");
-        res = DMERR_MALLOC;
-        goto error;
-    }
-
-    paletted = hdr.nplanes == 1;
-    pcx.bufLen = hdr.nplanes * hdr.bpl;
-    if ((pcx.buf = dmMalloc(pcx.bufLen)) == NULL)
-    {
-        dmError("PCX: Could not allocate RLE buffer.\n");
-        res = DMERR_MALLOC;
-        goto error;
-    }
-
-    // Read image data
-    dp = img->data;
-    for (yc = 0; yc < img->height; yc++)
-    {
-        // Decode row of RLE'd data
-        if (!dmPCXDecodeRLERow(fp, pcx.buf, pcx.bufLen))
-        {
-            dmError("PCX: Error decoding RLE data.\n");
-            res = DMERR_INVALID_DATA;
-            goto error;
-        }
-        
-        // Decode bitplanes
-        switch (hdr.nplanes)
-        {
-            case 1:
-                memcpy(dp, pcx.buf, img->width);
-                break;
-            
-            case 3:
-                {
-                    Uint8 *dptr = dp,
-                            *sptr1 = pcx.buf,
-                            *sptr2 = sptr1 + hdr.bpl,
-                            *sptr3 = sptr2 + hdr.bpl;
-
-                    for (xc = 0; xc < img->width; xc++)
-                    {
-                        *dptr++ = *sptr1++;
-                        *dptr++ = *sptr2++;
-                        *dptr++ = *sptr3++;
-                    }
-                }
-                break;
-        }
-        
-        dp += img->pitch;
-    }
-
-    // Read VGA palette
-    if (paletted)
-    {
-        int i;
-        Uint8 tmpb;
-        BOOL read;
-
-        if (!dm_fread_byte(fp, &tmpb) || tmpb != 0x0C)
-        {
-            read = FALSE;
-            img->ncolors = 16;
-        }
-        else
-        {
-            read = TRUE;
-            img->ncolors = 256;
-        }
-
-        if ((img->pal = dmCalloc(img->ncolors, sizeof(DMColor))) == NULL)
-        {
-            dmError("PCX: Could not allocate palette data!\n");
-            res = DMERR_MALLOC;
-            goto error;
-        }
-        
-        if (read)
-        {
-            for (i = 0; i < img->ncolors; i++)
-            {
-                Uint8 tmpR, tmpG, tmpB;
-                if (!dm_fread_byte(fp, &tmpR) ||
-                    !dm_fread_byte(fp, &tmpG) ||
-                    !dm_fread_byte(fp, &tmpB))
-                    goto error;
-
-                img->pal[i].r = tmpR;
-                img->pal[i].g = tmpG;
-                img->pal[i].b = tmpB;
-            }
-        }
-        else
-        {
-            for (i = 0; i < img->ncolors; i++)
-            {
-                if (i < 16)
-                {
-                    img->pal[i].r = hdr.colormap[i].r;
-                    img->pal[i].g = hdr.colormap[i].g;
-                    img->pal[i].b = hdr.colormap[i].b;
-                }
-            }
-        }
-        
-
-    }
-
-error:
-    dmFree(pcx.buf);
-    return res;
-}
-
-
-int dmReadPCXImage(const char *filename, DMImage **pimg)
-{
-    FILE *fp;
-    int res;
-
-    if ((fp = fopen(filename, "rb")) == NULL)
-    {
-        dmError("PCX: Could not open file '%s' for reading.\n", filename);
-        return -15;
-    }
-    
-    res = dmReadPCXImageFILE(fp, pimg);
-
-    fclose(fp);
-    return res;
-}
-
-
-static int fmtProbePNG(const Uint8 *buf, const size_t len)
-{
-    if (len > 64 && buf[0] == 0x89 &&
-        buf[1] == 'P' && buf[2] == 'N' && buf[3] == 'G' &&
-        buf[4] == 0x0d && buf[5] == 0x0a)
-        return DM_PROBE_SCORE_GOOD;
-
-    return DM_PROBE_SCORE_FALSE;
-}
-
-
-static int fmtProbePCX(const Uint8 *buf, const size_t len)
-{
-    if (len > 128 + 64 &&
-        buf[0] == 10 &&
-        buf[1] == 5 &&
-        buf[2] == 1 &&
-        buf[3] == 8)
-        return DM_PROBE_SCORE_GOOD;
-
-    return DM_PROBE_SCORE_FALSE;
-}
-
-
 #ifdef UNFINISHED
 int dmConvertBMP2(DMImage *screen, const DM64Image *img)
 {
@@ -1400,43 +513,46 @@
 #endif
 
 
-int dmWriteImage(char *filename, DMImage *image, BOOL info)
+int dmWriteImage(const char *filename, DMImage *image, DMImageSpec *spec, int iformat, BOOL info)
 {
     if (info)
     {
         dmMsg(1, "Outputting %s image %d x %d -> %d x %d [%d]\n",
-            imageFormatList[optOutSubFormat],
+            dmImageFormatList[iformat],
             image->width, image->height,
-            image->width * optScale, image->height * optScale, optScale);
+            image->width * spec->scale, image->height * spec->scale,
+            spec->scale);
     }
-    
-    switch (optOutSubFormat)
+
+    switch (iformat)
     {
 #ifdef DM_USE_LIBPNG
         case IMGFMT_PNG:
-            if (info) dmMsg(2, "%s output.\n", optPaletted ? "Indexed 8bpp" : "32bit RGBA");
-            return dmWritePNGImage(filename, image, optScale, optPaletted ? DM_IFMT_PALETTE : DM_IFMT_RGBA);
+            if (info) dmMsg(2, "%s output.\n", spec->paletted ? "Indexed 8bpp" : "32bit RGBA");
+            spec->format = spec->paletted ? DM_IFMT_PALETTE : DM_IFMT_RGBA;
+            return dmWritePNGImage(filename, image, spec);
 #endif
 
         case IMGFMT_PPM:
             if (info) dmMsg(2, "24bit RGB output.\n");
-            return dmWritePPMImage(filename, image, optScale);
+            spec->format = DM_IFMT_RGB;
+            return dmWritePPMImage(filename, image, spec);
 
         case IMGFMT_PCX:
-            if (info) dmMsg(2, "%s output.\n", optPaletted ? "Indexed 8bpp" : "24bit RGB");
-            return dmWritePCXImage(filename, image, optScale, optPaletted);
+            if (info) dmMsg(2, "%s output.\n", spec->paletted ? "Indexed 8bpp" : "24bit RGB");
+            return dmWritePCXImage(filename, image, spec);
 
         case IMGFMT_ARAW:
             {
                 int res;
                 char *palFilename = dm_strdup_printf("%s.pal", filename);
-                res = dmWriteIFFMasterRAWPalette(palFilename, image, 1 << optBPP);
+                res = dmWriteIFFMasterRAWPalette(palFilename, image, 1 << optSpec.nplanes);
                 dmFree(palFilename);
                 if (res != DMERR_OK)
                     return res;
 
-                if (info) dmMsg(2, "%d bitplanes, %s interleave.\n", optBPP, optInterleave ? "with" : "without");
-                return dmWriteIFFMasterRAWImage(filename, image, optScale, optBPP, optInterleave);
+                if (info) dmMsg(2, "%d bitplanes, %s interleave.\n", spec->nplanes, spec->interleave ? "with" : "without");
+                return dmWriteIFFMasterRAWImage(filename, image, spec);
             }
 
         default:
@@ -1544,7 +660,7 @@
             dmMsg(1, "Outputting sequence of %d images @ %d x %d -> %d x %d.\n",
                 optItemCount,
                 outImage->width, outImage->height,
-                outImage->width * optScale, outImage->height * optScale);
+                outImage->width * optSpec.scale, outImage->height * optSpec.scale);
         }
         else
         {
@@ -1595,7 +711,7 @@
                     goto error;
                 }
                 
-                dmWriteImage(outFilename, outImage, FALSE);
+                dmWriteImage(optOutFilename, outImage, &optSpec, optOutSubFormat, TRUE);
                 dmFree(outFilename);
             }
             else
@@ -1612,7 +728,7 @@
 
         if (!optSequential)
         {
-            dmWriteImage(optOutFilename, outImage, TRUE);
+            dmWriteImage(optOutFilename, outImage, &optSpec, optOutSubFormat, TRUE);
         }
         
         dmImageFree(outImage);
@@ -1712,17 +828,12 @@
 
     if (optInFormat == FFMT_AUTO)
     {
-        // XXX, needs a proper probe loop
-        if (fmtProbePNG(dataBuf + optInSkip, dataSize - optInSkip))
+        DMImageFormat *ifmt = NULL;
+        int index;
+        if (dmImageProbeGeneric(dataBuf + optInSkip, dataSize - optInSkip, &ifmt, &index) > 0)
         {
             optInFormat = FFMT_IMAGE;
-            optInSubFormat = IMGFMT_PNG;
-        }
-        else
-        if (fmtProbePCX(dataBuf + optInSkip, dataSize - optInSkip))
-        {
-            optInFormat = FFMT_IMAGE;
-            optInSubFormat = IMGFMT_PCX;
+            optInSubFormat = index;
         }
     }
 
@@ -1767,7 +878,7 @@
         
         case FFMT_BITMAP:
             {
-                DMImage *img = NULL;
+                DMImage *outImage = NULL;
                 int res = DMERR_OK;
 
                 if (optOutFilename == NULL)
@@ -1779,29 +890,29 @@
                 switch (optOutFormat)
                 {
                     case FFMT_IMAGE:
-                        if ((img = dmImageAlloc(C64_SCR_WIDTH, C64_SCR_HEIGHT)) == NULL)
+                        if ((outImage = dmImageAlloc(C64_SCR_WIDTH, C64_SCR_HEIGHT)) == NULL)
                         {
                             dmError("Could not allocate output image surface %d x %d.\n",
                                 C64_SCR_WIDTH, C64_SCR_HEIGHT);
                             goto error;
                         }
                         
-                        img->pal      = (DMColor *) &dmC64Palette;
-                        img->ncolors  = C64_NCOLORS;
-                        img->constpal = TRUE;
+                        outImage->pal      = (DMColor *) &dmC64Palette;
+                        outImage->ncolors  = C64_NCOLORS;
+                        outImage->constpal = TRUE;
                         
                         if (cfmt->convert != NULL)
-                            res = cfmt->convert(img, &cimage);
+                            res = cfmt->convert(outImage, &cimage);
                         else
-                            res = dmC64ConvertGenericBMP2Image(img, &cimage);
+                            res = dmC64ConvertGenericBMP2Image(outImage, &cimage);
 
-                        if (res != DMERR_OK || img == NULL)
+                        if (res != DMERR_OK || outImage == NULL)
                         {
                             dmError("Error in bitmap to image conversion.\n");
                             goto error;
                         }
 
-                        res = dmWriteImage(optOutFilename, img, TRUE);
+                        res = dmWriteImage(optOutFilename, outImage, &optSpec, optOutSubFormat, TRUE);
                         break;
 
                     default:
@@ -1809,13 +920,13 @@
                         break;
                 }
                 
-                dmImageFree(img);
+                dmImageFree(outImage);
             }
             break;
 
         case FFMT_IMAGE:
             {
-                DMImage *img;
+                DMImage *outImage;
                 int res = DMERR_OK;
 
                 if (optOutFilename == NULL)
@@ -1827,22 +938,22 @@
                 // Read input
                 switch (optInSubFormat)
                 {
-                    case IMGFMT_PCX: res = dmReadPCXImageFILE(inFile, &img); break;
-//                    case IMGFMT_PNG: res = dmReadPNGImageFILE(inFile, &img); break;
-//                    case IMGFMT_ARAW: res = dmReadARAWImageFILE(inFile, &img, optBPP); break;
+                    case IMGFMT_PCX: res = dmReadPCXImageFILE(inFile, &outImage); break;
+//                    case IMGFMT_PNG: res = dmReadPNGImageFILE(inFile, &outImage); break;
+//                    case IMGFMT_ARAW: res = dmReadARAWImageFILE(inFile, &outImage, optSpec.nplanes); break;
                     default:
                         dmError("Unsupported input image format for bitmap/image conversion.\n");
                         break;
                     
                 }
 
-                if (res != DMERR_OK || img == NULL)
+                if (res != DMERR_OK || outImage == NULL)
                     break;
                 
                 switch (optOutFormat)
                 {
                     case FFMT_IMAGE:
-                        res = dmWriteImage(optOutFilename, img, TRUE);
+                        res = dmWriteImage(optOutFilename, outImage, &optSpec, optOutSubFormat, TRUE);
                         break;
 
                     default:
@@ -1850,7 +961,7 @@
                         break;
                 }
                 
-                dmImageFree(img);
+                dmImageFree(outImage);
             }
             break;
     }
--- a/lib64gfx.c	Sat Nov 03 14:52:52 2012 +0200
+++ b/lib64gfx.c	Sat Nov 03 16:08:30 2012 +0200
@@ -7,7 +7,7 @@
  * Please read file 'COPYING' for information on license and distribution.
  */
 #include "lib64gfx.h"
-#include <errno.h>
+
 
 const char *dmC64ImageTypeNames[DM_C64IFMT_LAST_TYPE] =
 {
@@ -53,55 +53,6 @@
 
 
 
-DMImage * dmImageAlloc(int width, int height)
-{
-    DMImage *img = dmCalloc(1, sizeof(DMImage));
-    if (img == NULL)
-        return NULL;
-    
-    img->width = img->pitch = width;
-    img->height = height;
-    img->data = dmMalloc(width * height * sizeof(Uint8));
-    if (img->data == NULL)
-    {
-        dmFree(img);
-        return NULL;
-    }
-    
-    return img;
-}
-
-
-void dmImageFree(DMImage *img)
-{
-    if (img != NULL)
-    {
-        if (!img->constpal)
-        {
-            dmFree(img->pal);
-        }
-        dmFree(img->data);
-        dmFree(img);
-    }
-}
-
-
-int dmImageGetBytesPerPixel(int format)
-{
-    switch (format)
-    {
-        case DM_IFMT_PALETTE   : return 1;
-
-        case DM_IFMT_RGB_PLANE :
-        case DM_IFMT_RGB       : return 3;
-
-        case DM_IFMT_RGBA      : return 4;
-
-        default:                 return 0;
-    }
-}
-
-
 int dmC64ConvertCSData(DMImage *img,
     int xoffs, int yoffs, const Uint8 *buf,
     int width, int height, BOOL multicolor, int *colors)
--- a/lib64gfx.h	Sat Nov 03 14:52:52 2012 +0200
+++ b/lib64gfx.h	Sat Nov 03 16:08:30 2012 +0200
@@ -9,7 +9,12 @@
 #ifndef LIB64GFX_H
 #define LIB64GFX_H 1
 
-#include "dmlib.h"
+#include "libgfx.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 
 // Bitmap constants
 #define C64_SCR_WIDTH          320
@@ -45,40 +50,6 @@
 #define C64_MAX_SPRITES        (C64_VIDBANK_SIZE / C64_SPR_SIZE)
 #define C64_MAX_CHARS          256
 
-// Probe scores
-#define DM_PROBE_SCORE_MAX     1000
-#define DM_PROBE_SCORE_GOOD    750
-#define DM_PROBE_SCORE_AVG     500
-#define DM_PROBE_SCORE_MAYBE   250
-#define DM_PROBE_SCORE_FALSE   0
-
-enum
-{
-    DM_IFMT_PALETTE,
-    DM_IFMT_RGB,
-    DM_IFMT_RGBA,
-    DM_IFMT_RGB_PLANE,
-};
-
-
-// RGBx color struct
-typedef struct
-{
-    Uint8 r, g, b, x;
-} DMColor;
-
-
-// Bitmapped image struct (can be one of types specified by DM_IFMT_*)
-typedef struct
-{
-    int width, height, pitch;
-    BOOL constpal;
-    int ncolors, ctrans;
-    DMColor *pal;
-    Uint8 *data;
-} DMImage;
-
-
 // Different supported C64 bitmap "modes"
 enum
 {
@@ -171,11 +142,6 @@
 extern const char *      dmC64ImageTypeNames[];
 
 
-DMImage * dmImageAlloc(int width, int height);
-void      dmImageFree(DMImage *img);
-int       dmImageGetBytesPerPixel(int format);
-
-
 int       dmC64ConvertCSData(DMImage *img, int xoffs, int yoffs, const Uint8 *inBuf, int width, int height, BOOL multicolor, int *colors);
 int       dmC64ProbeGeneric(const Uint8 *buf, const size_t len, DMC64ImageFormat **fmt);
 int       dmC64DecodeGenericBMP(DMC64Image *img, const Uint8 *buf, const size_t len, const DMC64ImageFormat *fmt);
@@ -184,4 +150,9 @@
 
 int       dmReadDataFile(FILE *inFile, const char *filename, Uint8 **buf, size_t *size);
 
+
+#ifdef __cplusplus
+}
+#endif
+
 #endif // LIB64GFX_H
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgfx.c	Sat Nov 03 16:08:30 2012 +0200
@@ -0,0 +1,1003 @@
+/*
+ * Functions for reading and converting various restricted
+ * C64/etc and/or indexed/paletted graphics formats.
+ * Programmed and designed by Matti 'ccr' Hamalainen
+ * (C) Copyright 2012 Tecnic Software productions (TNSP)
+ *
+ * Please read file 'COPYING' for information on license and distribution.
+ */
+#include "libgfx.h"
+#include "dmfile.h"
+#include "dmbstr.h"
+
+#ifdef DM_USE_LIBPNG
+#include <png.h>
+#endif
+
+
+DMImage * dmImageAlloc(int width, int height)
+{
+    DMImage *img = dmCalloc(1, sizeof(DMImage));
+    if (img == NULL)
+        return NULL;
+    
+    img->width = img->pitch = width;
+    img->height = height;
+    img->data = dmMalloc(width * height * sizeof(Uint8));
+    if (img->data == NULL)
+    {
+        dmFree(img);
+        return NULL;
+    }
+    
+    return img;
+}
+
+
+void dmImageFree(DMImage *img)
+{
+    if (img != NULL)
+    {
+        if (!img->constpal)
+        {
+            dmFree(img->pal);
+        }
+        dmFree(img->data);
+        dmFree(img);
+    }
+}
+
+
+int dmImageGetBytesPerPixel(int format)
+{
+    switch (format)
+    {
+        case DM_IFMT_PALETTE   : return 1;
+
+        case DM_IFMT_RGB_PLANE :
+        case DM_IFMT_RGB       : return 3;
+
+        case DM_IFMT_RGBA      : return 4;
+
+        default:                 return 0;
+    }
+}
+
+
+int dmWriteImageData(DMImage *img, void *cbdata, BOOL (*writeRowCB)(void *, Uint8 *, size_t), const DMImageSpec *spec)
+{
+    int x, y, yscale, xscale, res = 0, rowSize, rowWidth;
+    Uint8 *row = NULL;
+
+    // Allocate memory for row buffer
+    rowWidth = img->width * spec->scale;
+    rowSize = rowWidth * dmImageGetBytesPerPixel(spec->format);
+
+    if ((row = dmMalloc(rowSize + 16)) == NULL)
+    {
+        res = DMERR_MALLOC;
+        goto done;
+    }
+
+    // Generate the image
+    for (y = 0; y < img->height; y++)
+    {
+        Uint8 *ptr = row,
+                *ptr1 = row,
+                *ptr2 = ptr1 + rowWidth,
+                *ptr3 = ptr2 + rowWidth;
+
+        for (x = 0; x < img->width; x++)
+        {
+            Uint8 c = img->data[(y * img->pitch) + x], qr, qg, qb, qa;
+            switch (spec->format)
+            {
+                case DM_IFMT_PALETTE:
+                    for (xscale = 0; xscale < spec->scale; xscale++)
+                        *ptr++ = c;
+                    break;
+
+                case DM_IFMT_RGBA:
+                    qr = img->pal[c].r;
+                    qg = img->pal[c].g;
+                    qb = img->pal[c].b;
+                    qa = (c == img->ctrans) ? 0 : 255;
+                
+                    for (xscale = 0; xscale < spec->scale; xscale++)
+                    {
+                        *ptr++ = qr;
+                        *ptr++ = qg;
+                        *ptr++ = qb;
+                        *ptr++ = qa;
+                    }
+                    break;
+
+                case DM_IFMT_RGB:
+                    qr = img->pal[c].r;
+                    qg = img->pal[c].g;
+                    qb = img->pal[c].b;
+                
+                    for (xscale = 0; xscale < spec->scale; xscale++)
+                    {
+                        *ptr++ = qr;
+                        *ptr++ = qg;
+                        *ptr++ = qb;
+                    }
+                    break;
+
+                case DM_IFMT_RGB_PLANE:
+                    qr = img->pal[c].r;
+                    qg = img->pal[c].g;
+                    qb = img->pal[c].b;
+                
+                    for (xscale = 0; xscale < spec->scale; xscale++)
+                    {
+                        *ptr1++ = qr;
+                        *ptr2++ = qg;
+                        *ptr3++ = qb;
+                    }
+                    break;
+            }
+        }
+
+        for (yscale = 0; yscale < spec->scale; yscale++)
+        {
+            if (!writeRowCB(cbdata, row, rowSize))
+            {
+                res = DMERR_FWRITE;
+                goto done;
+            }
+        }
+    }
+
+done:
+    dmFree(row);    
+    return res;
+}
+
+
+#define DMCOL(x) (((x) >> 4) & 0xf)
+
+int dmWriteIFFMasterRAWPalette(const char *filename, DMImage *img, int ncolors)
+{
+    FILE *fp;
+    int i;
+
+    if ((fp = fopen(filename, "w")) == NULL)
+    {
+        dmError("IFFMasterRAW: Could not open file '%s' for writing.\n", filename);
+        return -15;
+    }
+
+    for (i = 0; i < ncolors; i++)
+    {
+        int color;
+        if (i < img->ncolors)
+        {
+            color = (DMCOL(img->pal[i].r) << 8) |
+                    (DMCOL(img->pal[i].g) << 4) |
+                    (DMCOL(img->pal[i].b));
+        }
+        else
+            color = 0;
+
+        fprintf(fp, "\tdc.w $%04X\n", color);
+    }
+
+    return 0;    
+}
+
+
+int dmWriteIFFMasterRAWImageFILE(FILE *fp, DMImage *img, DMImageSpec *spec)
+{
+    int xc, yc, plane, res;
+    DMBitStream bs;
+    
+    if ((res = dmInitBitStream(&bs, fp)) != DMERR_OK)
+        return res;
+
+    if (spec->interleave)
+    {
+        // Output bitplanes in interleaved format (each plane of line sequentially)
+        for (yc = 0; yc < img->height; yc++)
+        {
+            for (plane = 0; plane < spec->nplanes; plane++)
+            {
+                Uint8 *sp = img->data + yc * img->pitch;
+                for (xc = 0; xc < img->width; xc++)
+                {
+                    if (!dmPutBits(&bs, (sp[xc] & (1 << plane)) ? 1 : 0, 1))
+                        return DMERR_FWRITE;
+                }
+            }
+        }
+    }
+    else
+    {
+        // Output each bitplane in sequence
+        for (plane = 0; plane < spec->nplanes; plane++)
+        {
+            for (yc = 0; yc < img->height; yc++)
+            {
+                Uint8 *sp = img->data + yc * img->pitch;
+                for (xc = 0; xc < img->width; xc++)
+                {
+                    if (!dmPutBits(&bs, (sp[xc] & (1 << plane)) ? 1 : 0, 1))
+                        return DMERR_FWRITE;
+                }
+            }
+        }
+    }
+    
+    return dmFlushBitStream(&bs);
+}
+
+int dmWriteIFFMasterRAWImage(const char *filename, DMImage *img, DMImageSpec *spec)
+{
+    FILE *fp;
+    int res;
+
+    if ((fp = fopen(filename, "wb")) == NULL)
+    {
+        dmError("IFFMasterRAW: Could not open file '%s' for writing.\n", filename);
+        return DMERR_FOPEN;
+    }
+
+    res = dmWriteIFFMasterRAWImageFILE(fp, img, spec);
+
+    fclose(fp);
+    return res;
+}
+
+
+static BOOL dmWritePPMRow(void *cbdata, Uint8 *row, size_t len)
+{
+    return fwrite(row, sizeof(Uint8), len, (FILE *) cbdata) == len;
+}
+
+
+int dmWritePPMImageFILE(FILE *fp, DMImage *img, DMImageSpec *spec)
+{
+    // Write PPM header
+    fprintf(fp,
+        "P6\n%d %d\n255\n",
+        img->width * spec->scale,
+        img->height * spec->scale);
+
+    // Write image data
+    spec->format = DM_IFMT_RGB;
+    return dmWriteImageData(img, (void *) fp, dmWritePPMRow, spec);
+}
+
+
+int dmWritePPMImage(const char *filename, DMImage *img, DMImageSpec *spec)
+{
+    FILE *fp;
+    int res;
+
+    // Create output file
+    if ((fp = fopen(filename, "wb")) == NULL)
+    {
+        dmError("PPM: could not open file '%s' for writing.\n", filename);
+        return DMERR_FOPEN;
+    }
+
+    res = dmWritePPMImageFILE(fp, img, spec);
+
+    fclose(fp);
+    return res;
+}
+
+
+#ifdef DM_USE_LIBPNG
+static BOOL dmWritePNGRow(void *cbdata, Uint8 *row, size_t len)
+{
+    png_structp png_ptr = cbdata;
+    (void) len;
+
+    if (setjmp(png_jmpbuf(png_ptr)))
+        return FALSE;
+
+    png_write_row(png_ptr, row);
+
+    return TRUE;
+}
+
+
+int dmWritePNGImageFILE(FILE *fp, DMImage *img, DMImageSpec *spec)
+{
+    png_structp png_ptr = NULL;
+    png_infop info_ptr = NULL;
+    png_colorp palette = NULL;
+    int fmt, res = DMERR_OK;
+
+    // Create PNG structures
+    png_ptr = png_create_write_struct(
+        PNG_LIBPNG_VER_STRING,
+        NULL, NULL, NULL);
+
+    if (png_ptr == NULL)
+    {
+        dmError("PNG: png_create_write_struct() failed.\n");
+        res = DMERR_MALLOC;
+        goto error;
+    }
+    
+    info_ptr = png_create_info_struct(png_ptr);
+    if (info_ptr == NULL)
+    {
+        dmError("PNG: png_create_info_struct(%p) failed.\n", png_ptr);
+        res = DMERR_INIT_FAIL;
+        goto error;
+    }
+    
+    if (setjmp(png_jmpbuf(png_ptr)))
+    {
+        dmError("PNG: Error during image writing..\n");
+        res = DMERR_INIT_FAIL;
+        goto error;
+    }
+
+    png_init_io(png_ptr, fp);
+
+    // Write PNG header info
+    switch (spec->format)
+    {
+        case DM_IFMT_PALETTE: fmt = PNG_COLOR_TYPE_PALETTE; break;
+        case DM_IFMT_RGB    : fmt = PNG_COLOR_TYPE_RGB; break;
+        case DM_IFMT_RGBA   : fmt = PNG_COLOR_TYPE_RGB_ALPHA; break;
+        default:
+            dmError("PNG: Internal error, unsupported image format %d.\n", spec->format);
+            goto error;
+    }
+ 
+    png_set_IHDR(png_ptr, info_ptr,
+        img->width * spec->scale,
+        img->height * spec->scale,
+        8,                    /* bits per component */
+        fmt,
+        PNG_INTERLACE_NONE,
+        PNG_COMPRESSION_TYPE_DEFAULT,
+        PNG_FILTER_TYPE_DEFAULT);
+
+    // Palette
+    if (spec->format == DM_IFMT_PALETTE)
+    {
+        int i;
+
+        palette = png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH * sizeof(png_color));
+        if (palette == NULL)
+        {
+            dmError("PNG: Could not allocate palette structure.");
+            goto error;
+        }
+        
+        memset(palette, 0, PNG_MAX_PALETTE_LENGTH * sizeof(png_color));
+
+        for (i = 0; i < img->ncolors; i++)
+        {
+            palette[i].red   = img->pal[i].r;
+            palette[i].green = img->pal[i].g;
+            palette[i].blue  = img->pal[i].b;
+        }
+
+        png_set_PLTE(png_ptr, info_ptr, palette, PNG_MAX_PALETTE_LENGTH);
+    }
+
+//    png_set_gAMA(png_ptr, info_ptr, 2.2);
+
+    png_write_info(png_ptr, info_ptr);
+
+
+    // Write compressed image data
+    dmWriteImageData(img, (void *) png_ptr, dmWritePNGRow, spec);
+
+    // Write footer
+    png_write_end(png_ptr, NULL);
+
+error:
+    png_free(png_ptr, palette);
+    palette = NULL;
+
+    if (png_ptr && info_ptr)
+        png_destroy_write_struct(&png_ptr, &info_ptr);
+
+    return res;
+}
+
+
+int dmWritePNGImage(const char *filename, DMImage *img, DMImageSpec *spec)
+{
+    int res;
+    FILE *fp;
+
+    if ((fp = fopen(filename, "wb")) == NULL)
+    {
+        dmError("PNG: could not open file '%s' for writing.\n", filename);
+        return DMERR_FOPEN;
+    }
+
+    res = dmWritePNGImageFILE(fp, img, spec);
+
+    fclose(fp);
+    return res;
+}
+#endif
+
+
+typedef struct
+{
+    Uint8 r,g,b;
+} DMPCXColor;
+
+
+typedef struct
+{
+    Uint8 manufacturer,
+            version,
+            encoding,
+            bpp;
+    Uint16 xmin, ymin, xmax, ymax;
+    Uint16 hres, vres;
+    DMPCXColor colormap[16];
+    Uint8 reserved;
+    Uint8 nplanes;
+    Uint16 bpl;
+    Uint16 palinfo;
+    Uint8 filler[58];
+} DMPCXHeader;
+
+
+typedef struct
+{
+    DMPCXHeader *header;
+    Uint8 *buf;
+    size_t bufLen, bufOffs;
+    int format;
+    FILE *fp;
+} DMPCXData;
+
+
+static inline Uint8 dmPCXGetByte(Uint8 *row, const size_t len, const size_t soffs)
+{
+    return (soffs < len) ? row[soffs] : 0;
+}
+
+static BOOL dmPCXFlush(DMPCXData *pcx)
+{
+    BOOL ret = TRUE;
+    if (pcx->bufOffs > 0)
+        ret = fwrite(pcx->buf, sizeof(Uint8), pcx->bufOffs, pcx->fp) == pcx->bufOffs;
+    pcx->bufOffs = 0;
+    return ret;
+}
+
+static inline BOOL dmPCXPutByte(DMPCXData *pcx, const Uint8 val)
+{
+    if (pcx->bufOffs < pcx->bufLen)
+    {
+        pcx->buf[pcx->bufOffs++] = val;
+        return TRUE;
+    }
+    else
+        return dmPCXFlush(pcx);
+}
+
+static BOOL dmWritePCXRow(void *cbdata, Uint8 *row, size_t len)
+{
+    DMPCXData *pcx = (DMPCXData *) cbdata;
+    int plane;
+    size_t soffs = 0;
+    
+//    fprintf(stderr, "%d, %d * %d = %d\n", len, pcx->header->bpl, pcx->header->nplanes, pcx->header->nplanes * pcx->header->bpl);
+
+    pcx->bufOffs = 0;
+
+    for (plane = 0; plane < pcx->header->nplanes; plane++)
+    {
+        Uint8 data = dmPCXGetByte(row, len, soffs++),
+              count = 1;
+
+//        size_t blen = pcx->header->bpl * pcx->header->nplanes;
+        size_t blen = pcx->header->bpl;
+        while (soffs < blen)
+        {
+            if (data == dmPCXGetByte(row, len, soffs) && count < 63)
+            {
+                count++;
+                soffs++;
+            }
+            else
+            {
+                if (count == 1 && (data & 0xC0) != 0xC0)
+                {
+                    if (!dmPCXPutByte(pcx, data))
+                        return FALSE;
+                }
+                else
+                {
+                    if (!dmPCXPutByte(pcx, 0xC0 | count) ||
+                        !dmPCXPutByte(pcx, data))
+                        return FALSE;
+                }
+
+                data = dmPCXGetByte(row, len, soffs++);
+                count = 1;
+            }
+        }
+
+        if (count > 1)
+        {
+            if (!dmPCXPutByte(pcx, 0xC0 | count) ||
+                !dmPCXPutByte(pcx, data))
+                return FALSE;
+        }
+
+        if (!dmPCXFlush(pcx))
+            return FALSE;
+    }
+
+
+    return TRUE;
+}
+
+
+int dmWritePCXImageFILE(FILE *fp, DMImage *img, DMImageSpec *spec)
+{
+    DMPCXData pcx;
+    DMPCXHeader hdr;
+    int res;
+
+    // Create output file
+    pcx.buf    = NULL;
+    pcx.format = spec->paletted ? DM_IFMT_PALETTE : DM_IFMT_RGB_PLANE;
+    pcx.header = &hdr;
+    pcx.fp     = fp;
+
+    // Create PCX header
+    memset(&hdr, 0, sizeof(hdr));
+    if (spec->paletted)
+    {
+        int i;
+        for (i = 0; i < (img->ncolors > 16 ? 16 : img->ncolors); i++)
+        {
+            hdr.colormap[i].r = img->pal[i].r;
+            hdr.colormap[i].g = img->pal[i].g;
+            hdr.colormap[i].b = img->pal[i].b;
+        }
+    }
+    hdr.manufacturer = 10;
+    hdr.version      = 5;
+    hdr.encoding     = 1;
+    hdr.bpp          = 8;
+    hdr.hres         = img->width * spec->scale;
+    hdr.vres         = img->height * spec->scale;
+    hdr.xmin         = hdr.ymin = 0;
+    hdr.xmax         = hdr.hres - 1;
+    hdr.ymax         = hdr.vres - 1;
+    hdr.nplanes      = dmImageGetBytesPerPixel(pcx.format);
+    hdr.palinfo      = 1;
+
+    res = (img->width * spec->scale);
+    hdr.bpl = res / 2;
+    if (res % 2) hdr.bpl++;
+    hdr.bpl *= 2;
+
+    dmMsg(2, "PCX: paletted=%d, nplanes=%d, bpp=%d, bpl=%d\n",
+        spec->paletted, hdr.nplanes, hdr.bpp, hdr.bpl);
+
+    pcx.bufLen       = hdr.bpl * 4;
+    if ((pcx.buf = dmMalloc(pcx.bufLen)) == NULL)
+    {
+        dmError("PCX: Could not allocate %d bytes for RLE compression buffer.\n",
+            pcx.bufLen);
+        res = DMERR_MALLOC;
+        goto error;
+    }
+
+    // Write PCX header
+    if (!dm_fwrite_byte(pcx.fp, hdr.manufacturer) ||
+        !dm_fwrite_byte(pcx.fp, hdr.version) ||
+        !dm_fwrite_byte(pcx.fp, hdr.encoding) ||
+        !dm_fwrite_byte(pcx.fp, hdr.bpp))
+    {
+        dmError("PCX: Could not write basic header data.\n");
+        res = DMERR_FWRITE;
+        goto error;
+    }
+    
+    if (!dm_fwrite_le16(pcx.fp, hdr.xmin) ||
+        !dm_fwrite_le16(pcx.fp, hdr.ymin) ||
+        !dm_fwrite_le16(pcx.fp, hdr.xmax) ||
+        !dm_fwrite_le16(pcx.fp, hdr.ymax) ||
+        !dm_fwrite_le16(pcx.fp, hdr.hres) ||
+        !dm_fwrite_le16(pcx.fp, hdr.vres))
+    {
+        dmError("PCX: Could not write image dimensions.\n");
+        res = DMERR_FWRITE;
+        goto error;
+    }
+
+    if (!dm_fwrite_str(pcx.fp, (Uint8 *) &hdr.colormap, sizeof(hdr.colormap)))
+    {
+        dmError("PCX: Could not write colormap.\n");
+        res = DMERR_FWRITE;
+        goto error;
+    }
+    
+    if (!dm_fwrite_byte(pcx.fp, hdr.reserved) ||
+        !dm_fwrite_byte(pcx.fp, hdr.nplanes) ||
+        !dm_fwrite_le16(pcx.fp, hdr.bpl) ||
+        !dm_fwrite_le16(pcx.fp, hdr.palinfo) ||
+        !dm_fwrite_str(pcx.fp, (Uint8 *) &hdr.filler, sizeof(hdr.filler)))
+    {
+        dmError("PCX: Could not write header remainder.\n");
+        res = DMERR_FWRITE;
+        goto error;
+    }
+
+    // Write image data
+    res = dmWriteImageData(img, (void *) &pcx, dmWritePCXRow, spec);
+
+    // Write VGA palette
+    if (spec->paletted)
+    {
+        int i;
+        dm_fwrite_byte(pcx.fp, 0x0C);
+        dmMsg(2, "PCX: Writing palette of %d active entries.\n", img->ncolors);
+
+        for (i = 0; i < img->ncolors; i++)
+        {
+            dm_fwrite_byte(pcx.fp, img->pal[i].r);
+            dm_fwrite_byte(pcx.fp, img->pal[i].g);
+            dm_fwrite_byte(pcx.fp, img->pal[i].b);
+        }
+
+        // Pad the palette, if necessary        
+        for (; i < 256; i++)
+        {
+            dm_fwrite_byte(pcx.fp, 0);
+            dm_fwrite_byte(pcx.fp, 0);
+            dm_fwrite_byte(pcx.fp, 0);
+        }
+    }
+    
+error:
+    dmFree(pcx.buf);
+    return res;
+}
+
+
+int dmWritePCXImage(const char *filename, DMImage *img, DMImageSpec *spec)
+{
+    FILE *fp;
+    int res;
+
+    if ((fp = fopen(filename, "wb")) == NULL)
+    {
+        dmError("PCX: Could not open file '%s' for writing.\n", filename);
+        return DMERR_FOPEN;
+    }
+    
+    res = dmWritePCXImageFILE(fp, img, spec);
+    
+    fclose(fp);
+    return res;
+}
+
+
+static BOOL dmPCXDecodeRLERow(FILE *fp, Uint8 *buf, const size_t bufLen)
+{
+    size_t offs = 0;
+    do
+    {
+        int count;
+        Uint8 data;
+
+        if (!dm_fread_byte(fp, &data))
+            return FALSE;
+        
+        if ((data & 0xC0) == 0xC0)
+        {
+            count = data & 0x3F;
+            if (!dm_fread_byte(fp, &data))
+                return FALSE;
+        }
+        else
+            count = 1;
+
+        while (count-- && offs < bufLen)
+            buf[offs++] = data;
+
+    } while (offs < bufLen);
+
+    return TRUE;
+}
+
+
+int dmReadPCXImageFILE(FILE *fp, DMImage **pimg)
+{
+    DMImage *img;
+    DMPCXData pcx;
+    DMPCXHeader hdr;
+    BOOL paletted;
+    int res = 0, yc, xc;
+    Uint8 *dp;
+
+    pcx.buf = NULL;
+
+    // Read PCX header
+    if (!dm_fread_byte(fp, &hdr.manufacturer) ||
+        !dm_fread_byte(fp, &hdr.version) ||
+        !dm_fread_byte(fp, &hdr.encoding) ||
+        !dm_fread_byte(fp, &hdr.bpp))
+    {
+        dmError("PCX: Could not read basic header data.\n");
+        res = DMERR_FREAD;
+        goto error;
+    }
+    
+    if (hdr.manufacturer != 10 ||
+        hdr.version != 5 ||
+        hdr.encoding != 1 ||
+        hdr.bpp != 8)
+    {
+        dmError("PCX: Not a PCX file, or unsupported variant.\n");
+        res = DMERR_FREAD;
+        goto error;
+    }
+    
+    if (!dm_fread_le16(fp, &hdr.xmin) ||
+        !dm_fread_le16(fp, &hdr.ymin) ||
+        !dm_fread_le16(fp, &hdr.xmax) ||
+        !dm_fread_le16(fp, &hdr.ymax) ||
+        !dm_fread_le16(fp, &hdr.hres) ||
+        !dm_fread_le16(fp, &hdr.vres))
+    {
+        dmError("PCX: Could not read image dimensions.\n");
+        res = DMERR_FREAD;
+        goto error;
+    }
+
+    if (!dm_fread_str(fp, (Uint8 *) &hdr.colormap, sizeof(hdr.colormap)))
+    {
+        dmError("PCX: Could not read colormap.\n");
+        res = DMERR_FREAD;
+        goto error;
+    }
+    
+    if (!dm_fread_byte(fp, &hdr.reserved) ||
+        !dm_fread_byte(fp, &hdr.nplanes) ||
+        !dm_fread_le16(fp, &hdr.bpl) ||
+        !dm_fread_le16(fp, &hdr.palinfo) ||
+        !dm_fread_str(fp, (Uint8 *) &hdr.filler, sizeof(hdr.filler)))
+    {
+        dmError("PCX: Could not read header remainder.\n");
+        res = DMERR_FREAD;
+        goto error;
+    }
+    
+    if (hdr.nplanes != 3 && hdr.nplanes != 1)
+    {
+        dmError("PCX: Unsupported number of bitplanes %d.\n", hdr.nplanes);
+        res = DMERR_FREAD;
+        goto error;
+    }
+
+    // Allocate image
+    if ((*pimg = img = dmImageAlloc(hdr.xmax - hdr.xmin + 1, hdr.ymax - hdr.ymin + 1)) == NULL)
+    {
+        dmError("PCX: Could not allocate image structure.\n");
+        res = DMERR_MALLOC;
+        goto error;
+    }
+
+    paletted = hdr.nplanes == 1;
+    pcx.bufLen = hdr.nplanes * hdr.bpl;
+    if ((pcx.buf = dmMalloc(pcx.bufLen)) == NULL)
+    {
+        dmError("PCX: Could not allocate RLE buffer.\n");
+        res = DMERR_MALLOC;
+        goto error;
+    }
+
+    // Read image data
+    dp = img->data;
+    for (yc = 0; yc < img->height; yc++)
+    {
+        // Decode row of RLE'd data
+        if (!dmPCXDecodeRLERow(fp, pcx.buf, pcx.bufLen))
+        {
+            dmError("PCX: Error decoding RLE data.\n");
+            res = DMERR_INVALID_DATA;
+            goto error;
+        }
+        
+        // Decode bitplanes
+        switch (hdr.nplanes)
+        {
+            case 1:
+                memcpy(dp, pcx.buf, img->width);
+                break;
+            
+            case 3:
+                {
+                    Uint8 *dptr = dp,
+                            *sptr1 = pcx.buf,
+                            *sptr2 = sptr1 + hdr.bpl,
+                            *sptr3 = sptr2 + hdr.bpl;
+
+                    for (xc = 0; xc < img->width; xc++)
+                    {
+                        *dptr++ = *sptr1++;
+                        *dptr++ = *sptr2++;
+                        *dptr++ = *sptr3++;
+                    }
+                }
+                break;
+        }
+        
+        dp += img->pitch;
+    }
+
+    // Read VGA palette
+    if (paletted)
+    {
+        int i;
+        Uint8 tmpb;
+        BOOL read;
+
+        if (!dm_fread_byte(fp, &tmpb) || tmpb != 0x0C)
+        {
+            read = FALSE;
+            img->ncolors = 16;
+        }
+        else
+        {
+            read = TRUE;
+            img->ncolors = 256;
+        }
+
+        if ((img->pal = dmCalloc(img->ncolors, sizeof(DMColor))) == NULL)
+        {
+            dmError("PCX: Could not allocate palette data!\n");
+            res = DMERR_MALLOC;
+            goto error;
+        }
+        
+        if (read)
+        {
+            for (i = 0; i < img->ncolors; i++)
+            {
+                Uint8 tmpR, tmpG, tmpB;
+                if (!dm_fread_byte(fp, &tmpR) ||
+                    !dm_fread_byte(fp, &tmpG) ||
+                    !dm_fread_byte(fp, &tmpB))
+                    goto error;
+
+                img->pal[i].r = tmpR;
+                img->pal[i].g = tmpG;
+                img->pal[i].b = tmpB;
+            }
+        }
+        else
+        {
+            for (i = 0; i < img->ncolors; i++)
+            {
+                if (i < 16)
+                {
+                    img->pal[i].r = hdr.colormap[i].r;
+                    img->pal[i].g = hdr.colormap[i].g;
+                    img->pal[i].b = hdr.colormap[i].b;
+                }
+            }
+        }
+        
+
+    }
+
+error:
+    dmFree(pcx.buf);
+    return res;
+}
+
+
+int dmReadPCXImage(const char *filename, DMImage **pimg)
+{
+    FILE *fp;
+    int res;
+
+    if ((fp = fopen(filename, "rb")) == NULL)
+    {
+        dmError("PCX: Could not open file '%s' for reading.\n", filename);
+        return -15;
+    }
+    
+    res = dmReadPCXImageFILE(fp, pimg);
+
+    fclose(fp);
+    return res;
+}
+
+
+static int fmtProbePNG(const Uint8 *buf, const size_t len)
+{
+    if (len > 64 && buf[0] == 0x89 &&
+        buf[1] == 'P' && buf[2] == 'N' && buf[3] == 'G' &&
+        buf[4] == 0x0d && buf[5] == 0x0a)
+        return DM_PROBE_SCORE_GOOD;
+
+    return DM_PROBE_SCORE_FALSE;
+}
+
+
+static int fmtProbePCX(const Uint8 *buf, const size_t len)
+{
+    if (len > 128 + 64 &&
+        buf[0] == 10 &&
+        buf[1] == 5 &&
+        buf[2] == 1 &&
+        buf[3] == 8)
+        return DM_PROBE_SCORE_GOOD;
+
+    return DM_PROBE_SCORE_FALSE;
+}
+
+
+DMImageFormat dmImageFormatList[IMGFMT_LAST] =
+{
+    {
+        "PNG", "Portable Network Graphics",
+        fmtProbePNG,
+        NULL, NULL,
+#ifdef DM_USE_LIBPNG
+        dmWritePNGImage, dmWritePNGImageFILE,
+#else
+        NULL, NULL,
+#endif
+    },
+    {
+        "PPM", "Portable PixMap",
+        NULL,
+        NULL, NULL,
+        dmWritePPMImage, dmWritePPMImageFILE,
+    },
+    {
+        "PCX", "Z-Soft Paintbrush",
+        fmtProbePCX,
+        dmReadPCXImage, dmReadPCXImageFILE,
+        dmWritePCXImage, dmWritePCXImageFILE,
+    },
+    {
+        "ARAW", "IFFMaster Amiga RAW",
+        NULL,
+        NULL, NULL,
+        dmWriteIFFMasterRAWImage, dmWriteIFFMasterRAWImageFILE,
+    }
+};
+
+
+int dmImageProbeGeneric(const Uint8 *buf, const size_t len, DMImageFormat **pfmt, int *index)
+{
+    int i, scoreMax = DM_PROBE_SCORE_FALSE, scoreIndex = -1;
+
+    for (i = 0; i < IMGFMT_LAST; i++)
+    {
+        DMImageFormat *fmt = &dmImageFormatList[i];
+        int score = fmt->probe(buf, len);
+        if (score > scoreMax)
+        {
+            scoreMax = score;
+            scoreIndex = i;
+        }
+    }
+
+    if (scoreIndex >= 0)
+    {
+        *pfmt = &dmImageFormatList[scoreIndex];
+        *index = scoreIndex;
+        return scoreMax;
+    }
+    else
+        return DM_PROBE_SCORE_FALSE;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgfx.h	Sat Nov 03 16:08:30 2012 +0200
@@ -0,0 +1,117 @@
+/*
+ * Functions for loading and saving bitmap images
+ * Programmed and designed by Matti 'ccr' Hamalainen
+ * (C) Copyright 2012 Tecnic Software productions (TNSP)
+ *
+ * Please read file 'COPYING' for information on license and distribution.
+ */
+#ifndef LIBMGFX_H
+#define LIBMGFX_H 1
+
+#include "dmlib.h"
+#include "dmfile.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+enum
+{
+    IMGFMT_PNG,
+    IMGFMT_PPM,
+    IMGFMT_PCX,
+    IMGFMT_ARAW,
+
+    IMGFMT_LAST
+};
+
+
+enum
+{
+    DM_IFMT_PALETTE,
+    DM_IFMT_RGB,
+    DM_IFMT_RGBA,
+    DM_IFMT_RGB_PLANE,
+};
+
+
+// RGBx color struct
+typedef struct
+{
+    Uint8 r, g, b, x;
+} DMColor;
+
+
+// Bitmapped image struct (can be one of types specified by DM_IFMT_*)
+typedef struct
+{
+    int width, height, pitch;
+    BOOL constpal;
+    int ncolors, ctrans;
+    DMColor *pal;
+    Uint8 *data;
+} DMImage;
+
+
+typedef struct
+{
+    int scale, nplanes, format;
+    BOOL interleave, paletted;
+} DMImageSpec;
+
+
+typedef struct
+{
+    char *fext;
+    char *desc;
+    int  (*probe)(const Uint8 *buf, const size_t len);
+    int  (*read)(const char *filename, DMImage **pimg);
+    int  (*readFILE)(FILE *fp, DMImage **pimg);
+    int  (*write)(const char *filename, DMImage *pimg, DMImageSpec *spec);
+    int  (*writeFILE)(FILE *fp, DMImage *pimg, DMImageSpec *spec);
+} DMImageFormat;
+
+
+// Probe scores
+#define DM_PROBE_SCORE_MAX     1000
+#define DM_PROBE_SCORE_GOOD    750
+#define DM_PROBE_SCORE_AVG     500
+#define DM_PROBE_SCORE_MAYBE   250
+#define DM_PROBE_SCORE_FALSE   0
+
+
+extern DMImageFormat dmImageFormatList[IMGFMT_LAST];
+
+
+DMImage * dmImageAlloc(int width, int height);
+void      dmImageFree(DMImage *img);
+int       dmImageGetBytesPerPixel(int format);
+int       dmImageProbeGeneric(const Uint8 *buf, const size_t len, DMImageFormat **fmt, int *index);
+
+
+int dmWriteImageData(DMImage *img, void *cbdata, BOOL (*writeRowCB)(void *, Uint8 *, size_t), const DMImageSpec *spec);
+
+int dmWriteIFFMasterRAWPalette(const char *filename, DMImage *img, int ncolors);
+int dmWriteIFFMasterRAWImageFILE(FILE *fp, DMImage *img, DMImageSpec *spec);
+int dmWriteIFFMasterRAWImage(const char *filename, DMImage *img, DMImageSpec *spec);
+
+int dmWritePPMImageFILE(FILE *fp, DMImage *img, DMImageSpec *spec);
+int dmWritePPMImage(const char *filename, DMImage *img, DMImageSpec *spec);
+
+#ifdef DM_USE_LIBPNG
+int dmWritePNGImageFILE(FILE *fp, DMImage *img, DMImageSpec *spec);
+int dmWritePNGImage(const char *filename, DMImage *img, DMImageSpec *spec);
+#endif
+
+int dmWritePCXImageFILE(FILE *fp, DMImage *img, DMImageSpec *spec);
+int dmWritePCXImage(const char *filename, DMImage *img, DMImageSpec *spec);
+int dmReadPCXImageFILE(FILE *fp, DMImage **pimg);
+int dmReadPCXImage(const char *filename, DMImage **pimg);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // LIBMGFX_H