diff options
author | godspeed1989 <tongxinjichu@gmail.com> | 2013-05-03 10:14:09 +0800 |
---|---|---|
committer | godspeed1989 <tongxinjichu@gmail.com> | 2013-05-03 10:14:09 +0800 |
commit | 5c4c50c1171f1cf084b1cc0f02cefa421f4e1914 (patch) | |
tree | 3632b1609bb8859fbb6b726f562180606db99b70 | |
download | fbv-5c4c50c1171f1cf084b1cc0f02cefa421f4e1914.tar.gz fbv-5c4c50c1171f1cf084b1cc0f02cefa421f4e1914.zip |
init commit
-rw-r--r-- | Make.conf | 2 | ||||
-rw-r--r-- | Makefile | 36 | ||||
-rw-r--r-- | README.md | 34 | ||||
-rw-r--r-- | VERSION | 1 | ||||
-rw-r--r-- | bmp.c | 222 | ||||
-rwxr-xr-x | configure | 155 | ||||
-rw-r--r-- | fb_display.c | 343 | ||||
-rw-r--r-- | fbv.1 | 58 | ||||
-rw-r--r-- | fbv.h | 50 | ||||
-rw-r--r-- | jpeg.c | 128 | ||||
-rw-r--r-- | main.c | 554 | ||||
-rw-r--r-- | png.c | 166 | ||||
-rw-r--r-- | transforms.c | 158 |
13 files changed, 1907 insertions, 0 deletions
diff --git a/Make.conf b/Make.conf new file mode 100644 index 0000000..7834c49 --- /dev/null +++ b/Make.conf @@ -0,0 +1,2 @@ +-e error: + @echo Please run ./configure first... diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..5332f2b --- /dev/null +++ b/Makefile @@ -0,0 +1,36 @@ +# +# Makefile +# +# Makefile for fbv + +include Make.conf + +CC = gcc +CFLAGS = -Wall -D_GNU_SOURCE + +SOURCES = main.c jpeg.c png.c bmp.c fb_display.c transforms.c +OBJECTS = ${SOURCES:.c=.o} + +OUT = fbv + +all: $(OUT) + @echo Build DONE. + +$(OUT): $(OBJECTS) + $(CC) $(LDFLAGS) -o $(OUT) $(OBJECTS) $(LIBS) + +clean: + rm -f $(OBJECTS) *~ $$$$~* *.bak core config.log $(OUT) + +distclean: clean + @echo -e "error:\n\t@echo Please run ./configure first..." >Make.conf + rm -f $(OUT) config.h + +install: $(OUT) + cp $(OUT) $(bindir) + gzip -9c $(OUT).1 > $(mandir)/man1/$(OUT).1.gz + +uninstall: $(bindir)/$(OUT) + rm -f $(bindir)/$(OUT) + rm -f $(mandir)/man1/$(OUT).1.gz + diff --git a/README.md b/README.md new file mode 100644 index 0000000..ae2fc70 --- /dev/null +++ b/README.md @@ -0,0 +1,34 @@ +## fbv +A framebuffer image viewer. +fork from `http://s-tech.elsat.net.pl/fbv/` +remove gif support for the libungif is obsolete. +------------ +1. OVERVIEW + fbv (FrameBuffer Viewer) is a simple program to view pictures on a linux + framebuffer device. In 2000, when fbv was created, there were no other + situable programs performing the same task, so the authors decided to + follow the rule: 'If you need a tool - write it yourself!' :-) + +2. REQUIREMENTS + - Linux, configured to provide the framebuffer device interface + - libjpeg for JPEG support + - libpng for PNG support + - build in BMP support + +3. INSTALLATION + - run ./configure + - type: make + - type: make install + +4. USAGE + Just run fbv without any arguments, and a short help message will appear. + +5. AUTHORS + Tomasz 'smoku' Sterna <tomek@smoczy.net> + Mateusz 'mteg' Golicz <mtg@elsat.net.pl> + + Feel free to send any comments, patches, bugfixes, suggestions, etc. The + authors are not native english speakers, and they are aware of the fact + that their english is far from perfect. Because of that, reports on + grammar and vocabulary mistakes in this file are also welcome. + @@ -0,0 +1 @@ +1.1 @@ -0,0 +1,222 @@ +#include "config.h" + +#ifdef FBV_SUPPORT_BMP + +#include "fbv.h" +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> + +#define BMP_TORASTER_OFFSET 10 +#define BMP_SIZE_OFFSET 18 +#define BMP_BPP_OFFSET 28 +#define BMP_RLE_OFFSET 30 +#define BMP_COLOR_OFFSET 54 + +#define fill4B(a) ( ( 4 - ( (a) % 4 ) ) & 0x03) + +struct color +{ + unsigned char red; + unsigned char green; + unsigned char blue; +}; + +int fh_bmp_id(char *name) +{ + int fd; + char id[2]; + + fd = open(name, O_RDONLY); + if (fd == -1) { + return(0); + } + + read(fd, id, 2); + close(fd); + if ( id[0]=='B' && id[1]=='M' ) { + return(1); + } + return(0); +} + +void fetch_pallete(int fd, struct color pallete[], int count) +{ + unsigned char buff[4]; + int i; + + lseek(fd, BMP_COLOR_OFFSET, SEEK_SET); + for (i=0; i<count; i++) { + read(fd, buff, 4); + pallete[i].red = buff[2]; + pallete[i].green = buff[1]; + pallete[i].blue = buff[0]; + } + return; +} + +int fh_bmp_load(char *name,unsigned char *buffer, unsigned char **alpha, int x,int y) +{ + int fd, bpp, raster, i, j, k, skip; + unsigned char buff[4]; + unsigned char *wr_buffer = buffer + x*(y-1)*3; + struct color pallete[256]; + + fd = open(name, O_RDONLY); + if (fd == -1) { + return(FH_ERROR_FILE); + } + + if (lseek(fd, BMP_TORASTER_OFFSET, SEEK_SET) == -1) { + return(FH_ERROR_FORMAT); + } + read(fd, buff, 4); + raster = buff[0] + (buff[1]<<8) + (buff[2]<<16) + (buff[3]<<24); + + if (lseek(fd, BMP_BPP_OFFSET, SEEK_SET) == -1) { + return(FH_ERROR_FORMAT); + } + read(fd, buff, 2); + bpp = buff[0] + (buff[1]<<8); + + switch (bpp) + { + case 1: /* monochrome */ + skip = fill4B(x/8+(x%8?1:0)); + lseek(fd, raster, SEEK_SET); + for (i=0; i<y; i++) { + for (j=0; j<x/8; j++) { + read(fd, buff, 1); + for (k=0; k<8; k++) { + if (buff[0] & 0x80) { + *wr_buffer++ = 0xff; + *wr_buffer++ = 0xff; + *wr_buffer++ = 0xff; + } else { + *wr_buffer++ = 0x00; + *wr_buffer++ = 0x00; + *wr_buffer++ = 0x00; + } + buff[0] = buff[0]<<1; + } + + } + if (x%8) { + read(fd, buff, 1); + for (k=0; k<x%8; k++) { + if (buff[0] & 0x80) { + *wr_buffer++ = 0xff; + *wr_buffer++ = 0xff; + *wr_buffer++ = 0xff; + } else { + *wr_buffer++ = 0x00; + *wr_buffer++ = 0x00; + *wr_buffer++ = 0x00; + } + buff[0] = buff[0]<<1; + } + + } + if (skip) { + read(fd, buff, skip); + } + wr_buffer -= x*6; /* backoff 2 lines - x*2 *3 */ + } + break; + case 4: /* 4bit palletized */ + skip = fill4B(x/2+x%2); + fetch_pallete(fd, pallete, 16); + lseek(fd, raster, SEEK_SET); + for (i=0; i<y; i++) { + for (j=0; j<x/2; j++) { + read(fd, buff, 1); + buff[1] = buff[0]>>4; + buff[2] = buff[0] & 0x0f; + *wr_buffer++ = pallete[buff[1]].red; + *wr_buffer++ = pallete[buff[1]].green; + *wr_buffer++ = pallete[buff[1]].blue; + *wr_buffer++ = pallete[buff[2]].red; + *wr_buffer++ = pallete[buff[2]].green; + *wr_buffer++ = pallete[buff[2]].blue; + } + if (x%2) { + read(fd, buff, 1); + buff[1] = buff[0]>>4; + *wr_buffer++ = pallete[buff[1]].red; + *wr_buffer++ = pallete[buff[1]].green; + *wr_buffer++ = pallete[buff[1]].blue; + } + if (skip) { + read(fd, buff, skip); + } + wr_buffer -= x*6; /* backoff 2 lines - x*2 *3 */ + } + break; + case 8: /* 8bit palletized */ + skip = fill4B(x); + fetch_pallete(fd, pallete, 256); + lseek(fd, raster, SEEK_SET); + for (i=0; i<y; i++) { + for (j=0; j<x; j++) { + read(fd, buff, 1); + *wr_buffer++ = pallete[buff[0]].red; + *wr_buffer++ = pallete[buff[0]].green; + *wr_buffer++ = pallete[buff[0]].blue; + } + if (skip) { + read(fd, buff, skip); + } + wr_buffer -= x*6; /* backoff 2 lines - x*2 *3 */ + } + break; + case 16: /* 16bit RGB */ + return(FH_ERROR_FORMAT); + break; + case 24: /* 24bit RGB */ + skip = fill4B(x*3); + lseek(fd, raster, SEEK_SET); + for (i=0; i<y; i++) { + for (j=0; j<x; j++) { + read(fd, buff, 3); + *wr_buffer++ = buff[2]; + *wr_buffer++ = buff[1]; + *wr_buffer++ = buff[0]; + } + if (skip) { + read(fd, buff, skip); + } + wr_buffer -= x*6; /* backoff 2 lines - x*2 *3 */ + } + break; + default: + return(FH_ERROR_FORMAT); + } + + close(fd); + return(FH_ERROR_OK); +} + +int fh_bmp_getsize(char *name,int *x,int *y) +{ + int fd; + unsigned char size[4]; + + fd = open(name, O_RDONLY); + if (fd == -1) { + return(FH_ERROR_FILE); + } + if (lseek(fd, BMP_SIZE_OFFSET, SEEK_SET) == -1) { + return(FH_ERROR_FORMAT); + } + + read(fd, size, 4); + *x = size[0] + (size[1]<<8) + (size[2]<<16) + (size[3]<<24); + read(fd, size, 4); + *y = size[0] + (size[1]<<8) + (size[2]<<16) + (size[3]<<24); + + close(fd); + return(FH_ERROR_OK); +} +#endif /*FBV_SUPPORT_BMP*/ + diff --git a/configure b/configure new file mode 100755 index 0000000..7179ceb --- /dev/null +++ b/configure @@ -0,0 +1,155 @@ +#!/bin/sh +## +## fbv configuration script +## + +# See TGT's ./configure script for in-depth comments, becouse this +# one is delivered from it... + +# If You touch anything below, You're asking for trouble + +BASENAME=$(basename "$0") + +unset prefix +unset infodir +unset mandir +unset srcdir +unset bindir +unset libs +unset jpeg +unset png +unset bmp +unset dfb + +help(){ +cat << EOF >&2 +Usage: ./configure [options] +Options: [defaults in brackets after descriptions] + +If a long option shows an argument as mandatory, then it is mandatory +for the equivalent short option also. Similarly for optional arguments. + +General: + --help print this message + --libs=LIBS additional libraries required + +Directory and file names: + --prefix=PREFIX install files in PREFIX [/usr/local] + --bindir=DIR binary executable in DIR [PREFIX/lib] + --infodir=DIR info documentation in DIR [PREFIX/info] + --mandir=DIR man documentation in DIR [PREFIX/man] + +Features and packages: + --without-libjpeg disable libjpeg support even if found + --without-libpng disable libpng support even if found + --without-bmp disable bmp support +EOF +} + +# get options +TEMP=$(getopt -o h \ +--long help,\ +prefix:,srcdir:,bindir:,\ +infodir:,mandir:,\ +without-libjpeg,without-libpng,without-bmp,libs: \ +-n "$BASENAME" -- "$@") + +if [ $? != 0 ] ; then help ; exit 1 ; fi +# +eval set -- "$TEMP" + +# process options +while true ; do + case "$1" in + -h|--help) help ; exit 0 ;; + --libs) libs="$2"; shift 2 ;; + --prefix) prefix="$2" ; shift 2 ;; + --srcdir) srcdir="$2" ; shift 2 ;; + --bindir) bindir="$2" ; shift 2 ;; + --infodir) infodir="$2" ; shift 2 ;; + --mandir) mandir="$2" ; shift 2 ;; + --without-libjpeg) jpeg="disabled" ; shift ;; + --without-libpng) png="disabled" ; shift ;; + --without-bmp) bmp="disabled" ; shift ;; + + --) shift ; break ;; + *) help ; exit 1 ;; + esac +done + +[ -z "$prefix" ] && prefix="/usr/local" +[ -z "$bindir" ] && bindir="${prefix}/bin" +[ -z "$mandir" ] && mandir="${prefix}/man" +[ -z "$infodir" ] && infodir="${prefix}/info" + +cat << EOF | tee ./config.log >Make.conf +prefix = $prefix +bindir = $bindir +mandir = $mandir +infodir = $infodir +EOF + +# tests +rm -f \$\$~test \$\$~test.c +cat > \$\$~test.c << EOF +main() +{ +} +EOF + +### +echo -n "checking for libjpeg presence... " +if [ "$jpeg" != "disabled" ]; then +jpeg="no" +cc 2>>./config.log >>./config.log -o \$\$~test \$\$~test.c -ljpeg $libs +if [ -e \$\$~test ]; then + libs="-ljpeg $libs" ; jpeg="yes" +fi +fi +echo $jpeg +echo "libjpeg: $jpeg" >> ./config.log +### +echo -n "checking for libpng presence... " +if [ "$png" != "disabled" ]; then +png="no" +cc 2>>./config.log >>./config.log -o \$\$~test \$\$~test.c -lpng $libs +if [ -e \$\$~test ]; then + libs="-lpng $libs" ; png="yes" +fi +fi +echo $png +echo "libpng: $png" >> ./config.log +### +echo -n "building with bmp support... " +if [ "$bmp" != "disabled" ]; then +bmp="yes" +fi +echo $bmp +echo "bmp: $bmp" >> ./config.log + +### +rm -f \$\$~test \$\$~test.c + +### +echo -n "checking for DEFAULT_FRAMEBUFFER... " +if [ -n "$FRAMEBUFFER" ]; then + dfb="$FRAMEBUFFER" +else + dfb="/dev/fb0" +fi +echo $dfb +echo "fb: $dfb" >> ./config.log + +### +echo >> Make.conf +echo "LIBS = $libs" | tee -a ./config.log >>Make.conf +echo "#define IDSTRING \"fbv "`cat VERSION`"\"" | tee -a ./config.log >config.h +echo "#define DEFAULT_FRAMEBUFFER \"$dfb\"" | tee -a ./config.log >>config.h +[ "$jpeg" != "disabled" ] && echo "#define FBV_SUPPORT_JPEG" | tee -a ./config.log >>config.h +[ "$png" != "disabled" ] && echo "#define FBV_SUPPORT_PNG" | tee -a ./config.log >>config.h +[ "$bmp" != "disabled" ] && echo "#define FBV_SUPPORT_BMP" | tee -a ./config.log >>config.h +echo "installation dir: $bindir" +echo "manuals dir: $mandir" + +exit 0 +## EOF diff --git a/fb_display.c b/fb_display.c new file mode 100644 index 0000000..a9b3752 --- /dev/null +++ b/fb_display.c @@ -0,0 +1,343 @@ +#include "config.h" + +#include <linux/fb.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <sys/mman.h> +#include <asm/types.h> + +#include <errno.h> +#include <fcntl.h> +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +/* Public Use Functions: + * + * extern void fb_display(unsigned char *rgbbuff, + * int x_size, int y_size, + * int x_pan, int y_pan, + * int x_offs, int y_offs); + * + * extern void getCurrentRes(int *x,int *y); + * + */ + +unsigned short red[256], green[256], blue[256]; +struct fb_cmap map332 = {0, 256, red, green, blue, NULL}; +unsigned short red_b[256], green_b[256], blue_b[256]; +struct fb_cmap map_back = {0, 256, red_b, green_b, blue_b, NULL}; + + +int openFB(const char *name); +void closeFB(int fh); +void getVarScreenInfo(int fh, struct fb_var_screeninfo *var); +void setVarScreenInfo(int fh, struct fb_var_screeninfo *var); +void getFixScreenInfo(int fh, struct fb_fix_screeninfo *fix); +void set332map(int fh); +void* convertRGB2FB(int fh, unsigned char *rgbbuff, unsigned long count, int bpp, int *cpp); +void blit2FB(int fh, void *fbbuff, unsigned char *alpha, + unsigned int pic_xs, unsigned int pic_ys, + unsigned int scr_xs, unsigned int scr_ys, + unsigned int xp, unsigned int yp, + unsigned int xoffs, unsigned int yoffs, + int cpp); + +void fb_display(unsigned char *rgbbuff, unsigned char * alpha, int x_size, int y_size, int x_pan, int y_pan, int x_offs, int y_offs) +{ + struct fb_var_screeninfo var; + struct fb_fix_screeninfo fix; + unsigned short *fbbuff = NULL; + int fh = -1, bp = 0; + unsigned long x_stride; + + /* get the framebuffer device handle */ + fh = openFB(NULL); + + /* read current video mode */ + getVarScreenInfo(fh, &var); + getFixScreenInfo(fh, &fix); + + x_stride = (fix.line_length * 8) / var.bits_per_pixel; + + /* correct panning */ + if(x_pan > x_size - x_stride) x_pan = 0; + if(y_pan > y_size - var.yres) y_pan = 0; + /* correct offset */ + if(x_offs + x_size > x_stride) x_offs = 0; + if(y_offs + y_size > var.yres) y_offs = 0; + + /* blit buffer 2 fb */ + fbbuff = convertRGB2FB(fh, rgbbuff, x_size * y_size, var.bits_per_pixel, &bp); +#if 0 + blit2FB(fh, fbbuff, alpha, x_size, y_size, x_stride, var.yres, x_pan, y_pan, x_offs, y_offs, bp); +#else + blit2FB(fh, fbbuff, alpha, x_size, y_size, x_stride, var.yres_virtual, x_pan, y_pan, x_offs, y_offs + var.yoffset, bp); +#endif + free(fbbuff); + + /* close device */ + closeFB(fh); +} + +void getCurrentRes(int *x, int *y) +{ + struct fb_var_screeninfo var; + int fh = -1; + fh = openFB(NULL); + getVarScreenInfo(fh, &var); + *x = var.xres; + *y = var.yres; + closeFB(fh); +} + +int openFB(const char *name) +{ + int fh; + char *dev; + + if(name == NULL) + { + dev = getenv("FRAMEBUFFER"); + if(dev) name = dev; + else name = DEFAULT_FRAMEBUFFER; + } + + if ((fh = open(name, O_RDWR)) == -1) + { + fprintf(stderr, "open %s: %s\n", name, strerror(errno)); + exit(1); + } + return fh; +} + +void closeFB(int fh) +{ + close(fh); +} + +void getVarScreenInfo(int fh, struct fb_var_screeninfo *var) +{ + if (ioctl(fh, FBIOGET_VSCREENINFO, var)) + { + fprintf(stderr, "ioctl FBIOGET_VSCREENINFO: %s\n", strerror(errno)); + exit(1); + } +} + +void setVarScreenInfo(int fh, struct fb_var_screeninfo *var) +{ + if (ioctl(fh, FBIOPUT_VSCREENINFO, var)) + { + fprintf(stderr, "ioctl FBIOPUT_VSCREENINFO: %s\n", strerror(errno)); + exit(1); + } +} + +void getFixScreenInfo(int fh, struct fb_fix_screeninfo *fix) +{ + if (ioctl(fh, FBIOGET_FSCREENINFO, fix)){ + fprintf(stderr, "ioctl FBIOGET_FSCREENINFO: %s\n", strerror(errno)); + exit(1); + } +} + +void make332map(struct fb_cmap *map) +{ + int rs, gs, bs, i; + int r = 8, g = 8, b = 4; + + map->red = red; + map->green = green; + map->blue = blue; + + rs = 256 / (r - 1); + gs = 256 / (g - 1); + bs = 256 / (b - 1); + + for (i = 0; i < 256; i++) { + map->red[i] = (rs * ((i / (g * b)) % r)) * 255; + map->green[i] = (gs * ((i / b) % g)) * 255; + map->blue[i] = (bs * ((i) % b)) * 255; + } +} + +void set8map(int fh, struct fb_cmap *map) +{ + if (ioctl(fh, FBIOPUTCMAP, map) < 0) + { + fprintf(stderr, "Error putting colormap"); + exit(1); + } +} + +void get8map(int fh, struct fb_cmap *map) +{ + if (ioctl(fh, FBIOGETCMAP, map) < 0) + { + fprintf(stderr, "Error getting colormap"); + exit(1); + } +} + +void set332map(int fh) +{ + make332map(&map332); + set8map(fh, &map332); +} + +void blit2FB(int fh, void *fbbuff, unsigned char *alpha, + unsigned int pic_xs, unsigned int pic_ys, + unsigned int scr_xs, unsigned int scr_ys, + unsigned int xp, unsigned int yp, + unsigned int xoffs, unsigned int yoffs, + int cpp) +{ + int i, xc, yc; + unsigned char *fb; + + unsigned char *fbptr; + unsigned char *imptr; + + xc = (pic_xs > scr_xs) ? scr_xs : pic_xs; + yc = (pic_ys > scr_ys) ? scr_ys : pic_ys; + + fb = mmap(NULL, scr_xs * scr_ys * cpp, PROT_WRITE | PROT_READ, MAP_SHARED, fh, 0); + + if(fb == MAP_FAILED) + { + perror("mmap"); + return; + } + + if(cpp == 1) + { + get8map(fh, &map_back); + set332map(fh); + } + + fbptr = fb + (yoffs * scr_xs + xoffs) * cpp; + imptr = fbbuff + (yp * pic_xs + xp) * cpp; + + if(alpha) + { + unsigned char * alphaptr; + int from, to, x; + + alphaptr = alpha + (yp * pic_xs + xp); + + for(i = 0; i < yc; i++, fbptr += scr_xs * cpp, imptr += pic_xs * cpp, alphaptr += pic_xs) + { + for(x = 0; x<xc; x++) + { + int v; + + from = to = -1; + for(v = x; v<xc; v++) + { + if(from == -1) + { + if(alphaptr[v] > 0x80) from = v; + } + else + { + if(alphaptr[v] < 0x80) + { + to = v; + break; + } + } + } + if(from == -1) + break; + + if(to == -1) to = xc; + + memcpy(fbptr + (from * cpp), imptr + (from * cpp), (to - from - 1) * cpp); + x += to - from - 1; + } + } + } + else + for(i = 0; i < yc; i++, fbptr += scr_xs * cpp, imptr += pic_xs * cpp) + memcpy(fbptr, imptr, xc * cpp); + + if(cpp == 1) + set8map(fh, &map_back); + + munmap(fb, scr_xs * scr_ys * cpp); +} + +inline static unsigned char make8color(unsigned char r, unsigned char g, unsigned char b) +{ + return ( + (((r >> 5) & 7) << 5) | + (((g >> 5) & 7) << 2) | + ((b >> 6) & 3) ); +} + +inline static unsigned short make15color(unsigned char r, unsigned char g, unsigned char b) +{ + return ( + (((r >> 3) & 31) << 10) | + (((g >> 3) & 31) << 5) | + ((b >> 3) & 31) ); +} + +inline static unsigned short make16color(unsigned char r, unsigned char g, unsigned char b) +{ + return ( + (((r >> 3) & 31) << 11) | + (((g >> 2) & 63) << 5) | + ((b >> 3) & 31) ); +} + +void* convertRGB2FB(int fh, unsigned char *rgbbuff, unsigned long count, int bpp, int *cpp) +{ + unsigned long i; + void *fbbuff = NULL; + u_int8_t *c_fbbuff; + u_int16_t *s_fbbuff; + u_int32_t *i_fbbuff; + + switch(bpp) + { + case 8: + *cpp = 1; + c_fbbuff = (unsigned char *) malloc(count * sizeof(unsigned char)); + for(i = 0; i < count; i++) + c_fbbuff[i] = make8color(rgbbuff[i*3], rgbbuff[i*3+1], rgbbuff[i*3+2]); + fbbuff = (void *) c_fbbuff; + break; + case 15: + *cpp = 2; + s_fbbuff = (unsigned short *) malloc(count * sizeof(unsigned short)); + for(i = 0; i < count ; i++) + s_fbbuff[i] = make15color(rgbbuff[i*3], rgbbuff[i*3+1], rgbbuff[i*3+2]); + fbbuff = (void *) s_fbbuff; + break; + case 16: + *cpp = 2; + s_fbbuff = (unsigned short *) malloc(count * sizeof(unsigned short)); + for(i = 0; i < count ; i++) + s_fbbuff[i] = make16color(rgbbuff[i*3], rgbbuff[i*3+1], rgbbuff[i*3+2]); + fbbuff = (void *) s_fbbuff; + break; + case 24: + case 32: + *cpp = 4; + i_fbbuff = (unsigned int *) malloc(count * sizeof(unsigned int)); + for(i = 0; i < count ; i++) + i_fbbuff[i] = ((rgbbuff[i*3] << 16) & 0xFF0000) | + ((rgbbuff[i*3+1] << 8) & 0xFF00) | + (rgbbuff[i*3+2] & 0xFF); + fbbuff = (void *) i_fbbuff; + break; + default: + fprintf(stderr, "Unsupported video mode! You've got: %dbpp\n", bpp); + exit(1); + } + return fbbuff; +} + @@ -0,0 +1,58 @@ +.TH fbv 1 "2001-02-18" +.\" Some roff macros, for reference: +.\" .nh disable hyphenation +.\" .hy enable hyphenation +.\" .ad l left justify +.\" .ad b justify to both left and right margins +.\" .nf disable filling +.\" .fi enable filling +.\" .br insert line break +.\" .sp <n> insert n+1 empty lines +.\" for manpage-specific macros, see man(7) +.SH NAME +FrameBuffer Viewer +.SH SYNOPSIS +\fBfbv\fP [options] image1 image2 image3 ... +.SH DESCRIPTION +This is a simple program to view pictures on a framebuffer console. +.PP +.nh +.SH OPTIONS +.TP +.BR "\fB--help\fP" , \fB-h\fP +help +.TP +.BR \fB--alpha\fP , \fB-a\fP +Respect alpha channel (if applicable) +.TP +.BR \fB--noclear\fP , \fB-c\fP +Do not clear the screen before/after displaying image +.TP +.BR \fB--unhide\fP , \fB-u\fP +Do not hide/show cursor before/after displaying image +.TP +.BR \fB--noinfo\fP , \fB-i\fP +Do not show image information +.TP +.BR \fB--stretch\fP , \fB-f\fP +Strech (using simple resize) the image to fit onto screen if necessary +.TP +.BR \fB--colorstretch\fP , \fB-k\fP +Strech (using color average resize) the image to fit onto screen if necessary +.TP +.BR \fB--delay\fP , "\fB-s\fP \fI<delay>\fP" +Slideshow, wait 'delay' tenths of a second before displaying each image + +.BR + Use a,d,w and x to scroll the image + + + +.SH AUTHOR +Tomasz 'smoku' Sterna <tomek@smoczy.net> +.br +Mateusz 'mteg' Golicz <mtg@elsat.net.pl> +.br +Marcin 'Piaskowy' Zieba <piaskowy@irc.pl> +.br + @@ -0,0 +1,50 @@ +#ifndef __FBV_H__ +#define __FBV_H__ + +#define FH_ERROR_OK 0 +#define FH_ERROR_FILE 1 /* read/access error */ +#define FH_ERROR_FORMAT 2 /* file format error */ + +void fb_display(unsigned char *rgbbuff, unsigned char * alpha, int x_size, int y_size, int x_pan, int y_pan, int x_offs, int y_offs); +void getCurrentRes(int *x, int *y); + +#ifdef FBV_SUPPORT_BMP +int fh_bmp_id(char *name); +int fh_bmp_load(char *name,unsigned char *buffer, unsigned char **alpha, int x,int y); +int fh_bmp_getsize(char *name,int *x,int *y); +#endif + +#ifdef FBV_SUPPORT_JPEG +int fh_jpeg_id(char *name); +int fh_jpeg_load(char *name,unsigned char *buffer, unsigned char **alpha, int x,int y); +int fh_jpeg_getsize(char *name,int *x,int *y); +#endif + +#ifdef FBV_SUPPORT_PNG +int fh_png_id(char *name); +int fh_png_load(char *name,unsigned char *buffer, unsigned char **alpha, int x,int y); +int fh_png_getsize(char *name,int *x,int *y); +#endif + +struct image +{ + int width, height; + unsigned char *rgb; + unsigned char *alpha; + int do_free; +}; + +#ifndef min +#define min(a,b) ((a) < (b) ? (a) : (b)) +#endif +#ifndef max +#define max(a,b) ((a) > (b) ? (a) : (b)) +#endif +unsigned char * simple_resize(unsigned char * orgin,int ox,int oy,int dx,int dy); +unsigned char * alpha_resize(unsigned char * alpha,int ox,int oy,int dx,int dy); +unsigned char * color_average_resize(unsigned char * orgin,int ox,int oy,int dx,int dy); +unsigned char * rotate(unsigned char *i, int ox, int oy, int rot); +unsigned char * alpha_rotate(unsigned char *i, int ox, int oy, int rot); + +#endif + @@ -0,0 +1,128 @@ +#include "config.h" + +#ifdef FBV_SUPPORT_JPEG +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <jpeglib.h> +#include <setjmp.h> +#include <unistd.h> +#include <string.h> +#include "fbv.h" + +struct r_jpeg_error_mgr +{ + struct jpeg_error_mgr pub; + jmp_buf envbuffer; +}; + + +int fh_jpeg_id(char *name) +{ + int fd; + unsigned char id[10]; + fd = open(name,O_RDONLY); if(fd==-1) return(0); + read(fd,id,10); + close(fd); + if(id[6]=='J' && id[7]=='F' && id[8]=='I' && id[9]=='F') return(1); + if(id[0]==0xff && id[1]==0xd8 && id[2]==0xff) return(1); + return(0); +} + + +void jpeg_cb_error_exit(j_common_ptr cinfo) +{ + struct r_jpeg_error_mgr *mptr; + mptr=(struct r_jpeg_error_mgr*) cinfo->err; + (*cinfo->err->output_message) (cinfo); + longjmp(mptr->envbuffer,1); +} + +int fh_jpeg_load(char *filename,unsigned char *buffer, unsigned char ** alpha, int x,int y) +{ + struct jpeg_decompress_struct cinfo; + struct jpeg_decompress_struct *ciptr; + struct r_jpeg_error_mgr emgr; + unsigned char *bp; + int px, py, c; + FILE *fh; + JSAMPLE *lb; + + ciptr=&cinfo; + if(!(fh=fopen(filename,"rb"))) return(FH_ERROR_FILE); + ciptr->err=jpeg_std_error(&emgr.pub); + emgr.pub.error_exit=jpeg_cb_error_exit; + if(setjmp(emgr.envbuffer)==1) + { + // FATAL ERROR - Free the object and return... + jpeg_destroy_decompress(ciptr); + fclose(fh); + return(FH_ERROR_FORMAT); + } + + jpeg_create_decompress(ciptr); + jpeg_stdio_src(ciptr,fh); + jpeg_read_header(ciptr,TRUE); + ciptr->out_color_space=JCS_RGB; + jpeg_start_decompress(ciptr); + + px=ciptr->output_width; + py=ciptr->output_height; + c=ciptr->output_components; + + + if(c==3) + { + lb=(*ciptr->mem->alloc_small)((j_common_ptr) ciptr,JPOOL_PERMANENT,c*px); + bp=buffer; + while (ciptr->output_scanline < ciptr->output_height) + { + jpeg_read_scanlines(ciptr, &lb, 1); + memcpy(bp,lb,px*c); + bp+=px*c; + } + } + jpeg_finish_decompress(ciptr); + jpeg_destroy_decompress(ciptr); + fclose(fh); + return(FH_ERROR_OK); +} + +int fh_jpeg_getsize(char *filename, int *x, int *y) +{ + struct jpeg_decompress_struct cinfo; + struct jpeg_decompress_struct *ciptr; + struct r_jpeg_error_mgr emgr; + int px, py, c; + FILE *fh; + + ciptr=&cinfo; + if(!(fh=fopen(filename,"rb"))) return(FH_ERROR_FILE); + + ciptr->err=jpeg_std_error(&emgr.pub); + emgr.pub.error_exit=jpeg_cb_error_exit; + if(setjmp(emgr.envbuffer)==1) + { + // FATAL ERROR - Free the object and return... + jpeg_destroy_decompress(ciptr); + fclose(fh); + return(FH_ERROR_FORMAT); + } + + jpeg_create_decompress(ciptr); + jpeg_stdio_src(ciptr,fh); + jpeg_read_header(ciptr,TRUE); + ciptr->out_color_space=JCS_RGB; + jpeg_start_decompress(ciptr); + px=ciptr->output_width; + py=ciptr->output_height; + c = ciptr->output_components; + *x=px; + *y=py; + jpeg_destroy_decompress(ciptr); + fclose(fh); + return(FH_ERROR_OK); +} +#endif /*FBV_SUPPORT_JPEG*/ + @@ -0,0 +1,554 @@ +#include "config.h" +#include "fbv.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <sys/time.h> +#include <sys/types.h> +#include <unistd.h> +#include <getopt.h> +#include <termios.h> +#include <signal.h> + + +#define PAN_STEPPING 20 + +static int opt_clear = 1; +static int opt_alpha = 0; +static int opt_hide_cursor = 1; +static int opt_image_info = 1; +static int opt_stretch = 0; +static int opt_delay = 0; +static int opt_enlarge = 0; +static int opt_ignore_aspect = 0; + +void setup_console(int t) +{ + struct termios our_termios; + static struct termios old_termios; + + if(t) + { + tcgetattr(0, &old_termios); + memcpy(&our_termios, &old_termios, sizeof(struct termios)); + our_termios.c_lflag &= !(ECHO | ICANON); + tcsetattr(0, TCSANOW, &our_termios); + } + else + tcsetattr(0, TCSANOW, &old_termios); + +} + +static inline void do_rotate(struct image *i, int rot) +{ + if(rot) + { + unsigned char *image, *alpha = NULL; + int t; + + image = rotate(i->rgb, i->width, i->height, rot); + if(i->alpha) + alpha = alpha_rotate(i->alpha, i->width, i->height, rot); + if(i->do_free) + { + free(i->alpha); + free(i->rgb); + } + + i->rgb = image; + i->alpha = alpha; + i->do_free = 1; + + if(rot & 1) + { + t = i->width; + i->width = i->height; + i->height = t; + } + } +} + + +static inline void do_enlarge(struct image *i, int screen_width, int screen_height, int ignoreaspect) +{ + if(((i->width > screen_width) || (i->height > screen_height)) && (!ignoreaspect)) + return; + if((i->width < screen_width) || (i->height < screen_height)) + { + int xsize = i->width, ysize = i->height; + unsigned char * image, * alpha = NULL; + + if(ignoreaspect) + { + if(i->width < screen_width) + xsize = screen_width; + if(i->height < screen_height) + ysize = screen_height; + + goto have_sizes; + } + + if((i->height * screen_width / i->width) <= screen_height) + { + xsize = screen_width; + ysize = i->height * screen_width / i->width; + goto have_sizes; + } + + if((i->width * screen_height / i->height) <= screen_width) + { + xsize = i->width * screen_height / i->height; + ysize = screen_height; + goto have_sizes; + } + return; +have_sizes: + image = simple_resize(i->rgb, i->width, i->height, xsize, ysize); + if(i->alpha) + alpha = alpha_resize(i->alpha, i->width, i->height, xsize, ysize); + + if(i->do_free) + { + free(i->alpha); + free(i->rgb); + } + + i->rgb = image; + i->alpha = alpha; + i->do_free = 1; + i->width = xsize; + i->height = ysize; + } +} + + +static inline void do_fit_to_screen(struct image *i, int screen_width, int screen_height, int ignoreaspect, int cal) +{ + if((i->width > screen_width) || (i->height > screen_height)) + { + unsigned char * new_image, * new_alpha = NULL; + int nx_size = i->width, ny_size = i->height; + + if(ignoreaspect) + { + if(i->width > screen_width) + nx_size = screen_width; + if(i->height > screen_height) + ny_size = screen_height; + } + else + { + if((i->height * screen_width / i->width) <= screen_height) + { + nx_size = screen_width; + ny_size = i->height * screen_width / i->width; + } + else + { + nx_size = i->width * screen_height / i->height; + ny_size = screen_height; + } + } + + if(cal) + new_image = color_average_resize(i->rgb, i->width, i->height, nx_size, ny_size); + else + new_image = simple_resize(i->rgb, i->width, i->height, nx_size, ny_size); + + if(i->alpha) + new_alpha = alpha_resize(i->alpha, i->width, i->height, nx_size, ny_size); + + if(i->do_free) + { + free(i->alpha); + free(i->rgb); + } + + i->rgb = new_image; + i->alpha = new_alpha; + i->do_free = 1; + i->width = nx_size; + i->height = ny_size; + } +} + + +int show_image(char *filename) +{ + int (*load)(char *, unsigned char *, unsigned char **, int, int); + + unsigned char * image = NULL; + unsigned char * alpha = NULL; + + int x_size, y_size, screen_width, screen_height; + int x_pan, y_pan, x_offs, y_offs, refresh = 1, c, ret = 1; + int delay = opt_delay, retransform = 1; + + int transform_stretch = opt_stretch, transform_enlarge = opt_enlarge, transform_cal = (opt_stretch == 2), + transform_iaspect = opt_ignore_aspect, transform_rotation = 0; + + struct image i; + +#ifdef FBV_SUPPORT_PNG + if(fh_png_id(filename)) + if(fh_png_getsize(filename, &x_size, &y_size) == FH_ERROR_OK) + { + load = fh_png_load; + goto identified; + } +#endif + +#ifdef FBV_SUPPORT_JPEG + if(fh_jpeg_id(filename)) + if(fh_jpeg_getsize(filename, &x_size, &y_size) == FH_ERROR_OK) + { + load = fh_jpeg_load; + goto identified; + } +#endif + +#ifdef FBV_SUPPORT_BMP + if(fh_bmp_id(filename)) + if(fh_bmp_getsize(filename, &x_size, &y_size) == FH_ERROR_OK) + { + load = fh_bmp_load; + goto identified; + } +#endif + fprintf(stderr, "%s: Unable to access file or file format unknown.\n", filename); + return(1); + +identified: + + if(!(image = (unsigned char*) malloc(x_size * y_size * 3))) + { + fprintf(stderr, "%s: Out of memory.\n", filename); + goto error_mem; + } + + if(load(filename, image, &alpha, x_size, y_size) != FH_ERROR_OK) + { + fprintf(stderr, "%s: Image data is corrupt?\n", filename); + goto error_mem; + } + + if(!opt_alpha) + { + free(alpha); + alpha = NULL; + } + + + + getCurrentRes(&screen_width, &screen_height); + i.do_free = 0; + while(1) + { + if(retransform) + { + if(i.do_free) + { + free(i.rgb); + free(i.alpha); + } + i.width = x_size; + i.height = y_size; + i.rgb = image; + i.alpha = alpha; + i.do_free = 0; + + + if(transform_rotation) + do_rotate(&i, transform_rotation); + + if(transform_stretch) + do_fit_to_screen(&i, screen_width, screen_height, transform_iaspect, transform_cal); + + if(transform_enlarge) + do_enlarge(&i, screen_width, screen_height, transform_iaspect); + + x_pan = y_pan = 0; + refresh = 1; retransform = 0; + if(opt_clear) + { + printf("\033[H\033[J"); + fflush(stdout); + } + if(opt_image_info) + printf("fbv - The Framebuffer Viewer\n%s\n%d x %d\n", filename, x_size, y_size); + } + if(refresh) + { + if(i.width < screen_width) + x_offs = (screen_width - i.width) / 2; + else + x_offs = 0; + + if(i.height < screen_height) + y_offs = (screen_height - i.height) / 2; + else + y_offs = 0; + + fb_display(i.rgb, i.alpha, i.width, i.height, x_pan, y_pan, x_offs, y_offs); + refresh = 0; + } + if(delay) + { + struct timeval tv; + fd_set fds; + tv.tv_sec = delay / 10; + tv.tv_usec = (delay % 10) * 100000; + FD_ZERO(&fds); + FD_SET(0, &fds); + + if(select(1, &fds, NULL, NULL, &tv) <= 0) + break; + delay = 0; + } + + c = getchar(); + switch(c) + { + case EOF: + case 'q': + ret = 0; + goto done; + case ' ': case 10: case 13: + goto done; + case '>': case '.': + goto done; + case '<': case ',': + ret = -1; + goto done; + case 'r': + refresh = 1; + break; + case 'a': case 'D': + if(x_pan == 0) break; + x_pan -= i.width / PAN_STEPPING; + if(x_pan < 0) x_pan = 0; + refresh = 1; + break; + case 'd': case 'C': + if(x_offs) break; + if(x_pan >= (i.width - screen_width)) break; + x_pan += i.width / PAN_STEPPING; + if(x_pan > (i.width - screen_width)) x_pan = i.width - screen_width; + refresh = 1; + break; + case 'w': case 'A': + if(y_pan == 0) break; + y_pan -= i.height / PAN_STEPPING; + if(y_pan < 0) y_pan = 0; + refresh = 1; + break; + case 'x': case 'B': + if(y_offs) break; + if(y_pan >= (i.height - screen_height)) break; + y_pan += i.height / PAN_STEPPING; + if(y_pan > (i.height - screen_height)) y_pan = i.height - screen_height; + refresh = 1; + break; + case 'f': + transform_stretch = !transform_stretch; + retransform = 1; + break; + case 'e': + transform_enlarge = !transform_enlarge; + retransform = 1; + break; + case 'k': + transform_cal = !transform_cal; + retransform = 1; + break; + case 'i': + transform_iaspect = !transform_iaspect; + retransform = 1; + break; + case 'p': + transform_cal = 0; + transform_iaspect = 0; + transform_enlarge = 0; + transform_stretch = 0; + retransform = 1; + break; + case 'n': + transform_rotation -= 1; + if(transform_rotation < 0) + transform_rotation += 4; + retransform = 1; + break; + case 'm': + transform_rotation += 1; + if(transform_rotation > 3) + transform_rotation -= 4; + retransform = 1; + break; + + } + + } + +done: + if(opt_clear) + { + printf("\033[H\033[J"); + fflush(stdout); + } + +error_mem: + free(image); + free(alpha); + if(i.do_free) + { + free(i.rgb); + free(i.alpha); + } + return(ret); + +} + +void help(char *name) +{ + printf("Usage: %s [options] image1 image2 image3 ...\n\n" + "Available options:\n" + " --help | -h : Show this help\n" + " --alpha | -a : Use the alpha channel (if applicable)\n" + " --dontclear | -c : Do not clear the screen before and after displaying the image\n" + " --donthide | -u : Do not hide the cursor before and after displaying the image\n" + " --noinfo | -i : Supress image information\n" + " --stretch | -f : Strech (using a simple resizing routine) the image to fit onto screen if necessary\n" + " --colorstretch| -k : Strech (using a 'color average' resizing routine) the image to fit onto screen if necessary\n" + " --enlarge | -e : Enlarge the image to fit the whole screen if necessary\n" + " --ignore-aspect| -r : Ignore the image aspect while resizing\n" + " --delay <d> | -s <delay> : Slideshow, 'delay' is the slideshow delay in tenths of seconds.\n\n" + "Keys:\n" + " r : Redraw the image\n" + " a, d, w, x : Pan the image\n" + " f : Toggle resizing on/off\n" + " k : Toggle resizing quality\n" + " e : Toggle enlarging on/off\n" + " i : Toggle respecting the image aspect on/off\n" + " n : Rotate the image 90 degrees left\n" + " m : Rotate the image 90 degrees right\n" + " p : Disable all transformations\n" + "Copyright (C) 2000 - 2004 Mateusz Golicz, Tomasz Sterna.\n", name); +} + +void sighandler(int s) +{ + if(opt_hide_cursor) + { + printf("\033[?25h"); + fflush(stdout); + } + setup_console(0); + _exit(128 + s); +} + +int main(int argc, char **argv) +{ + static struct option long_options[] = + { + {"help", no_argument, 0, 'h'}, + {"noclear", no_argument, 0, 'c'}, + {"alpha", no_argument, 0, 'a'}, + {"unhide", no_argument, 0, 'u'}, + {"noinfo", no_argument, 0, 'i'}, + {"stretch", no_argument, 0, 'f'}, + {"colorstrech", no_argument, 0, 'k'}, + {"delay", required_argument, 0, 's'}, + {"enlarge", no_argument, 0, 'e'}, + {"ignore-aspect", no_argument, 0, 'r'}, + {0, 0, 0, 0} + }; + int c, i; + + if(argc < 2) + { + help(argv[0]); + fprintf(stderr, "Error: Required argument missing.\n"); + return(1); + } + + while((c = getopt_long_only(argc, argv, "hcauifks:er", long_options, NULL)) != EOF) + { + switch(c) + { + case 'a': + opt_alpha = 1; + break; + case 'c': + opt_clear = 0; + break; + case 's': + opt_delay = atoi(optarg); + break; + case 'u': + opt_hide_cursor = 0; + break; + case 'h': + help(argv[0]); + return(0); + case 'i': + opt_image_info = 0; + break; + case 'f': + opt_stretch = 1; + break; + case 'k': + opt_stretch = 2; + break; + case 'e': + opt_enlarge = 1; + break; + case 'r': + opt_ignore_aspect = 1; + break; + } + } + + if(!argv[optind]) + { + fprintf(stderr, "Required argument missing! Consult %s -h.\n", argv[0]); + return(1); + } + + signal(SIGHUP, sighandler); + signal(SIGINT, sighandler); + signal(SIGQUIT, sighandler); + signal(SIGSEGV, sighandler); + signal(SIGTERM, sighandler); + signal(SIGABRT, sighandler); + + if(opt_hide_cursor) + { + printf("\033[?25l"); + fflush(stdout); + } + + setup_console(1); + + for(i = optind; argv[i]; ) + { + int r = show_image(argv[i]); + + if(!r) break; + + i += r; + if(i < optind) + i = optind; + } + + setup_console(0); + + if(opt_hide_cursor) + { + printf("\033[?25h"); + fflush(stdout); + } + return(0); +} + @@ -0,0 +1,166 @@ +#include "config.h" + +#ifdef FBV_SUPPORT_PNG +#include <png.h> +#include "fbv.h" +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> + +#define PNG_BYTES_TO_CHECK 4 +#ifndef min +#define min(x,y) ((x) < (y) ? (x) : (y)) +#endif + +int fh_png_id(char *name) +{ + int fd; + char id[4]; + fd=open(name,O_RDONLY); if(fd==-1) return(0); + read(fd,id,4); + close(fd); + if(id[1]=='P' && id[2]=='N' && id[3]=='G') return(1); + return(0); +} + + +int fh_png_load(char *name,unsigned char *buffer, unsigned char ** alpha,int x,int y) +{ + png_structp png_ptr; + png_infop info_ptr; + png_uint_32 width, height; + int i; + int bit_depth, color_type, interlace_type; + int number_passes,pass, trans = 0; + png_bytep rptr[2]; + unsigned char *rp; + unsigned char *fbptr; + FILE *fh; + + if(!(fh=fopen(name,"rb"))) return(FH_ERROR_FILE); + + png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,NULL,NULL,NULL); + if (png_ptr == NULL) return(FH_ERROR_FORMAT); + info_ptr = png_create_info_struct(png_ptr); + if (info_ptr == NULL) + { + png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); + fclose(fh); + return(FH_ERROR_FORMAT); + } + rp=0; + if (setjmp(png_ptr->jmpbuf)) + { + png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); + if(rp) free(rp); + fclose(fh); + return(FH_ERROR_FORMAT); + } + + png_init_io(png_ptr,fh); + + png_read_info(png_ptr, info_ptr); + png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,&interlace_type, NULL, NULL); + if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_expand(png_ptr); + if (bit_depth < 8) png_set_packing(png_ptr); + if (color_type == PNG_COLOR_TYPE_GRAY || color_type== PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(png_ptr); + if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) + { + trans = 1; + png_set_tRNS_to_alpha(png_ptr); + } + + if(bit_depth == 16) png_set_strip_16(png_ptr); + number_passes = png_set_interlace_handling(png_ptr); + png_read_update_info(png_ptr,info_ptr); + + if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA || color_type == PNG_COLOR_TYPE_RGB_ALPHA || trans) + { + unsigned char * alpha_buffer = (unsigned char*) malloc(width * height); + unsigned char * aptr; + + rp = (unsigned char*)malloc(width * 4); + rptr[0] = (png_bytep) rp; + + *alpha = alpha_buffer; + + for (pass = 0; pass < number_passes; pass++) + { + fbptr = buffer; + aptr = alpha_buffer; + + for(i=0; i<height; i++) + { + int n; + unsigned char *trp = rp; + + png_read_rows(png_ptr, rptr, NULL, 1); + + for(n = 0; n < width; n++, fbptr += 3, trp += 4) + { + memcpy(fbptr, trp, 3); + *(aptr++) = trp[3]; + } + } + } + free(rp); + } + else + { + for (pass = 0; pass < number_passes; pass++) + { + fbptr = buffer; + for(i=0; i<height; i++, fbptr += width*3) + { + rptr[0] = (png_bytep) fbptr; + png_read_rows(png_ptr, rptr, NULL, 1); + } + } + } + png_read_end(png_ptr, info_ptr); + png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); + fclose(fh); + return(FH_ERROR_OK); +} +int fh_png_getsize(char *name,int *x,int *y) +{ + png_structp png_ptr; + png_infop info_ptr; + png_uint_32 width, height; + int bit_depth, color_type, interlace_type; + char *rp; + FILE *fh; + + if(!(fh=fopen(name,"rb"))) return(FH_ERROR_FILE); + + png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,NULL,NULL,NULL); + if (png_ptr == NULL) return(FH_ERROR_FORMAT); + info_ptr = png_create_info_struct(png_ptr); + if (info_ptr == NULL) + { + png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); + fclose(fh); + return(FH_ERROR_FORMAT); + } + rp=0; + if (setjmp(png_ptr->jmpbuf)) + { + png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); + if(rp) free(rp); + fclose(fh); + return(FH_ERROR_FORMAT); + } + + png_init_io(png_ptr,fh); + png_read_info(png_ptr, info_ptr); + png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,&interlace_type, NULL, NULL); + png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); + *x=width; + *y=height; + fclose(fh); + return(FH_ERROR_OK); +} +#endif /*FBV_SUPPORT_PNG*/ diff --git a/transforms.c b/transforms.c new file mode 100644 index 0000000..69c69cd --- /dev/null +++ b/transforms.c @@ -0,0 +1,158 @@ +#include <stdio.h> +#include <stdlib.h> +#include <assert.h> + +unsigned char * simple_resize(unsigned char * orgin,int ox,int oy,int dx,int dy) +{ + unsigned char *cr,*p,*l; + int i,j,k,ip; + assert(cr = (unsigned char*) malloc(dx*dy*3)); + l=cr; + + for(j=0;j<dy;j++,l+=dx*3) + { + p=orgin+(j*oy/dy*ox*3); + for(i=0,k=0;i<dx;i++,k+=3) + { + ip=i*ox/dx*3; + l[k]=p[ip]; + l[k+1]=p[ip+1]; + l[k+2]=p[ip+2]; + } + } + return(cr); +} + +unsigned char * alpha_resize(unsigned char * alpha,int ox,int oy,int dx,int dy) +{ + unsigned char *cr,*p,*l; + int i,j,k; + cr=(unsigned char*) malloc(dx*dy); l=cr; + + for(j=0;j<dy;j++,l+=dx) + { + p = alpha+(j*oy/dy*ox); + for(i=0,k=0;i<dx;i++) + l[k++]=p[i*ox/dx]; + } + + return(cr); +} + +unsigned char * color_average_resize(unsigned char * orgin,int ox,int oy,int dx,int dy) +{ + unsigned char *cr,*p,*q; + int i,j,k,l,xa,xb,ya,yb; + int sq,r,g,b; + assert(cr=(unsigned char*) malloc(dx*dy*3)); p=cr; + + for(j=0;j<dy;j++) + { + for(i=0;i<dx;i++,p+=3) + { + xa=i*ox/dx; + ya=j*oy/dy; + xb=(i+1)*ox/dx; if(xb>=ox) xb=ox-1; + yb=(j+1)*oy/dy; if(yb>=oy) yb=oy-1; + for(l=ya,r=0,g=0,b=0,sq=0;l<=yb;l++) + { + q=orgin+((l*ox+xa)*3); + for(k=xa;k<=xb;k++,q+=3,sq++) + { + r+=q[0]; g+=q[1]; b+=q[2]; + } + } + p[0]=r/sq; p[1]=g/sq; p[2]=b/sq; + } + } + return(cr); +} + +unsigned char * rotate(unsigned char *i, int ox, int oy, int rot) +{ + unsigned char * n, * p; + int x, y; + assert(n = (unsigned char*) malloc(ox * oy * 3)); + + switch(rot) + { + case 1: /* 90 deg right */ + p = n + (oy - 1) * 3; + for(y = 0; y<oy; y++, p -= 3) + { + unsigned char * r = p; + for(x = 0; x<ox; x++, r += oy * 3) + { + r[0] = *(i++); + r[1] = *(i++); + r[2] = *(i++); + } + } + break; + case 2: /* 180 deg */ + i += ox * oy * 3; p = n; + for(y = ox * oy; y > 0; y--) + { + i -= 3; + p[0] = i[0]; + p[1] = i[1]; + p[2] = i[2]; + p += 3; + } + break; + case 3: /* 90 deg left */ + p = n; + for(y = 0; y<oy; y++, p += 3) + { + unsigned char * r = p + ((ox * 3) * oy); + for(x = 0; x<ox; x++) + { + r -= oy * 3; + r[0] = *(i++); + r[1] = *(i++); + r[2] = *(i++); + } + } + break; + } + return(n); +} + +unsigned char * alpha_rotate(unsigned char *i, int ox, int oy, int rot) +{ + unsigned char * n, * p; + int x, y; + assert(n = (unsigned char*) malloc(ox * oy)); + + switch(rot) + { + case 1: /* 90 deg right */ + p = n + (oy - 1); + for(y = 0; y<oy; y++, p --) + { + unsigned char * r = p; + for(x = 0; x<ox; x++, r += oy) + *r = *(i++); + } + break; + case 2: /* 180 deg */ + i += ox * oy; p = n; + for(y = ox * oy; y > 0; y--) + *(p++) = *(i--); + break; + case 3: /* 90 deg left */ + p = n; + for(y = 0; y<oy; y++, p++) + { + unsigned char * r = p + (ox * oy); + for(x = 0; x<ox; x++) + { + r -= oy; + *r = *(i++); + } + } + break; + } + return(n); +} + |