--- a/ss.c +++ b/ss.c @@ -1,8 +1,11 @@ #include #include +#include + #include #include +#include static unsigned long lowbit(unsigned long x) @@ -27,6 +30,69 @@ return (unsigned char)((v * 255UL + (max / 2UL)) / max); } +static int +haspngext(const char *path) +{ + size_t n; + + n = strlen(path); + if (n < 4) + return 0; + return !strcmp(path + n - 4, ".png"); +} + +static int +writepng(FILE *f, XImage *img, unsigned int w, unsigned int h) +{ + png_structp png; + png_infop info; + unsigned char *row; + int ix; + int iy; + + png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + if (png == NULL) + return 0; + info = png_create_info_struct(png); + if (info == NULL) { + png_destroy_write_struct(&png, NULL); + return 0; + } + if (setjmp(png_jmpbuf(png))) { + png_destroy_write_struct(&png, &info); + return 0; + } + + png_init_io(png, f); + png_set_IHDR(png, info, w, h, 8, + PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); + png_write_info(png, info); + + row = malloc((size_t)w * 3U); + if (row == NULL) { + png_destroy_write_struct(&png, &info); + return 0; + } + + for (iy = 0; iy < (int)h; iy++) { + for (ix = 0; ix < (int)w; ix++) { + unsigned long p; + + p = XGetPixel(img, ix, iy); + row[ix * 3 + 0] = chan(p, img->red_mask); + row[ix * 3 + 1] = chan(p, img->green_mask); + row[ix * 3 + 2] = chan(p, img->blue_mask); + } + png_write_row(png, row); + } + + png_write_end(png, info); + free(row); + png_destroy_write_struct(&png, &info); + return 1; +} + int main(int argc, char **argv) { @@ -45,7 +111,7 @@ char tail; if (argc != 3) { - fprintf(stderr, "usage: ss WIDTHxHEIGHT+X+Y file.ppm\n"); + fprintf(stderr, "usage: ss WIDTHxHEIGHT+X+Y file.(ppm|png)\n"); return 1; } if (sscanf(argv[1], "%ux%u+%d+%d%c", &w, &h, &x, &y, &tail) != 4 || w == 0 || h == 0) { @@ -81,22 +147,32 @@ return 1; } - fprintf(f, "P6\n%u %u\n255\n", w, h); - for (iy = 0; iy < (int)h; iy++) { - for (ix = 0; ix < (int)w; ix++) { - unsigned long p; - unsigned char rgb[3]; + if (haspngext(argv[2])) { + if (!writepng(f, img, w, h)) { + fprintf(stderr, "png write failed: %s\n", argv[2]); + fclose(f); + XDestroyImage(img); + XCloseDisplay(dpy); + return 1; + } + } else { + fprintf(f, "P6\n%u %u\n255\n", w, h); + for (iy = 0; iy < (int)h; iy++) { + for (ix = 0; ix < (int)w; ix++) { + unsigned long p; + unsigned char rgb[3]; - p = XGetPixel(img, ix, iy); - rgb[0] = chan(p, img->red_mask); - rgb[1] = chan(p, img->green_mask); - rgb[2] = chan(p, img->blue_mask); - if (fwrite(rgb, 1, 3, f) != 3) { - fprintf(stderr, "write failed: %s\n", argv[2]); - fclose(f); - XDestroyImage(img); - XCloseDisplay(dpy); - return 1; + p = XGetPixel(img, ix, iy); + rgb[0] = chan(p, img->red_mask); + rgb[1] = chan(p, img->green_mask); + rgb[2] = chan(p, img->blue_mask); + if (fwrite(rgb, 1, 3, f) != 3) { + fprintf(stderr, "write failed: %s\n", argv[2]); + fclose(f); + XDestroyImage(img); + XCloseDisplay(dpy); + return 1; + } } } } --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ CFLAGS = -std=c89 -Wall -Wextra -Werror -pedantic CPPFLAGS = -I/usr/X11R6/include LDFLAGS = -L/usr/X11R6/lib -LDLIBS = -lX11 +LDLIBS = -lX11 -lpng all: ss