[hackers] [sent] [PATCH 2/2] replace farbfeld with libnetpbm

From: Grant Mathews <grant.m.mathews_AT_gmail.com>
Date: Wed, 9 Dec 2015 20:56:38 -0800

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
_AT_@ -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
_AT_@ -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
 
_AT_@ -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
_AT_@ -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
_AT_@ -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
_AT_@ -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
_AT_@ -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>
_AT_@ -41,7 +42,7 @@ typedef struct {
 	unsigned int bufwidth, bufheight;
 	imgstate state;
 	XImage *ximg;
-	int fd;
+	struct pam pamimg;
 	int numpasses;
 } Image;
 
_AT_@ -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();
_AT_@ -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;
_AT_@ -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)
_AT_@ -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;
_AT_@ -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;
_AT_@ -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;
_AT_@ -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;
_AT_@ -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;
_AT_@ -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;
_AT_@ -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;
_AT_@ -480,7 +481,7 @@ void load(FILE *fp)
 			/* only make image slide if first line of a slide starts with _AT_ */
 			if (s->linecount == 0 && s->lines[0][0] == '_AT_') {
 				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] == '\\')
_AT_@ -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]);
 	}
 }
_AT_@ -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);
 	}
 }
 
_AT_@ -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
Received on Thu Dec 10 2015 - 05:56:38 CET

This archive was generated by hypermail 2.3.0 : Thu Dec 10 2015 - 06:00:16 CET