add png support

This commit is contained in:
Markus Teich 2014-06-29 23:43:01 +02:00
parent 501a86cb94
commit 5b4a35ead5
5 changed files with 256 additions and 21 deletions

View File

@ -1,6 +1,8 @@
The MIT License (MIT) The MIT License (MIT)
Copyright (c) 2014 markus.teich@stusta.mhn.de Copyright (c) 2014 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

View File

@ -12,7 +12,7 @@ X11LIB = /usr/X11R6/lib
# includes and libs # includes and libs
INCS = -I. -I/usr/include -I${X11INC} INCS = -I. -I/usr/include -I${X11INC}
LIBS = -L/usr/lib -lc -lm -L${X11LIB} -lX11 LIBS = -L/usr/lib -lc -lm -L${X11LIB} -lX11 -lpng
# flags # flags
CPPFLAGS = -DVERSION=\"${VERSION}\" -D_BSD_SOURCE -D_XOPEN_SOURCE=600 CPPFLAGS = -DVERSION=\"${VERSION}\" -D_BSD_SOURCE -D_XOPEN_SOURCE=600

View File

@ -1,9 +1,11 @@
sent sent
why? why?
@nyan.png
easy to use easy to use
few dependencies (X11) depends on Xlib, libpng
no bloat no bloat
how? how?
sent FILENAME sent FILENAME
one slide per line one slide per line
@FILE.png
thanks / questions? thanks / questions?

BIN
nyan.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 901 B

261
sent.c
View File

@ -1,8 +1,10 @@
/* See LICENSE for licence details. */ /* See LICENSE for licence details. */
#include <errno.h> #include <errno.h>
#include <math.h> #include <math.h>
#include <png.h>
#include <stdarg.h> #include <stdarg.h>
#include <stdio.h> #include <stdio.h>
#include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <X11/keysym.h> #include <X11/keysym.h>
@ -19,8 +21,27 @@ char *argv0;
#define LEN(a) (sizeof(a) / sizeof(a)[0]) #define LEN(a) (sizeof(a) / sizeof(a)[0])
#define LIMIT(x, a, b) (x) = (x) < (a) ? (a) : (x) > (b) ? (b) : (x) #define LIMIT(x, a, b) (x) = (x) < (a) ? (a) : (x) > (b) ? (b) : (x)
typedef enum {
NONE = 0,
LOADED = 1,
SCALED = 2,
DRAWN = 4
} imgstate;
struct image {
unsigned char *buf;
unsigned int bufwidth, bufheight;
imgstate state;
XImage *ximg;
FILE *f;
png_structp png_ptr;
png_infop info_ptr;
int numpasses;
};
typedef struct { typedef struct {
char *text; char *text;
struct image *img;
} Slide; } Slide;
/* Purely graphic info */ /* Purely graphic info */
@ -32,6 +53,7 @@ typedef struct {
XSetWindowAttributes attrs; XSetWindowAttributes attrs;
int scr; int scr;
int w, h; int w, h;
int uw, uh; /* usable dimensions for drawing text and images */
} XWindow; } XWindow;
/* Drawing Context linked list*/ /* Drawing Context linked list*/
@ -60,12 +82,11 @@ typedef struct {
const Arg arg; const Arg arg;
} Shortcut; } Shortcut;
/* function definitions used in config.h */ static struct image *pngopen(char *filename);
static void advance(const Arg *); static int pngread(struct image *img);
static void quit(const Arg *); static int pngprepare(struct image *img);
static void pngscale(struct image *img);
/* config.h for applying patches and the configuration. */ static void pngdraw(struct image *img);
#include "config.h"
static Bool xfontisscalable(char *name); static Bool xfontisscalable(char *name);
static XFontStruct *xloadqueryscalablefont(char *name, int size); static XFontStruct *xloadqueryscalablefont(char *name, int size);
@ -75,6 +96,7 @@ static void eprintf(const char *, ...);
static void load(FILE *fp); static void load(FILE *fp);
static void advance(const Arg *arg); static void advance(const Arg *arg);
static void quit(const Arg *arg); static void quit(const Arg *arg);
static void resize(int width, int height);
static void run(); static void run();
static void usage(); static void usage();
static void xdraw(); static void xdraw();
@ -86,7 +108,10 @@ static void bpress(XEvent *);
static void cmessage(XEvent *); static void cmessage(XEvent *);
static void expose(XEvent *); static void expose(XEvent *);
static void kpress(XEvent *); static void kpress(XEvent *);
static void resize(XEvent *); static void configure(XEvent *);
/* config.h for applying patches and the configuration. */
#include "config.h"
/* Globals */ /* Globals */
static Slide *slides = NULL; static Slide *slides = NULL;
@ -100,11 +125,193 @@ static char *opt_font = NULL;
static void (*handler[LASTEvent])(XEvent *) = { static void (*handler[LASTEvent])(XEvent *) = {
[ButtonPress] = bpress, [ButtonPress] = bpress,
[ClientMessage] = cmessage, [ClientMessage] = cmessage,
[ConfigureNotify] = resize, [ConfigureNotify] = configure,
[Expose] = expose, [Expose] = expose,
[KeyPress] = kpress, [KeyPress] = kpress,
}; };
struct image *pngopen(char *filename)
{
FILE *f;
unsigned char buf[8];
struct image *img;
if (!(f = fopen(filename, "rb"))) {
eprintf("could not open file %s:", filename);
return NULL;
}
if (fread(buf, 1, 8, f) != 8 || png_sig_cmp(buf, 1, 8))
return NULL;
img = malloc(sizeof(struct 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))) {
png_destroy_read_struct(&img->png_ptr, NULL, NULL);
free(img);
return NULL;
}
if (setjmp(png_jmpbuf(img->png_ptr))) {
png_destroy_read_struct(&img->png_ptr, &img->info_ptr, NULL);
free(img);
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);
return img;
}
int pngread(struct image *img)
{
unsigned int y;
png_bytepp row_pointers;
if (!img)
return 0;
if (img->state & LOADED)
return 2;
if (img->buf)
free(img->buf);
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);
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);
}
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);
img->state |= LOADED;
return 1;
}
int pngprepare(struct image *img)
{
int depth = DefaultDepth(xw.dpy, xw.scr);
int width = xw.uw;
int height = xw.uh;
if (xw.uw * img->bufheight > xw.uh * img->bufwidth)
width = img->bufwidth * xw.uh / img->bufheight;
else
height = img->bufheight * xw.uw / img->bufwidth;
if (depth < 24) {
eprintf("display depths <24 not supported.");
return 0;
}
if (!(img->ximg = XCreateImage(xw.dpy, CopyFromParent, depth, ZPixmap, 0,
NULL, width, height, 32, 0))) {
eprintf("could not create XImage");
return 0;
}
if (!(img->ximg->data = malloc(img->ximg->bytes_per_line * height))) {
eprintf("could not alloc data section for XImage");
XDestroyImage(img->ximg);
img->ximg = NULL;
return 0;
}
if (!XInitImage(img->ximg)) {
eprintf("could not init XImage");
free(img->ximg->data);
XDestroyImage(img->ximg);
img->ximg = NULL;
return 0;
}
pngscale(img);
img->state |= SCALED;
return 1;
}
void pngscale(struct image *img)
{
unsigned int x, y;
unsigned int width = img->ximg->width;
unsigned int height = img->ximg->height;
char* __restrict__ newBuf = img->ximg->data;
unsigned char * __restrict__ ibuf;
unsigned int jdy = img->ximg->bytes_per_line / 4 - width;
unsigned int dx = (img->bufwidth << 10) / width;
for (y = 0; y < height; y++) {
unsigned int bufx = img->bufwidth / width;
ibuf = &img->buf[y * img->bufheight / height * img->bufwidth * 3];
for (x = 0; x < width; x++) {
*newBuf++ = (ibuf[(bufx >> 10)*3+2]);
*newBuf++ = (ibuf[(bufx >> 10)*3+1]);
*newBuf++ = (ibuf[(bufx >> 10)*3+0]);
newBuf++;
bufx += dx;
}
newBuf += jdy;
}
}
void pngdraw(struct image *img)
{
int xoffset = (xw.w - img->ximg->width) / 2;
int yoffset = (xw.h - img->ximg->height) / 2;
XPutImage(xw.dpy, xw.win, dc.gc, img->ximg, 0, 0,
xoffset, yoffset, img->ximg->width, img->ximg->height);
XFlush(xw.dpy);
img->state |= DRAWN;
}
Bool xfontisscalable(char *name) Bool xfontisscalable(char *name)
{ {
@ -177,8 +384,7 @@ struct DC *getfontsize(char *str, size_t len, int *width, int *height)
do { do {
XTextExtents(cur->font, str, len, &unused, &unused, &unused, &info); XTextExtents(cur->font, str, len, &unused, &unused, &unused, &info);
if (info.width > usablewidth * xw.w if (info.width > xw.uw || info.ascent + info.descent > xw.uh)
|| info.ascent + info.descent > usableheight * xw.h)
break; break;
pre = cur; pre = cur;
} while ((cur = cur->next)); } while ((cur = cur->next));
@ -245,6 +451,8 @@ void load(FILE *fp)
*p = '\0'; *p = '\0';
if (!(slides[i].text = strdup(buf))) if (!(slides[i].text = strdup(buf)))
eprintf("cannot strdup %u bytes:", strlen(buf)+1); eprintf("cannot strdup %u bytes:", strlen(buf)+1);
if (slides[i].text[0] == '@')
slides[i].img = pngopen(slides[i].text + 1);
} }
if (slides) if (slides)
slides[i].text = NULL; slides[i].text = NULL;
@ -256,8 +464,14 @@ void advance(const Arg *arg)
int new_idx = idx + arg->i; int new_idx = idx + arg->i;
LIMIT(new_idx, 0, slidecount-1); LIMIT(new_idx, 0, slidecount-1);
if (new_idx != idx) { if (new_idx != idx) {
if (slides[idx].img)
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))
eprintf("could not read image %s", slides[idx + 1].text + 1);
if (0 < idx && slides[idx - 1].img && !pngread(slides[idx - 1].img))
eprintf("could not read image %s", slides[idx - 1].text + 1);
} }
} }
@ -266,6 +480,14 @@ void quit(const Arg *arg)
running = 0; running = 0;
} }
void resize(int width, int height)
{
xw.w = width;
xw.h = height;
xw.uw = usablewidth * width;
xw.uh = usableheight * height;
}
void run() void run()
{ {
XEvent ev; XEvent ev;
@ -274,8 +496,7 @@ void run()
while (1) { while (1) {
XNextEvent(xw.dpy, &ev); XNextEvent(xw.dpy, &ev);
if (ev.type == ConfigureNotify) { if (ev.type == ConfigureNotify) {
xw.w = ev.xconfigure.width; resize(ev.xconfigure.width, ev.xconfigure.height);
xw.h = ev.xconfigure.height;
} else if (ev.type == MapNotify) { } else if (ev.type == MapNotify) {
break; break;
} }
@ -300,10 +521,19 @@ void xdraw()
int height; int height;
int width; int width;
struct DC *dc = getfontsize(slides[idx].text, line_len, &width, &height); struct DC *dc = getfontsize(slides[idx].text, line_len, &width, &height);
struct image *im = slides[idx].img;
XClearWindow(xw.dpy, xw.win); XClearWindow(xw.dpy, xw.win);
if (!im)
XDrawString(xw.dpy, xw.win, dc->gc, (xw.w - width)/2, (xw.h + height)/2, XDrawString(xw.dpy, xw.win, dc->gc, (xw.w - width)/2, (xw.h + height)/2,
slides[idx].text, line_len); slides[idx].text, line_len);
else if (!(im->state & LOADED) && !pngread(im))
eprintf("could not read image %s", slides[idx].text + 1);
else if (!(im->state & SCALED) && !pngprepare(im))
eprintf("could not prepare image %s for drawing", slides[idx].text + 1);
else if (!(im->state & DRAWN))
pngdraw(im);
} }
void xhints() void xhints()
@ -427,10 +657,11 @@ void kpress(XEvent *e)
shortcuts[i].func(&(shortcuts[i].arg)); shortcuts[i].func(&(shortcuts[i].arg));
} }
void resize(XEvent *e) void configure(XEvent *e)
{ {
xw.w = e->xconfigure.width; resize(e->xconfigure.width, e->xconfigure.height);
xw.h = e->xconfigure.height; if (slides[idx].img)
slides[idx].img->state &= ~(DRAWN | SCALED);
xdraw(); xdraw();
} }