comparison 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
comparison
equal deleted inserted replaced
654:78fdc9c16db9 655:064c942d342e
1 /*
2 * fontconv - Convert bitmap fonts
3 * Programmed and designed by Matti 'ccr' Hamalainen
4 * (C) Copyright 2012 Tecnic Software productions (TNSP)
5 *
6 * Please read file 'COPYING' for information on license and distribution.
7 */
8 #include <stdio.h>
9 #include <errno.h>
10 #include "dmlib.h"
11 #include "dmargs.h"
12 #include "dmfile.h"
13 #include "dmimage.h"
14 #include "dmtext.h"
15 #include "dmresw.h"
16
17 char *optInFilename = NULL, *optOutFilename = NULL;
18
19 int optSplitWidth = 8,
20 optSplitHeight = 8;
21
22 SDL_Color optColor = { 255, 255, 255, 100 };
23
24
25 DMOptArg optList[] =
26 {
27 { 0, '?', "help", "Show this help", OPT_NONE },
28 { 1, 'v', "verbose", "Be more verbose", OPT_NONE },
29 { 2, 'o', "output", "Set output filename", OPT_ARGREQ },
30 { 3, 's', "size", "Set glyph dimensions (-s WxH) for image->font conversion", OPT_ARGREQ },
31 { 4, 'c', "color", "TTF font rendering color (def: 0xFFFFFF)", OPT_ARGREQ },
32 };
33
34 const int optListN = sizeof(optList) / sizeof(optList[0]);
35
36
37 BOOL argHandleOpt(const int optN, char *optArg, char *currArg)
38 {
39 switch (optN)
40 {
41 case 0:
42 dmPrintBanner(stdout, dmProgName,
43 "[options] <sourcefile.(ttf|fnt|dmf|png)> <outputfile.dmf>");
44
45 dmArgsPrintHelp(stdout, optList, optListN);
46 printf(
47 "\n"
48 "This utility can be used to convert TSFONT files to bitmap DMFONT (DMF)\n"
49 "files, render TrueType TTF to DMFONT at desired glyph resolution, or\n"
50 "cut a PNG (or JPEG) image to glyphs of desired size.\n");
51
52 exit(0);
53 break;
54
55 case 1:
56 dmVerbosity++;
57 break;
58
59 case 2:
60 optOutFilename = optArg;
61 break;
62
63 case 3:
64 {
65 int w, h;
66 if (sscanf(optArg, "%dx%d", &w, &h) != 2)
67 {
68 dmError("Invalid argument for -s option, '%s'.\n",
69 optArg);
70 return FALSE;
71 }
72 if (w < DMFONT_MIN_WIDTH || w > DMFONT_MAX_WIDTH ||
73 h < DMFONT_MIN_HEIGHT || h > DMFONT_MAX_HEIGHT)
74 {
75 dmError("Invalid dimensions, must be %d < W %d, %d < H < %d.\n",
76 DMFONT_MIN_WIDTH , DMFONT_MAX_WIDTH,
77 DMFONT_MIN_HEIGHT , DMFONT_MAX_HEIGHT);
78 return FALSE;
79 }
80 optSplitWidth = w;
81 optSplitHeight = h;
82 }
83 break;
84
85 case 4:
86 {
87 int colR, colG, colB, colA = 100;
88 if (optArg[0] == '#' || optArg[0] == '$') optArg++;
89 else
90 if (optArg[0] == '0' && optArg[1] == 'x') optArg += 2;
91
92 if (sscanf(optArg, "%02x%02x%02x", &colR, &colG, &colB) != 3 &&
93 sscanf(optArg, "%02x%02x%02x%02x", &colR, &colG, &colB, &colA) != 4)
94 {
95 dmError("Invalid RGB hex representation '%s'.\n",
96 optArg);
97 return FALSE;
98 }
99
100 optColor.r = colR;
101 optColor.g = colG;
102 optColor.b = colB;
103 optColor.unused = colA;
104 }
105 break;
106
107 default:
108 dmError("Unknown argument '%s'.\n", currArg);
109 return FALSE;
110 }
111
112 return TRUE;
113 }
114
115
116 BOOL argHandleFile(char *currArg)
117 {
118 if (!optInFilename)
119 optInFilename = currArg;
120 else
121 if (!optOutFilename)
122 optOutFilename = currArg;
123 else
124 {
125 dmError("Too many filename arguments, '%s'\n", currArg);
126 return FALSE;
127 }
128
129 return TRUE;
130 }
131
132
133 int dmCreateBitmapFontFromImage(SDL_Surface *image, int width, int height, DMBitmapFont **pfont)
134 {
135 int nglyph, xc, yc, xglyphs, yglyphs;
136 DMBitmapFont *font;
137
138 if (image->w < width || width < 4 || image->h < height || height < 4)
139 return DMERR_INVALID_ARGS;
140
141 xglyphs = image->w / width;
142 yglyphs = image->h / height;
143
144 if ((font = dmNewBitmapFont(xglyphs * yglyphs, width, height)) == NULL)
145 return DMERR_MALLOC;
146
147 dmMsg(1, "%d x %d split as %d x %d blocks => %d x %d = %d glyphs.\n",
148 image->w, image->h,
149 width, height,
150 xglyphs, yglyphs, xglyphs * yglyphs);
151
152 nglyph = 0;
153 for (yc = 0; yc < yglyphs; yc++)
154 for (xc = 0; xc < xglyphs; xc++)
155 {
156 SDL_Surface *glyph = SDL_CreateRGBSurface(SDL_SWSURFACE, width, height,
157 image->format->BitsPerPixel,
158 image->format->Rmask,
159 image->format->Gmask,
160 image->format->Bmask,
161 image->format->Amask);
162
163 if (glyph == NULL)
164 {
165 dmFreeBitmapFont(font);
166 return DMERR_MALLOC;
167 }
168
169 SDL_Rect r;
170 r.x = xc * width;
171 r.y = yc * height;
172 r.w = width;
173 r.h = height;
174
175 SDL_BlitSurface(image, &r, glyph, NULL);
176
177 font->glyphs[nglyph++] = glyph;
178 }
179
180 *pfont = font;
181 return DMERR_OK;
182 }
183
184
185 int dmSaveBitmapFont(DMResource *res, DMBitmapFont *font)
186 {
187 int maxglyph, nglyphs, n;
188 if (font == NULL)
189 return DMERR_NULLPTR;
190
191 if (font->nglyphs > DMFONT_MAX_GLYPHS ||
192 font->width > DMFONT_MAX_WIDTH ||
193 font->height > DMFONT_MAX_HEIGHT ||
194 font->width < DMFONT_MIN_WIDTH ||
195 font->height < DMFONT_MIN_HEIGHT)
196 return DMERR_INVALID_DATA;
197
198 // Count number of actually existing glyphs
199 for (maxglyph = nglyphs = n = 0; n < font->nglyphs; n++)
200 {
201 SDL_Surface *glyph = font->glyphs[n];
202 if (glyph != NULL)
203 {
204 maxglyph = n;
205 if (glyph->w < DMFONT_MIN_WIDTH ||
206 glyph->h < DMFONT_MIN_HEIGHT ||
207 glyph->w > DMFONT_MAX_WIDTH ||
208 glyph->h > DMFONT_MAX_HEIGHT)
209 continue;
210 nglyphs++;
211 }
212 }
213
214 // Write the DMFONT header
215 if (!dmf_write_str(res, (Uint8 *) DMFONT_MAGIC, 6))
216 return DMERR_FWRITE;
217
218 dmf_write_le16(res, DMFONT_VERSION);
219 dmf_write_le16(res, nglyphs);
220 dmf_write_le16(res, maxglyph + 1);
221 dmfputc(font->width, res);
222 dmfputc(font->height, res);
223
224 if (nglyphs > 0)
225 {
226 int i;
227 SDL_Surface *glyph = font->glyphs[maxglyph];
228
229 // If there are actual glyphs stored, save this
230 dmfputc(glyph->format->BitsPerPixel, res);
231 dmf_write_le32(res, glyph->format->Rmask);
232 dmf_write_le32(res, glyph->format->Gmask);
233 dmf_write_le32(res, glyph->format->Bmask);
234 dmf_write_le32(res, glyph->format->Amask);
235
236 for (i = 0; i < font->nglyphs; i++)
237 {
238 glyph = font->glyphs[i];
239 if (glyph != NULL)
240 {
241 int y;
242 Uint8 *pixels = glyph->pixels;
243
244 if (glyph->w < DMFONT_MIN_WIDTH ||
245 glyph->h < DMFONT_MIN_HEIGHT ||
246 glyph->w > DMFONT_MAX_WIDTH ||
247 glyph->h > DMFONT_MAX_HEIGHT)
248 continue;
249
250 // Each glyph has its table index and w/h stored
251 dmf_write_le16(res, i);
252 dmfputc(glyph->w, res);
253 dmfputc(glyph->h, res);
254
255 // Write the pixel data
256 for (y = 0; y < glyph->h; y++)
257 {
258 if (dmfwrite(pixels, glyph->format->BytesPerPixel, glyph->w, res) != (size_t) glyph->w)
259 return DMERR_FWRITE;
260 pixels += glyph->pitch;
261 }
262 }
263 }
264 }
265
266 return DMERR_OK;
267 }
268
269
270 int main(int argc, char *argv[])
271 {
272 DMResource *inFile = NULL, *outFile = NULL;
273 DMBitmapFont *font = NULL;
274 SDL_Surface *fontbmap = NULL;
275 int res;
276 #ifdef DM_GFX_TTF_TEXT
277 BOOL initTTF = FALSE;
278 TTF_Font *ttf = NULL;
279 #endif
280
281 dmInitProg("fontconv", "Bitmap font converter", "0.3", NULL, NULL);
282 dmVerbosity = 1;
283
284 // Parse arguments
285 if (!dmArgsProcess(argc, argv, optList, optListN,
286 argHandleOpt, argHandleFile, TRUE))
287 exit(1);
288
289 // Check arguments
290 if (!optInFilename || !optOutFilename)
291 {
292 dmError("Input or output file not specified!\n");
293 return 1;
294 }
295
296 #ifdef DM_GFX_TTF_TEXT
297 if (TTF_Init() < 0)
298 {
299 dmError("Could not initialize FreeType/TTF: %s\n", SDL_GetError());
300 goto error_exit;
301 }
302 initTTF = TRUE;
303 #endif
304
305 // Open the source file
306 if ((inFile = dmf_create_stdio(optInFilename, "rb")) == NULL)
307 {
308 dmError("Error opening input file '%s', %d: %s\n",
309 optInFilename, errno, strerror(errno));
310 return 1;
311 }
312
313
314 if ((res = dmLoadBitmapFont(inFile, &font)) == DMERR_OK)
315 {
316 dmMsg(1, "Input is a TSFONT/DMFONT font file.\n");
317 }
318 #ifdef DM_GFX_TTF_TEXT
319 else
320 if ((ttf = TTF_OpenFont(optInFilename, optSplitWidth)) != NULL)
321 {
322 int i;
323 dmMsg(1, "Input is a TTF TrueType font, rendering at %d x %d.\n",
324 optSplitWidth, optSplitHeight);
325
326 TTF_SetFontStyle(ttf, TTF_STYLE_NORMAL);
327
328 if ((font = dmNewBitmapFont(256, optSplitWidth - 1, optSplitHeight+4)) == NULL)
329 {
330 goto error_exit;
331 }
332
333 for (i = 0; i < 255; i++)
334 {
335 char str[2];
336 str[0] = i;
337 str[1] = 0;
338 font->glyphs[i] = TTF_RenderText_Blended(ttf, str, optColor);
339 }
340 }
341 #endif
342 else
343 {
344 dmfseek(inFile, 0L, SEEK_SET);
345
346 if ((fontbmap = dmLoadImage(inFile)) == NULL)
347 {
348 dmError("Could not load image file '%s'.\n", optInFilename);
349 goto error_exit;
350 }
351
352 dmMsg(1, "Input is a bitmap image (%d x %d, %d bpp), splitting to %d x %d.\n",
353 fontbmap->w, fontbmap->h, fontbmap->format->BitsPerPixel,
354 optSplitWidth, optSplitHeight);
355
356 if ((res = dmCreateBitmapFontFromImage(fontbmap, optSplitWidth, optSplitHeight, &font)) != DMERR_OK)
357 {
358 dmError("Could not create a font from image, %d: %s\n",
359 res, dmErrorStr(res));
360 goto error_exit;
361 }
362 }
363
364 if (font == NULL)
365 {
366 dmError("No font loaded.\n");
367 goto error_exit;
368 }
369
370 dmMsg(1, "Outputting a DMFONT format bitmap font.\n");
371
372 if ((outFile = dmf_create_stdio(optOutFilename, "wb")) == NULL)
373 {
374 dmError("Error creating file '%s', %d: %s\n",
375 optInFilename, errno, strerror(errno));
376 goto error_exit;
377 }
378
379 res = dmSaveBitmapFont(outFile, font);
380 dmf_close(outFile);
381
382 if (res != DMERR_OK)
383 {
384 dmError("Error saving font, %d: %s\n",
385 res, dmErrorStr(res));
386 }
387
388 error_exit:
389
390 #ifdef DM_GFX_TTF_TEXT
391 if (initTTF)
392 TTF_Quit();
393 #endif
394
395 dmf_close(inFile);
396 dmFreeBitmapFont(font);
397 SDL_FreeSurface(fontbmap);
398
399 return 0;
400 }