Mercurial > hg > dmlib
diff tools/fontconv.c @ 655:064c942d342e
Work towards fixing the build.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Tue, 16 Apr 2013 07:24:06 +0300 |
parents | fontconv.c@8986893fd5e5 |
children | 3d813c81f33c |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/fontconv.c Tue Apr 16 07:24:06 2013 +0300 @@ -0,0 +1,400 @@ +/* + * 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" +#include "dmresw.h" + +char *optInFilename = NULL, *optOutFilename = NULL; + +int optSplitWidth = 8, + optSplitHeight = 8; + +SDL_Color optColor = { 255, 255, 255, 100 }; + + +DMOptArg optList[] = +{ + { 0, '?', "help", "Show this help", OPT_NONE }, + { 1, 'v', "verbose", "Be more verbose", OPT_NONE }, + { 2, 'o', "output", "Set output filename", OPT_ARGREQ }, + { 3, 's', "size", "Set glyph dimensions (-s WxH) for image->font conversion", OPT_ARGREQ }, + { 4, 'c', "color", "TTF font rendering color (def: 0xFFFFFF)", 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.(ttf|fnt|dmf|png)> <outputfile.dmf>"); + + dmArgsPrintHelp(stdout, optList, optListN); + printf( + "\n" + "This utility can be used to convert TSFONT files to bitmap DMFONT (DMF)\n" + "files, render TrueType TTF to DMFONT at desired glyph resolution, or\n" + "cut a PNG (or JPEG) image to glyphs of desired size.\n"); + + 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; + + case 4: + { + int colR, colG, colB, colA = 100; + if (optArg[0] == '#' || optArg[0] == '$') optArg++; + else + if (optArg[0] == '0' && optArg[1] == 'x') optArg += 2; + + if (sscanf(optArg, "%02x%02x%02x", &colR, &colG, &colB) != 3 && + sscanf(optArg, "%02x%02x%02x%02x", &colR, &colG, &colB, &colA) != 4) + { + dmError("Invalid RGB hex representation '%s'.\n", + optArg); + return FALSE; + } + + optColor.r = colR; + optColor.g = colG; + optColor.b = colB; + optColor.unused = colA; + } + break; + + default: + dmError("Unknown argument '%s'.\n", currArg); + return FALSE; + } + + return TRUE; +} + + +BOOL argHandleFile(char *currArg) +{ + if (!optInFilename) + optInFilename = currArg; + else + if (!optOutFilename) + optOutFilename = 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; + + dmMsg(1, "%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 dmSaveBitmapFont(DMResource *res, DMBitmapFont *font) +{ + int maxglyph, nglyphs, n; + if (font == NULL) + return DMERR_NULLPTR; + + if (font->nglyphs > DMFONT_MAX_GLYPHS || + font->width > DMFONT_MAX_WIDTH || + font->height > DMFONT_MAX_HEIGHT || + font->width < DMFONT_MIN_WIDTH || + font->height < DMFONT_MIN_HEIGHT) + return DMERR_INVALID_DATA; + + // Count number of actually existing glyphs + for (maxglyph = nglyphs = n = 0; n < font->nglyphs; n++) + { + SDL_Surface *glyph = font->glyphs[n]; + if (glyph != NULL) + { + maxglyph = n; + if (glyph->w < DMFONT_MIN_WIDTH || + glyph->h < DMFONT_MIN_HEIGHT || + glyph->w > DMFONT_MAX_WIDTH || + glyph->h > DMFONT_MAX_HEIGHT) + continue; + nglyphs++; + } + } + + // Write the DMFONT header + if (!dmf_write_str(res, (Uint8 *) DMFONT_MAGIC, 6)) + return DMERR_FWRITE; + + dmf_write_le16(res, DMFONT_VERSION); + dmf_write_le16(res, nglyphs); + dmf_write_le16(res, maxglyph + 1); + dmfputc(font->width, res); + dmfputc(font->height, res); + + if (nglyphs > 0) + { + int i; + SDL_Surface *glyph = font->glyphs[maxglyph]; + + // If there are actual glyphs stored, save this + dmfputc(glyph->format->BitsPerPixel, res); + dmf_write_le32(res, glyph->format->Rmask); + dmf_write_le32(res, glyph->format->Gmask); + dmf_write_le32(res, glyph->format->Bmask); + dmf_write_le32(res, glyph->format->Amask); + + for (i = 0; i < font->nglyphs; i++) + { + glyph = font->glyphs[i]; + if (glyph != NULL) + { + int y; + Uint8 *pixels = glyph->pixels; + + if (glyph->w < DMFONT_MIN_WIDTH || + glyph->h < DMFONT_MIN_HEIGHT || + glyph->w > DMFONT_MAX_WIDTH || + glyph->h > DMFONT_MAX_HEIGHT) + continue; + + // Each glyph has its table index and w/h stored + dmf_write_le16(res, i); + dmfputc(glyph->w, res); + dmfputc(glyph->h, res); + + // Write the pixel data + for (y = 0; y < glyph->h; y++) + { + if (dmfwrite(pixels, glyph->format->BytesPerPixel, glyph->w, res) != (size_t) glyph->w) + return DMERR_FWRITE; + pixels += glyph->pitch; + } + } + } + } + + return DMERR_OK; +} + + +int main(int argc, char *argv[]) +{ + DMResource *inFile = NULL, *outFile = NULL; + DMBitmapFont *font = NULL; + SDL_Surface *fontbmap = NULL; + int res; +#ifdef DM_GFX_TTF_TEXT + BOOL initTTF = FALSE; + TTF_Font *ttf = NULL; +#endif + + dmInitProg("fontconv", "Bitmap font converter", "0.3", NULL, NULL); + dmVerbosity = 1; + + // Parse arguments + if (!dmArgsProcess(argc, argv, optList, optListN, + argHandleOpt, argHandleFile, TRUE)) + exit(1); + + // Check arguments + if (!optInFilename || !optOutFilename) + { + dmError("Input or output file not specified!\n"); + return 1; + } + +#ifdef DM_GFX_TTF_TEXT + if (TTF_Init() < 0) + { + dmError("Could not initialize FreeType/TTF: %s\n", SDL_GetError()); + goto error_exit; + } + initTTF = TRUE; +#endif + + // 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) + { + dmMsg(1, "Input is a TSFONT/DMFONT font file.\n"); + } +#ifdef DM_GFX_TTF_TEXT + else + if ((ttf = TTF_OpenFont(optInFilename, optSplitWidth)) != NULL) + { + int i; + dmMsg(1, "Input is a TTF TrueType font, rendering at %d x %d.\n", + optSplitWidth, optSplitHeight); + + TTF_SetFontStyle(ttf, TTF_STYLE_NORMAL); + + if ((font = dmNewBitmapFont(256, optSplitWidth - 1, optSplitHeight+4)) == NULL) + { + goto error_exit; + } + + for (i = 0; i < 255; i++) + { + char str[2]; + str[0] = i; + str[1] = 0; + font->glyphs[i] = TTF_RenderText_Blended(ttf, str, optColor); + } + } +#endif + else + { + dmfseek(inFile, 0L, SEEK_SET); + + if ((fontbmap = dmLoadImage(inFile)) == NULL) + { + dmError("Could not load image file '%s'.\n", optInFilename); + goto error_exit; + } + + dmMsg(1, "Input is a bitmap image (%d x %d, %d bpp), splitting to %d x %d.\n", + fontbmap->w, fontbmap->h, fontbmap->format->BitsPerPixel, + optSplitWidth, optSplitHeight); + + 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; + } + } + + if (font == NULL) + { + dmError("No font loaded.\n"); + goto error_exit; + } + + dmMsg(1, "Outputting a DMFONT format bitmap font.\n"); + + if ((outFile = dmf_create_stdio(optOutFilename, "wb")) == NULL) + { + dmError("Error creating file '%s', %d: %s\n", + optInFilename, errno, strerror(errno)); + goto error_exit; + } + + res = dmSaveBitmapFont(outFile, font); + dmf_close(outFile); + + if (res != DMERR_OK) + { + dmError("Error saving font, %d: %s\n", + res, dmErrorStr(res)); + } + +error_exit: + +#ifdef DM_GFX_TTF_TEXT + if (initTTF) + TTF_Quit(); +#endif + + dmf_close(inFile); + dmFreeBitmapFont(font); + SDL_FreeSurface(fontbmap); + + return 0; +}