diff --git a/LICENSE b/LICENSE index d1da8fc..8d5665e 100644 --- a/LICENSE +++ b/LICENSE @@ -2,8 +2,6 @@ The MIT License (MIT) Copyright (c) 2014-2015 Markus Teich -png handling stuff adapted from meh by John Hawthorn - 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 diff --git a/README.md b/README.md index 007564b..e213efb 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,6 @@ presentation file could look like this: depends on - Xlib - - libpng sent FILENAME one slide per paragraph diff --git a/config.def.h b/config.def.h index 2dae620..94ed09e 100644 --- a/config.def.h +++ b/config.def.h @@ -45,3 +45,8 @@ static Shortcut shortcuts[] = { { XK_n, advance, {.i = +1} }, { XK_p, advance, {.i = -1} }, }; + +static Filter filters[] = { + { "\\.png$", "png2ff" }, + { "\\.(jpg|gif)$", "2ff" }, +}; diff --git a/config.mk b/config.mk index ed08199..52d5fb1 100644 --- a/config.mk +++ b/config.mk @@ -12,7 +12,7 @@ X11LIB = /usr/X11R6/lib # includes and libs INCS = -I. -I/usr/include -I/usr/include/freetype2 -I${X11INC} -LIBS = -L/usr/lib -lc -lm -L${X11LIB} -lXft -lfontconfig -lX11 -lpng +LIBS = -L/usr/lib -lc -lm -L${X11LIB} -lXft -lfontconfig -lX11 # flags CPPFLAGS = -DVERSION=\"${VERSION}\" -D_XOPEN_SOURCE=600 diff --git a/example b/example index 39e0206..d4b62d2 100644 --- a/example +++ b/example @@ -20,7 +20,6 @@ easy to use depends on ♽ Xlib -☢ libpng ~1000 lines of code diff --git a/sent.c b/sent.c index e717a69..eb3aadc 100644 --- a/sent.c +++ b/sent.c @@ -1,12 +1,17 @@ /* See LICENSE for licence details. */ +#include +#include + #include +#include #include -#include +#include #include #include #include #include #include +#include #include #include #include @@ -36,12 +41,15 @@ typedef struct { unsigned int bufwidth, bufheight; imgstate state; XImage *ximg; - FILE *f; - png_structp png_ptr; - png_infop info_ptr; + int fd; int numpasses; } Image; +typedef struct { + char *regex; + char *bin; +} Filter; + typedef struct { unsigned int linecount; char **lines; @@ -79,12 +87,12 @@ typedef struct { const Arg arg; } Shortcut; -static Image *pngopen(char *filename); -static void pngfree(Image *img); -static int pngread(Image *img); -static int pngprepare(Image *img); -static void pngscale(Image *img); -static void pngdraw(Image *img); +static Image *ffopen(char *filename); +static void fffree(Image *img); +static int ffread(Image *img); +static int ffprepare(Image *img); +static void ffscale(Image *img); +static void ffdraw(Image *img); static void getfontsize(Slide *s, unsigned int *width, unsigned int *height); static void cleanup(); @@ -128,56 +136,87 @@ static void (*handler[LASTEvent])(XEvent *) = { [KeyPress] = kpress, }; -Image *pngopen(char *filename) +int +filter(int fd, const char *cmd) { - FILE *f; - unsigned char buf[8]; - Image *img; + int fds[2]; - if (!(f = fopen(filename, "rb"))) { + if (pipe(fds) < 0) + eprintf("pipe:"); + + switch (fork()) { + case -1: + eprintf("fork:"); + case 0: + dup2(fd, 0); + dup2(fds[1], 1); + close(fds[0]); + close(fds[1]); + execlp(cmd, cmd, (char *)0); + eprintf("execlp %s:", cmd); + } + close(fds[1]); + return fds[0]; +} + +Image *ffopen(char *filename) +{ + unsigned char hdr[16]; + char *bin; + regex_t regex; + Image *img; + size_t i; + int tmpfd, fd; + + for (bin = NULL, i = 0; i < LEN(filters); i++) { + if (regcomp(®ex, filters[i].regex, + REG_NOSUB | REG_EXTENDED | REG_ICASE)) + continue; + if (!regexec(®ex, filename, 0, NULL, 0)) { + bin = filters[i].bin; + break; + } + } + + if ((fd = open(filename, O_RDONLY)) < 0) { eprintf("Unable to open file %s:", filename); return NULL; } - if (fread(buf, 1, 8, f) != 8 || png_sig_cmp(buf, 1, 8)) + tmpfd = fd; + fd = filter(fd, bin); + if (fd < 0) + eprintf("could not filter %s:", filename); + close(tmpfd); + + if (read(fd, hdr, 16) != 16) return NULL; - img = malloc(sizeof(Image)); - memset(img, 0, sizeof(Image)); - if (!(img->png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, - NULL, NULL))) { - free(img); + if (memcmp("farbfeld", hdr, 8)) return NULL; - } - if (!(img->info_ptr = png_create_info_struct(img->png_ptr)) - || setjmp(png_jmpbuf(img->png_ptr))) { - pngfree(img); - return NULL; - } - img->f = f; - rewind(f); - png_init_io(img->png_ptr, f); - png_read_info(img->png_ptr, img->info_ptr); - img->bufwidth = png_get_image_width(img->png_ptr, img->info_ptr); - img->bufheight = png_get_image_height(img->png_ptr, img->info_ptr); + img = calloc(1, sizeof(Image)); + img->fd = fd; + img->bufwidth = ntohl(*(uint32_t *)&hdr[8]); + img->bufheight = ntohl(*(uint32_t *)&hdr[12]); return img; } -void pngfree(Image *img) +void fffree(Image *img) { - png_destroy_read_struct(&img->png_ptr, img->info_ptr ? &img->info_ptr : NULL, NULL); free(img->buf); if (img->ximg) XDestroyImage(img->ximg); free(img); } -int pngread(Image *img) +int ffread(Image *img) { - unsigned int y; - png_bytepp row_pointers; + uint32_t y, x; + uint16_t *row; + size_t rowlen, off, nbytes; + ssize_t r; if (!img) return 0; @@ -187,59 +226,42 @@ int pngread(Image *img) if (img->buf) free(img->buf); + /* internally the image is stored in 888 format */ if (!(img->buf = malloc(3 * img->bufwidth * img->bufheight))) return 0; - if (setjmp(png_jmpbuf(img->png_ptr))) { - png_destroy_read_struct(&img->png_ptr, &img->info_ptr, NULL); + /* scratch buffer to read row by row */ + rowlen = img->bufwidth * 2 * strlen("RGBA"); + row = malloc(rowlen); + if (!row) { + free(img->buf); + img->buf = NULL; return 0; } - { - int color_type = png_get_color_type(img->png_ptr, img->info_ptr); - int bit_depth = png_get_bit_depth(img->png_ptr, img->info_ptr); - if (color_type == PNG_COLOR_TYPE_PALETTE) - png_set_expand(img->png_ptr); - if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) - png_set_expand(img->png_ptr); - if (png_get_valid(img->png_ptr, img->info_ptr, PNG_INFO_tRNS)) - png_set_expand(img->png_ptr); - if (bit_depth == 16) - png_set_strip_16(img->png_ptr); - if (color_type == PNG_COLOR_TYPE_GRAY - || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) - png_set_gray_to_rgb(img->png_ptr); - - png_color_16 my_background = {.red = 0xff, .green = 0xff, .blue = 0xff}; - png_color_16p image_background; - - if (png_get_bKGD(img->png_ptr, img->info_ptr, &image_background)) - png_set_background(img->png_ptr, image_background, PNG_BACKGROUND_GAMMA_FILE, 1, 1.0); - else - png_set_background(img->png_ptr, &my_background, PNG_BACKGROUND_GAMMA_SCREEN, 2, 1.0); - - if (png_get_interlace_type(img->png_ptr, img->info_ptr) == PNG_INTERLACE_ADAM7) - img->numpasses = png_set_interlace_handling(img->png_ptr); - else - img->numpasses = 1; - png_read_update_info(img->png_ptr, img->info_ptr); + for (off = 0, y = 0; y < img->bufheight; y++) { + nbytes = 0; + while (nbytes < rowlen) { + r = read(img->fd, (char *)row + nbytes, rowlen - nbytes); + if (r < 0) + eprintf("read:"); + nbytes += r; + } + for (x = 0; x < rowlen / 2; x += 4) { + img->buf[off++] = ntohs(row[x + 0]) / 257; + img->buf[off++] = ntohs(row[x + 1]) / 257; + img->buf[off++] = ntohs(row[x + 2]) / 257; + } } - row_pointers = (png_bytepp)malloc(img->bufheight * sizeof(png_bytep)); - for (y = 0; y < img->bufheight; y++) - row_pointers[y] = img->buf + y * img->bufwidth * 3; - - png_read_image(img->png_ptr, row_pointers); - free(row_pointers); - - png_destroy_read_struct(&img->png_ptr, &img->info_ptr, NULL); - fclose(img->f); + free(row); + close(img->fd); img->state |= LOADED; return 1; } -int pngprepare(Image *img) +int ffprepare(Image *img) { int depth = DefaultDepth(xw.dpy, xw.scr); int width = xw.uw; @@ -276,12 +298,12 @@ int pngprepare(Image *img) return 0; } - pngscale(img); + ffscale(img); img->state |= SCALED; return 1; } -void pngscale(Image *img) +void ffscale(Image *img) { unsigned int x, y; unsigned int width = img->ximg->width; @@ -306,7 +328,7 @@ void pngscale(Image *img) } } -void pngdraw(Image *img) +void ffdraw(Image *img) { int xoffset = (xw.w - img->ximg->width) / 2; int yoffset = (xw.h - img->ximg->height) / 2; @@ -364,7 +386,7 @@ void cleanup() free(slides[i].lines[j]); free(slides[i].lines); if (slides[i].img) - pngfree(slides[i].img); + fffree(slides[i].img); } free(slides); slides = NULL; @@ -443,7 +465,7 @@ void load(FILE *fp) /* only make image slide if first line of a slide starts with @ */ if (s->linecount == 0 && s->lines[0][0] == '@') { memmove(s->lines[0], &s->lines[0][1], blen); - s->img = pngopen(s->lines[0]); + s->img = ffopen(s->lines[0]); } if (s->lines[s->linecount][0] == '\\') @@ -465,10 +487,10 @@ void advance(const Arg *arg) slides[idx].img->state &= ~(DRAWN | SCALED); idx = new_idx; xdraw(); - if (slidecount > idx + 1 && slides[idx + 1].img && !pngread(slides[idx + 1].img)) - die("Unable to read image %s.", slides[idx + 1].lines[0]); - if (0 < idx && slides[idx - 1].img && !pngread(slides[idx - 1].img)) - die("Unable to read image %s.", slides[idx - 1].lines[0]); + if (slidecount > idx + 1 && slides[idx + 1].img && !ffread(slides[idx + 1].img)) + die("Unable to read image %s", slides[idx + 1].lines[0]); + if (0 < idx && slides[idx - 1].img && !ffread(slides[idx - 1].img)) + die("Unable to read image %s", slides[idx - 1].lines[0]); } } @@ -532,12 +554,12 @@ void xdraw() slides[idx].lines[i], 0); drw_map(d, xw.win, 0, 0, xw.w, xw.h); - } else if (!(im->state & LOADED) && !pngread(im)) { - eprintf("Unable to read image %s.", slides[idx].lines[0]); - } else if (!(im->state & SCALED) && !pngprepare(im)) { - eprintf("Unable to prepare image %s for drawing.", slides[idx].lines[0]); + } else if (!(im->state & LOADED) && !ffread(im)) { + eprintf("Unable to read image %s", slides[idx].lines[0]); + } else if (!(im->state & SCALED) && !ffprepare(im)) { + eprintf("Unable to prepare image %s for drawing", slides[idx].lines[0]); } else if (!(im->state & DRAWN)) { - pngdraw(im); + ffdraw(im); } }