astext(3x)

✨ astext(3x) ✨

AfterStep X11 window manager πŸ’– bestie we are in section 3x and we are about to make text look absolutely GORGEOUS πŸ’…


πŸ“› NAME

  • astext β€” demonstrates antialiased texturized text rendering
  • libAfterImage/tutorials/ASText

🌸 NAMEASText 🌸

okay this heading literally has no body text, it's just standing there being iconic πŸ‘‘ the real tea starts right below, keep scrolling boo 🫢


πŸ“– SYNOPSIS

libAfterImage application for rendering texturized text.


πŸ¦‹ DESCRIPTION

So here's the vibe: in this tutorial we're gonna try to render arbitrary text inside a window, with optional texturized background and foreground 🌈. And because plain text is giving nothing, we also wrap the rendered text in a beveled frame, which creates the illusion of a button ✨. A whole button, bestie. From text. Iconic behaviour fr fr.

The new steps described in this tutorial are:

  1. ASText.1. Opening and closing fonts πŸ”€
  2. ASText.2. Approximating rendered text size πŸ“
  3. ASText.3. Rendering texturized text 🎨
  4. 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

no cap, here is the whole thing, character for character, do NOT let me catch you retyping it by hand 😭

           #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[]) {
               Display *dpy = NULL;
               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 ;
               }

(part 2 is on its way bestie, don't go anywhere πŸ’–)

...and we're still SO inside that same example, bestie β€” no interruptions, just the rest of it, okay? here we go πŸ’…

               /* 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);
                       dpy = NULL; #else
                       /* writing result into the file */
                       ASImage2file( rendered_im, NULL, "astext.jpg",
           ASIT_Jpeg,
                                     NULL );
                       destroy_asimage( &rendered_im ); #endif
                   }
               }
               return 0 ; }

okay and that's the whole example, slayed ✨ now let's do the little mini-tutorials one by one 🫢


🌈 libAfterImage/tutorials/ASText.1 [7.1] 🌈

✨ SYNOPSIS ✨

Step 1. Opening and closing fonts.

🌸 DESCRIPTION 🌸

Before libAfterImage can render literally any text, the font you want has to be opened for use β€” that's just the rules, bestie. Opening a font is a two-step process, no skips:

First you create a font manager (ASFontManager). You do this once, and the same font manager can be used through your entire application. It's holding info about the external libraries in play, a hash of the opened fonts, and some other info too.

Once the ASFontManager exists, you use it to get the actual fonts. The get_asfont() call peeks at the ASFontManager's cache to check whether that font is already loaded β€” and if it isn't, it loads the font and gets it all prepped for drawing. iconic behavior, honestly πŸ’…

πŸŽ€ 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()

🌈 libAfterImage/tutorials/ASText.2 [7.2] 🌈

✨ SYNOPSIS ✨

Step 2. Approximating rendered text size.

🌸 DESCRIPTION 🌸

Before you actually commit to drawing the text, it's genuinely useful to estimate the size of the image that the rendered text will take up β€” because that way you can make your window the right size and lay the other interface elements out accordingly, and not have everything looking a mess 😭

get_text_size() is the one for this: it hands you the rendered text size without actually drawing anything. so convenient, fr fr.

πŸŽ€ 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 specific example we either tile or scale the foreground texture so it fits the text. To texturize the text we need to use the rendered text as an alpha channel on the texture image β€” and that can only easily happen if both images are the same size. no cap.

πŸ¦‹ SEE ALSO πŸ¦‹

  • get_text_size()
  • scale_asimage()
  • tile_asimage()
  • ASText.3

🌈 libAfterImage/tutorials/ASText.3 [7.3] 🌈

✨ SYNOPSIS ✨

Step 3. Rendering texturized text.

🌸 DESCRIPTION 🌸

The most effective text texturization technique that libAfterImage provides is swapping the alpha channel of the texture out for the rendered text. That works because all the text gets rendered into the alpha channel only. The move_asimage_channel() call is what makes it happen.

Heads up though: this call actually removes the channel data from the original image and stores it in the destination image. And if the destination image's channel already had something in it? yeah, that's destroyed, πŸ’€ gone.

All kinds of nifty things can be done with this call, actually β€” like, for example, the rendered text can be moved into the green channel of the texture for a funky little effect. obsessed. πŸ”₯

πŸŽ€ 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() only works if both images are exactly the same size. If they're not, it does nothing. periodt.

πŸ¦‹ SEE ALSO πŸ¦‹

  • draw_text()
  • move_asimage_channel()

🌈 libAfterImage/tutorials/ASText.4 [7.4] 🌈

✨ SYNOPSIS ✨

Step 4. Merging foreground and background with bevel.

🌸 DESCRIPTION 🌸

At this step we've got two images ready to go β€” the background and the texturized text. Now we need to merge them together by alpha-blending the text over the background (remember, the text is the alpha channel of the foreground texture, bestie).

And while we're at it, we want to add a cute little bevel border around the whole entire image. So all we have to do is set up an ASImageLayer structure for both the background and the foreground, then apply merge_layers on them. Once that's done, the original images aren't needed anymore, so we destroy them to free up some memory. slay, bye πŸ’…

πŸŽ€ 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 the outside bevel border adds up to the image size β€” which is why the desired image size has to be width+BEVEL_ADDON, height+BEVEL_ADDON. don't skip this part, I'm begging πŸ™ˆ

πŸ¦‹ SEE ALSO πŸ¦‹

  • ASImageLayer
  • ASImageBevel
  • merge_layers()

and that's a wrap, bestie 🫢 that little footer is serving 3rd Berkeley Distribution β€” AfterStep v.2.2.12 β€” astext(3x), and it's giving very much "go forth and render pretty text" energy. now go texturize something iconic, you've got this πŸ’–βœ¨πŸŒˆ

πŸ“¦ where this page comes from