#include "config.h" #include #include /****h* libAfterImage/tutorials/ASText * NAME * ASText * SYNOPSIS * libAfterImage application for rendering texturized text. * DESCRIPTION * In this tutorial we will attempt to render arbitrary text in window, * with optional texturized background and foreground. We shall also * surround rendered text with beveled frame, creating an illusion of a * button. * * New steps described in this tutorial are : * ASText.1. Openning and closing fonts. * ASText.2. Approximating rendered text size. * ASText.3. Rendering texturized text. * ASText.4. Merging foreground and background with bevel. * SEE ALSO * Tutorial 1: ASView - explanation of basic steps needed to use * libAfterImage and some other simple things. * Tutorial 2: ASScale - image scaling basics. * Tutorial 3: ASTile - image tiling and tinting. * Tutorial 4: ASMerge - scaling and blending of arbitrary number of * images. * Tutorial 5: ASGrad - drawing multipoint linear gradients. * Tutorial 6: ASFlip - image rotation. * SOURCE */ #include "../afterbase.h" #include "../afterimage.h" #include "common.h" /* Usage: astext [-f font] [-s size] [-t text] [-S 3D_style] [-c text_color] [-b background_color] [-T foreground_texture] [-B background_image] [-r foreground_resize_type] [-R background_resize_type] */ #define BEVEL_HI_WIDTH 20 #define BEVEL_LO_WIDTH 30 #define BEVEL_ADDON (BEVEL_HI_WIDTH+BEVEL_LO_WIDTH) void usage() { printf( " Usage: astext [-h] [-f font] [-s size] [-t text] " "[-S 3D_style] \n"); printf( " [-c text_color] [-b background_color]\n"); printf( " [-T foreground_texture] " "[-B background_image]\n"); printf( " [-r foreground_resize_type] " "[-R background_resize_type]\n"); printf( " [-m ]\n"); printf( " Where: font - TrueType font's filename or X font spec or " "alias;\n"); printf( " size - size in points for TrueType fonts;\n"); printf( " text - text to be drawn;\n"); printf( " 3D_style - 3D style of text. " "One of the following:\n"); printf( " 0 - plain 2D tetx, 1 - embossed, 2 - sunken, " "3 - shade above,\n"); printf( " 4 - shade below, 5 - embossed thick, " "6 - sunken thick.\n"); printf( " 7 - ouline above, 8 - ouline below, " "9 - full ouline.\n"); printf( " resize_type - tells how texture/image should be " "transformed to fit\n"); printf( " the text size. Could be: scale or tile." "Default is tile\n"); printf( " -m make font monospaced. \n"); } int main(int argc, char* argv[]) { ASVisual *asv = NULL ; int screen = 0, depth = 0; char *font_name = "test.ttf"; int size = 32 ; #if 0 char *text = "  还没有"; /* chinese */ #else char *text = "Smart Brown Dog jumps\nOver The Lazy Fox,\n" "and falls into the ditch."; #endif ARGB32 text_color = ARGB32_White, back_color = ARGB32_Black; char *text_color_name = "#FFFFFFFF", *back_color_name = "#FF000000"; char *fore_image_file = "fore.xpm" ; char *back_image_file = "back.xpm" ; Bool scale_fore_image = False, scale_back_image = False ; ASImage *fore_im = NULL, *back_im = NULL; ASImage *text_im = NULL ; struct ASFontManager *fontman = NULL; struct ASFont *font = NULL; unsigned int width, height ; int i ; int text_margin = size/2 ; Bool monospaced = False ; char * font_path = NULL; ASTextAttributes attr = {ASTA_VERSION_1, ASTA_UseTabStops, AST_ShadeBelow, ASCT_UTF8, 8, 0, NULL, 0, ARGB32_White }; /* see ASView.1 : */ set_application_name( argv[0] ); #if (HAVE_AFTERBASE_FLAG==1) set_output_threshold(OUTPUT_LEVEL_DEBUG); #endif if( argc == 1 ) usage(); else for( i = 1 ; i < argc ; i++ ) { if( strncmp( argv[i], "-h", 2 ) == 0 ) { usage(); return 0; } if( strncmp( argv[i], "-m", 2 ) == 0 ) { monospaced = True ; }else if( i+1 < argc ) { if( strncmp( argv[i], "-f", 2 ) == 0 ) font_name = argv[i+1] ; else if( strncmp( argv[i], "-s", 2 ) == 0 ) { size = atoi(argv[i+1]); text_margin = size/2 ; }else if( strncmp( argv[i], "-t", 2 ) == 0 ) text = argv[i+1] ; else if( strncmp( argv[i], "-S", 2 ) == 0 ) { attr.type = atoi(argv[i+1]); if( attr.type >= AST_3DTypes ) { show_error( "3D type is wrong. " "Using 2D Plain instead."); attr.type = AST_Plain ; } }else if( strncmp( argv[i], "-c", 2 ) == 0 ) text_color_name = argv[i+1] ; else if( strncmp( argv[i], "-b", 2 ) == 0 ) back_color_name = argv[i+1] ; else if( strncmp( argv[i], "-T", 2 ) == 0 ) fore_image_file = argv[i+1] ; else if( strncmp( argv[i], "-B", 2 ) == 0 ) back_image_file = argv[i+1] ; else if( strncmp( argv[i], "-r", 2 ) == 0 ) scale_fore_image = (strcmp( argv[i+1], "scale") == 0); else if( strncmp( argv[i], "-R", 2 ) == 0 ) scale_back_image = (strcmp( argv[i+1], "scale") == 0); } } #ifndef X_DISPLAY_MISSING dpy = XOpenDisplay(NULL); _XA_WM_DELETE_WINDOW = XInternAtom( dpy, "WM_DELETE_WINDOW", False); screen = DefaultScreen(dpy); depth = DefaultDepth( dpy, screen ); #endif /* see ASText.1 : */ if( getenv("FONT_PATH") != NULL ) { font_path = safemalloc( strlen(getenv("FONT_PATH"))+1+2+1); sprintf( font_path, "%s:./", getenv("FONT_PATH") ); } if( (fontman = create_font_manager( dpy, font_path, NULL )) != NULL ) font = get_asfont( fontman, font_name, 0, size, ASF_GuessWho|(monospaced?ASF_Monospaced:0) ); if( font == NULL ) { show_error( "unable to load requested font \"%s\". " "Falling back to \"fixed\".", font_name ); font = get_asfont( fontman, "fixed", 0, size, ASF_GuessWho ); if( font == NULL ) { show_error("font \"fixed\" is not available either. Aborting."); return 1; } } /*for( i = 0 ; i < 128 ; ++i ) print_asglyph( stderr, font, i); */ parse_argb_color( text_color_name, &text_color ); parse_argb_color( back_color_name, &back_color ); attr.fore_color = text_color ; if( attr.type >= AST_OutlineAbove ) fore_image_file = NULL ; /* see ASView.3 : */ asv = create_asvisual( dpy, screen, depth, NULL ); /* see ASText.2 : */ /*set_asfont_glyph_spacing( font, 10, 40 );*/ /*Simple way:get_text_size( text, font, attr.type, &width, &height ); */ /*Fancy way : */ get_fancy_text_size( text, font, &attr, &width, &height, 0, NULL ); /* show_progress( "extimated text size = %dx%d", width, height ); */ if( fore_image_file ) { ASImage *tmp = file2ASImage( fore_image_file, 0xFFFFFFFF, SCREEN_GAMMA, 0, getenv("IMAGE_PATH"), NULL ); if( tmp ) { if( tmp->width != width || tmp->height != height ) { /* see ASScale.2 : */ if( scale_fore_image ) fore_im = scale_asimage( asv, tmp, width, height, ASA_ASImage, 0, ASIMAGE_QUALITY_DEFAULT ); else fore_im = tile_asimage( asv, tmp, 0, 0, width, height, 0, ASA_ASImage, 0, ASIMAGE_QUALITY_DEFAULT ); destroy_asimage( &tmp ); }else fore_im = tmp ; }else fore_im = NULL ; } width += text_margin*2 + BEVEL_ADDON; height += text_margin*2 + BEVEL_ADDON; if( back_image_file ) { /* see ASView.2 : */ ASImage *tmp = file2ASImage( back_image_file, 0xFFFFFFFF, SCREEN_GAMMA, 0, getenv("IMAGE_PATH"), NULL ); if( tmp ) { if( scale_back_image && (tmp->width != width || tmp->height != height) ) { /* see ASScale.2 : */ back_im = scale_asimage( asv, tmp, width, height, ASA_ASImage, 0, ASIMAGE_QUALITY_DEFAULT ); destroy_asimage( &tmp ); }else back_im = tmp ; }else back_im = NULL ; } /* see ASText.3 : */ /* simple way : text_im = draw_text( text, font, attr.type, 0 ); */ text_im = draw_fancy_text( text, font, &attr, 0, 0 ); if( fore_im ) { move_asimage_channel( fore_im, IC_ALPHA, text_im, IC_ALPHA ); destroy_asimage( &text_im ); }else fore_im = text_im ; /* see ASText.1 : */ release_font( font ); destroy_font_manager( fontman, False ); if( fore_im ) { ASImage *rendered_im ; ASImageLayer layers[2] ; ASImageBevel bevel = {0/*BEVEL_SOLID_INLINE*/, 0xFFDDDDDD, 0xFF555555, 0xFFFFFFFF, 0xFF777777, 0xFF222222, BEVEL_HI_WIDTH, BEVEL_HI_WIDTH, BEVEL_LO_WIDTH, BEVEL_LO_WIDTH, BEVEL_HI_WIDTH, BEVEL_HI_WIDTH, BEVEL_LO_WIDTH, BEVEL_LO_WIDTH } ; /* see ASText.4 : */ init_image_layers( &(layers[0]), 2 ); if( back_im ) back_im->back_color = back_color ; if( fore_im ) fore_im->back_color = text_color ; layers[0].im = back_im ; layers[0].dst_x = 0 ; layers[0].dst_y = 0 ; layers[0].clip_width = width ; layers[0].clip_height = height ; layers[0].bevel = &bevel ; layers[1].im = fore_im ; layers[1].dst_x = text_margin+BEVEL_HI_WIDTH*2 ; layers[1].dst_y = text_margin+ MIN( (int)text_margin, ((int)font->max_height- (int)font->max_ascend))/2+ BEVEL_HI_WIDTH*2; if( fore_im ) { layers[1].clip_width = fore_im->width ; layers[1].clip_height = fore_im->height ; } rendered_im = merge_layers( asv, &(layers[0]), 2, width+BEVEL_ADDON, height+BEVEL_ADDON, #ifndef X_DISPLAY_MISSING ASA_XImage, #else ASA_ASImage, #endif 0, ASIMAGE_QUALITY_DEFAULT); destroy_asimage( &fore_im ); destroy_asimage( &back_im ); if( rendered_im ) { #ifndef X_DISPLAY_MISSING Window w; /* see ASView.4 : */ w = create_top_level_window( asv, DefaultRootWindow(dpy), 32, 32, width+BEVEL_ADDON, height+BEVEL_ADDON, 1, 0, NULL, "ASText", text ); if( w != None ) { Pixmap p ; XMapRaised (dpy, w); /* see ASView.5 : */ p = asimage2pixmap( asv, DefaultRootWindow(dpy), rendered_im, NULL, True ); destroy_asimage( &rendered_im ); /* see common.c: set_window_background_and_free() : */ p = set_window_background_and_free( w, p ); /* see common.c: wait_closedown() : */ wait_closedown(w); } if( dpy ) XCloseDisplay (dpy); #else /* writing result into the file */ ASImage2file( rendered_im, NULL, "astext.jpg", ASIT_Jpeg, NULL ); destroy_asimage( &rendered_im ); #endif } } return 0 ; } /**************/ /****f* libAfterImage/tutorials/ASText.1 [7.1] * SYNOPSIS * Step 1. Openning and closing fonts. * DESCRIPTION * Before any text can be rendered using libAfterImage - desired font * has to be opened for use. Font opening process is two-step. At first * we need to create font manager ( ASFontManager ). That is done once, * and same font manager can be used throughout entire application. It * contains information about used external libraries, hash of opened * fonts, and some other info. * * When ASFontManager is created it could be used to obtain actuall fonts. * get_asfont() call is used to query cahce of the ASFontManager, to see * if the font has been loaded already, and if not - then it will load * the font and prepare it for drawing. * * EXAMPLE * if( (fontman = create_font_manager( dpy, NULL, NULL )) != NULL ) * font = get_asfont( fontman, font_name, 0, size, ASF_GuessWho); * if( font == NULL ) * { * font = get_asfont( fontman, "fixed", 0, size, ASF_GuessWho ); * if( font == NULL ) * { * show_error( "font \"fixed\" is not available either. * Aborting."); * return 1; * } * } * ... * destroy_font( font ); * destroy_font_manager( fontman, False ); * SEE ALSO * create_font_manager(), get_asfont(), destroy_font(), * destroy_font_manager() ********/ /****f* libAfterImage/tutorials/ASText.2 [7.2] * SYNOPSIS * Step 2. Approximating rendered text size. * DESCRIPTION * Prior to actually drawing the text it is usefull to estimate the size * of the image, that rendered text will occupy, So that window can be * created of appropriate size, and othe interface elements laid out * accordingly. get_text_size() could be used to obtain rendered text * size without actually drawing it. * EXAMPLE * get_text_size( text, font, type_3d, &width, &height ); * if( fore_image_file ) * { * ASImage *tmp = file2ASImage( fore_image_file, 0xFFFFFFFF, * SCREEN_GAMMA, 0, NULL ); * if( tmp ) * { * if( tmp->width != width || tmp->height != height ) * { * if( scale_fore_image ) * fore_im = scale_asimage( asv, tmp, width, height, * ASA_ASImage, 0, * ASIMAGE_QUALITY_DEFAULT ); * else * fore_im = tile_asimage( asv, tmp, 0, 0, * width, height, 0, * ASA_ASImage, 0, * ASIMAGE_QUALITY_DEFAULT ); * destroy_asimage( &tmp ); * }else * fore_im = tmp ; * } * } * NOTES * In this particular example we either tile or scale foreground texture * to fit the text. In order to texturize the text - we need to use * rendered text as an alpha channel on texture image. That can easily * be done only if both images are the same size. * SEE ALSO * get_text_size(), scale_asimage(), tile_asimage(), ASText.3 ********/ /****f* libAfterImage/tutorials/ASText.3 [7.3] * SYNOPSIS * Step 3. Rendering texturized text. * DESCRIPTION * The most effective text texturization technique provided by * libAfterImage consists of substitution of the alpha channel of the * texture, with rendered text. That is possible since all the text is * rendered into alpha channel only. move_asimage_channel() call is used * to accomplish this operation. This call actually removes channel * data from the original image and stores it in destination image. If * there was something in destination image's channel already - it will * be destroyed. * All kinds of nifty things could be done using this call, actually. * Like, for example, rendered text can be moved into green channel of * the texture, creating funky effect. * EXAMPLE * text_im = draw_text( text, font, 0 ); * if( fore_im ) * { * move_asimage_channel( fore_im, IC_ALPHA, text_im, IC_ALPHA ); * destroy_asimage( &text_im ); * }else * fore_im = text_im ; * NOTES * move_asimage_channel() will only work if both images have exactly the * same size. It will do nothing otherwise. * SEE ALSO * draw_text(), move_asimage_channel() ********/ /****f* libAfterImage/tutorials/ASText.4 [7.4] * SYNOPSIS * Step 4. Merging foreground and background with bevel. * DESCRIPTION * On this step we have 2 images ready for us - background and texturized * text. At this point we need to merge them together by alpha-blending * text over background (remeber - text is alpha-channel of foreground * texture). At the same time we would like to add some nice bevel border * around entire image. To accomplish that task all we have to do is setup * ASImageLayer structure for both background and foreground, and apply * merge_layers on them. When it is done - we no longer need original * images and we destroy them to free up some memory. * EXAMPLE * ASImageLayer layers[2] ; * ASImageBevel bevel = {0, 0xFFDDDDDD, 0xFF555555, * 0xFFFFFFFF, 0xFF777777, 0xFF444444, * BEVEL_HI_WIDTH, BEVEL_HI_WIDTH, * BEVEL_LO_WIDTH, BEVEL_LO_WIDTH, * BEVEL_HI_WIDTH, BEVEL_HI_WIDTH, * BEVEL_LO_WIDTH, BEVEL_LO_WIDTH } ; * memset( &(layers[0]), 0x00, sizeof(layers) ); * layers[0].im = back_im ; * layers[0].clip_width = width ; * layers[0].clip_height = height ; * layers[0].merge_scanlines = alphablend_scanlines ; * layers[0].bevel = &bevel ; * layers[1].im = fore_im ; * layers[1].dst_x = TEXT_MARGIN ; * layers[1].dst_y = TEXT_MARGIN ; * layers[1].clip_width = fore_im->width ; * layers[1].clip_height = fore_im->height ; * layers[1].back_color = text_color ; * layers[1].merge_scanlines = alphablend_scanlines ; * rendered_im = merge_layers( asv, &(layers[0]), 2, * width+BEVEL_ADDON, height+BEVEL_ADDON, * ASA_XImage, 0, ASIMAGE_QUALITY_DEFAULT); * destroy_asimage( &fore_im ); * destroy_asimage( &back_im ); * NOTES * We have to remember that outside bevel border will addup to the image * size, hence we have to use width+BEVEL_ADDON , height+BEVEL_ADDON as * desired image size. * SEE ALSO * ASImageLayer, ASImageBevel, merge_layers() ********/