xscreenshot

suckless screen capture tool
git clone git://git.2f30.org/xscreenshot.git
Log | Files | Refs | README | LICENSE

commit 1cf03c53b280d3fe21dac843504dd54e9b64e4b6
Author: Hiltjo Posthuma <hiltjo@codemadness.org>
Date:   Sun Jul 27 21:22:39 +0000

initial import

Signed-off-by: Hiltjo Posthuma <hiltjo@codemadness.org>

Diffstat:
.gitignore | 2++
LICENSE | 21+++++++++++++++++++++
Makefile | 9+++++++++
README | 31+++++++++++++++++++++++++++++++
TODO | 5+++++
xscreenshot.c | 133+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
6 files changed, 201 insertions(+), 0 deletions(-)
diff --git a/.gitignore b/.gitignore @@ -0,0 +1,2 @@ +xscreenshot +*.o diff --git a/LICENSE b/LICENSE @@ -0,0 +1,21 @@ +MIT/X Consortium License + +(c) 2014 Hiltjo Posthuma <hiltjo@codemadness.org> + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/Makefile b/Makefile @@ -0,0 +1,9 @@ +build: clean + cc xscreenshot.c -o xscreenshot -lX11 -lpng -Wall -Wextra -pedantic -std=c99 + +test: build + ./xscreenshot > screen.png + meh screen.png + +clean: + rm -f xscreenshot diff --git a/README b/README @@ -0,0 +1,31 @@ +xscreenshot - make screenshot +============================= + +xscreenshot is a simple screenshot utility. It writes image data to stdout. + + +Dependencies +------------ + +- libpng +- libX11 + + +Compile +------- + +run make or: + +cc xscreenshot.c -o xscreenshot -lX11 -lpng + + +Usage +----- + +xscreenshot [winid] > file.png + + +Known issues +------------ + +A specified windowid has to be visible on the screen. diff --git a/TODO b/TODO @@ -0,0 +1,5 @@ +- I might have missed a few cases of color conversion (convertrow_*). +- write a man page. +- write a Makefile (suckless-style). +- better multi-monitor support. +- write a "if" output: http://git.2f30.org/imagefile/. diff --git a/xscreenshot.c b/xscreenshot.c @@ -0,0 +1,133 @@ +/* see LICENSE / README for more info */ +#include <stdio.h> +#include <stdint.h> +#include <string.h> +#include <stdlib.h> +#include <errno.h> + +/* X11 */ +#include <X11/X.h> +#include <X11/Xlib.h> +#include <X11/Xutil.h> + +/* png */ +#include <png.h> + +static void +die(const char *s) { + fprintf(stderr, "xscreenshot: %s\n", s); + exit(EXIT_FAILURE); +} + +/* LSBFirst: BGRA -> RGBA */ +static void +convertrow_lsb(unsigned char *drow, unsigned char *srow, XImage *img) { + int sx, dx; + + for(sx = 0, dx = 0; dx < img->bytes_per_line - 4; sx += 4) { + drow[dx++] = srow[sx + 2]; /* B -> R */ + drow[dx++] = srow[sx + 1]; /* G -> G */ + drow[dx++] = srow[sx]; /* R -> B */ + if(img->depth == 32) + drow[dx++] = srow[sx + 3]; /* A -> A */ + else + drow[dx++] = 255; + } +} + +/* MSBFirst: ARGB -> RGBA */ +static void +convertrow_msb(unsigned char *drow, unsigned char *srow, XImage *img) { + int sx, dx; + + for(sx = 0, dx = 0; dx < img->bytes_per_line - 4; sx += 4) { + drow[dx++] = srow[sx + 1]; /* G -> R */ + drow[dx++] = srow[sx + 2]; /* B -> G */ + drow[dx++] = srow[sx + 3]; /* A -> B */ + if(img->depth == 32) + drow[dx++] = srow[sx]; /* R -> A */ + else + drow[dx++] = 255; + } +} + +static void +pngstdout(XImage *img) +{ + png_structp png_struct_p; + png_infop png_info_p; + void (*convert)(unsigned char *, unsigned char *, XImage *); + unsigned char *drow = NULL, *srow; + int h; + + png_struct_p = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, + NULL); + png_info_p = png_create_info_struct(png_struct_p); + + if(!png_struct_p || !png_info_p || setjmp(png_jmpbuf(png_struct_p))) + die("failed to initialize libpng"); + + png_init_io(png_struct_p, stdout); + png_set_IHDR(png_struct_p, png_info_p, img->width, img->height, 8, + PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); + png_write_info(png_struct_p, png_info_p); + + srow = (unsigned char *)img->data; + drow = calloc(1, img->width * 4); /* output RGBA */ + if(!drow) + die("Can't calloc"); + + if(img->byte_order == LSBFirst) + convert = convertrow_lsb; + else + convert = convertrow_msb; + + for(h = 0; h < img->height; h++) { + convert(drow, srow, img); + srow += img->bytes_per_line; + png_write_row(png_struct_p, drow); + } + png_write_end(png_struct_p, NULL); + + free(drow); + png_free_data(png_struct_p, png_info_p, PNG_FREE_ALL, -1); + png_destroy_write_struct(&png_struct_p, NULL); +} + +int +main(int argc, char *argv[]) +{ + XImage *img; + Display *dpy; + Window win; + XWindowAttributes attr; + + dpy = XOpenDisplay(NULL); + if(!dpy) + die("Can't XOpenDisplay"); + + /* win */ + if(argc > 1) { + errno = 0; + win = (Window)strtol(argv[1], NULL, 0); + if(errno != 0) + die("input not a number"); + } else { + win = RootWindow(dpy, 0); + } + + XGrabServer(dpy); + XGetWindowAttributes(dpy, win, &attr); + + img = XGetImage(dpy, win, 0, 0, attr.width, attr.height, 0xffffffff, + ZPixmap); + if(!img) + die("Can't XGetImage"); + pngstdout(img); + XDestroyImage(img); + XUngrabServer(dpy); + XCloseDisplay(dpy); + + return EXIT_SUCCESS; +}