Since the PNM/PAM format already exist as a minimal intermediate representation with a rich set of commandline tools to manipulate them, use Netpbm to handle images. --- README.md | 8 ++--- config.def.h | 5 +-- config.mk | 2 +- example | 2 +- sent.c | 105 ++++++++++++++++++++++++++++++----------------------------- 5 files changed, 62 insertions(+), 60 deletions(-)
diff --git a/README.md b/README.md index 3fda5ee..43ba423 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ sent is a simple plaintext presentation tool. sent does not need latex, libreoffice or any other fancy file format, it uses -plaintext files to describe the slides and can include images via farbfeld. +plaintext files to describe the slides and can include images via libnetpbm. Every paragraph represents a slide in the presentation. The presentation is displayed in a simple X11 window. The content of each slide @@ -11,8 +11,8 @@ worry about alignment. Instead you can really concentrate on the content. Dependencies -You need Xlib to build sent and the farbfeld[0] tools installed to use images in -your presentations. +You need Xlib and libnetpbm to build sent and the Netpbm tools installed to use +images in your presentations. Demo @@ -53,5 +53,3 @@ Development sent is developed at http://tools.suckless.org/sent - -0: http://git.2f30.org/farbfeld/about/ diff --git a/config.def.h b/config.def.h index 94ed09e..3a4f1d8 100644 --- a/config.def.h +++ b/config.def.h @@ -47,6 +47,7 @@ static Shortcut shortcuts[] = { }; static Filter filters[] = { - { "\\.png$", "png2ff" }, - { "\\.(jpg|gif)$", "2ff" }, + { "\\.png$", "pngtopam -alphapam" }, + { "\\.(jpg|gif)$", "anytopnm" }, + { "\\.p[bgp]m$", "cat" }, }; diff --git a/config.mk b/config.mk index 52d5fb1..78055bd 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 +LIBS = -L/usr/lib -lc -lm -L${X11LIB} -lXft -lfontconfig -lX11 -lnetpbm # flags CPPFLAGS = -DVERSION=\"${VERSION}\" -D_XOPEN_SOURCE=600 diff --git a/example b/example index 8b385f0..f7f6f61 100644 --- a/example +++ b/example @@ -20,7 +20,7 @@ easy to use depends on ♽ Xlib -☃ farbfeld +☃ libnetpbm ~1000 lines of code diff --git a/sent.c b/sent.c index 99361e8..978e3ef 100644 --- a/sent.c +++ b/sent.c @@ -12,6 +12,7 @@ #include <stdlib.h> #include <string.h> #include <unistd.h> +#include <netpbm/pam.h> #include <X11/keysym.h> #include <X11/XKBlib.h> #include <X11/Xatom.h> @@ -41,7 +42,7 @@ typedef struct { unsigned int bufwidth, bufheight; imgstate state; XImage *ximg; - int fd; + struct pam pamimg; int numpasses; } Image; @@ -87,12 +88,12 @@ typedef struct { const Arg arg; } Shortcut; -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 Image *pamopen(char *filename); +static void pamfree(Image *img); +static int pamread(Image *img); +static int pamprepare(Image *img); +static void pamscale(Image *img); +static void pamdraw(Image *img); static void getfontsize(Slide *s, unsigned int *width, unsigned int *height); static void cleanup(); @@ -159,9 +160,9 @@ filter(int fd, const char *cmd) return fds[0]; } -Image *ffopen(char *filename) +Image *pamopen(char *filename) { - unsigned char hdr[16]; + struct pam inpam; char *bin = NULL; regex_t regex; Image *img; @@ -192,21 +193,17 @@ Image *ffopen(char *filename) eprintf("Unable to filter %s:", filename); close(tmpfd); - if (read(fd, hdr, 16) != 16) - return NULL; - - if (memcmp("farbfeld", hdr, 8)) - return NULL; + pnm_readpaminit(fdopen(fd, "r"), &inpam, PAM_STRUCT_SIZE(tuple_type)); img = calloc(1, sizeof(Image)); - img->fd = fd; - img->bufwidth = ntohl(*(uint32_t *)&hdr[8]); - img->bufheight = ntohl(*(uint32_t *)&hdr[12]); + img->pamimg = inpam; + img->bufwidth = inpam.width; + img->bufheight = inpam.height; return img; } -void fffree(Image *img) +void pamfree(Image *img) { free(img->buf); if (img->ximg) @@ -214,14 +211,13 @@ void fffree(Image *img) free(img); } -int ffread(Image *img) +int pamread(Image *img) { - uint32_t y, x; - uint16_t *row; + uint32_t y, x, depth; uint8_t opac; uint8_t fg_r, fg_g, fg_b, bg_r, bg_g, bg_b; - size_t rowlen, off, nbytes; - ssize_t count; + tuple *pamrow; + size_t off; if (!img) return 0; @@ -236,9 +232,8 @@ int ffread(Image *img) return 0; /* scratch buffer to read row by row */ - rowlen = img->bufwidth * 2 * strlen("RGBA"); - row = malloc(rowlen); - if (!row) { + pamrow = pnm_allocpamrow(&(img->pamimg)); + if (!pamrow) { free(img->buf); img->buf = NULL; return 0; @@ -249,19 +244,25 @@ int ffread(Image *img) bg_g = (sc->bg.pix >> 8) % 256; bg_b = (sc->bg.pix >> 0) % 256; + depth = img->pamimg.depth; + for (off = 0, y = 0; y < img->bufheight; y++) { - nbytes = 0; - while (nbytes < rowlen) { - count = read(img->fd, (char *)row + nbytes, rowlen - nbytes); - if (count < 0) - eprintf("Unable to read from pipe:"); - nbytes += count; - } - for (x = 0; x < rowlen / 2; x += 4) { - fg_r = ntohs(row[x + 0]) / 256; - fg_g = ntohs(row[x + 1]) / 256; - fg_b = ntohs(row[x + 2]) / 256; - opac = ntohs(row[x + 3]) / 256; + pnm_readpamrow(&(img->pamimg), pamrow); + for (x = 0; x < img->bufwidth; x++) { + fg_r = 255*pamrow[x][0] / img->pamimg.maxval; + + if (depth < 3) { + fg_g = fg_b = fg_r; + } else { + fg_g = 255*pamrow[x][1] / img->pamimg.maxval; + fg_b = 255*pamrow[x][2] / img->pamimg.maxval; + } + /* check for alpha channel */ + if ((depth & 1) == 0) { + opac = 255*pamrow[x][depth - 1] / img->pamimg.maxval; + } else { + opac = 255; + } /* blend opaque part of image data with window background color to * emulate transparency */ img->buf[off++] = (fg_r * opac + bg_r * (255 - opac)) / 256; @@ -270,14 +271,14 @@ int ffread(Image *img) } } - free(row); - close(img->fd); + pnm_freepamrow(pamrow); + fclose(img->pamimg.file); img->state |= LOADED; return 1; } -int ffprepare(Image *img) +int pamprepare(Image *img) { int depth = DefaultDepth(xw.dpy, xw.scr); int width = xw.uw; @@ -314,12 +315,12 @@ int ffprepare(Image *img) return 0; } - ffscale(img); + pamscale(img); img->state |= SCALED; return 1; } -void ffscale(Image *img) +void pamscale(Image *img) { unsigned int x, y; unsigned int width = img->ximg->width; @@ -344,7 +345,7 @@ void ffscale(Image *img) } } -void ffdraw(Image *img) +void pamdraw(Image *img) { int xoffset = (xw.w - img->ximg->width) / 2; int yoffset = (xw.h - img->ximg->height) / 2; @@ -401,7 +402,7 @@ void cleanup() free(slides[i].lines[j]); free(slides[i].lines); if (slides[i].img) - fffree(slides[i].img); + pamfree(slides[i].img); } free(slides); slides = NULL; @@ -480,7 +481,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 = ffopen(s->lines[0]); + s->img = pamopen(s->lines[0]); } if (s->lines[s->linecount][0] == '\\') @@ -502,9 +503,9 @@ void advance(const Arg *arg) slides[idx].img->state &= ~(DRAWN | SCALED); idx = new_idx; xdraw(); - if (slidecount > idx + 1 && slides[idx + 1].img && !ffread(slides[idx + 1].img)) + if (slidecount > idx + 1 && slides[idx + 1].img && !pamread(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)) + if (0 < idx && slides[idx - 1].img && !pamread(slides[idx - 1].img)) die("Unable to read image %s", slides[idx - 1].lines[0]); } } @@ -569,12 +570,12 @@ void xdraw() slides[idx].lines[i], 0); drw_map(d, xw.win, 0, 0, xw.w, xw.h); - } else if (!(im->state & LOADED) && !ffread(im)) { + } else if (!(im->state & LOADED) && !pamread(im)) { eprintf("Unable to read image %s", slides[idx].lines[0]); - } else if (!(im->state & SCALED) && !ffprepare(im)) { + } else if (!(im->state & SCALED) && !pamprepare(im)) { eprintf("Unable to prepare image %s for drawing", slides[idx].lines[0]); } else if (!(im->state & DRAWN)) { - ffdraw(im); + pamdraw(im); } } @@ -710,6 +711,8 @@ int main(int argc, char *argv[]) usage(); } ARGEND; + pm_init(argv[0], 0); + for (i = 0; i < argc; i++) { if ((fp = strcmp(argv[i], "-") ? fopen(argv[i], "r") : stdin)) { load(fp); -- 2.4.10