t* My version of sent
       
   URI git clone git://git.codevoid.de/sent-sdk.git
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
   DIR commit b516f468faa3a80c31932cbcb1ea8ccd1468ffc1
   DIR parent 7e558105e6e46a6a2592f2ee15220b99922cd1f0
   URI Author: sin <sin@2f30.org>
       Date:   Wed, 18 Nov 2015 10:41:02 +0000
       
       Support farbfeld as an intermediate format
       
       Sent now uses farbfeld[0] as an intermediate format.  A series of
       filters is specified in config.h that matches file extensions to
       filter programs.  The programs will convert between formats such as
       png to farbfeld.  Internally in sent we do not need to worry on how
       tto parse png or any other format.
       
       This also works with jpg and gif and others.  The 2ff wrapper will
       use imagemagick conversion tools.  This is temporary as jpg2ff and
       gif2ff will also be implemented.
       
       To make this work, you will have to clone[0] and put png2ff and 2ff
       in your PATH.
       
       t[0] http://git.2f30.org/farbfeld/
       
       Diffstat:
         M LICENSE                             |       2 --
         M README.md                           |       1 -
         M config.def.h                        |       5 +++++
         M config.mk                           |       2 +-
         M example                             |       1 -
         M sent.c                              |     204 +++++++++++++++++--------------
       
       6 files changed, 119 insertions(+), 96 deletions(-)
       ---
   DIR diff --git a/LICENSE b/LICENSE
       t@@ -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
   DIR diff --git a/README.md b/README.md
       t@@ -33,7 +33,6 @@ presentation file could look like this:
                
                depends on
                - Xlib
       -        - libpng
                
                sent FILENAME
                one slide per paragraph
   DIR diff --git a/config.def.h b/config.def.h
       t@@ -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" },
       +};
   DIR diff --git a/config.mk b/config.mk
       t@@ -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
   DIR diff --git a/example b/example
       t@@ -20,7 +20,6 @@ easy to use
        
        depends on
        ♽ Xlib
       -☢ libpng
        
        ~1000 lines of code
        
   DIR diff --git a/sent.c b/sent.c
       t@@ -1,12 +1,17 @@
        /* See LICENSE for licence details. */
       +#include <sys/types.h>
       +#include <arpa/inet.h>
       +
        #include <errno.h>
       +#include <fcntl.h>
        #include <math.h>
       -#include <png.h>
       +#include <regex.h>
        #include <stdarg.h>
        #include <stdio.h>
        #include <stdint.h>
        #include <stdlib.h>
        #include <string.h>
       +#include <unistd.h>
        #include <X11/keysym.h>
        #include <X11/XKBlib.h>
        #include <X11/Xatom.h>
       t@@ -36,13 +41,16 @@ 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;
                Image *img;
       t@@ -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();
       t@@ -128,56 +136,87 @@ static void (*handler[LASTEvent])(XEvent *) = {
                [KeyPress] = kpress,
        };
        
       -Image *pngopen(char *filename)
       +int
       +filter(int fd, const char *cmd)
       +{
       +        int fds[2];
       +
       +        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)
        {
       -        FILE *f;
       -        unsigned char buf[8];
       +        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(&regex, filters[i].regex,
       +                            REG_NOSUB | REG_EXTENDED | REG_ICASE))
       +                        continue;
       +                if (!regexec(&regex, filename, 0, NULL, 0)) {
       +                        bin = filters[i].bin;
       +                        break;
       +                }
       +        }
        
       -        if (!(f = fopen(filename, "rb"))) {
       +        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))
       -                return NULL;
       +        tmpfd = fd;
       +        fd = filter(fd, bin);
       +        if (fd < 0)
       +                eprintf("could not filter %s:", filename);
       +        close(tmpfd);
        
       -        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 (read(fd, hdr, 16) != 16)
                        return NULL;
       -        }
       -        if (!(img->info_ptr = png_create_info_struct(img->png_ptr))
       -            || setjmp(png_jmpbuf(img->png_ptr))) {
       -                pngfree(img);
       +
       +        if (memcmp("farbfeld", hdr, 8))
                        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;
       t@@ -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;
       t@@ -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;
       t@@ -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;
       t@@ -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;
       t@@ -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] == '\\')
       t@@ -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]);
                }
        }
        
       t@@ -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);
                }
        }