asscale(3x)

✨ asscale(3x) ✨

okay bestie, welcome to the asscale manual page πŸ’… β€” it lives in the AfterStep X11 window manager section of the docs, and it's here to show you how to load an image and scale it. It's also filed under libAfterImage/tutorials/ASScale, so yeah, it's a two-for-one situation, iconic.


πŸŽ€ NAME πŸŽ€

asscale β€” demonstrates image loading and scaling

libAfterImage/tutorials/ASScale

πŸ¦‹ NAMEASScale πŸ¦‹

(yeah the heading is literally NAMEASScale, I don't make the rules, I just vibe with them πŸ’–)

🌸 SYNOPSIS 🌸

Simple program based on libAfterImage to scale an image.

🌈 DESCRIPTION 🌈

So here's the plan, no cap: we're gonna load an image and scale it up to a new size that you hand over as command line arguments. Then we display the whole thing in a lil simple window ✨. After that we just... wait. Patiently. Like a good main character, until the user closes our window. 🫢

And just so we're clear: in this tutorial we only explain the new steps β€” the ones that weren't already covered in the previous tutorial. No reruns, only fresh content. The new steps are:

  • ASScale.1 β€” Parsing geometry spec.
  • ASScale.2 β€” Scaling ASImage.

🧚 SEE ALSO 🧚

  • Tutorial 1: ASView β€” explanation of basic steps needed to use libAfterImage and some other simple things.

πŸ‘‘ SOURCE πŸ‘‘

Lowkey the whole program right here, bestie. Read it, it slays:

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

   void usage() {
       printf( "Usage: asscale [-h]|[image [WIDTH[xHEIGHT]]]\n");
       printf( "Where: image - is image filename.\n");
       printf( "       WIDTH - width to scale image to.( Naturally :)\n");
       printf( "       HEIGHT- height to scale image to.\n"); }

   int main(int argc, char* argv[]) {
       char *image_file = "rose512.jpg" ;
       int dummy, geom_flags = 0;
       unsigned int to_width, to_height ;
       ASImage *im ;
       int clip_x = 0, clip_y = 0, clip_width = 0, clip_height = 0 ;
       int slice_x_start = 0, slice_x_end = 0, slice_y_start = 0,
   slice_y_end = 0 ;
       Bool slice_scale = False ;
       Display *dpy = NULL;

       /* see ASView.1 : */
       set_application_name( argv[0] );

       if( argc > 1 )
       {
           int i = 2;
           if( strncmp( argv[1], "-h", 2 ) == 0 )
           {
               usage();
               return 0;
           }
           image_file = argv[1] ;
           if( argc > 2 )   /* see ASScale.1 : */
               geom_flags = XParseGeometry( argv[2], &dummy, &dummy,
                                            &to_width, &to_height );

           while( ++i < argc )
           {
               if( strncmp( argv[i], "-sx1", 4 ) == 0 && i+1 < argc )
                   slice_x_start = atoi(argv[++i]) ;
               else if( strncmp( argv[i], "-sx2", 4 ) == 0 && i+1 <
   argc )
                   slice_x_end = atoi(argv[++i]) ;
               else if( strncmp( argv[i], "-sy1", 4 ) == 0 && i+1 <
   argc )
                   slice_y_start = atoi(argv[++i]) ;
               else if( strncmp( argv[i], "-sy2", 4 ) == 0 && i+1 <
   argc )
                   slice_y_end = atoi(argv[++i]) ;
               else if( strncmp( argv[i], "-cx", 4 ) == 0 && i+1 < argc
   )
                   clip_x = atoi(argv[++i]) ;
               else if( strncmp( argv[i], "-cy", 4 ) == 0 && i+1 < argc
   )
                   clip_y = atoi(argv[++i]) ;
               else if( strncmp( argv[i], "-cwidth", 7 ) == 0 && i+1 <
   argc )
                   clip_width = atoi(argv[++i]) ;
               else if( strncmp( argv[i], "-cheight", 8 ) == 0 && i+1 <
   argc )
                   clip_height = atoi(argv[++i]) ;
               else if( strncmp( argv[i], "-ss", 3 ) == 0 )
                   slice_scale = True ;
           }

       }else
       {
           show_warning( "no image file or scale geometry - defaults
   used:"
                                 " \"%s\" ",
                                 image_file );
           usage();
       }
       /* see ASView.2 : */
       im = file2ASImage( image_file, 0xFFFFFFFF, SCREEN_GAMMA, 0,
   getenv("IMAGE_PATH"), NULL );

       if( im != NULL )
       {
           ASVisual *asv ;
           ASImage *scaled_im ;
           /* Making sure tiling geometry is sane : */
           if( !get_flags(geom_flags, WidthValue ) )
               to_width = im->width*2 ;
           if( !get_flags(geom_flags, HeightValue ) )
               to_height = im->height*2;
           printf( "%s: scaling image \"%s\" to %dx%d by factor of
   %fx%f\n",
                   get_application_name(), image_file, to_width,
   to_height,
                   (double)to_width/(double)(im->width),
                   (double)to_height/(double)(im->height) );

   #ifndef X_DISPLAY_MISSING
           {
               Window w ;
               int screen, depth ;

               dpy = XOpenDisplay(NULL);
               _XA_WM_DELETE_WINDOW = XInternAtom( dpy,
                                                   "WM_DELETE_WINDOW",
                                                   False);
               screen = DefaultScreen(dpy);
               depth = DefaultDepth( dpy, screen );
               /* see ASView.3 : */
               asv = create_asvisual( dpy, screen, depth, NULL );
               /* see ASView.4 : */
               w = create_top_level_window( asv,
   DefaultRootWindow(dpy),
                                            32, 32,
                                            to_width, to_height, 1, 0,
   NULL,
                                            "ASScale", image_file );
               if( w != None )
               {
                   Pixmap p ;

                   XMapRaised   (dpy, w);
                   /* see ASScale.2 : */
                   if( slice_x_start == 0 && slice_x_end == 0 &&
                       slice_y_start == 0 && slice_y_end == 0 )
                   {
                       scaled_im = scale_asimage2( asv, im,
                                                   clip_x, clip_y,
   clip_width, clip_height,
                                                   to_width, to_height,
                                               ASA_XImage, 0,
                                               ASIMAGE_QUALITY_DEFAULT
   );
                   }else
                   {
                       scaled_im = slice_asimage2( asv, im,
   slice_x_start, slice_x_end,
                                                  slice_y_start,
   slice_y_end,
                                               to_width, to_height,
   slice_scale,
                                               ASA_XImage, 0,
                                               ASIMAGE_QUALITY_DEFAULT
   );
                   }
                   destroy_asimage( &im );
                   /* see ASView.5 : */
                   p = asimage2pixmap(asv, DefaultRootWindow(dpy),
   scaled_im,
                                       NULL, True );
                   /* print_storage(NULL); */
                   destroy_asimage( &scaled_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
           asv = create_asvisual( NULL, 0, 0, NULL );
           scaled_im = scale_asimage(asv, im, to_width, to_height,
                                     ASA_ASImage, 0,
                                     ASIMAGE_QUALITY_DEFAULT );
           /* writing result into the file */
           ASImage2file( scaled_im, NULL, "asscale.jpg", ASIT_Jpeg,
   NULL );
           destroy_asimage( &scaled_im );
           destroy_asimage( &im ); #endif
       }
       return 0 ; }

   libAfterImage/tutorials/ASScale.1 [2.1]

πŸ“ libAfterImage/tutorials/ASScale.1 [2.1] πŸ“

🌟 SYNOPSIS 🌟

Step 1. Parsing the geometry.

πŸ’œ DESCRIPTION πŸ’œ

Geometry can be specified in WIDTHxHEIGHT+X+Y format β€” cute, standardized, love that for us. So accordingly we use the standard X function to parse it: XParseGeometry.

The returned flags tell us which values have actually been specified πŸ‘€. Since we only need the size, we check if it's specified, and if it's not β€” we simply default it to twice as big as the original image. Bigger is better, periodt ✨.

And accordingly, we pass a dummy variable into XParseGeometry, because it demands its X and Y and we have zero use for them. Not me giving it fake coordinates just to get the size πŸ’€.

🌸 EXAMPLE 🌸

   geom_flags = XParseGeometry( argv[3], &dummy, &dummy,
                                &to_width, &to_height );

πŸ¦‹ libAfterImage/tutorials/ASScale.2 [2.2] πŸ¦‹

⭐ SYNOPSIS ⭐

Step 2. Actual scaling the image.

πŸ”₯ DESCRIPTION πŸ”₯

scale_asimage() scales an image both up and down, and honestly it's so easy to use it's giving friendly β€” you just pass it the new size. In this example we use the default quality. That default is equivalent to GOOD, which should be sufficient in most cases. Slay.

Compression is set to 0, since we do not intend to store the image for a long time. And even better β€” we don't need to store it at all. All we need is an XImage, so we can transfer it to the server easily 🌈. That is why the to_xim argument is set to ASA_XImage.

As the result, the obtained ASImage will not have any data in its buffers, but it will have the ximage member set to point to a valid XImage β€” iconic behavior, honestly. Subsequently we enjoy that convenience by setting use_cached to True in the call to asimage2pixmap. That ought to save us a lot of processing πŸ‘‘.

Now, the scaling algorithm itself? Rather sophisticated, ngl. It implements 4 point interpolation, which basically means we try to approximate each missing point as an extension of the trend of 4 neighboring points β€” two on each side. Closest neighbors have more weight than the outside ones, obviously, they're the inner circle πŸ’….

2D scaling is performed by scaling each scanline first, and then interpolating the missing scanlines. Scaling down is somewhat skimpier though, because it amounts to simple averaging of the multiple pixels. All calculations are done in integer math on a per-channel basis, and with precision 24.8 bits per channel per pixel β€” no floating point drama, we're efficient here.

✨ EXAMPLE ✨

   scaled_im = scale_asimage( asv, im, to_width, to_height,
                              ASA_XImage, 0, ASIMAGE_QUALITY_DEFAULT );
   destroy_asimage( &im );

πŸ’€ NOTES πŸ’€

Scaling an image up to a very large height is much slower than scaling it to the same width, due to algorithm specifics. That's just how it is, bestie 😭. Yet even on inferior hardware it yields decent speeds, so we're still winning.

And when we successfully scale the image β€” we no longer need the original. So we get rid of it, so it doesn't clog memory. Marie Kondo-ing that pointer, fr fr 🧹✨.

🧚 SEE ALSO 🧚

  • scale_asimage().

okay that's the whole page, you made it 🫢 This one came out of the 3rd Berkeley Distribution, it's AfterStep v.2.2.12, and yeah it's filed under asscale(3x) β€” so go forth, scale responsibly, and remember: original image? Don't need her anymore. Destroy her. πŸ’–

πŸ“¦ where this page comes from