Mercurial > hg > dmlib
view fontconv.c @ 410:e4b2f689aff6
Stdint -> SDL types conversion.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Sat, 03 Nov 2012 02:41:15 +0200 |
parents | d6c184800384 |
children | f87446a81887 |
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" #include "dmresw.h" enum { OFMT_DMFONT, OFMT_C }; char *optInFilename = NULL, *optOutFilename = NULL, *optOutName = 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 }, { 4, 'C', "csource", "DMFONT as C source", OPT_NONE }, { 5, 'n', "name", "Variable name prefix for C output", 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; case 4: optOutFormat = OFMT_C; break; case 5: optOutName = optArg; 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; } static int dm_csrc_ferror(DMResource * f) { return f->error; } static int dm_csrc_fputc(int v, DMResource * f) { if (f->dataSize++ >= 16) { fprintf(f->fh, "\n"); f->dataSize = 0; } fprintf(f->fh, "%3d,", v); f->error = dmGetErrno(); return 1; } static size_t dm_csrc_fwrite(void *ptr, size_t size, size_t nmemb, DMResource * f) { size_t n; Uint8 *p = (Uint8 *) ptr; for (n = 0; n < size * nmemb; n++, p++) { if (f->dataSize++ >= 16) { fprintf(f->fh, "\n"); f->dataSize = 0; } fprintf(f->fh, "%3d,", *p); } f->error = dmGetErrno(); return nmemb; } static int dm_csrc_fopen(DMResource * f) { fprintf(f->fh, "const Uint8 %s[] = {\n", (char *) f->data ); return DMERR_OK; } static void dm_csrc_fclose(DMResource * f) { if (f->fh != NULL) { fprintf(f->fh, "\n};\n" "const unsigned int %s_size = sizeof(%s) / sizeof(%s[0]);\n", (char *)f->data, (char *)f->data, (char *)f->data ); fclose(f->fh); f->fh = NULL; } } DMResourceOps dfCSourceFileOps = { dm_csrc_ferror, NULL, NULL, NULL, NULL, NULL, dm_csrc_fputc, NULL, dm_csrc_fwrite, dm_csrc_fopen, dm_csrc_fclose, NULL }; DMResource * dmf_create_csrc(const char *filename, const char *name) { DMResource *handle = dmres_new(NULL, filename, 0, 0); if (handle == NULL) return NULL; handle->fops = &dfCSourceFileOps; handle->fh = fopen(filename, "w"); handle->error = dmGetErrno(); handle->data = (Uint8 *) dm_strdup(name); if (handle->fh != NULL) { handle->fops->fopen(handle); dmres_ref(handle); return handle; } else { dmres_free(handle); return NULL; } } DMResource * dmf_create_csrc_stream(FILE *fh, const char *name) { DMResource *handle = dmres_new(NULL, NULL, 0, 0); if (handle == NULL) return NULL; handle->fops = &dfCSourceFileOps; handle->fh = fh; handle->error = dmGetErrno(); handle->data = (Uint8 *) dm_strdup(name); handle->fops->fopen(handle); dmres_ref(handle); return handle; } 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.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; } #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; SDL_Color col = { 255, 255, 255, 100 }; 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, col); } } #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; } if (optOutFormat == OFMT_DMFONT) { dmMsg(1, "Outputting a DMFONT format bitmap font.\n"); if (optOutFilename == NULL) outFile = dmf_create_stdio_stream(stdout); else outFile = dmf_create_stdio(optOutFilename, "wb"); } else if (optOutFormat == OFMT_C) { if (optOutName == NULL) { dmError("C source output selected, but variable name not specified.\n"); goto error_exit; } dmMsg(1, "Outputting a DMFONT format bitmap font as C source file.\n"); if (optOutFilename == NULL) outFile = dmf_create_csrc_stream(stdout, optOutName); else outFile = dmf_create_csrc(optOutFilename, optOutName); } if (outFile == 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; }