]> git.cworth.org Git - spritext/blob - spritext.c
Account for x_bearing/y_bearing to align each glyph properly
[spritext] / spritext.c
1 /* XXX: Copyright/license blurb needed here */
2
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include <libgen.h>
7 #include <cairo.h>
8 #include <cairo-ft.h>
9
10 #ifndef CAIRO_HAS_PNG_FUNCTIONS
11 #error This program requires cairo with PNG support
12 #endif
13
14 #include <ft2build.h>
15 #include FT_FREETYPE_H
16
17 #define ARRAY_SIZE(arr) (sizeof(arr)/sizeof(arr[0]))
18
19 #define TRUE (1==1)
20 #define FALSE (!TRUE)
21
22 static double
23 get_max_width (cairo_t *cr, const char *characters, int num_characters)
24 {
25     int i;
26     double max_width = 0.;
27     char string[2];
28     string[1] = '\0';
29     for (i = 0; i < num_characters; i++) {
30         cairo_text_extents_t extents;
31         string[0] = characters[i];
32         cairo_text_extents (cr, string, &extents);
33         if ((extents.width + (extents.x_bearing * 2)) > max_width)
34             max_width = extents.width + (extents.x_bearing * 2);
35     }
36     return max_width;
37 }
38
39 static double
40 get_max_height (cairo_t *cr, const char *characters, int num_characters)
41 {
42     int i;
43     double max_height = 0.;
44     char string[2];
45     string[1] = '\0';
46     for (i = 0; i < num_characters; i++) {
47         cairo_text_extents_t extents;
48         string[0] = characters[i];
49         cairo_text_extents (cr, string, &extents);
50         if ((extents.height) > max_height)
51             max_height = extents.height;
52     }
53     return max_height;
54 }
55
56 typedef struct {
57     char *family;
58     double size;
59     struct {
60         double red;
61         double green;
62         double blue;
63     } color;
64 } args_t;
65
66 static void
67 parse_args (args_t *args)
68 {
69     /* First some defaults */
70     args->family = "Vera";
71     args->size = 40;
72     args->color.red = 0.0;
73     args->color.green = 0.3;
74     args->color.blue = 0.0;
75
76     /* XXX: Next, we should override the defaults based on
77      * command-line arguments. */
78
79     /* XXX: Finally, we'll want to allow CGI-based arguments as
80      * well. */
81 #if USE_CGIG
82     /* QueryString */
83     int fontsize;
84     char format[5];
85     char fillcolor[20];
86     char fontname[20];
87     cgiFormStringNoNewlines("fontname", fontname, 20);
88     cgiFormInteger("fontsize", &fontsize, 50);
89     cgiFormStringNoNewlines("format", format, 5);
90     cgiFormStringNoNewlines("fillcolor", fillcolor, 20);
91
92     int fillcolor_red;
93     int fillcolor_green;
94     int fillcolor_blue;
95     sscanf (fillcolor, " rgb : %d , %d , %d ", &fillcolor_red, &fillcolor_green, &fillcolor_blue);
96     if ( format[0] == 'j' && format[1] == 's' && format[2] == 'o' && format[3] == 'n' )
97         outputJson = TRUE;
98 #endif
99 }
100
101 static FT_Face
102 load_ft_face_for_family (const char *family)
103 {
104     /* XXX: Instead of a hard-coded filename here, we should really be
105      * taking family and using fontconfig to map that to a
106      * filename. */
107     const char font_filename[] = "./Vera.ttf";
108
109     int error;
110     FT_Face     ft_face;
111     FT_Library  library;
112
113     error = FT_Init_FreeType( &library );
114     if ( error ) {
115         fprintf (stderr, "Fatal error initializing freetype.\n");
116         exit (1);
117     }
118
119     error = FT_New_Face( library, font_filename,
120                          0,
121                          &ft_face );
122     if ( error == FT_Err_Unknown_File_Format ) {
123         fprintf (stderr, "Unsupported font format: %s\n", font_filename);
124         exit (1);
125     } else if ( error ) {
126         fprintf (stderr, "Failed to open file: %s\n", font_filename);
127         exit (1);
128     }
129
130     return ft_face;
131 }
132
133 static void
134 get_characters_max_width_height (FT_Face ft_face, double size,
135                                  const char *characters, int num_characters,
136                                  double *max_width, double *max_height)
137 {
138     cairo_surface_t *surface;
139     cairo_t *cr;
140     cairo_font_face_t *cr_face;
141
142     surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
143                                           1, 1);
144
145     cr = cairo_create (surface);
146
147     cr_face = cairo_ft_font_face_create_for_ft_face (ft_face, 0);
148     cairo_set_font_face (cr, cr_face);
149
150     cairo_set_font_size (cr, size);
151
152     cairo_set_line_width (cr, 1.0);
153
154     *max_width = get_max_width(cr, characters, num_characters);
155     *max_height = get_max_height(cr, characters, num_characters);
156
157     cairo_font_face_destroy (cr_face);
158
159     cairo_destroy (cr);
160
161     cairo_surface_destroy(surface);
162 }
163
164 static void
165 draw_character_table (cairo_t *cr,
166                       FT_Face ft_face, double size,
167                       const char *characters, int num_characters,
168                       double character_width, double character_height)
169 {
170     cairo_font_face_t *cr_face;
171     int i;
172
173     cr_face = cairo_ft_font_face_create_for_ft_face (ft_face, 0);
174     cairo_set_font_face (cr, cr_face);
175
176     cairo_set_font_size (cr, size);
177
178     cairo_text_extents_t extents;
179     double x = 0.0;
180     double y = 0.0;
181
182     char string[2];
183     string[1] = '\0';
184
185     cairo_set_line_width (cr, 2.0);
186     for (i = 0; i < num_characters; i++)
187     {
188         cairo_rectangle (cr, x, y, character_width, character_height);
189         cairo_stroke_preserve (cr);
190         cairo_save (cr);
191         cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* white */
192         cairo_fill (cr);
193         cairo_restore (cr);
194
195         string[0] = characters[i];
196
197         cairo_text_extents (cr, string, &extents);
198
199         cairo_move_to (cr, x - extents.x_bearing, y - extents.y_bearing);
200         cairo_show_text (cr, string);
201
202         if ((i+1) % 10 == 0)
203         {
204             x = 0.;
205             y += character_height;
206         } else {
207             x += character_width;
208         }
209     }
210
211     cairo_scale (cr, 1, -1);
212     cairo_push_group (cr);
213 }
214
215 int
216 main (void)
217 {
218     char characters[] = {
219         '!', '"', '#', '$', '%', '&','\'', '(',
220         ')', '*', '+', ',', '-', '.', '/', '0',
221         '1', '2', '3', '4', '5', '6', '7', '8',
222         '9', ':', ';', '<', '=', '>', '?', '@',
223         'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
224         'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
225         'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
226         'Y', 'Z', '[','\\', ']', '^', '_', '`',
227         'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
228         'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p',
229         'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
230         'y', 'z', '{', '|', '}', '~'
231     };
232
233     args_t args;
234     FT_Face ft_face;
235     double max_width, max_height;
236     cairo_surface_t *surface;
237     cairo_t *cr;
238
239     parse_args (&args);
240
241     ft_face = load_ft_face_for_family (args.family);
242
243     get_characters_max_width_height (ft_face, args.size,
244                                      characters, ARRAY_SIZE (characters),
245                                      &max_width, &max_height);
246
247     /* Draw */
248     surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
249                                           max_width * 10,
250                                           max_height * 10);
251
252     cr = cairo_create (surface);
253
254     cairo_set_source_rgb (cr,
255                           args.color.red,
256                           args.color.green,
257                           args.color.blue);
258
259     draw_character_table (cr, ft_face, args.size,
260                           characters, ARRAY_SIZE (characters),
261                           max_width, max_height);
262
263     cairo_surface_write_to_png (surface, "spritext-output.png");
264     printf ("Result written to spritext-output.png\n");
265
266     cairo_destroy (cr);
267
268     cairo_surface_destroy (surface);
269
270     return 0;
271 }