asgrad(3x)

✨ NAME ✨

okay so bestie, meet asgrad(3x) β€” yes, section 3x, and it's living in the AfterStep X11 window manager household πŸ’–. Her whole thing? She demonstrates rendering of multi point linear gradients. that's it, that's the vibe. She hangs out at libAfterImage/tutorials/ASGrad, no cap. πŸŽ€

πŸ’« NAMEASGrad πŸ’«

(don't come for me, the page literally has this second heading called NAMEASGrad β€” we respect the lore.) it's just more name energy for the exact same beautiful program. πŸ¦‹

🌸 SYNOPSIS 🌸

libAfterImage application for drawing multipoint linear gradients. that's the whole tea, periodt. ✨

πŸ’… DESCRIPTION πŸ’…

New steps described in this tutorial are:

  • ASGrad.1. Building gradient specs.
  • ASGrad.2. Actual rendering gradient.

two steps, two moods, both iconic. 🌈

πŸ”₯ 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.

go read your siblings too, they're all slaying in their own lanes πŸ‘‘


πŸ‘‘ SOURCE πŸ‘‘

here's the actual source, literally verbatim, do not touch a single character bestie:

#include "../afterbase.h" #include "../afterimage.h" #include
"common.h"

ARGB32 default_colors[] = {
    0xFF000000,
    0xFF700070,                                /* violet */
    0xFF0000FF,                                /* blue   */
    0xFF00FFFF,                                /* cyan   */
    0xFF00FF00,
    0XFFFFFF00,
    0XFF700000,
    0XFFFF0000,
    0xFF8080A0,
    0xFFE0E0FF,
    0xFFa0a0FF, }; double default_offsets[] = { 0, 0.1, 0.15, 0.20,
0.35, 0.45, 0.55, 0.50,
                             0.65, 0.8, 1.0} ;

void usage() {
    printf( "  Usage: asgrad -h | <geometry> <gradient_type> <color1> "
            "<offset2> <color2> [ <offset3> <color3> ...]\n");
    printf( "  Where: geometry - size of the resulting image and window;\n");
    printf( "         gradient_type - One of the fiollowing values :\n");
    printf( "            0 - linear   left-to-right gradient,\n");
    printf( "            1 - diagonal lefttop-to-rightbottom,\n");
    printf( "            2 - linear   top-to-bottom gradient,\n");
    printf( "            3 - diagonal righttop-to-leftbottom;\n");
    printf( "         offset   - floating point value from 0.0 to 1.0\n"); }

int main(int argc, char* argv[]) {
    Display *dpy = NULL;
    ASVisual *asv ;
    int screen = 0, depth = 0;
    int dummy, geom_flags = 0;
    unsigned int to_width, to_height ;
    ASGradient grad ;
    ASGradient default_grad = { 1, 11, &(default_colors[0]),
                                       &(default_offsets[0])} ;
    ASImage *grad_im = NULL;

    /* see ASView.1 : */
    set_application_name( argv[0] ); #if (HAVE_AFTERBASE_FLAG==1)
    set_output_threshold(OUTPUT_LEVEL_DEBUG); #endif

    if( argc > 1 )
    {
        if( strcmp( argv[1], "-h") == 0 )
        {
            usage();
            return 0;
        }
        /* see ASScale.1 : */
        geom_flags = XParseGeometry( argv[1], &dummy, &dummy,
                                     &to_width, &to_height );
    }else
        usage();
    memset( &grad, 0x00, sizeof(ASGradient));

#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

    if( argc >= 5 )
    {
        int i = 2;
        /* see ASGrad.1 : */
        grad.type = atoi( argv[2] );
        grad.npoints = 0 ;
        grad.color = safemalloc( ((argc-2)/2)*sizeof(ARGB32));
        grad.offset = safemalloc( ((argc-2)/2)*sizeof(double));
        while( ++i < argc )
        {
            if( grad.npoints > 0 )
            {
                if( i == argc-1 )
                    grad.offset[grad.npoints] = 1.0;
                else
                    grad.offset[grad.npoints] = atof( argv[i] );
                ++i ;
            }

            /* see ASTile.1 : */
            if( parse_argb_color( argv[i], &(grad.color[grad.npoints]))
                != argv[i] )
                if( grad.offset[grad.npoints] >= 0. &&
                    grad.offset[grad.npoints]<= 1.0 )
                    grad.npoints++ ;
        }
    }else
    {
        grad = default_grad ;
        if( argc >= 3 )
            grad.type = atoi( argv[2] );
    }

    if( grad.npoints <= 0 )
    {
        show_error( " not enough gradient points specified.");
        return 1;
    }

    /* Making sure tiling geometry is sane : */ #ifndef X_DISPLAY_MISSING
    if( !get_flags(geom_flags, WidthValue ) )
        to_width  = DisplayWidth(dpy, screen)*2/3 ;
    if( !get_flags(geom_flags, HeightValue ) )
        to_height = DisplayHeight(dpy, screen)*2/3 ; #else
    if( !get_flags(geom_flags, WidthValue ) )
        to_width  = 500 ;
    if( !get_flags(geom_flags, HeightValue ) )
        to_height = 500 ; #endif
    printf( "%s: rendering gradient of type %d to %dx%d\n",
            get_application_name(), grad.type&GRADIENT_TYPE_MASK,
            to_width, to_height );

    /* see ASView.3 : */
    asv = create_asvisual( dpy, screen, depth, NULL );
    /* see ASGrad.2 : */
    grad_im = make_gradient( asv, &grad, to_width, to_height,
                             SCL_DO_ALL, #ifndef X_DISPLAY_MISSING
                             ASA_XImage, #else
                             ASA_ASImage, #endif
                             0, ASIMAGE_QUALITY_DEFAULT );
    if( grad_im )
    { #ifndef X_DISPLAY_MISSING
        /* see ASView.4 : */
        Window w = create_top_level_window( asv, DefaultRootWindow(dpy), 32, 32,
                                            to_width, to_height, 1, 0, NULL,
                                            "ASGradient", NULL );
        if( w != None )
        {
            Pixmap p ;

            XMapRaised   (dpy, w);
            /* see ASView.5 : */
            p = asimage2pixmap( asv, DefaultRootWindow(dpy), grad_im,
                                NULL, True );
            destroy_asimage( &grad_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
        ASImage2file( grad_im, NULL, "asgrad.jpg", ASIT_Jpeg, NULL );
        destroy_asimage( &grad_im ); #endif
    }
    return 0 ; }

libAfterImage/tutorials/ASGrad.1 [5.1] 🫢


πŸŽ€ ASGrad.1 [5.1] πŸŽ€

✨ SYNOPSIS ✨

Step 1. Building gradient specs.

πŸ’– DESCRIPTION πŸ’–

so a multipoint gradient is literally just a set of color values, each one with an offset marking how far that point sits from the beginning of the gradient β€” all on a 1.0 scale, bestie. and the rules? the first and last point in the gradient should always be at 0. and 1.0 respectively, and every other point has to live in between them. like, a 2 point gradient will always have offsets 0. and 1.0. a 3 point gradient gets 0. for the first color, 1.0 for the last color, and anything in between for the middle color. πŸ’«

and if an offset is incorrect?? the point gets skipped at the time of rendering. no warning, just gone. tragic but that's the deal 😭

There are 4 types of gradients supported:

  • horizontal
  • top-left to bottom-right diagonal
  • vertical
  • top-right to bottom-left diagonal

also, any cilindrical gradient could be drawn as a 3 point gradient with the border colors being the same. cute little trick, iykyk πŸŽ€

and here's the slay part: each gradient point has an ARGB color, which means it's possible to draw gradients in the alpha channel as well as RGB. that means semitransparent gradients, fading gradients, etc. etc. iconique ✨

🌈 EXAMPLE 🌈

    grad.type = atoi( argv[2] );
        grad.npoints = 0 ;
        grad.color = safemalloc( ((argc-2)/2)*sizeof(ARGB32));
        grad.offset = safemalloc( ((argc-2)/2)*sizeof(double));
        while( ++i < argc )
        {
            if( grad.npoints > 0 )
            {
                if( i == argc-1 )
                    grad.offset[grad.npoints] = 1.0;
                else
                    grad.offset[grad.npoints] = atof( argv[i] );
                ++i ;
            }
        if( parse_argb_color( argv[i], &(grad.color[grad.npoints]))
             != argv[i] )
            if(grad.offset[grad.npoints] >= 0. &&
            grad.offset[grad.npoints]<= 1.0 )
                grad.npoints++ ;
        }

πŸ’œ SEE ALSO πŸ’œ

ARGB32, parse_argb_color(), ASGradient

libAfterImage/tutorials/ASGrad.2 [5.2] πŸ¦‹


πŸ¦‹ ASGrad.2 [5.2] πŸ¦‹

✨ SYNOPSIS ✨

Step 2. Actually rendering gradient.

πŸ’– DESCRIPTION πŸ’–

okay so the entire fandom of actually drawing a gradient is: call make_gradient() and hand her a pointer to the ASGradient structure that describes your gradient. obviously you also need the size of the gradient, duh. another parameter is the filter β€” that's a bit mask that lets you draw the gradient using only a subset of the channels, represented by the set bits. SCL_DO_ALL means all 4 channels must be rendered, periodt. πŸ’…

make_gradient() creates an ASImage of the requested size and fills it with the gradient. and because the devs ate, a special techinque based on error diffusion is utilized to avoid sharp steps between grades of colors when a limited range of colors is used for the gradient. no ugly banding, we don't know her 🫢

🌈 EXAMPLE 🌈

    grad_im = make_gradient( asv, &grad, to_width, to_height,
                             SCL_DO_ALL,
                             ASA_XImage, 0, ASIMAGE_QUALITY_DEFAULT );

πŸ“ NOTES πŸ“

make_gradient(), ASScanline, ASImage.


and that's the page bestie πŸ’– this whole tutorial came to you from the 3rd Berkeley Distribution, running AfterStep v.2.2.12, and it's filed under the asgrad(3x) header. go forth and gradient, you're the main character now βœ¨πŸŽ€πŸŒˆ

πŸ“¦ where this page comes from