Hi, Very quick and dirty patch. This is intended to generate a discussion on the applicability of farbfeld in sent. I can polish the patch later depending on the outcome of the discussion.
diff --git a/LICENSE b/LICENSE index d1da8fc..8d5665e 100644 --- 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 index 007564b..3d85d6f 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 and png images. Every paragraph represents a slide in the +plaintext files and farbfeld[0] images. Every paragraph represents a slide in the presentation. The presentation is displayed in a simple X11 window. The content of each slide @@ -29,18 +29,17 @@ presentation file could look like this: sent - @nyan.png + @nyan.ff depends on - Xlib - - libpng sent FILENAME one slide per paragraph # This is a comment and will not be part of the presentation \# This and the next line start with backslashes - \@FILE.png + \@FILE.ff thanks / questions? @@ -48,3 +47,5 @@ presentation file could look like this: Development sent is developed at http://tools.suckless.org/sent + +[0] http://git.2f30.org/farbfeld/ diff --git a/config.mk b/config.mk index ed08199..52d5fb1 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 -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 index 39e0206..51ec822 100644 --- a/example +++ b/example @@ -12,7 +12,7 @@ also: terminal presentations don't support images… -@nyan.png +@nyan.ff this text will not be displayed, since the @ at the start of the first line makes this paragraph an image slide. @@ -20,7 +20,6 @@ easy to use depends on ♽ Xlib -☢ libpng ~1000 lines of code @@ -29,7 +28,7 @@ $ sent FILE1 [FILE2 …] ▸ one slide per paragraph ▸ lines starting with # are ignored -▸ image slide: paragraph containing @FILE.png +▸ image slide: paragraph containing @FILE.ff ▸ empty slide: just use a \ as a paragraph # This is a comment and will not be part of the presentation @@ -45,7 +44,7 @@ $ sent FILE1 [FILE2 …] \ \ -\@this_line_actually_started_with_a_\.png +\@this_line_actually_started_with_a_\.ff \#This line as well ⇒ Prepend a backslash to kill behaviour of special characters diff --git a/nyan.png b/nyan.png deleted file mode 100644 index 377b9d0..0000000 Binary files a/nyan.png and /dev/null differ diff --git a/sent.c b/sent.c index 4e2e810..bcdbf51 100644 --- a/sent.c +++ b/sent.c @@ -1,7 +1,8 @@ /* See LICENSE for licence details. */ +#include <arpa/inet.h> + #include <errno.h> #include <math.h> -#include <png.h> #include <stdarg.h> #include <stdio.h> #include <stdint.h> @@ -37,8 +38,6 @@ typedef struct { imgstate state; XImage *ximg; FILE *f; - png_structp png_ptr; - png_infop info_ptr; int numpasses; } Image; @@ -79,12 +78,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,10 +127,10 @@ static void (*handler[LASTEvent])(XEvent *) = { [KeyPress] = kpress, }; -Image *pngopen(char *filename) +Image *ffopen(char *filename) { FILE *f; - unsigned char buf[8]; + unsigned char hdr[16]; Image *img; if (!(f = fopen(filename, "rb"))) { @@ -139,45 +138,33 @@ Image *pngopen(char *filename) return NULL; } - if (fread(buf, 1, 8, f) != 8 || png_sig_cmp(buf, 1, 8)) + if (fread(hdr, 1, 16, f) != 16) return NULL; - 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); - 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 = calloc(1, sizeof(Image)); 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->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; if (!img) return 0; @@ -187,59 +174,39 @@ 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); 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++) { + if (fread(row, 1, rowlen, img->f) != rowlen) { + free(row); + free(img->buf); + return 0; + } + 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); + free(row); fclose(img->f); 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 +243,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 +273,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 +331,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; @@ -447,7 +414,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] == '\\') @@ -469,9 +436,9 @@ 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)) + if (slidecount > idx + 1 && slides[idx + 1].img && !ffread(slides[idx + 1].img)) die("could not 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("could not read image %s", slides[idx - 1].lines[0]); } } @@ -536,12 +503,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)) { + } else if (!(im->state & LOADED) && !ffread(im)) { eprintf("could not read image %s", slides[idx].lines[0]); - } else if (!(im->state & SCALED) && !pngprepare(im)) { + } else if (!(im->state & SCALED) && !ffprepare(im)) { eprintf("could not prepare image %s for drawing", slides[idx].lines[0]); } else if (!(im->state & DRAWN)) { - pngdraw(im); + ffdraw(im); } }