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/
This commit is contained in:
parent
7e558105e6
commit
b516f468fa
2
LICENSE
2
LICENSE
@ -2,8 +2,6 @@ The MIT License (MIT)
|
|||||||
|
|
||||||
Copyright (c) 2014-2015 Markus Teich
|
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
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
in the Software without restriction, including without limitation the rights
|
in the Software without restriction, including without limitation the rights
|
||||||
|
@ -33,7 +33,6 @@ presentation file could look like this:
|
|||||||
|
|
||||||
depends on
|
depends on
|
||||||
- Xlib
|
- Xlib
|
||||||
- libpng
|
|
||||||
|
|
||||||
sent FILENAME
|
sent FILENAME
|
||||||
one slide per paragraph
|
one slide per paragraph
|
||||||
|
@ -45,3 +45,8 @@ static Shortcut shortcuts[] = {
|
|||||||
{ XK_n, advance, {.i = +1} },
|
{ XK_n, advance, {.i = +1} },
|
||||||
{ XK_p, advance, {.i = -1} },
|
{ XK_p, advance, {.i = -1} },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static Filter filters[] = {
|
||||||
|
{ "\\.png$", "png2ff" },
|
||||||
|
{ "\\.(jpg|gif)$", "2ff" },
|
||||||
|
};
|
||||||
|
@ -12,7 +12,7 @@ X11LIB = /usr/X11R6/lib
|
|||||||
|
|
||||||
# includes and libs
|
# includes and libs
|
||||||
INCS = -I. -I/usr/include -I/usr/include/freetype2 -I${X11INC}
|
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
|
# flags
|
||||||
CPPFLAGS = -DVERSION=\"${VERSION}\" -D_XOPEN_SOURCE=600
|
CPPFLAGS = -DVERSION=\"${VERSION}\" -D_XOPEN_SOURCE=600
|
||||||
|
1
example
1
example
@ -20,7 +20,6 @@ easy to use
|
|||||||
|
|
||||||
depends on
|
depends on
|
||||||
♽ Xlib
|
♽ Xlib
|
||||||
☢ libpng
|
|
||||||
|
|
||||||
~1000 lines of code
|
~1000 lines of code
|
||||||
|
|
||||||
|
206
sent.c
206
sent.c
@ -1,12 +1,17 @@
|
|||||||
/* See LICENSE for licence details. */
|
/* See LICENSE for licence details. */
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <png.h>
|
#include <regex.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
#include <X11/keysym.h>
|
#include <X11/keysym.h>
|
||||||
#include <X11/XKBlib.h>
|
#include <X11/XKBlib.h>
|
||||||
#include <X11/Xatom.h>
|
#include <X11/Xatom.h>
|
||||||
@ -36,12 +41,15 @@ typedef struct {
|
|||||||
unsigned int bufwidth, bufheight;
|
unsigned int bufwidth, bufheight;
|
||||||
imgstate state;
|
imgstate state;
|
||||||
XImage *ximg;
|
XImage *ximg;
|
||||||
FILE *f;
|
int fd;
|
||||||
png_structp png_ptr;
|
|
||||||
png_infop info_ptr;
|
|
||||||
int numpasses;
|
int numpasses;
|
||||||
} Image;
|
} Image;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char *regex;
|
||||||
|
char *bin;
|
||||||
|
} Filter;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
unsigned int linecount;
|
unsigned int linecount;
|
||||||
char **lines;
|
char **lines;
|
||||||
@ -79,12 +87,12 @@ typedef struct {
|
|||||||
const Arg arg;
|
const Arg arg;
|
||||||
} Shortcut;
|
} Shortcut;
|
||||||
|
|
||||||
static Image *pngopen(char *filename);
|
static Image *ffopen(char *filename);
|
||||||
static void pngfree(Image *img);
|
static void fffree(Image *img);
|
||||||
static int pngread(Image *img);
|
static int ffread(Image *img);
|
||||||
static int pngprepare(Image *img);
|
static int ffprepare(Image *img);
|
||||||
static void pngscale(Image *img);
|
static void ffscale(Image *img);
|
||||||
static void pngdraw(Image *img);
|
static void ffdraw(Image *img);
|
||||||
|
|
||||||
static void getfontsize(Slide *s, unsigned int *width, unsigned int *height);
|
static void getfontsize(Slide *s, unsigned int *width, unsigned int *height);
|
||||||
static void cleanup();
|
static void cleanup();
|
||||||
@ -128,56 +136,87 @@ static void (*handler[LASTEvent])(XEvent *) = {
|
|||||||
[KeyPress] = kpress,
|
[KeyPress] = kpress,
|
||||||
};
|
};
|
||||||
|
|
||||||
Image *pngopen(char *filename)
|
int
|
||||||
|
filter(int fd, const char *cmd)
|
||||||
{
|
{
|
||||||
FILE *f;
|
int fds[2];
|
||||||
unsigned char buf[8];
|
|
||||||
Image *img;
|
|
||||||
|
|
||||||
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);
|
eprintf("Unable to open file %s:", filename);
|
||||||
return NULL;
|
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;
|
return NULL;
|
||||||
|
|
||||||
img = malloc(sizeof(Image));
|
if (memcmp("farbfeld", hdr, 8))
|
||||||
memset(img, 0, sizeof(Image));
|
|
||||||
if (!(img->png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL,
|
|
||||||
NULL, NULL))) {
|
|
||||||
free(img);
|
|
||||||
return NULL;
|
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;
|
img = calloc(1, sizeof(Image));
|
||||||
rewind(f);
|
img->fd = fd;
|
||||||
png_init_io(img->png_ptr, f);
|
img->bufwidth = ntohl(*(uint32_t *)&hdr[8]);
|
||||||
png_read_info(img->png_ptr, img->info_ptr);
|
img->bufheight = ntohl(*(uint32_t *)&hdr[12]);
|
||||||
img->bufwidth = png_get_image_width(img->png_ptr, img->info_ptr);
|
|
||||||
img->bufheight = png_get_image_height(img->png_ptr, img->info_ptr);
|
|
||||||
|
|
||||||
return img;
|
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);
|
free(img->buf);
|
||||||
if (img->ximg)
|
if (img->ximg)
|
||||||
XDestroyImage(img->ximg);
|
XDestroyImage(img->ximg);
|
||||||
free(img);
|
free(img);
|
||||||
}
|
}
|
||||||
|
|
||||||
int pngread(Image *img)
|
int ffread(Image *img)
|
||||||
{
|
{
|
||||||
unsigned int y;
|
uint32_t y, x;
|
||||||
png_bytepp row_pointers;
|
uint16_t *row;
|
||||||
|
size_t rowlen, off, nbytes;
|
||||||
|
ssize_t r;
|
||||||
|
|
||||||
if (!img)
|
if (!img)
|
||||||
return 0;
|
return 0;
|
||||||
@ -187,59 +226,42 @@ int pngread(Image *img)
|
|||||||
|
|
||||||
if (img->buf)
|
if (img->buf)
|
||||||
free(img->buf);
|
free(img->buf);
|
||||||
|
/* internally the image is stored in 888 format */
|
||||||
if (!(img->buf = malloc(3 * img->bufwidth * img->bufheight)))
|
if (!(img->buf = malloc(3 * img->bufwidth * img->bufheight)))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (setjmp(png_jmpbuf(img->png_ptr))) {
|
/* scratch buffer to read row by row */
|
||||||
png_destroy_read_struct(&img->png_ptr, &img->info_ptr, NULL);
|
rowlen = img->bufwidth * 2 * strlen("RGBA");
|
||||||
|
row = malloc(rowlen);
|
||||||
|
if (!row) {
|
||||||
|
free(img->buf);
|
||||||
|
img->buf = NULL;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
for (off = 0, y = 0; y < img->bufheight; y++) {
|
||||||
int color_type = png_get_color_type(img->png_ptr, img->info_ptr);
|
nbytes = 0;
|
||||||
int bit_depth = png_get_bit_depth(img->png_ptr, img->info_ptr);
|
while (nbytes < rowlen) {
|
||||||
if (color_type == PNG_COLOR_TYPE_PALETTE)
|
r = read(img->fd, (char *)row + nbytes, rowlen - nbytes);
|
||||||
png_set_expand(img->png_ptr);
|
if (r < 0)
|
||||||
if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
|
eprintf("read:");
|
||||||
png_set_expand(img->png_ptr);
|
nbytes += r;
|
||||||
if (png_get_valid(img->png_ptr, img->info_ptr, PNG_INFO_tRNS))
|
}
|
||||||
png_set_expand(img->png_ptr);
|
for (x = 0; x < rowlen / 2; x += 4) {
|
||||||
if (bit_depth == 16)
|
img->buf[off++] = ntohs(row[x + 0]) / 257;
|
||||||
png_set_strip_16(img->png_ptr);
|
img->buf[off++] = ntohs(row[x + 1]) / 257;
|
||||||
if (color_type == PNG_COLOR_TYPE_GRAY
|
img->buf[off++] = ntohs(row[x + 2]) / 257;
|
||||||
|| 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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
row_pointers = (png_bytepp)malloc(img->bufheight * sizeof(png_bytep));
|
free(row);
|
||||||
for (y = 0; y < img->bufheight; y++)
|
close(img->fd);
|
||||||
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);
|
|
||||||
img->state |= LOADED;
|
img->state |= LOADED;
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int pngprepare(Image *img)
|
int ffprepare(Image *img)
|
||||||
{
|
{
|
||||||
int depth = DefaultDepth(xw.dpy, xw.scr);
|
int depth = DefaultDepth(xw.dpy, xw.scr);
|
||||||
int width = xw.uw;
|
int width = xw.uw;
|
||||||
@ -276,12 +298,12 @@ int pngprepare(Image *img)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
pngscale(img);
|
ffscale(img);
|
||||||
img->state |= SCALED;
|
img->state |= SCALED;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pngscale(Image *img)
|
void ffscale(Image *img)
|
||||||
{
|
{
|
||||||
unsigned int x, y;
|
unsigned int x, y;
|
||||||
unsigned int width = img->ximg->width;
|
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 xoffset = (xw.w - img->ximg->width) / 2;
|
||||||
int yoffset = (xw.h - img->ximg->height) / 2;
|
int yoffset = (xw.h - img->ximg->height) / 2;
|
||||||
@ -364,7 +386,7 @@ void cleanup()
|
|||||||
free(slides[i].lines[j]);
|
free(slides[i].lines[j]);
|
||||||
free(slides[i].lines);
|
free(slides[i].lines);
|
||||||
if (slides[i].img)
|
if (slides[i].img)
|
||||||
pngfree(slides[i].img);
|
fffree(slides[i].img);
|
||||||
}
|
}
|
||||||
free(slides);
|
free(slides);
|
||||||
slides = NULL;
|
slides = NULL;
|
||||||
@ -443,7 +465,7 @@ void load(FILE *fp)
|
|||||||
/* only make image slide if first line of a slide starts with @ */
|
/* only make image slide if first line of a slide starts with @ */
|
||||||
if (s->linecount == 0 && s->lines[0][0] == '@') {
|
if (s->linecount == 0 && s->lines[0][0] == '@') {
|
||||||
memmove(s->lines[0], &s->lines[0][1], blen);
|
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] == '\\')
|
if (s->lines[s->linecount][0] == '\\')
|
||||||
@ -465,10 +487,10 @@ void advance(const Arg *arg)
|
|||||||
slides[idx].img->state &= ~(DRAWN | SCALED);
|
slides[idx].img->state &= ~(DRAWN | SCALED);
|
||||||
idx = new_idx;
|
idx = new_idx;
|
||||||
xdraw();
|
xdraw();
|
||||||
if (slidecount > idx + 1 && slides[idx + 1].img && !pngread(slides[idx + 1].img))
|
if (slidecount > idx + 1 && slides[idx + 1].img && !ffread(slides[idx + 1].img))
|
||||||
die("Unable to read image %s.", slides[idx + 1].lines[0]);
|
die("Unable to read image %s", slides[idx + 1].lines[0]);
|
||||||
if (0 < idx && slides[idx - 1].img && !pngread(slides[idx - 1].img))
|
if (0 < idx && slides[idx - 1].img && !ffread(slides[idx - 1].img))
|
||||||
die("Unable to read image %s.", slides[idx - 1].lines[0]);
|
die("Unable to read image %s", slides[idx - 1].lines[0]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -532,12 +554,12 @@ void xdraw()
|
|||||||
slides[idx].lines[i],
|
slides[idx].lines[i],
|
||||||
0);
|
0);
|
||||||
drw_map(d, xw.win, 0, 0, xw.w, xw.h);
|
drw_map(d, xw.win, 0, 0, xw.w, xw.h);
|
||||||
} else if (!(im->state & LOADED) && !pngread(im)) {
|
} else if (!(im->state & LOADED) && !ffread(im)) {
|
||||||
eprintf("Unable to read image %s.", slides[idx].lines[0]);
|
eprintf("Unable to read image %s", slides[idx].lines[0]);
|
||||||
} else if (!(im->state & SCALED) && !pngprepare(im)) {
|
} else if (!(im->state & SCALED) && !ffprepare(im)) {
|
||||||
eprintf("Unable to prepare image %s for drawing.", slides[idx].lines[0]);
|
eprintf("Unable to prepare image %s for drawing", slides[idx].lines[0]);
|
||||||
} else if (!(im->state & DRAWN)) {
|
} else if (!(im->state & DRAWN)) {
|
||||||
pngdraw(im);
|
ffdraw(im);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user