commit 1cf03c53b280d3fe21dac843504dd54e9b64e4b6
Author: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Sun, 27 Jul 2014 21:22:39 +0000
initial import
Signed-off-by: Hiltjo Posthuma <hiltjo@codemadness.org>
Diffstat:
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;
+}