changeset 419:936bc27a79d6

Modularize some functions to lib64gfx, fix bitmap -> image conversion, and implement various cleanups.
author Matti Hamalainen <ccr@tnsp.org>
date Sat, 03 Nov 2012 07:53:38 +0200
parents b6a1dc3bd2c3
children 8d15443ce209
files gfxconv.c lib64gfx.c lib64gfx.h view64.c
diffstat 4 files changed, 420 insertions(+), 263 deletions(-) [+]
line wrap: on
line diff
--- a/gfxconv.c	Sat Nov 03 07:52:26 2012 +0200
+++ b/gfxconv.c	Sat Nov 03 07:53:38 2012 +0200
@@ -15,51 +15,97 @@
 
 //#define UNFINISHED 1
 
-#ifdef HAVE_LIBPNG
+#ifdef DM_USE_LIBPNG
 #include <png.h>
 #endif
 
 enum
 {
-    INFMT_AUTO = 0,
-    INFMT_CHAR,
-    INFMT_SPRITE,
-    INFMT_BITMAP,
-    INFMT_IMAGE,
+    IMGFMT_PNG,
+    IMGFMT_PPM,
+    IMGFMT_PCX,
+    IMGFMT_ARAW,
+
+    IMGFMT_LAST
+};
+
+static const char *imageFormatList[IMGFMT_LAST] =
+{
+    "PNG",
+    "PPM",
+    "PCX",
+    "ARAW",
 };
 
 enum
 {
-    OUTFMT_ASCII,
-    OUTFMT_ANSI,
-    OUTFMT_PNG,
-    OUTFMT_PPM,
-    OUTFMT_PCX,
-    OUTFMT_ARAW,
+    FFMT_AUTO = 0,
+
+    FFMT_ASCII,
+    FFMT_ANSI,
+    FFMT_IMAGE,
 
-#ifdef UNFINISHED
-    OUTFMT_SPRITE,
-    OUTFMT_CHAR,
-#endif
+    FFMT_CHAR,
+    FFMT_SPRITE,
+    FFMT_BITMAP,
 
-    OUTFMT_LAST
+    FFMT_LAST
 };
 
-char * outFormatList[OUTFMT_LAST] =
+
+typedef struct
+{
+    char *name;
+    char *fext;
+    BOOL in, out;
+    int format;
+    int subformat;
+} DMConvFormat;
+
+
+static DMConvFormat convFormatList[] =
 {
-    "ascii",
-    "ansi",
-    "png",
-    "ppm",
-    "pcx",
-    "araw",
-#ifdef UNFINISHED
-    "spr",
-    "char",
-#endif
+    {
+        "ASCII text", "asc", FALSE, TRUE,
+        FFMT_ASCII  , 0,
+    },
+    {
+        "ANSI colored text", "ansi", FALSE, TRUE,
+        FFMT_ANSI   , 0,
+    },
+    {
+        "PNG image file", "png", FALSE, TRUE,
+        FFMT_IMAGE  , IMGFMT_PNG,
+    },
+    {
+        "PPM image file", "ppm", FALSE, TRUE,
+        FFMT_IMAGE  , IMGFMT_PPM,
+    },
+    {
+        "PCX image file", "pcx", TRUE, TRUE,
+        FFMT_IMAGE  , IMGFMT_PCX,
+    },
+    {
+        "IFFMaster RAW image file", "araw", FALSE, TRUE,
+        FFMT_IMAGE  , IMGFMT_ARAW,
+    },
+
+    {
+        "C64 bitmap image file", NULL, TRUE, FALSE,
+        FFMT_BITMAP , 0,
+    },
+
+    {
+        "C64 character/font data", "chr", TRUE, FALSE,
+        FFMT_CHAR   , 0
+    },
+    {
+        "C64 sprite data", "spr", TRUE, FALSE,
+        FFMT_SPRITE , 0
+    },
 };
 
-static const int noutFormatList = sizeof(outFormatList) / sizeof(outFormatList[0]);
+static const int nconvFormatList = sizeof(convFormatList) / sizeof(convFormatList[0]);
 
 
 #define ASC_NBITS    8
@@ -69,11 +115,14 @@
 
 char    *optInFilename = NULL,
         *optOutFilename = NULL;
-int     optInFormat = INFMT_AUTO,
-        optOutFormat = OUTFMT_ASCII,
+int     optInFormat = FFMT_AUTO,
+        optOutFormat = FFMT_ASCII,
+        optInSubFormat = IMGFMT_PNG,
+        optOutSubFormat = IMGFMT_PNG,
         optItemCount = -1,
         optScale = 2,
         optPlanedWidth = 1,
+        optForcedFormat = -1,
         optBPP = 4;
 int     optInSkip = 0;
 BOOL    optInMulticolor = FALSE,
@@ -86,6 +135,7 @@
 static DMOptArg optList[] =
 {
     { 0, '?', "help",         "Show this help", OPT_NONE },
+    {15, 'v', "verbose",      "Increase verbosity", OPT_NONE },
     { 3, 'o', "output",       "Output filename", OPT_ARGREQ },
     { 1, 'i', "informat",     "Set input format ([s]prite, [c]har, [b]itmap, [i]mage)", OPT_ARGREQ },
     { 2, 'm', "multicolor",   "Input is multicolor", OPT_NONE },
@@ -95,9 +145,7 @@
     { 6, 'c', "colormap",     "Color mappings (see below for information)", OPT_ARGREQ },
     { 7, 'n', "numitems",     "How many 'items' to view (default: all)", OPT_ARGREQ },
     { 9, 'S', "scale",        "Scale output by x (image output only)", OPT_ARGREQ },
-#ifdef UNFINISHED
     {10, 'b', "bformat",      "Force input bitmap format (see below)", OPT_ARGREQ },
-#endif
     {11, 'w', "width",        "Item width (number of items per row, min 1)", OPT_ARGREQ },
     {12, 'P', "paletted",     "Use indexed/paletted output (png, pcx output only)", OPT_NONE },
     {13, 'b', "bplanes",      "Bits per pixel OR # of bitplanes (certain output formats)", OPT_ARGREQ },
@@ -114,27 +162,23 @@
     dmPrintBanner(stdout, dmProgName, "[options] <input file>");
     dmArgsPrintHelp(stdout, optList, optListN);
 
-    printf("\nAvailable output formats: ");
-    for (i = 0; i < noutFormatList; i++)
+    printf("\nAvailable output formats:\n");
+    for (i = 0; i < nconvFormatList; i++)
     {
-        printf("%s", outFormatList[i]);
-        if (i < noutFormatList - 1)
-            printf(", ");
-        else
-            printf("\n");
+        DMConvFormat *fmt = &convFormatList[i];
+        printf("%3d | %-5s | %s\n",
+            i, fmt->fext, fmt->name);
     }
 
-#ifdef UNFINISHED
     printf("\nAvailable bitmap formats:\n");
     for (i = 0; i < ndmC64ImageFormats; i++)
     {
-        DM64ImageFormat *fmt = &dmC64ImageFormats[i];
+        DMC64ImageFormat *fmt = &dmC64ImageFormats[i];
         printf("%3d | %-5s | %-15s | %s\n",
             i, fmt->extension,
             dmC64ImageTypeNames[fmt->type],
             fmt->name);
     }
-#endif
 
     printf(
     "\n"
@@ -149,6 +193,37 @@
 }
 
 
+int dmGetConvFormat(int format, int subformat)
+{
+    int i;
+    for (i = 0; i < nconvFormatList; i++)
+    {
+        DMConvFormat *fmt = &convFormatList[i];
+        if (fmt->format == format &&
+            fmt->subformat == subformat)
+            return i;
+    }
+    return -1;
+}
+
+
+BOOL dmGetFormatByExt(const char *fext, int *format, int *subformat)
+{
+    int i;
+    for (i = 0; i < nconvFormatList; i++)
+    {
+        DMConvFormat *fmt = &convFormatList[i];
+        if (strcasecmp(fext, fmt->fext) == 0)
+        {
+            *format = fmt->format;
+            *subformat = fmt->subformat;
+            return TRUE;
+        }
+    }
+    return FALSE;
+}
+
+
 BOOL argHandleOpt(const int optN, char *optArg, char *currArg)
 {
     switch (optN)
@@ -158,20 +233,24 @@
             exit(0);
             break;
 
+        case 15:
+            dmVerbosity++;
+            break;
+
         case 1:
             switch (tolower(optArg[0]))
             {
                 case 's':
-                    optInFormat = INFMT_SPRITE;
+                    optInFormat = FFMT_SPRITE;
                     break;
                 case 'c':
-                    optInFormat = INFMT_CHAR;
+                    optInFormat = FFMT_CHAR;
                     break;
                 case 'b':
-                    optInFormat = INFMT_BITMAP;
+                    optInFormat = FFMT_BITMAP;
                     break;
                 case 'i':
-                    optInFormat = INFMT_IMAGE;
+                    optInFormat = FFMT_IMAGE;
                     break;
                 default:
                     dmError("Invalid input format '%s'.\n", optArg);
@@ -196,22 +275,10 @@
             break;
 
         case 5:
+            if (!dmGetFormatByExt(optArg, &optOutFormat, &optOutSubFormat))
             {
-                int i, format = -1;
-                for (i = 0; i < noutFormatList; i++)
-                if (strcasecmp(optArg, outFormatList[i]) == 0)
-                {
-                    format = i;
-                    break;
-                }
-                
-                if (format < 0)
-                {
-                    dmError("Invalid output format '%s'.\n", optArg);
-                    return FALSE;
-                }
-                
-                optOutFormat = format;
+                dmError("Invalid output format '%s'.\n", optArg);
+                return FALSE;
             }
             break;
 
@@ -337,11 +404,11 @@
             char ch;
             switch (format)
             {
-                case OUTFMT_ASCII:
+                case FFMT_ASCII:
                     ch = dmASCIIPalette[val];
                     fprintf(out, "%c%c", ch, ch);
                     break;
-                case OUTFMT_ANSI:
+                case FFMT_ANSI:
                     fprintf(out, "%c[0;%d;%dm##%c[0m",
                         0x1b,
                         1,
@@ -359,11 +426,11 @@
             char ch;
             switch (format)
             {
-                case OUTFMT_ASCII:
+                case FFMT_ASCII:
                     ch = val ? '#' : '.';
                     fputc(ch, out);
                     break;
-                case OUTFMT_ANSI:
+                case FFMT_ANSI:
                     fprintf(out, "%c[0;%d;%dm %c[0m",
                         0x1b,
                         1,
@@ -633,7 +700,7 @@
 }
 
 
-#ifdef HAVE_LIBPNG
+#ifdef DM_USE_LIBPNG
 static BOOL dmWritePNGRow(void *cbdata, Uint8 *row, size_t len)
 {
     png_structp png_ptr = cbdata;
@@ -912,10 +979,13 @@
     hdr.xmax         = hdr.hres - 1;
     hdr.ymax         = hdr.vres - 1;
     hdr.nplanes      = dmImageGetBytesPerPixel(pcx.format);
-    hdr.bpl          = (((img->width * scale) / 2) + 1) * 2;
     hdr.palinfo      = 1;
+    res = (img->width * scale);
+    hdr.bpl = res / 2;
+    if (res % 2) hdr.bpl++;
+    hdr.bpl *= 2;
 
-    dmMsg(1, "PCX: paletted=%d, nplanes=%d, bpp=%d, bpl=%d\n",
+    dmMsg(2, "PCX: paletted=%d, nplanes=%d, bpp=%d, bpl=%d\n",
         paletted, hdr.nplanes, hdr.bpp, hdr.bpl);
 
     pcx.bufLen       = hdr.bpl * 4;
@@ -976,6 +1046,7 @@
     {
         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++)
         {
@@ -1251,28 +1322,24 @@
 }
 
 
-int fmtProbePNGImageFILE(FILE *fp)
+static int fmtProbePNG(const Uint8 *buf, const size_t len)
 {
-    Uint8 buf[6];
-//    if (!dm_fread_str(fp, 
+    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;
 }
 
 
-int fmtProbePCXImageFILE(FILE *fp)
+static int fmtProbePCX(const Uint8 *buf, const size_t len)
 {
-    DMPCXHeader hdr;
-
-    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))
-        return DM_PROBE_SCORE_FALSE;
-    
-    if (hdr.manufacturer == 10 &&
-        hdr.version == 5 &&
-        hdr.encoding == 1 &&
-        hdr.bpp == 8)
+    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;
@@ -1321,22 +1388,33 @@
 #endif
 
 
-int dmWriteImage(char *filename, DMImage *image)
+int dmWriteImage(char *filename, DMImage *image, BOOL info)
 {
-    switch (optOutFormat)
+    if (info)
     {
-#ifdef HAVE_LIBPNG
-        case OUTFMT_PNG:
+        dmMsg(1, "Outputting %s image %d x %d -> %d x %d [%d]\n",
+            imageFormatList[optOutSubFormat],
+            image->width, image->height,
+            image->width * optScale, image->height * optScale, optScale);
+    }
+    
+    switch (optOutSubFormat)
+    {
+#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);
 #endif
 
-        case OUTFMT_PPM:
+        case IMGFMT_PPM:
+            if (info) dmMsg(2, "24bit RGB output.\n");
             return dmWritePPMImage(filename, image, optScale);
 
-        case OUTFMT_PCX:
+        case IMGFMT_PCX:
+            if (info) dmMsg(2, "%s output.\n", optPaletted ? "Indexed 8bpp" : "24bit RGB");
             return dmWritePCXImage(filename, image, optScale, optPaletted);
 
-        case OUTFMT_ARAW:
+        case IMGFMT_ARAW:
             {
                 int res;
                 char *palFilename = dm_strdup_printf("%s.pal", filename);
@@ -1345,6 +1423,7 @@
                 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);
             }
 
@@ -1362,18 +1441,20 @@
 
     switch (optInFormat)
     {
-        case INFMT_CHAR:
+        case FFMT_CHAR:
             bufSize = C64_CHR_SIZE;
             outWidth = C64_CHR_WIDTH;
             outWidthPX = C64_CHR_WIDTH_PX;
             outHeight = C64_CHR_HEIGHT;
             break;
-        case INFMT_SPRITE:
+
+        case FFMT_SPRITE:
             bufSize = C64_SPR_SIZE;
             outWidth = C64_SPR_WIDTH;
             outWidthPX = C64_SPR_WIDTH_PX;
             outHeight = C64_SPR_HEIGHT;
             break;
+
         default:
             dmError("Invalid input format %d, internal error.\n", optInFormat);
             return -1;
@@ -1389,7 +1470,7 @@
     dataOffs = optInSkip;
     itemCount = 0;
 
-    if (optOutFormat == OUTFMT_ANSI || optOutFormat == OUTFMT_ASCII)
+    if (optOutFormat == FFMT_ANSI || optOutFormat == FFMT_ASCII)
     {
         BOOL error = FALSE;
         FILE *outFile;
@@ -1420,10 +1501,10 @@
 
             switch (optInFormat)
             {
-                case INFMT_CHAR:
+                case FFMT_CHAR:
                     dmDumpCharASCII(outFile, bufData, &dataOffs, optOutFormat, optInMulticolor);
                     break;
-                case INFMT_SPRITE:
+                case FFMT_SPRITE:
                     dmDumpSpriteASCII(outFile, bufData, &dataOffs, optOutFormat, optInMulticolor);
                     break;
             }
@@ -1433,7 +1514,7 @@
         fclose(outFile);
     }
     else
-    if (optOutFormat == OUTFMT_PNG || optOutFormat == OUTFMT_PPM || optOutFormat == OUTFMT_PCX)
+    if (optOutFormat == IMGFMT_PNG || optOutFormat == IMGFMT_PPM || optOutFormat == IMGFMT_PCX)
     {
         DMImage *outImage = NULL;
         char *outFilename = NULL;
@@ -1468,9 +1549,6 @@
                 outIHeight++;
             
             outImage = dmImageAlloc(outWidthPX * outIWidth, outIHeight * outHeight);
-            dmMsg(1, "Outputting image %d x %d -> %d x %d.\n",
-                outImage->width, outImage->height,
-                outImage->width * optScale, outImage->height * optScale);
         }
 
         outImage->constpal = TRUE;
@@ -1498,14 +1576,14 @@
 
             if (optSequential)
             {
-                outFilename = dm_strdup_printf("%s%04d.%s", optOutFilename, itemCount, outFormatList[optOutFormat]);
+                outFilename = dm_strdup_printf("%s%04d.%s", optOutFilename, itemCount, convFormatList[optOutFormat].fext);
                 if (outFilename == NULL)
                 {
                     dmError("Could not allocate memory for filename template?\n");
                     goto error;
                 }
                 
-                dmWriteImage(outFilename, outImage);
+                dmWriteImage(outFilename, outImage, FALSE);
                 dmFree(outFilename);
             }
             else
@@ -1522,7 +1600,7 @@
 
         if (!optSequential)
         {
-            dmWriteImage(optOutFilename, outImage);
+            dmWriteImage(optOutFilename, outImage, TRUE);
         }
         
         dmImageFree(outImage);
@@ -1540,7 +1618,11 @@
 int main(int argc, char *argv[])
 {
     FILE *inFile;
-    int i, optInImageFormat;
+    DMC64ImageFormat *cfmt;
+    DMC64Image cimage;
+    Uint8 *dataBuf = NULL;
+    size_t dataSize;
+    int i;
 
     // Default colors
     for (i = 0; i < C64_MAX_COLORS; i++)
@@ -1553,36 +1635,30 @@
         argHandleOpt, argHandleFile, TRUE))
         exit(1);
 
-#ifndef HAVE_LIBPNG
-    if (optOutFormat == OUTFMT_PNG)
+#ifndef DM_USE_LIBPNG
+    if (optOutFormat == IMGFMT_PNG)
     {
         dmError("PNG output format support not compiled in, sorry.\n");
-        exit(3);
+        goto error;
     }
 #endif
 
     // Determine input format, if not specified'
-    if (optInFormat == INFMT_AUTO && optInFilename != NULL)
+    if (optInFormat == FFMT_AUTO && optInFilename != NULL)
     {
         char *dext = strrchr(optInFilename, '.');
         if (dext)
         {
-            dext++;
-            if (!strcasecmp(dext, "fnt") || !strcasecmp(dext, "chr"))
-                optInFormat = INFMT_CHAR;
-            else if (!strcasecmp(dext, "spr"))
-                optInFormat = INFMT_SPRITE;
-            else if (!strcasecmp(dext, "png") || !strcasecmp(dext, "pcx"))
-                optInFormat = INFMT_IMAGE;
+            dmGetFormatByExt(dext + 1, &optInFormat, &optInSubFormat);
         }
     }
 
     if (optInFilename == NULL)
     {
-        if (optInFormat == INFMT_AUTO)
+        if (optInFormat == FFMT_AUTO)
         {
             dmError("Standard input cannot be used without specifying input format.\n");
-            exit(3);
+            goto error;
         }
         inFile = stdin;
     }
@@ -1592,49 +1668,53 @@
         int res = errno;
         dmError("Error opening input file '%s'. (%s)\n",
               optInFilename, strerror(res));
-        exit(3);
+        goto error;
     }
 
-    if (optInFormat == INFMT_AUTO)
+    if (dmReadDataFile(inFile, NULL, &dataBuf, &dataSize) != 0)
+        goto error;
+
+    if (optInFormat == FFMT_AUTO || optInFormat == FFMT_BITMAP)
     {
-        // Skip, if needed
-        if (fseek(inFile, optInSkip, SEEK_SET) != 0)
+        // Probe for format
+        DMC64ImageFormat *forced = NULL;
+        int res;
+
+        if (optForcedFormat >= 0)
         {
-            int res = errno;
-            dmError("Could not seek to file position %d (0x%x): %s\n",
-                optInSkip, optInSkip, strerror(res));
-            exit(3);
+            forced = &dmC64ImageFormats[optForcedFormat];
+            dmMsg(0,"Forced %s format image, type %d, %s\n",
+                forced->name, forced->type, forced->extension);
         }
-#if 0
-        if (optInFormat == INFMT_AUTO)
-        {
-            int ret = dmC64ProbeGeneric
-        }
-#endif
 
-        if (optInFormat == INFMT_AUTO || optInFormat == INFMT_IMAGE)
+        res = dmC64DecodeBMP(&cimage, dataBuf, dataSize, optInSkip, optInSkip + 2, &cfmt, forced);
+        if (forced == NULL && cfmt != NULL)
         {
-            if (fmtProbePNGImageFILE(inFile))
-            {
-                optInFormat = INFMT_IMAGE;
-                optInImageFormat = OUTFMT_PNG;
-            }
-            else
-            if (fmtProbePCXImageFILE(inFile))
-            {
-                optInFormat = INFMT_IMAGE;
-                optInImageFormat = OUTFMT_PCX;
-            }
-            else
-            if (optInFormat == INFMT_IMAGE)
-            {
-                dmError("Unsupported image input format.\n");
-                exit(4);
-            }
+            dmMsg(1,"Probed %s format image, type %d, %s\n",
+                cfmt->name, cfmt->type, cfmt->extension);
+        }
+        
+        if (res == 0)
+            optInFormat = FFMT_BITMAP;
+    }
+
+    if (optInFormat == FFMT_AUTO)
+    {
+        // XXX, needs a proper probe loop
+        if (fmtProbePNG(dataBuf + optInSkip, dataSize - optInSkip))
+        {
+            optInFormat = FFMT_IMAGE;
+            optInSubFormat = IMGFMT_PNG;
+        }
+        else
+        if (fmtProbePCX(dataBuf + optInSkip, dataSize - optInSkip))
+        {
+            optInFormat = FFMT_IMAGE;
+            optInSubFormat = IMGFMT_PCX;
         }
     }
 
-    if (optInFormat == INFMT_AUTO)
+    if (optInFormat == FFMT_AUTO)
     {
         dmError("No input format specified, and could not be determined automatically.\n");
         exit(1);
@@ -1646,61 +1726,119 @@
         int res = errno;
         dmError("Could not seek to file position %d (0x%x): %s\n",
             optInSkip, optInSkip, strerror(res));
-        exit(3);
+        goto error;
+    }
+    
+    int inFormat = dmGetConvFormat(optInFormat, optInSubFormat),
+        outFormat = dmGetConvFormat(optOutFormat, optOutSubFormat);
+    
+    if (inFormat != -1 && outFormat != -1)
+    {
+        char *inFmtName = convFormatList[inFormat].name,
+             *inFmtExt = convFormatList[inFormat].fext,
+             *outFmtName = convFormatList[outFormat].name,
+             *outFmtExt = convFormatList[outFormat].fext;
+
+        if (optInFormat == FFMT_BITMAP)
+            inFmtExt = cfmt->name;
+
+        dmMsg(1, "Attempting conversion %s (%s) -> %s (%s)\n",
+            inFmtName, inFmtExt, outFmtName, outFmtExt);
     }
 
     switch (optInFormat)
     {
-        case INFMT_SPRITE:
-        case INFMT_CHAR:
+        case FFMT_SPRITE:
+        case FFMT_CHAR:
             dmDumpSpritesAndChars(inFile);
             break;
         
-        case INFMT_BITMAP:
-        case INFMT_IMAGE:
+        case FFMT_BITMAP:
             {
-                DMImage *img;
-                int res;
+                DMImage *img = NULL;
+                int res = DMERR_OK;
 
                 if (optOutFilename == NULL)
                 {
                     dmError("Output filename not set, required for image formats.\n");
-                    exit(3);
+                    goto error;
+                }
+
+                switch (optOutFormat)
+                {
+                    case FFMT_IMAGE:
+                        if ((img = 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;
+                        
+                        if (cfmt->convert != NULL)
+                            res = cfmt->convert(img, &cimage);
+                        else
+                            res = dmC64ConvertGenericBMP2Image(img, &cimage);
+
+                        if (res != DMERR_OK || img == NULL)
+                        {
+                            dmError("Error in bitmap to image conversion.\n");
+                            goto error;
+                        }
+
+                        res = dmWriteImage(optOutFilename, img, TRUE);
+                        break;
+
+                    default:
+                        dmError("Unsupported output format for bitmap/image conversion.\n");
+                        break;
+                }
+                
+                dmImageFree(img);
+            }
+            break;
+
+        case FFMT_IMAGE:
+            {
+                DMImage *img;
+                int res = DMERR_OK;
+
+                if (optOutFilename == NULL)
+                {
+                    dmError("Output filename not set, required for image formats.\n");
+                    goto error;
                 }
 
                 // Read input
-                switch (optInImageFormat)
+                switch (optInSubFormat)
                 {
-                    case OUTFMT_PCX:
-                        res = dmReadPCXImageFILE(inFile, &img);
-                        break;
-/*
-                    case OUTFMT_PNG:
-                        res = dmReadPNGImageFILE(inFile, &img);
-                        break;
-*/
+                    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;
                     default:
                         dmError("Unsupported input image format for bitmap/image conversion.\n");
                         break;
                     
                 }
 
-                if (res != DMERR_OK)
+                if (res != DMERR_OK || img == NULL)
                     break;
                 
                 switch (optOutFormat)
                 {
-                    case OUTFMT_PCX:
-                    case OUTFMT_PPM:
-                    case OUTFMT_PNG:
-                    case OUTFMT_ARAW:
-                        res = dmWriteImage(optOutFilename, img);
+                    case FFMT_IMAGE:
+                        res = dmWriteImage(optOutFilename, img, TRUE);
                         break;
 
                     default:
                         dmError("Unsupported output format for bitmap/image conversion.\n");
                         break;
                 }
+                
+                dmImageFree(img);
             }
             break;
     }
@@ -1709,4 +1847,8 @@
 
     exit(0);
     return 0;
+
+error:
+    return -3;
+    exit(3);
 }
--- a/lib64gfx.c	Sat Nov 03 07:52:26 2012 +0200
+++ b/lib64gfx.c	Sat Nov 03 07:53:38 2012 +0200
@@ -245,6 +245,8 @@
 
 static BOOL fmtDrazLaceSetLaceType(DMC64Image *img, const struct _DMDecodeOp *op, const Uint8 *buf, const size_t len)
 {
+    (void) len;
+
     img->laceType = buf[op->offs] ? DM_C64ILACE_RES : DM_C64ILACE_COLOR;
     img->laceBank2 = 0;
     return TRUE;
@@ -324,6 +326,9 @@
 
 static BOOL fmtTruePaintSetLaceType(DMC64Image *img, const struct _DMDecodeOp *op, const Uint8 *buf, const size_t len)
 {
+    (void) op;
+    (void) buf;
+    (void) len;
     img->laceType = DM_C64ILACE_RES;
     img->laceBank2 = 1;
     return TRUE;
@@ -428,10 +433,9 @@
 const int ndmC64ImageFormats = sizeof(dmC64ImageFormats) / sizeof(dmC64ImageFormats[0]);
 
 
-int dmC64ProbeGeneric(const Uint8 *buf, const size_t len,
-    DMC64ImageFormat **pfmt)
+int dmC64ProbeGeneric(const Uint8 *buf, const size_t len, DMC64ImageFormat **pfmt)
 {
-    int i, scoreMax = 0, scoreIndex = -1;
+    int i, scoreMax = DM_PROBE_SCORE_FALSE, scoreIndex = -1;
 
     for (i = 0; i < ndmC64ImageFormats; i++)
     {
@@ -450,7 +454,7 @@
         return scoreMax;
     }
     else
-        return 0;
+        return DM_PROBE_SCORE_FALSE;
 }
 
 
@@ -667,61 +671,99 @@
 
 
 #define BUF_SIZE_INITIAL   (16*1024)
-#define BUF_SIZE_GROW      (2*1024)
+#define BUF_SIZE_GROW      (8*1024)
 
-int dmReadDataFile(const char *filename, Uint8 **pbuf, size_t *pbufSize)
+int dmReadDataFile(FILE *inFile, const char *filename, Uint8 **pbuf, size_t *pbufSize)
 {
     FILE *f;
+    int res = DMERR_OK;
     Uint8 *dataBuf = NULL, *dataPtr;
-    size_t bufSize, readSize, dataSize;
+    size_t readSize, dataSize, dataRead;
     
-    if (filename == NULL)
-        f = stdin;
+    if (inFile != NULL)
+        f = inFile;
     else
-    if ((f = fopen(filename, "rb")) == NULL)
+    if (filename != NULL)
     {
-        int err = errno;
-        dmError("Could not open input file '%s': %d, %s\n",
-            filename, err, strerror(err));
-        return -1;
+        if ((f = fopen(filename, "rb")) == NULL)
+        {
+            dmError("Could not open '%s' for reading.\n", filename);
+            return DMERR_FOPEN;
+        }
+    }
+    else
+    {
+        dmError("NULL filename and stream pointers.\n");
+        return DMERR_NULLPTR;
     }
 
-    readSize = bufSize = BUF_SIZE_INITIAL;
-    if ((dataBuf = dmMalloc(bufSize)) == NULL)
+    // Allocate initial data buffer
+    readSize = dataSize = BUF_SIZE_INITIAL;
+    if ((dataBuf = dmMalloc(dataSize)) == NULL)
     {
-        fclose(f);
-        dmError("Error allocating memory for data, %d bytes.\n", bufSize);
-        return -4;
+        dmError("Error allocating memory for data, %d bytes.\n", dataSize);
+        res = DMERR_MALLOC;
+        goto error;
     }
 
     dataPtr = dataBuf;
-    dataSize = 0;
+    dataRead = 0;
+        dataPtr += read;
+        dataRead += read;
 
     while (!feof(f) && !ferror(f))
     {
         size_t read = fread(dataPtr, 1, readSize, f);
 
-        dataSize += read;
-        dataPtr += read;
-
-        if (read == readSize && !feof(f))
+        if (dataRead >= dataSize)
         {
             readSize = BUF_SIZE_GROW;
-            bufSize += BUF_SIZE_GROW;
-            if ((dataBuf = dmRealloc(dataBuf, bufSize)) == NULL)
+            dataSize += BUF_SIZE_GROW;
+            if ((dataBuf = dmRealloc(dataBuf, dataSize)) == NULL)
             {
-                dmError("Error reallocating memory for data, %d bytes.\n", bufSize);
-                return -4;
+                dmError("Error reallocating memory for data, %d bytes.\n", dataSize);
+                res = DMERR_MALLOC;
+                goto error;
             }
         }
         else
             break;
     }
 
-    fclose(f);
-
+    *pbufSize = dataRead;
     *pbuf = dataBuf;
-    *pbufSize = dataSize;
+
+error:
+    if (f != inFile)
+        fclose(f);
     
-    return 0;
+    return res;
 }
+
+
+int dmC64DecodeBMP(DMC64Image *img, const Uint8 *buf, const size_t len,
+    const size_t probeOffs, const size_t loadOffs,
+    DMC64ImageFormat **fmt, DMC64ImageFormat *forced)
+{
+    // Check for forced format
+    if (forced != NULL)
+        *fmt = forced;
+    else
+    {
+        // Nope, perform a generic probe
+        if (probeOffs >= len)
+            return -200;
+
+        if (dmC64ProbeGeneric(buf + probeOffs, len - probeOffs, fmt) == DM_PROBE_SCORE_FALSE)
+            return -201;
+    }
+
+    if (loadOffs >= len)
+        return -203;
+
+    // Decode the bitmap to memory layout
+    if ((*fmt)->decode != NULL)
+        return (*fmt)->decode(img, buf + loadOffs, len - loadOffs, *fmt);
+    else
+        return dmC64DecodeGenericBMP(img, buf + loadOffs, len - loadOffs, *fmt);
+}
--- a/lib64gfx.h	Sat Nov 03 07:52:26 2012 +0200
+++ b/lib64gfx.h	Sat Nov 03 07:53:38 2012 +0200
@@ -180,6 +180,8 @@
 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);
 int       dmC64ConvertGenericBMP2Image(DMImage *screen, const DMC64Image *img);
-int       dmReadDataFile(const char *filename, Uint8 **buf, size_t *size);
+int       dmC64DecodeBMP(DMC64Image *img, const Uint8 *buf, const size_t len, const size_t probeOffs, const size_t loadOffs, DMC64ImageFormat **fmt, DMC64ImageFormat *forced);
+
+int       dmReadDataFile(FILE *inFile, const char *filename, Uint8 **buf, size_t *size);
 
 #endif // LIB64GFX_H
--- a/view64.c	Sat Nov 03 07:52:26 2012 +0200
+++ b/view64.c	Sat Nov 03 07:53:38 2012 +0200
@@ -155,12 +155,12 @@
     SDL_Surface *screen = NULL, *surf = NULL;
     DMImage bmap;
     BOOL initSDL = FALSE, exitFlag, needRedraw;
-    DMC64ImageFormat *fmt;
+    DMC64ImageFormat *fmt, *forced;
     DMC64Image image;
     char *windowTitle;
     Uint8 *dataBuf = NULL;
     size_t dataSize;
-    int i, ret;
+    int ret;
 
     dmSetScaleFactor(2.0);
     
@@ -175,71 +175,42 @@
     if (optFilename == NULL)
     {
         dmError("No input file specified, perhaps you need some --help\n");
-        goto error_exit;
+        goto error;
     }
         
-    if (dmReadDataFile(optFilename, &dataBuf, &dataSize) != 0)
-        goto error_exit;
+    if ((ret = dmReadDataFile(NULL, optFilename, &dataBuf, &dataSize)) != DMERR_OK)
+        goto error;
+
+    dmMsg(1, "Read %d bytes of input.\n", dataSize);
 
     // Probe for format
     if (optForcedFormat >= 0)
     {
-        fmt = &dmC64ImageFormats[optForcedFormat];
-        dmMsg(0,"Forced %s format image, type %d, %s\n", fmt->name, fmt->type, fmt->extension);
-
-        if (fmt->decode != NULL)
-            ret = fmt->decode(&image, dataBuf + 2, dataSize - 2, fmt);
-        else
-            ret = dmC64DecodeGenericBMP(&image, dataBuf + 2, dataSize - 2, fmt);
-
-        if (ret < 0)
-        {
-            dmError("Error decoding image format.\n");
-            return -1;
-        }
+        forced = &dmC64ImageFormats[optForcedFormat];
+        dmMsg(0,"Forced %s format image, type %d, %s\n", forced->name, forced->type, forced->extension);
     }
     else
-    {
-        BOOL found = FALSE;
-        for (i = 0; i < ndmC64ImageFormats; i++)
-        {
-            fmt = &dmC64ImageFormats[i];
-            ret = fmt->probe(dataBuf, dataSize);
-            if (ret > 0)
-            {
-                dmMsg(0,"Probed %s format image, type %d, %s\n", fmt->name, fmt->type, fmt->extension);
-                if (fmt->decode != NULL)
-                    ret = fmt->decode(&image, dataBuf + 2, dataSize - 2, fmt);
-                else
-                    ret = dmC64DecodeGenericBMP(&image, dataBuf + 2, dataSize - 2, fmt);
+        forced = NULL;
 
-                if (ret < 0)
-                {
-                    dmError("Error decoding image format.\n");
-                    return -1;
-                }
-                
-                found = TRUE;
-                break;
-            }
-            else
-            if (ret < 0)
-            {
-                dmError("Error in probing.\n");
-            }
-        }
-        if (!found)
-        {
-            dmError("Probing could not find any matching image format. Perhaps try forcing a format via -f\n");
-            return -2;
-        }
+    ret = dmC64DecodeBMP(&image, dataBuf, dataSize, 0, 2, &fmt, forced);
+    if (forced == NULL && fmt != NULL)
+    {
+        dmMsg(0,"Probed %s format image, type %d, %s\n",
+            fmt->name, fmt->type, fmt->extension);
     }
 
+    if (ret < 0)
+    {
+        dmError("Probing could not find any matching image format (%d). Perhaps try forcing a format via -f\n", ret);
+        return -1;
+    }
+
+
     // Initialize libSDL
     if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) != 0)
     {
         dmError("Could not initialize SDL: %s\n", SDL_GetError());
-        goto error_exit;
+        goto error;
     }
     initSDL = TRUE;
 
@@ -249,7 +220,7 @@
     if (screen == NULL)
     {
         dmError("Can't SDL_SetVideoMode(): %s\n", SDL_GetError());
-        goto error_exit;
+        goto error;
     }
 
     // Create surface (we are lazy and ugly)
@@ -302,7 +273,7 @@
                 optScrHeight = event.resize.h;
 
                 if (!dmInitializeVideo(&screen))
-                    goto error_exit;
+                    goto error;
 
                 needRedraw = TRUE;
                 break;
@@ -320,7 +291,7 @@
             if (SDL_MUSTLOCK(screen) != 0 && SDL_LockSurface(screen) != 0)
             {
                 dmError("Can't lock surface.\n");
-                goto error_exit;
+                goto error;
             }
             
             dmScaledBlitSurface8to8(surf, 0, 0, screen->w, screen->h, screen);
@@ -337,7 +308,7 @@
     }
 
 
-error_exit:
+error:
     if (screen)
         SDL_FreeSurface(screen);