Support farbfeld as an intermediate format - sent - simple plaintext presentati… | |
git clone git://git.suckless.org/sent | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
commit b516f468faa3a80c31932cbcb1ea8ccd1468ffc1 | |
parent 7e558105e6e46a6a2592f2ee15220b99922cd1f0 | |
Author: sin <[email protected]> | |
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 | |
to 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. | |
[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(-) | |
--- | |
diff --git 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 | |
@@ -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 | |
@@ -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 | |
@@ -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 | |
@@ -20,7 +20,6 @@ easy to use | |
depends on | |
♽ Xlib | |
-☢ libpng | |
~1000 lines of code | |
diff --git a/sent.c b/sent.c | |
@@ -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> | |
@@ -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; | |
@@ -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) | |
+{ | |
+ 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(®ex, filters[i].regex, | |
+ REG_NOSUB | REG_EXTENDED | REG_ICASE)) | |
+ continue; | |
+ if (!regexec(®ex, 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, NUL… | |
- 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 … | |
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_pt… | |
- 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, .blu… | |
- png_color_16p image_background; | |
- | |
- if (png_get_bKGD(img->png_ptr, img->info_ptr, &image_backgroun… | |
- png_set_background(img->png_ptr, image_background, PNG… | |
- else | |
- png_set_background(img->png_ptr, &my_background, PNG_B… | |
- | |
- if (png_get_interlace_type(img->png_ptr, img->info_ptr) == PNG… | |
- img->numpasses = png_set_interlace_handling(img->png_p… | |
- 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 - nbyte… | |
+ 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 star… | |
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(sl… | |
- die("Unable to read image %s.", slides[idx + 1].lines[… | |
- if (0 < idx && slides[idx - 1].img && !pngread(slides[idx - 1]… | |
- die("Unable to read image %s.", slides[idx - 1].lines[… | |
+ if (slidecount > idx + 1 && slides[idx + 1].img && !ffread(sli… | |
+ die("Unable to read image %s", slides[idx + 1].lines[0… | |
+ if (0 < idx && slides[idx - 1].img && !ffread(slides[idx - 1].… | |
+ 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]… | |
+ } 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].… | |
} else if (!(im->state & DRAWN)) { | |
- pngdraw(im); | |
+ ffdraw(im); | |
} | |
} | |