@ -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,12 +41,15 @@ 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 ;
@ -79,12 +87,12 @@ typedef struct {
const Arg arg ;
} Shortcut ;
static Image * png open( char * filename ) ;
static void png free( Image * img ) ;
static int png read( Image * img ) ;
static int png prepare( Image * img ) ;
static void png scale( Image * img ) ;
static void png draw( Image * img ) ;
static Image * ff open( char * filename ) ;
static void ff free( Image * img ) ;
static int ff read( Image * img ) ;
static int ff prepare( Image * img ) ;
static void ff scale( Image * img ) ;
static void ff draw( 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 ( & regex , filters [ i ] . regex ,
REG_NOSUB | REG_EXTENDED | REG_ICASE ) )
continue ;
if ( ! regexec ( & regex , 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 , NULL ,
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 png free( Image * img )
void ff free( 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 png read( Image * img )
int ff read( 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_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 + + ) {
nbytes = 0 ;
while ( nbytes < rowlen ) {
r = read ( img - > fd , ( char * ) row + nbytes , rowlen - nbytes ) ;
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 png prepare( 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 ;
}
png scale( img ) ;
ff scale( img ) ;
img - > state | = SCALED ;
return 1 ;
}
void png scale( Image * img )
void ff scale( Image * img )
{
unsigned int x , y ;
unsigned int width = img - > ximg - > width ;
@ -306,7 +328,7 @@ void pngscale(Image *img)
}
}
void png draw( Image * img )
void ff draw( 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 )
png free( slides [ i ] . img ) ;
ff free( 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 starts with @ */
if ( s - > linecount = = 0 & & s - > lines [ 0 ] [ 0 ] = = ' @ ' ) {
memmove ( s - > lines [ 0 ] , & s - > lines [ 0 ] [ 1 ] , blen ) ;
s - > img = png open( s - > lines [ 0 ] ) ;
s - > img = ff open( 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 & & ! png read( slides [ idx + 1 ] . img ) )
die ( " Unable to read image %s . " , slides [ idx + 1 ] . lines [ 0 ] ) ;
if ( 0 < idx & & slides [ idx - 1 ] . img & & ! png read( slides [ idx - 1 ] . img ) )
die ( " Unable to read image %s . " , slides [ idx - 1 ] . lines [ 0 ] ) ;
if ( slidecount > idx + 1 & & slides [ idx + 1 ] . img & & ! ff read( slides [ idx + 1 ] . img ) )
die ( " Unable to read image %s " , slides [ idx + 1 ] . lines [ 0 ] ) ;
if ( 0 < idx & & slides [ idx - 1 ] . img & & ! ff read( slides [ idx - 1 ] . img ) )
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 ) & & ! png read( im ) ) {
eprintf ( " Unable to read image %s . " , slides [ idx ] . lines [ 0 ] ) ;
} else if ( ! ( im - > state & SCALED ) & & ! png prepare( im ) ) {
eprintf ( " Unable to prepare image %s for drawing . " , slides [ idx ] . lines [ 0 ] ) ;
} else if ( ! ( im - > state & LOADED ) & & ! ff read( im ) ) {
eprintf ( " Unable to read image %s " , slides [ idx ] . lines [ 0 ] ) ;
} else if ( ! ( im - > state & SCALED ) & & ! ff prepare( im ) ) {
eprintf ( " Unable to prepare image %s for drawing " , slides [ idx ] . lines [ 0 ] ) ;
} else if ( ! ( im - > state & DRAWN ) ) {
png draw( im ) ;
ff draw( im ) ;
}
}