summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorgodspeed1989 <tongxinjichu@gmail.com>2013-05-03 10:14:09 +0800
committergodspeed1989 <tongxinjichu@gmail.com>2013-05-03 10:14:09 +0800
commit5c4c50c1171f1cf084b1cc0f02cefa421f4e1914 (patch)
tree3632b1609bb8859fbb6b726f562180606db99b70
downloadfbv-5c4c50c1171f1cf084b1cc0f02cefa421f4e1914.tar.gz
fbv-5c4c50c1171f1cf084b1cc0f02cefa421f4e1914.zip
init commit
-rw-r--r--Make.conf2
-rw-r--r--Makefile36
-rw-r--r--README.md34
-rw-r--r--VERSION1
-rw-r--r--bmp.c222
-rwxr-xr-xconfigure155
-rw-r--r--fb_display.c343
-rw-r--r--fbv.158
-rw-r--r--fbv.h50
-rw-r--r--jpeg.c128
-rw-r--r--main.c554
-rw-r--r--png.c166
-rw-r--r--transforms.c158
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.
+
diff --git a/VERSION b/VERSION
new file mode 100644
index 0000000..9459d4b
--- /dev/null
+++ b/VERSION
@@ -0,0 +1 @@
+1.1
diff --git a/bmp.c b/bmp.c
new file mode 100644
index 0000000..1712bc8
--- /dev/null
+++ b/bmp.c
@@ -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;
+}
+
diff --git a/fbv.1 b/fbv.1
new file mode 100644
index 0000000..b7e0bb3
--- /dev/null
+++ b/fbv.1
@@ -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
+
diff --git a/fbv.h b/fbv.h
new file mode 100644
index 0000000..2bf2751
--- /dev/null
+++ b/fbv.h
@@ -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
+
diff --git a/jpeg.c b/jpeg.c
new file mode 100644
index 0000000..b5a8822
--- /dev/null
+++ b/jpeg.c
@@ -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*/
+
diff --git a/main.c b/main.c
new file mode 100644
index 0000000..dd32049
--- /dev/null
+++ b/main.c
@@ -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);
+}
+
diff --git a/png.c b/png.c
new file mode 100644
index 0000000..cbcc699
--- /dev/null
+++ b/png.c
@@ -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);
+}
+
OpenPOWER on IntegriCloud