/* ** Permission to use, copy, modify, and distribute this software and its ** documentation for any purpose and without fee is hereby granted, ** provided that the above copyright notice appear in all copies and that ** both that copyright notice and this permission notice appear in ** supporting documentation. ** ** This file is provided AS IS with no warranties of any kind. The author ** shall have no liability with respect to the infringement of copyrights, ** trade secrets or any patents by this file or any part thereof. In no ** event will the author be liable for any lost revenue or profits or ** other special, indirect and consequential damages. ** ** Revision History: ** ** 20030828 1.0 acd First Release. ** Changed to get dimensions from window. */ #include #include #include #include #include #define RGB_SIZE 3 /* one byte each for r, g and b */ /* ** function to grab image data from screen and create a jpeg from it. ** each time it's called the image name will increment giving a sequence. ** ** uses libjpeg and needs -ljpeg during linking. ** ** use -geometry {w}x{h} on command line to set grab size. ** pal vcd is 352x288. use 702x576 and scale down for anti-aliasing. ** convert to movie using something like this: ** mencoder -mf on -ovc lavc -lavcopts vcodec=mpeg4 grab\*.jpg */ void grab_frame(Display *display, Window window) { static int my_grabcount = 0; char grabname[100]; FILE *outfile; XImage *grabimage; unsigned char *row_pointer; unsigned char *end; int i; unsigned char *my_buffer = NULL; struct jpeg_compress_struct cinfo; struct jpeg_error_mgr jerr; XWindowAttributes xgwa; cinfo.err = jpeg_std_error(&jerr); jpeg_create_compress(&cinfo); sprintf(grabname, "grab%05d.jpg", my_grabcount); if ((outfile = fopen(grabname, "wb")) == NULL) { fprintf(stderr, "can't open %s\n", grabname); exit(-1); } jpeg_stdio_dest(&cinfo, outfile); /* get window dimensions */ XGetWindowAttributes (display, window, &xgwa); cinfo.image_width = xgwa.width; cinfo.image_height = xgwa.height; cinfo.input_components = RGB_SIZE; /* # of color components per pixel */ cinfo.in_color_space = JCS_RGB; /* colorspace of input image */ /* buffer for line - rgb * width */ my_buffer = (unsigned char *)malloc(xgwa.width * RGB_SIZE); if (my_buffer == NULL) { fprintf(stderr, "Cannot allocate memory for grab buffer\n"); exit(-1); } jpeg_set_defaults(&cinfo); jpeg_set_quality (&cinfo, 100, TRUE); jpeg_start_compress(&cinfo, TRUE); grabimage = XGetImage(display, window, 0, 0, xgwa.width, xgwa.height, ~0L, ZPixmap); row_pointer = grabimage->data; end = row_pointer + (grabimage->bytes_per_line * xgwa.height); while (row_pointer < end) { /* ** XGetImage gives us back a 32 bit value (rgba) but libjpeg only ** wants 24 bits (rgb) so compact the current scanline into my_buffer ** by ignoring every 4th byte */ int j = 0; for (i = 0 ; i < grabimage->bytes_per_line ; i += 4) { /* acd XXX sneaky byte swapping here, red becomes blue otherwise */ /* almost definately an endian thing */ my_buffer[j++] = row_pointer[i + 2]; my_buffer[j++] = row_pointer[i + 1]; my_buffer[j++] = row_pointer[i + 0]; } /*printf("scanline:%d\n", cinfo.next_scanline);*/ jpeg_write_scanlines(&cinfo, &my_buffer, 1); row_pointer += grabimage->bytes_per_line; } free(grabimage->data); grabimage->data = NULL; XDestroyImage(grabimage); jpeg_finish_compress(&cinfo); jpeg_destroy_compress(&cinfo); my_grabcount++; if ((my_grabcount % 1000) == 0) { printf("Grabbed [%d]\n", my_grabcount); } if (my_buffer != NULL) { free(my_buffer); my_buffer = NULL; } fclose(outfile); }