Mercurial > hg > dmlib
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 } |