view fontconv.c @ 160:67d2cba58a87

Add fontconv tool.
author Matti Hamalainen <ccr@tnsp.org>
date Sat, 06 Oct 2012 07:29:26 +0300
parents
children 63ff0fb944cd
line wrap: on
line source

/*
 * fontconv - Convert bitmap fonts
 * 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 <stdio.h>
#include <errno.h>
#include "dmlib.h"
#include "dmargs.h"
#include "dmfile.h"
#include "dmimage.h"
#include "dmtext.h"

enum
{
    OFMT_DMFONT,
};

enum
{
    IFMT_IMAGE,
    IFMT_FONT,
};

char    *optInFilename = NULL, *optOutFilename = NULL;
int     optOutFormat = OFMT_DMFONT,
        optSplitWidth = 8,
        optSplitHeight = 8;


DMOptArg optList[] =
{
    {  0, '?', "help",     "Show this help", OPT_NONE },
    {  1, 'v', "verbose",  "Be more verbose", OPT_NONE },
    {  2, 'o', "output",   "Output file (default stdout)", OPT_ARGREQ },
    {  3, 's', "size",     "Set glyph dimensions (-s WxH) for image->font conversion", OPT_ARGREQ },
};

const int optListN = sizeof(optList) / sizeof(optList[0]);


BOOL argHandleOpt(const int optN, char *optArg, char *currArg)
{
    switch (optN)
    {
        case 0:
            dmPrintBanner(stdout, dmProgName,
                "[options] [sourcefile]");
                
            dmArgsPrintHelp(stdout, optList, optListN);
            exit(0);
            break;

        case 1:
            dmVerbosity++;
            break;
        
        case 2:
            optOutFilename = optArg;
            break;
        
        case 3:
            {
                int w, h;
                if (sscanf(optArg, "%dx%d", &w, &h) != 2)
                {
                    dmError("Invalid argument for -s option, '%s'.\n",
                        optArg);
                    return FALSE;
                }
                if (w < DMFONT_MIN_WIDTH  || w > DMFONT_MAX_WIDTH ||
                    h < DMFONT_MIN_HEIGHT || h > DMFONT_MAX_HEIGHT)
                {
                    dmError("Invalid dimensions, must be %d < W %d, %d < H < %d.\n",
                        DMFONT_MIN_WIDTH  , DMFONT_MAX_WIDTH,
                        DMFONT_MIN_HEIGHT , DMFONT_MAX_HEIGHT);
                    return FALSE;
                }
                optSplitWidth = w;
                optSplitHeight = h;
            }
            break;

        default:
            dmError("Unknown argument '%s'.\n", currArg);
            return FALSE;
    }
    
    return TRUE;
}


BOOL argHandleFile(char *currArg)
{
    if (!optInFilename)
        optInFilename = currArg;
    else
    {
        dmError("Too many filename arguments, '%s'\n", currArg);
        return FALSE;
    }
    
    return TRUE;
}


int dmCreateBitmapFontFromImage(SDL_Surface *image, int width, int height, DMBitmapFont **pfont)
{
    int nglyph, xc, yc, xglyphs, yglyphs;
    DMBitmapFont *font;

    if (image->w < width || width < 4 || image->h < height || height < 4)
        return DMERR_INVALID_ARGS;
    
    xglyphs = image->w / width;
    yglyphs = image->h / height;
    
    if ((font = dmNewBitmapFont(xglyphs * yglyphs, width, height)) == NULL)
        return DMERR_MALLOC;

/*
    fprintf(stderr, "%d x %d split as %d x %d blocks => %d x %d = %d glyphs\n",
        image->w, image->h,
        width, height,
        xglyphs, yglyphs, xglyphs * yglyphs);
*/
    
    nglyph = 0;
    for (yc = 0; yc < yglyphs; yc++)
    for (xc = 0; xc < xglyphs; xc++)
    {
        SDL_Surface *glyph = SDL_CreateRGBSurface(SDL_SWSURFACE, width, height,
            image->format->BitsPerPixel,
            image->format->Rmask,
            image->format->Gmask,
            image->format->Bmask,
            image->format->Amask);
        
        if (glyph == NULL)
        {
            dmFreeBitmapFont(font);
            return DMERR_MALLOC;
        }

        SDL_Rect r;
        r.x = xc * width;
        r.y = yc * height;
        r.w = width;
        r.h = height;
        
        SDL_BlitSurface(image, &r, glyph, NULL);
        
        font->glyphs[nglyph++] = glyph;
    }
    
    *pfont = font;
    return DMERR_OK;
}


int main(int argc, char *argv[])
{
    DMResource *inFile = NULL;
    DMBitmapFont *font = NULL;
    int res;

    dmInitProg("fontconv", "Bitmap font converter", "0.2", NULL, NULL);
    dmVerbosity = 1;

    // Parse arguments
    if (!dmArgsProcess(argc, argv, optList, optListN,
        argHandleOpt, argHandleFile, TRUE))
        exit(1);

    // Check arguments
    if (!optInFilename)
    {
        dmError("Input or output file not specified!\n");
        return 1;
    }
    
    // Open the source file
    if ((inFile = dmf_create_stdio(optInFilename, "rb")) == NULL)
    {
        dmError("Error opening input file '%s', %d: %s\n",
            optInFilename, errno, strerror(errno));
        return 1;
    }

    if ((res = dmLoadBitmapFont(inFile, &font)) != DMERR_OK)
    {
        SDL_Surface *fontbmap;

        dmfseek(inFile, 0L, SEEK_SET);

        if ((fontbmap = dmLoadImage(inFile)) == NULL)
        {
            dmError("Could not load image file '%s'.\n", optInFilename);
            goto error_exit;
        }

        if ((res = dmCreateBitmapFontFromImage(fontbmap, optSplitWidth, optSplitHeight, &font)) != DMERR_OK)
        {
            dmError("Could not create a font from image, %d: %s\n",
                res, dmErrorStr(res));
            goto error_exit;
        }
        SDL_FreeSurface(fontbmap);
    }

    if (font == NULL)
    {
        dmError("No font loaded.\n");
        goto error_exit;
    }
    
    if (optOutFormat == OFMT_DMFONT)
    {
        DMResource *file;

        if (optOutFilename == NULL)
            file = dmf_create_stdio_stream(stdout);
        else
            file = dmf_create_stdio(optOutFilename, "wb");

        if (file == NULL)
        {
            dmError("Error creating file '%s', %d: %s\n",
                optInFilename, errno, strerror(errno));
            goto error_exit;
        }

        res = dmSaveBitmapFont(file, font);
        dmf_close(file);
    }

    if (res != DMERR_OK)
    {
        dmError("Error saving font, %d: %s\n",
            res, dmErrorStr(res));
    }

error_exit:
    
    dmf_close(inFile);
    dmFreeBitmapFont(font);
    
    return 0;
}