Advertisement
Guest User

Efficient Screenshotting under X11 in Linux

a guest
Jul 29th, 2021
272
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 5.25 KB | None | 0 0
  1. /*
  2.     This has been posted in reference to the "Real-Time Neural Style Transfer in Quake 3" article posted on;
  3.     https://james-william-fletcher.medium.com/
  4.  
  5.     This code is an adaption of;
  6.     https://stackoverflow.com/questions/34176795/any-efficient-way-of-converting-ximage-data-to-pixel-map-e-g-array-of-rgb-quad/38298349#38298349
  7.  
  8.     Compile using:
  9.     gcc screenshot.c -o screenshot -std=c99 -lX11 -lXext -lpng -Ofast
  10. */
  11.  
  12. #include <stdio.h>
  13. #include <stdlib.h>
  14. #include <strings.h>
  15. #include <stdbool.h>
  16. #include <png.h>
  17. #include <sys/shm.h>
  18. #include <X11/Xlib.h>
  19. #include <X11/Xutil.h>
  20. #include <X11/extensions/XShm.h>
  21.  
  22. #define NAME  "screenshot"
  23. #define BPP   4
  24. #define uint unsigned int
  25.  
  26. struct shmimage
  27. {
  28.     XShmSegmentInfo shminfo;
  29.     XImage *ximage;
  30.     unsigned char *data; // will point to the image's BGRA packed pixels
  31. };
  32.  
  33. void initimage( struct shmimage * image )
  34. {
  35.     image->ximage = NULL;
  36.     image->shminfo.shmaddr = (char*)-1;
  37. }
  38.  
  39. void destroyimage( Display * dsp, struct shmimage * image )
  40. {
  41.     if( image->ximage )
  42.     {
  43.         XShmDetach( dsp, &image->shminfo ) ;
  44.         XDestroyImage( image->ximage ) ;
  45.         image->ximage = NULL ;
  46.     }
  47.  
  48.     if( image->shminfo.shmaddr != ( char * ) -1 )
  49.     {
  50.         shmdt( image->shminfo.shmaddr ) ;
  51.         image->shminfo.shmaddr = ( char * ) -1 ;
  52.     }
  53. }
  54.  
  55. int createimage( Display * dsp, struct shmimage * image, int width, int height )
  56. {
  57.     // Create a shared memory area
  58.     image->shminfo.shmid = shmget( IPC_PRIVATE, width * height * BPP, IPC_CREAT | 0600 ) ;
  59.     if( image->shminfo.shmid == -1 )
  60.     {
  61.         perror( NAME ) ;
  62.         return false ;
  63.     }
  64.  
  65.     // Map the shared memory segment into the address space of this process
  66.     image->shminfo.shmaddr = (char *) shmat( image->shminfo.shmid, 0, 0 ) ;
  67.     if( image->shminfo.shmaddr == (char *) -1 )
  68.     {
  69.         perror( NAME ) ;
  70.         return false ;
  71.     }
  72.  
  73.     image->data = (unsigned char*) image->shminfo.shmaddr ;
  74.     image->shminfo.readOnly = false ;
  75.  
  76.     // Mark the shared memory segment for removal
  77.     // It will be removed even if this program crashes
  78.     shmctl( image->shminfo.shmid, IPC_RMID, 0 ) ;
  79.  
  80.     // Allocate the memory needed for the XImage structure
  81.     image->ximage = XShmCreateImage( dsp, XDefaultVisual( dsp, XDefaultScreen( dsp ) ),
  82.                         DefaultDepth( dsp, XDefaultScreen( dsp ) ), ZPixmap, 0,
  83.                         &image->shminfo, 0, 0 ) ;
  84.     if( !image->ximage )
  85.     {
  86.         destroyimage( dsp, image ) ;
  87.         printf( NAME ": could not allocate the XImage structure\n" ) ;
  88.         return false ;
  89.     }
  90.  
  91.     image->ximage->data = (char *)image->data ;
  92.     image->ximage->width = width ;
  93.     image->ximage->height = height ;
  94.  
  95.     // Ask the X server to attach the shared memory segment and sync
  96.     XShmAttach( dsp, &image->shminfo ) ;
  97.     XSync( dsp, false ) ;
  98.     return true ;
  99. }
  100.  
  101. void getrootwindow( Display * dsp, struct shmimage * image )
  102. {
  103.     XShmGetImage( dsp, XDefaultRootWindow( dsp ), image->ximage, 0, 0, AllPlanes ) ;
  104.     // This is how you access the image's BGRA packed pixels
  105.     // Lets set the alpha channel of each pixel to 0xff
  106.     // int x, y ;
  107.     // unsigned int * p = image->data ;
  108.     // for( y = 0 ; y < image->ximage->height; ++y )
  109.     // {
  110.     //     for( x = 0 ; x < image->ximage->width; ++x )
  111.     //     {
  112.     //         *p++ |= 0xff000000 ;
  113.     //     }
  114.     // }
  115. }
  116.  
  117. void initpngimage( png_image * pi, struct shmimage * image )
  118. {
  119.     bzero( pi, sizeof( png_image ) ) ;
  120.     pi->version = PNG_IMAGE_VERSION ;
  121.     pi->width = image->ximage->width ;
  122.     pi->height = image->ximage->height ;
  123.     pi->format = PNG_FORMAT_BGRA ;
  124. }
  125.  
  126. int savepng( struct shmimage * image, char * path )
  127. {
  128.     FILE * f = fopen( path, "w" ) ;
  129.     if( !f )
  130.     {
  131.         perror( NAME ) ;
  132.         return false ;
  133.     }
  134.     png_image pi ;
  135.     initpngimage( &pi, image ) ;
  136.     unsigned int scanline = pi.width * BPP ;
  137.     if( !png_image_write_to_stdio( &pi, f, 0, image->data, scanline, NULL) )
  138.     {
  139.         fclose( f ) ;
  140.         printf( NAME ": could not save the png image\n" ) ;
  141.         return false ;
  142.     }
  143.     fclose( f ) ;
  144.     return true ;
  145. }
  146.  
  147. int main( int argc, char * argv[] )
  148. {
  149.     Display * dsp = XOpenDisplay( NULL ) ;
  150.     if( !dsp )
  151.     {
  152.         printf( NAME ": could not open a connection to the X server\n" ) ;
  153.         return 1 ;
  154.     }
  155.  
  156.     if( !XShmQueryExtension( dsp ) )
  157.     {
  158.         XCloseDisplay( dsp ) ;
  159.         printf( NAME ": the X server does not support the XSHM extension\n" ) ;
  160.         return 1 ;
  161.     }
  162.  
  163.     int screen = XDefaultScreen( dsp ) ;
  164.     struct shmimage image ;
  165.     initimage( &image ) ;
  166.     if( !createimage( dsp, &image, XDisplayWidth( dsp, screen ), XDisplayHeight( dsp, screen ) ) )
  167.     {
  168.         XCloseDisplay( dsp ) ;
  169.         return 1 ;
  170.     }
  171.  
  172.     const int ms = 8;
  173.     int c = 0;
  174.     time_t st = time(0);
  175.     while(time(0)-st <= ms)
  176.     {
  177.         //char name[32];
  178.         //sprintf(name, "%i.png", rand());
  179.         getrootwindow( dsp, &image ) ;
  180.         //savepng( &image, name );
  181.         c++;
  182.     }
  183.     printf("Screenshots Per Second: %i\n", c/ms);
  184.  
  185.     destroyimage( dsp, &image ) ;
  186.     XCloseDisplay( dsp ) ;
  187.     return 0 ;
  188. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement