1astext(1) AfterStep X11 window manager astext(1)
2
3
4
6 astext - demonstrates antialiased texturized text rendering libAfterIm‐
7 age/tutorials/ASText
8
11 libAfterImage application for rendering texturized text.
12
14 In this tutorial we will attempt to render arbitrary text in window,
15 with optional texturized background and foreground. We shall also
16 surround rendered text with beveled frame, creating an illusion of a
17 button.
18
19 New steps described in this tutorial are :
20 ASText.1. Openning and closing fonts.
21 ASText.2. Approximating rendered text size.
22 ASText.3. Rendering texturized text.
23 ASText.4. Merging foreground and background with bevel.
24
26 Tutorial 1: ASView - explanation of basic steps needed to use
27 libAfterImage and some other simple things.
28 Tutorial 2: ASScale - image scaling basics.
29 Tutorial 3: ASTile - image tiling and tinting.
30 Tutorial 4: ASMerge - scaling and blending of arbitrary number of
31 images.
32 Tutorial 5: ASGrad - drawing multipoint linear gradients.
33 Tutorial 6: ASFlip - image rotation.
34
36 Source :
37 #include "../afterbase.h"
38 #include "../afterimage.h"
39 #include "common.h"
40
41 /* Usage: astext [-f font] [-s size] [-t text] [-S 3D_style]
42 [-c text_color] [-b background_color]
43 [-T foreground_texture] [-B background_image]
44 [-r foreground_resize_type] [-R background_resize_type]
45 */
46
47 #define BEVEL_HI_WIDTH 20
48 #define BEVEL_LO_WIDTH 30
49 #define BEVEL_ADDON (BEVEL_HI_WIDTH+BEVEL_LO_WIDTH)
50
51 void usage()
52 {
53 printf( " Usage: astext [-h] [-f font] [-s size] [-t text] "
54 "[-S 3D_style] 0);
55 printf( " [-c text_color] [-b background_color]0);
56 printf( " [-T foreground_texture] "
57 "[-B background_image]0);
58 printf( " [-r foreground_resize_type] "
59 "[-R background_resize_type]0);
60 printf( " [-m ]0);
61 printf( " Where: font - TrueType font's filename or X font spec or "
62 "alias;0);
63 printf( " size - size in points for TrueType fonts;0);
64 printf( " text - text to be drawn;0);
65 printf( " 3D_style - 3D style of text. "
66 "One of the following:0);
67 printf( " 0 - plain 2D tetx, 1 - embossed, 2 - sunken, "
68 "3 - shade above,0);
69 printf( " 4 - shade below, 5 - embossed thick, "
70 "6 - sunken thick.0);
71 printf( " 7 - ouline above, 8 - ouline below, "
72 "9 - full ouline.0);
73 printf( " resize_type - tells how texture/image should be "
74 "transformed to fit0);
75 printf( " the text size. Could be: scale or tile."
76 "Default is tile0);
77 printf( " -m make font monospaced. 0);
78
79
80 }
81
82 int main(int argc, char* argv[])
83 {
84 ASVisual *asv = NULL ;
85 int screen = 0, depth = 0;
86 char *font_name = "test.ttf";
87 int size = 32 ;
88 #if 0
89 char *text = " 还没有"; /* chinese */
90 #else
91 char *text = "Smart Brown Dog jumps0ver The Lazy Fox,0
92 "and falls into the ditch.";
93 #endif
94 ARGB32 text_color = ARGB32_White, back_color = ARGB32_Black;
95 char *text_color_name = "#FFFFFFFF", *back_color_name = "#FF000000";
96 char *fore_image_file = "fore.xpm" ;
97 char *back_image_file = "back.xpm" ;
98 Bool scale_fore_image = False, scale_back_image = False ;
99 ASImage *fore_im = NULL, *back_im = NULL;
100 ASImage *text_im = NULL ;
101 struct ASFontManager *fontman = NULL;
102 struct ASFont *font = NULL;
103 unsigned int width, height ;
104 int i ;
105 int text_margin = size/2 ;
106 Bool monospaced = False ;
107 char * font_path = NULL;
108 ASTextAttributes attr = {ASTA_VERSION_1, ASTA_UseTabStops,
109 AST_ShadeBelow, ASCT_UTF8, 8, 0,
110 NULL, 0, ARGB32_White };
111
112 /* see ASView.1 : */
113 set_application_name( argv[0] );
114 #if (HAVE_AFTERBASE_FLAG==1)
115 set_output_threshold(OUTPUT_LEVEL_DEBUG);
116 #endif
117
118 if( argc == 1 )
119 usage();
120 else for( i = 1 ; i < argc ; i++ )
121 {
122 if( strncmp( argv[i], "-h", 2 ) == 0 )
123 {
124 usage();
125 return 0;
126 }
127 if( strncmp( argv[i], "-m", 2 ) == 0 )
128 {
129 monospaced = True ;
130 }else if( i+1 < argc )
131 {
132 if( strncmp( argv[i], "-f", 2 ) == 0 )
133 font_name = argv[i+1] ;
134 else if( strncmp( argv[i], "-s", 2 ) == 0 )
135 {
136 size = atoi(argv[i+1]);
137 text_margin = size/2 ;
138 }else if( strncmp( argv[i], "-t", 2 ) == 0 )
139 text = argv[i+1] ;
140 else if( strncmp( argv[i], "-S", 2 ) == 0 )
141 {
142 attr.type = atoi(argv[i+1]);
143 if( attr.type >= AST_3DTypes )
144 {
145 show_error( "3D type is wrong. "
146 "Using 2D Plain instead.");
147 attr.type = AST_Plain ;
148 }
149
150 }else if( strncmp( argv[i], "-c", 2 ) == 0 )
151 text_color_name = argv[i+1] ;
152 else if( strncmp( argv[i], "-b", 2 ) == 0 )
153 back_color_name = argv[i+1] ;
154 else if( strncmp( argv[i], "-T", 2 ) == 0 )
155 fore_image_file = argv[i+1] ;
156 else if( strncmp( argv[i], "-B", 2 ) == 0 )
157 back_image_file = argv[i+1] ;
158 else if( strncmp( argv[i], "-r", 2 ) == 0 )
159 scale_fore_image = (strcmp( argv[i+1], "scale") == 0);
160 else if( strncmp( argv[i], "-R", 2 ) == 0 )
161 scale_back_image = (strcmp( argv[i+1], "scale") == 0);
162 }
163 }
164
165
166 #ifndef X_DISPLAY_MISSING
167 dpy = XOpenDisplay(NULL);
168 _XA_WM_DELETE_WINDOW = XInternAtom( dpy, "WM_DELETE_WINDOW", False);
169 screen = DefaultScreen(dpy);
170 depth = DefaultDepth( dpy, screen );
171 #endif
172
173 /* see ASText.1 : */
174 if( getenv("FONT_PATH") != NULL )
175 {
176 font_path = safemalloc( strlen(getenv("FONT_PATH"))+1+2+1);
177 sprintf( font_path, "%s:./", getenv("FONT_PATH") );
178
179 }
180 if( (fontman = create_font_manager( dpy, font_path, NULL )) != NULL )
181 font = get_asfont( fontman, font_name, 0, size,
182 ASF_GuessWho|(monospaced?ASF_Monospaced:0) );
183
184 if( font == NULL )
185 {
186 show_error( "unable to load requested font
187 "Falling back to
188 font = get_asfont( fontman, "fixed", 0, size, ASF_GuessWho );
189 if( font == NULL )
190 {
191 show_error("font
192 return 1;
193 }
194 }
195
196 /*for( i = 0 ; i < 128 ; ++i )
197 print_asglyph( stderr, font, i); */
198
199 parse_argb_color( text_color_name, &text_color );
200 parse_argb_color( back_color_name, &back_color );
201
202 attr.fore_color = text_color ;
203 if( attr.type >= AST_OutlineAbove )
204 fore_image_file = NULL ;
205
206 /* see ASView.3 : */
207 asv = create_asvisual( dpy, screen, depth, NULL );
208
209 /* see ASText.2 : */
210 /*set_asfont_glyph_spacing( font, 10, 40 );*/
211 /*Simple way:get_text_size( text, font, attr.type, &width, &height ); */
212 /*Fancy way : */
213 get_fancy_text_size( text, font, &attr, &width, &height, 0, NULL );
214 /* show_progress( "extimated text size = %dx%d", width, height ); */
215
216 if( fore_image_file )
217 {
218 ASImage *tmp = file2ASImage( fore_image_file, 0xFFFFFFFF,
219 SCREEN_GAMMA, 0, getenv("IMAGE_PATH"), NULL );
220 if( tmp )
221 {
222 if( tmp->width != width || tmp->height != height )
223 { /* see ASScale.2 : */
224 if( scale_fore_image )
225 fore_im = scale_asimage( asv, tmp, width, height,
226 ASA_ASImage, 0,
227 ASIMAGE_QUALITY_DEFAULT );
228 else
229 fore_im = tile_asimage( asv, tmp, 0, 0,
230 width, height, 0,
231 ASA_ASImage, 0,
232 ASIMAGE_QUALITY_DEFAULT );
233 destroy_asimage( &tmp );
234 }else
235 fore_im = tmp ;
236 }else
237 fore_im = NULL ;
238 }
239 width += text_margin*2 + BEVEL_ADDON;
240 height += text_margin*2 + BEVEL_ADDON;
241 if( back_image_file )
242 { /* see ASView.2 : */
243 ASImage *tmp = file2ASImage( back_image_file, 0xFFFFFFFF,
244 SCREEN_GAMMA, 0, getenv("IMAGE_PATH"), NULL );
245 if( tmp )
246 {
247 if( scale_back_image &&
248 (tmp->width != width || tmp->height != height) )
249 { /* see ASScale.2 : */
250 back_im = scale_asimage( asv, tmp, width, height,
251 ASA_ASImage, 0,
252 ASIMAGE_QUALITY_DEFAULT );
253 destroy_asimage( &tmp );
254 }else
255 back_im = tmp ;
256 }else
257 back_im = NULL ;
258 }
259
260 /* see ASText.3 : */
261 /* simple way : text_im = draw_text( text, font, attr.type, 0 ); */
262 text_im = draw_fancy_text( text, font, &attr, 0, 0 );
263 if( fore_im )
264 {
265 move_asimage_channel( fore_im, IC_ALPHA, text_im, IC_ALPHA );
266 destroy_asimage( &text_im );
267 }else
268 fore_im = text_im ;
269
270 /* see ASText.1 : */
271 release_font( font );
272 destroy_font_manager( fontman, False );
273
274 if( fore_im )
275 {
276 ASImage *rendered_im ;
277 ASImageLayer layers[2] ;
278 ASImageBevel bevel = {0/*BEVEL_SOLID_INLINE*/, 0xFFDDDDDD,
279 0xFF555555, 0xFFFFFFFF,
280 0xFF777777, 0xFF222222,
281 BEVEL_HI_WIDTH, BEVEL_HI_WIDTH,
282 BEVEL_LO_WIDTH, BEVEL_LO_WIDTH,
283 BEVEL_HI_WIDTH, BEVEL_HI_WIDTH,
284 BEVEL_LO_WIDTH, BEVEL_LO_WIDTH } ;
285
286 /* see ASText.4 : */
287 init_image_layers( &(layers[0]), 2 );
288 if( back_im )
289 back_im->back_color = back_color ;
290 if( fore_im )
291 fore_im->back_color = text_color ;
292 layers[0].im = back_im ;
293 layers[0].dst_x = 0 ;
294 layers[0].dst_y = 0 ;
295 layers[0].clip_width = width ;
296 layers[0].clip_height = height ;
297 layers[0].bevel = &bevel ;
298 layers[1].im = fore_im ;
299 layers[1].dst_x = text_margin+BEVEL_HI_WIDTH*2 ;
300 layers[1].dst_y = text_margin+
301 MIN( (int)text_margin,
302 ((int)font->max_height-
303 (int)font->max_ascend))/2+
304 BEVEL_HI_WIDTH*2;
305 if( fore_im )
306 {
307 layers[1].clip_width = fore_im->width ;
308 layers[1].clip_height = fore_im->height ;
309 }
310 rendered_im = merge_layers( asv, &(layers[0]), 2,
311 width+BEVEL_ADDON, height+BEVEL_ADDON,
312 #ifndef X_DISPLAY_MISSING
313 ASA_XImage,
314 #else
315 ASA_ASImage,
316 #endif
317 0, ASIMAGE_QUALITY_DEFAULT);
318 destroy_asimage( &fore_im );
319 destroy_asimage( &back_im );
320
321 if( rendered_im )
322 {
323 #ifndef X_DISPLAY_MISSING
324 Window w;
325 /* see ASView.4 : */
326 w = create_top_level_window( asv, DefaultRootWindow(dpy),
327 32, 32,
328 width+BEVEL_ADDON,
329 height+BEVEL_ADDON,
330 1, 0, NULL,
331 "ASText", text );
332 if( w != None )
333 {
334 Pixmap p ;
335
336 XMapRaised (dpy, w);
337
338 /* see ASView.5 : */
339 p = asimage2pixmap( asv, DefaultRootWindow(dpy),
340 rendered_im, NULL, True );
341 destroy_asimage( &rendered_im );
342 /* see common.c: set_window_background_and_free() : */
343 p = set_window_background_and_free( w, p );
344 /* see common.c: wait_closedown() : */
345 wait_closedown(w);
346 }
347 if( dpy )
348 XCloseDisplay (dpy);
349 #else
350 /* writing result into the file */
351 ASImage2file( rendered_im, NULL, "astext.jpg", ASIT_Jpeg,
352 NULL );
353 destroy_asimage( &rendered_im );
354 #endif
355 }
356 }
357 return 0 ;
358 }
359
361 Step 1. Openning and closing fonts.
362
364 Before any text can be rendered using libAfterImage - desired font
365 has to be opened for use. Font opening process is two-step. At first
366 we need to create font manager ( ASFontManager ). That is done once,
367 and same font manager can be used throughout entire application. It
368 contains information about used external libraries, hash of opened
369 fonts, and some other info.
370
371 When ASFontManager is created it could be used to obtain actuall fonts.
372 get_asfont() call is used to query cahce of the ASFontManager, to see
373 if the font has been loaded already, and if not - then it will load
374 the font and prepare it for drawing.
375
377 if( (fontman = create_font_manager( dpy, NULL, NULL )) != NULL )
378 font = get_asfont( fontman, font_name, 0, size, ASF_GuessWho);
379 if( font == NULL )
380 {
381 font = get_asfont( fontman, "fixed", 0, size, ASF_GuessWho );
382 if( font == NULL )
383 {
384 show_error( "font
385 Aborting.");
386 return 1;
387 }
388 }
389 ...
390 destroy_font( font );
391 destroy_font_manager( fontman, False );
392
394 create_font_manager(), get_asfont(), destroy_font(),
395 destroy_font_manager()
396
398 Step 2. Approximating rendered text size.
399
401 Prior to actually drawing the text it is usefull to estimate the size
402 of the image, that rendered text will occupy, So that window can be
403 created of appropriate size, and othe interface elements laid out
404 accordingly. get_text_size() could be used to obtain rendered text
405 size without actually drawing it.
406
408 get_text_size( text, font, type_3d, &width, &height );
409 if( fore_image_file )
410 {
411 ASImage *tmp = file2ASImage( fore_image_file, 0xFFFFFFFF,
412 SCREEN_GAMMA, 0, NULL );
413 if( tmp )
414 {
415 if( tmp->width != width || tmp->height != height )
416 {
417 if( scale_fore_image )
418 fore_im = scale_asimage( asv, tmp, width, height,
419 ASA_ASImage, 0,
420 ASIMAGE_QUALITY_DEFAULT );
421 else
422 fore_im = tile_asimage( asv, tmp, 0, 0,
423 width, height, 0,
424 ASA_ASImage, 0,
425 ASIMAGE_QUALITY_DEFAULT );
426 destroy_asimage( &tmp );
427 }else
428 fore_im = tmp ;
429 }
430 }
431
433 In this particular example we either tile or scale foreground texture
434 to fit the text. In order to texturize the text - we need to use
435 rendered text as an alpha channel on texture image. That can easily
436 be done only if both images are the same size.
437
439 get_text_size(), scale_asimage(), tile_asimage(), ASText.3
440
442 Step 3. Rendering texturized text.
443
445 The most effective text texturization technique provided by
446 libAfterImage consists of substitution of the alpha channel of the
447 texture, with rendered text. That is possible since all the text is
448 rendered into alpha channel only. move_asimage_channel() call is used
449 to accomplish this operation. This call actually removes channel
450 data from the original image and stores it in destination image. If
451 there was something in destination image's channel already - it will
452 be destroyed.
453 All kinds of nifty things could be done using this call, actually.
454 Like, for example, rendered text can be moved into green channel of
455 the texture, creating funky effect.
456
458 text_im = draw_text( text, font, 0 );
459 if( fore_im )
460 {
461 move_asimage_channel( fore_im, IC_ALPHA, text_im, IC_ALPHA );
462 destroy_asimage( &text_im );
463 }else
464 fore_im = text_im ;
465
467 move_asimage_channel() will only work if both images have exactly the
468 same size. It will do nothing otherwise.
469
471 draw_text(), move_asimage_channel()
472
474 Step 4. Merging foreground and background with bevel.
475
477 On this step we have 2 images ready for us - background and texturized
478 text. At this point we need to merge them together by alpha-blending
479 text over background (remeber - text is alpha-channel of foreground
480 texture). At the same time we would like to add some nice bevel border
481 around entire image. To accomplish that task all we have to do is setup
482 ASImageLayer structure for both background and foreground, and apply
483 merge_layers on them. When it is done - we no longer need original
484 images and we destroy them to free up some memory.
485
487 ASImageLayer layers[2] ;
488 ASImageBevel bevel = {0, 0xFFDDDDDD, 0xFF555555,
489 0xFFFFFFFF, 0xFF777777, 0xFF444444,
490 BEVEL_HI_WIDTH, BEVEL_HI_WIDTH,
491 BEVEL_LO_WIDTH, BEVEL_LO_WIDTH,
492 BEVEL_HI_WIDTH, BEVEL_HI_WIDTH,
493 BEVEL_LO_WIDTH, BEVEL_LO_WIDTH } ;
494 memset( &(layers[0]), 0x00, sizeof(layers) );
495 layers[0].im = back_im ;
496 layers[0].clip_width = width ;
497 layers[0].clip_height = height ;
498 layers[0].merge_scanlines = alphablend_scanlines ;
499 layers[0].bevel = &bevel ;
500 layers[1].im = fore_im ;
501 layers[1].dst_x = TEXT_MARGIN ;
502 layers[1].dst_y = TEXT_MARGIN ;
503 layers[1].clip_width = fore_im->width ;
504 layers[1].clip_height = fore_im->height ;
505 layers[1].back_color = text_color ;
506 layers[1].merge_scanlines = alphablend_scanlines ;
507 rendered_im = merge_layers( asv, &(layers[0]), 2,
508 width+BEVEL_ADDON, height+BEVEL_ADDON,
509 ASA_XImage, 0, ASIMAGE_QUALITY_DEFAULT);
510 destroy_asimage( &fore_im );
511 destroy_asimage( &back_im );
512
514 We have to remember that outside bevel border will addup to the image
515 size, hence we have to use width+BEVEL_ADDON , height+BEVEL_ADDON as
516 desired image size.
517
519 ASImageLayer, ASImageBevel, merge_layers()
520
521
522
5233rd Berkeley Distribution AfterStep v.2.2.6 astext(1)