diff --git a/projects/recalbox-fbv/.gitignore b/projects/recalbox-fbv/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..bf797c5fe75b3e882c98b694e912b65ddcffd5e2 --- /dev/null +++ b/projects/recalbox-fbv/.gitignore @@ -0,0 +1 @@ +cmake-build-debug \ No newline at end of file diff --git a/projects/recalbox-fbv/.idea/.gitignore b/projects/recalbox-fbv/.idea/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..73f69e0958611ac6e00bde95641f6699030ad235 --- /dev/null +++ b/projects/recalbox-fbv/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml +# Editor-based HTTP Client requests +/httpRequests/ diff --git a/projects/recalbox-fbv/.idea/.name b/projects/recalbox-fbv/.idea/.name new file mode 100644 index 0000000000000000000000000000000000000000..27a223c909d2e4c5e2d1db904138a95750e0eb03 --- /dev/null +++ b/projects/recalbox-fbv/.idea/.name @@ -0,0 +1 @@ +fbv2 \ No newline at end of file diff --git a/projects/recalbox-fbv/.idea/fbv.iml b/projects/recalbox-fbv/.idea/fbv.iml new file mode 100644 index 0000000000000000000000000000000000000000..f08604bb65b25149b195f9e9f282f9683a428592 --- /dev/null +++ b/projects/recalbox-fbv/.idea/fbv.iml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/projects/recalbox-fbv/.idea/inspectionProfiles/Project_Default.xml b/projects/recalbox-fbv/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000000000000000000000000000000000000..1ac5b580d43a0d808b765c3dea3bff22bd84829a --- /dev/null +++ b/projects/recalbox-fbv/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,8 @@ + + + + \ No newline at end of file diff --git a/projects/recalbox-fbv/.idea/misc.xml b/projects/recalbox-fbv/.idea/misc.xml new file mode 100644 index 0000000000000000000000000000000000000000..8822db8f1c2b8ceffb5d86c69dd1952cf6552980 --- /dev/null +++ b/projects/recalbox-fbv/.idea/misc.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/projects/recalbox-fbv/.idea/modules.xml b/projects/recalbox-fbv/.idea/modules.xml new file mode 100644 index 0000000000000000000000000000000000000000..23361f90e879c908c7b078c2bcce801f0834e277 --- /dev/null +++ b/projects/recalbox-fbv/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/projects/recalbox-fbv/.idea/vcs.xml b/projects/recalbox-fbv/.idea/vcs.xml new file mode 100644 index 0000000000000000000000000000000000000000..94a25f7f4cb416c083d265558da75d457237d671 --- /dev/null +++ b/projects/recalbox-fbv/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/projects/recalbox-fbv/CMakeLists.txt b/projects/recalbox-fbv/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..d0d61ed2ef8d6f870b7e7c1dd952a79ad8d5c4b7 --- /dev/null +++ b/projects/recalbox-fbv/CMakeLists.txt @@ -0,0 +1,20 @@ +cmake_minimum_required(VERSION 2.8) +project(fbv2 C) + +set(CMAKE_C_STANDARD 11) + +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra") + +include_directories(.) + +add_executable(fbv2 + bmp.c + fb_display.c + fbv.h + gif.c + jpeg.c + main.c + png.c + transforms.c) + +target_link_libraries(fbv2 gif png jpeg) diff --git a/projects/recalbox-fbv/COPYING b/projects/recalbox-fbv/COPYING new file mode 100644 index 0000000000000000000000000000000000000000..42a1b9318c663105d1b5314ff6c2bf62b763e784 --- /dev/null +++ b/projects/recalbox-fbv/COPYING @@ -0,0 +1,5 @@ +The package is licensed under the GPL license, version 2. + +It was to large to include it here (bigger than the whole source). + +Obtain your copy from http://www.gnu.org diff --git a/projects/recalbox-fbv/README.md b/projects/recalbox-fbv/README.md new file mode 100644 index 0000000000000000000000000000000000000000..f64cac3558e6a24ac9d4997444a524ed104c18ea --- /dev/null +++ b/projects/recalbox-fbv/README.md @@ -0,0 +1,49 @@ +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 + (/dev/fb0 or /dev/fb/0) + - libungif for GIF support + - libjpeg for JPEG support + - libpng for PNG support + +3. INSTALLATION + - unpack the archive (you've propably already done it) + - run ./configure + - type: make + - type: make install + - enjoy... + +4. USAGE + Just run fbv without any arguments, and a short help message + will appear... + +5. AUTHORS + Tomasz 'smoku' Sterna + Mateusz 'mteg' Golicz + + 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. + +6. BUGS & TODO + - the code is really awfully formated and requires some fixes... + - the english in messages is not the best at all :-) + +7. ACKNOWLEDGEMENTS + - the fbset authors: some code in fb_display.c is based on it... + - Nat Ersoz - for his suggestions and bugfixes + - Mauro Meneghin - for the transparent GIF support + - Marcin 'Piaskowy' Zieba - for his minor bugfixes + - Mariusz 'Ma-rYu-sH' Witkowski - for his suggestions on alpha + channel support and testing + +8. LICENSE + The package is licensed under the GNU GPL license, version 2. + Obtain your copy at http://www.gnu.org. diff --git a/projects/recalbox-fbv/bmp.c b/projects/recalbox-fbv/bmp.c new file mode 100644 index 0000000000000000000000000000000000000000..5f143c660e02f62a96bbdbc4f5e49eab456b85e1 --- /dev/null +++ b/projects/recalbox-fbv/bmp.c @@ -0,0 +1,259 @@ +/* + fbv -- simple image viewer for the linux framebuffer + Copyright (C) 2002 Tomasz Sterna + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ +#include "config.h" +#ifdef FBV_SUPPORT_BMP +#include "fbv.h" +#include +#include +#include + +#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) +{ + char id[2]; + + int 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]; + + lseek(fd, BMP_COLOR_OFFSET, SEEK_SET); + for (int i=0; i> 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 */ + int skip = fill4B(x); + fetch_pallete(fd, pallete, 256); + lseek(fd, raster, SEEK_SET); + for (int i = 0; i < y; i++) + { + for (int 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); + case 24: + { /* 24bit RGB */ + int skip = fill4B(x * 3); + lseek(fd, raster, SEEK_SET); + for (int i = 0; i < y; i++) + { + for (int 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) +{ + unsigned char size[4]; + + int 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); +// *x-=1; + read(fd, size, 4); + *y = size[0] + (size[1]<<8) + (size[2]<<16) + (size[3]<<24); + + close(fd); + return(FH_ERROR_OK); +} +#endif diff --git a/projects/recalbox-fbv/config.h b/projects/recalbox-fbv/config.h new file mode 100644 index 0000000000000000000000000000000000000000..19b65d6fdac146422c77402dbd10963b3f050bca --- /dev/null +++ b/projects/recalbox-fbv/config.h @@ -0,0 +1,5 @@ +#define DEFAULT_FRAMEBUFFER "/dev/fb0" +#define FBV_SUPPORT_GIF +#define FBV_SUPPORT_JPEG +#define FBV_SUPPORT_PNG +#define FBV_SUPPORT_BMP \ No newline at end of file diff --git a/projects/recalbox-fbv/fb_display.c b/projects/recalbox-fbv/fb_display.c new file mode 100644 index 0000000000000000000000000000000000000000..885b5b36599424747613842e99577c8572fa0954 --- /dev/null +++ b/projects/recalbox-fbv/fb_display.c @@ -0,0 +1,398 @@ +/*` + fbv -- simple image viewer for the linux framebuffer + Copyright (C) 2000 Tomasz Sterna + Copyright (C) 2003 Mateusz Golicz + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "config.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, + int clear_before); + +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, int clear_before) +{ + struct fb_var_screeninfo var; + struct fb_fix_screeninfo fix; + int bp = 0; + + /* get the framebuffer device handle */ + int fh = openFB(NULL); + + /* read current video mode */ + getVarScreenInfo(fh, &var); + getFixScreenInfo(fh, &fix); + + int x_stride = (int)((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 - (int)var.yres) y_pan = 0; + /* correct offset */ + if (x_offs + x_size > x_stride) x_offs = 0; + if (y_offs + y_size > (int)var.yres) y_offs = 0; + + /* blit buffer 2 fb */ + unsigned short* 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, clear_before); + #endif + free(fbbuff); + + /* close device */ + closeFB(fh); +} + +void getCurrentRes(int* x, int* y) +{ + struct fb_var_screeninfo var; + int fh = openFB(NULL); + getVarScreenInfo(fh, &var); + *x = var.xres; + *y = var.yres; + closeFB(fh); +} + +int openFB(const char* name) +{ + if (name == NULL) + { + char* dev = getenv("FRAMEBUFFER"); + if (dev) name = dev; + else name = DEFAULT_FRAMEBUFFER; + } + + int fh = open(name, O_RDWR); + if (fh == -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 r = 8, g = 8, b = 4; + + map->red = red; + map->green = green; + map->blue = blue; + + int rs = 256 / (r - 1); + int gs = 256 / (g - 1); + int bs = 256 / (b - 1); + + for (int 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 clear_before) +{ + int xc = (int)((pic_xs > scr_xs) ? scr_xs : pic_xs); + int yc = (int)((pic_ys > scr_ys) ? scr_ys : pic_ys); + + unsigned char* fb = (unsigned char*)malloc(scr_xs * scr_ys * cpp); + if (clear_before != 0) memset(fb, 0, scr_xs * scr_ys * cpp); + else + { + read(fh, fb, scr_xs * scr_ys * cpp); + lseek(fh, 0, SEEK_SET); + } + + if (fb == NULL /*MAP_FAILED*/) + { + perror("mmap"); + return; + } + + if (cpp == 1) + { + get8map(fh, &map_back); + set332map(fh); + } + + unsigned char* fbptr = fb + (yoffs * scr_xs + xoffs) * cpp; + unsigned char* imptr = fbbuff + (yp * pic_xs + xp) * cpp; + + if (alpha) + { + unsigned char* alphaptr = alpha + (yp * pic_xs + xp); + + for (int i = 0; i < yc; i++, fbptr += scr_xs * cpp, imptr += pic_xs * cpp, alphaptr += pic_xs) + { + for (int x = 0; x < xc; x++) + { + int from = -1, to = -1; + for (int 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 (int 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); + + if (write(fh, fb, scr_xs * scr_ys * cpp) != scr_xs * scr_ys * cpp) + perror("write"); + lseek(fh, 0, SEEK_SET); + free(fb); +} + +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 make15color_bgr(unsigned char r, unsigned char g, unsigned char b) +{ + return ((((b >> 3) & 31) << 10) | (((g >> 3) & 31) << 5) | ((r >> 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) +{ + void* fbbuff = NULL; + u_int8_t* c_fbbuff = NULL; + u_int16_t* s_fbbuff = NULL; + u_int32_t* i_fbbuff = NULL; + + switch (bpp) + { + case 8: + { + *cpp = 1; + c_fbbuff = (unsigned char*) malloc(count * sizeof(unsigned char)); + for (unsigned long 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: + { + struct fb_var_screeninfo var; + getVarScreenInfo(fh, &var); + int is_bgr555 = (var.red.offset == 0 && var.green.offset == 5 && var.blue.offset == 10) ? 1 : 0; + *cpp = 2; + s_fbbuff = (unsigned short*) malloc(count * sizeof(unsigned short)); + if (is_bgr555 != 0) + for (unsigned long i = 0; i < count; i++) + s_fbbuff[i] = make15color_bgr(rgbbuff[i * 3], rgbbuff[i * 3 + 1], rgbbuff[i * 3 + 2]); + else + for (unsigned long 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: + { + struct fb_var_screeninfo var; + getVarScreenInfo(fh, &var); + int is_bgr555 = (var.red.offset == 0 && var.green.offset == 5 && var.blue.offset == 10) ? 1 : 0; + *cpp = 2; + s_fbbuff = (unsigned short*) malloc(count * sizeof(unsigned short)); + if (is_bgr555 != 0) + for (unsigned long i = 0; i < count; i++) + s_fbbuff[i] = make15color_bgr(rgbbuff[i * 3], rgbbuff[i * 3 + 1], rgbbuff[i * 3 + 2]); + else + for (unsigned long 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: + { + *cpp = 3; + c_fbbuff = (unsigned char *) malloc(count * 3 * sizeof(unsigned char)); + for(unsigned long i = 0; i < (3 * count); i += 3) + { + /* Big endian framebuffer. */ + c_fbbuff[i] = rgbbuff[i+2]; + c_fbbuff[i+1] = rgbbuff[i+1]; + c_fbbuff[i+2] = rgbbuff[i]; + } + fbbuff = (void *) c_fbbuff; + break; + } + case 32: + { + *cpp = 4; + i_fbbuff = (unsigned int*) malloc(count * sizeof(unsigned int)); + for (unsigned long 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/projects/recalbox-fbv/fbv.h b/projects/recalbox-fbv/fbv.h new file mode 100644 index 0000000000000000000000000000000000000000..694a57dbd22807910fb1c6baf1d2f3d501cdb72e --- /dev/null +++ b/projects/recalbox-fbv/fbv.h @@ -0,0 +1,61 @@ +/* + fbv -- simple image viewer for the linux framebuffer + Copyright (C) 2000, 2001, 2003 Mateusz Golicz + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#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, int clear_before); +void getCurrentRes(int *x, int *y); + +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); + +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); + +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); + +int fh_gif_id(char *name); +int fh_gif_load(char *name,unsigned char *buffer, unsigned char **alpha, int x,int y); +int fh_gif_getsize(char *name,int *x,int *y); + +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); diff --git a/projects/recalbox-fbv/gif.c b/projects/recalbox-fbv/gif.c new file mode 100644 index 0000000000000000000000000000000000000000..1eed1ac4f454b63ee4ad6d6185175005125574e7 --- /dev/null +++ b/projects/recalbox-fbv/gif.c @@ -0,0 +1,226 @@ +/* + fbv -- simple image viewer for the linux framebuffer + Copyright (C) 2000, 2001, 2003 Mateusz Golicz + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ +#include "config.h" + +#ifdef FBV_SUPPORT_GIF + + #include "fbv.h" + #include + //#include + //#include + #include + //#include + #include + //#include + #include + #include + #include + + #define min(a, b) ((a) < (b) ? (a) : (b)) + #define gflush do { return(FH_ERROR_FILE); } while(false) + #define grflush do { DGifCloseFile(gft, NULL); return(FH_ERROR_FORMAT); } while(false) + #define mgrflush do { free(lb); free(slb); DGifCloseFile(gft, NULL); return(FH_ERROR_FORMAT); } while(false) + //#define agflush return(FH_ERROR_FORMAT); + //#define agrflush { DGifCloseFile(gft); return(FH_ERROR_FORMAT); } + + +int fh_gif_id(char* name) +{ + char id[4]; + int fd = open(name, O_RDONLY); + if (fd == -1) return (0); + read(fd, id, 4); + close(fd); + if (id[0] == 'G' && id[1] == 'I' && id[2] == 'F') return (1); + return (0); +} + +void +m_rend_gif_decodecolormap(const unsigned char* cmb, unsigned char* rgbb, ColorMapObject* cm, int s, int l, int transparency) +{ + (void)s; + (void)transparency; + for (int i = 0; i < l; i++) + { + GifColorType* cmentry = &cm->Colors[cmb[i]]; + *(rgbb++) = cmentry->Red; + *(rgbb++) = cmentry->Green; + *(rgbb++) = cmentry->Blue; + } +} + + +/* Thanks goes here to Mauro Meneghin, who implemented interlaced GIF files support */ + +int fh_gif_load(char* name, unsigned char* buffer, unsigned char** alpha, int x, int y) +{ + (void)x; + (void)y; + int in_nextrow[4] = { 8, 8, 4, 2 }; //interlaced jump to the row current+in_nextrow + int in_beginrow[4] = { 0, 4, 2, 1 }; //begin pass j from that row number + int transparency = -1; //-1 means not transparency present + int ibxs = 0; + GifByteType* extension = NULL; + int extcode = 0; + + GifFileType* gft = DGifOpenFileName(name, NULL); + if (gft == NULL) + { + printf("err5\n"); + gflush; + } ////////// + GifRecordType rt = UNDEFINED_RECORD_TYPE; + do + { + if (DGifGetRecordType(gft, &rt) == GIF_ERROR) + grflush; + switch (rt) + { + case IMAGE_DESC_RECORD_TYPE: + if (DGifGetImageDesc(gft) == GIF_ERROR) + grflush; + int px = gft->Image.Width; + int py = gft->Image.Height; + char* lb = (char*) malloc(px * 3); + char* slb = (char*) malloc(px); + // printf("reading...\n"); + if (lb != NULL && slb != NULL) + { + unsigned char* alphaptr = NULL; + + ColorMapObject* cmap = (gft->Image.ColorMap ? gft->Image.ColorMap : gft->SColorMap); + int cmaps = cmap->ColorCount; + + ibxs = ibxs * 3; + char* fbptr = (char*) buffer; + + if (transparency != -1) + { + alphaptr = malloc(px * py); + *alpha = alphaptr; + } + + if (!(gft->Image.Interlace)) + { + for (int i = 0; i < py; i++, fbptr += px * 3) + { + if (DGifGetLine(gft, (GifPixelType*) slb, px) == GIF_ERROR) + mgrflush; + m_rend_gif_decodecolormap((unsigned char*) slb, (unsigned char*) lb, cmap, cmaps, px, transparency); + memcpy(fbptr, lb, px * 3); + if (alphaptr) + for (int j = 0; j < px; j++) *(alphaptr++) = (((unsigned char*) slb)[j] == transparency) ? 0x00 : 0xff; + } + } + else + { + unsigned char* aptr = NULL; + + for (int j = 0; j < 4; j++) + { + if (alphaptr) + aptr = alphaptr + (in_beginrow[j] * px); + + fbptr = (char*) buffer + (in_beginrow[j] * px * 3); + + for (int i = in_beginrow[j]; + i < py; i += in_nextrow[j], fbptr += px * 3 * in_nextrow[j], aptr += px * in_nextrow[j]) + { + if (DGifGetLine(gft, (GifPixelType*) slb, px) == GIF_ERROR) + mgrflush; ///////////// + m_rend_gif_decodecolormap((unsigned char*) slb, (unsigned char*) lb, cmap, cmaps, px, transparency); + memcpy(fbptr, lb, px * 3); + if (alphaptr) + for (int k = 0; k < px; k++) aptr[k] = (((unsigned char*) slb)[k] == transparency) ? 0x00 : 0xff; + } + } + } + } + if (lb) free(lb); + if (slb) free(slb); + break; + case EXTENSION_RECORD_TYPE: + if (DGifGetExtension(gft, &extcode, &extension) == GIF_ERROR) + grflush; ////////// + if (extcode == 0xf9) //look image transparency in graph ctr extension + { + if (extension[1] & 1) + { + transparency = extension[4]; + + } + // tran_off=(int)*extension; + // transparency=(int)*(extension+tran_off); + // printf("transparency: %d\n", transparency); + } + while (extension != NULL) + { + if (DGifGetExtensionNext(gft, &extension) == GIF_ERROR) + grflush; + } + break; + default: break; + } + } while (rt != TERMINATE_RECORD_TYPE); + DGifCloseFile(gft, NULL); + return (FH_ERROR_OK); +} + + +int fh_gif_getsize(char* name, int* x, int* y) +{ + GifByteType* extension = NULL; + int extcode = 0; + + GifFileType* gft = DGifOpenFileName(name, NULL); + if (gft == NULL) gflush; + GifRecordType rt = UNDEFINED_RECORD_TYPE; + do + { + if (DGifGetRecordType(gft, &rt) == GIF_ERROR) + grflush; + switch (rt) + { + case IMAGE_DESC_RECORD_TYPE: + + if (DGifGetImageDesc(gft) == GIF_ERROR) + grflush; + int px = gft->Image.Width; + int py = gft->Image.Height; + *x = px; + *y = py; + DGifCloseFile(gft, NULL); + return (FH_ERROR_OK); + case EXTENSION_RECORD_TYPE: + if (DGifGetExtension(gft, &extcode, &extension) == GIF_ERROR) + grflush; + while (extension != NULL) + { + if (DGifGetExtensionNext(gft, &extension) == GIF_ERROR) + grflush; + } + break; + default: break; + } + } while (rt != TERMINATE_RECORD_TYPE); + DGifCloseFile(gft, NULL); + return (FH_ERROR_FORMAT); +} + +#endif diff --git a/projects/recalbox-fbv/jpeg.c b/projects/recalbox-fbv/jpeg.c new file mode 100644 index 0000000000000000000000000000000000000000..4b253af7d5840ee74697ab648772bd8e284d64b3 --- /dev/null +++ b/projects/recalbox-fbv/jpeg.c @@ -0,0 +1,144 @@ +/* + fbv -- simple image viewer for the linux framebuffer + Copyright (C) 2000, 2001, 2003 Mateusz Golicz + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ +#include "config.h" + +#ifdef FBV_SUPPORT_JPEG + + #include +//#include +//#include + #include + #include + #include + #include + #include + #include "fbv.h" + +struct r_jpeg_error_mgr +{ + struct jpeg_error_mgr pub; + jmp_buf envbuffer; +}; + + +int fh_jpeg_id(char* name) +{ + unsigned char id[10]; + int 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 = (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) +{ + (void)alpha; + (void)x; + (void)y; + struct jpeg_decompress_struct cinfo; + struct r_jpeg_error_mgr emgr; + + struct jpeg_decompress_struct* ciptr = &cinfo; + FILE* fh = NULL; + 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); + + int px = ciptr->output_width; + //int py = ciptr->output_height; + int c = ciptr->output_components; + + + if (c == 3) + { + JSAMPLE* lb = (*ciptr->mem->alloc_small)((j_common_ptr) ciptr, JPOOL_PERMANENT, c * px); + unsigned char* 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 r_jpeg_error_mgr emgr; + + struct jpeg_decompress_struct* ciptr = &cinfo; + FILE* fh = NULL; + 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); + int px = ciptr->output_width; + int py = ciptr->output_height; + //int c = ciptr->output_components; + *x = px; + *y = py; + jpeg_destroy_decompress(ciptr); + fclose(fh); + return (FH_ERROR_OK); +} + +#endif diff --git a/projects/recalbox-fbv/main.c b/projects/recalbox-fbv/main.c new file mode 100644 index 0000000000000000000000000000000000000000..c685b874fb3285cfb991e2ef85a0759e4afd6daa --- /dev/null +++ b/projects/recalbox-fbv/main.c @@ -0,0 +1,345 @@ +/* + fbv -- simple image viewer for the linux framebuffer + Copyright (C) 2000, 2001, 2003, 2004 Mateusz 'mteg' Golicz + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include +#include +#include +#include +#include "config.h" +#include "fbv.h" + +static int opt_clear = 1, opt_alpha = 0, opt_image_info = 1, opt_stretch = 0, opt_delay = 0, opt_enlarge = 0, opt_ignore_aspect = 0, opt_loop = 0; + +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 = NULL, * 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 = NULL, * 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; + } +} + +static int always_false() +{ + return 0; +} + +int show_image(char* filename) +{ + int (* load)(char*, unsigned char*, unsigned char**, int, int) = NULL; + + unsigned char* image = NULL; + unsigned char* alpha = NULL; + + int x_size = 0, y_size = 0, screen_width = 0, screen_height = 0; + int ret = 1; + + int transform_stretch = opt_stretch, transform_enlarge = opt_enlarge, + transform_cal = (opt_stretch == 2), transform_iaspect = opt_ignore_aspect; + + struct image i; + + if (always_false()) + { + } +#ifdef FBV_SUPPORT_GIF + else if (fh_gif_id(filename)) + { + if (fh_gif_getsize(filename, &x_size, &y_size) == FH_ERROR_OK) + load = fh_gif_load; + } +#endif +#ifdef FBV_SUPPORT_PNG + else if (fh_png_id(filename)) + { + if (fh_png_getsize(filename, &x_size, &y_size) == FH_ERROR_OK) + load = fh_png_load; + } +#endif +#ifdef FBV_SUPPORT_JPEG + else if (fh_jpeg_id(filename)) + { + if (fh_jpeg_getsize(filename, &x_size, &y_size) == FH_ERROR_OK) + load = fh_jpeg_load; + } +#endif +#ifdef FBV_SUPPORT_BMP + else if (fh_bmp_id(filename)) + { + if (fh_bmp_getsize(filename, &x_size, &y_size) == FH_ERROR_OK) + load = fh_bmp_load; + } +#endif + else + { + fprintf(stderr, "%s: Unable to access file or file format unknown.\n", filename); + return (1); + } + + 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; + i.width = x_size; + i.height = y_size; + i.rgb = image; + i.alpha = alpha; + + 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); + + if (opt_image_info) + printf("fbv - The Framebuffer Viewer\n%s\n%d x %d\n", filename, x_size, y_size); + + int x_offs = (i.width < screen_width) ? (screen_width - i.width) / 2 : 0; + int y_offs = (i.height < screen_height) ? (screen_height - i.height) / 2 : 0; + + fb_display(i.rgb, i.alpha, i.width, i.height, 0, 0, x_offs, y_offs, opt_clear); + opt_clear = 0; // Clear only once + + if (opt_delay != 0) usleep(opt_delay * 100000); + + 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 | -s : Slideshow, 'delay' is the slideshow delay in tenths of seconds.\n\n" + " --loop | -l : Loop after displaying all images\n" + "Copyright (C) 2000 - 2004 Mateusz Golicz, Tomasz Sterna.\n", name); +} + +void sighandler(int s) +{ + _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'}, + {"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'}, + {"loop", no_argument, 0, 'l'}, + {0, 0, 0, 0}}; + + int c = argc; + if (c < 2) + { + help(argv[0]); + fprintf(stderr, "Error: Required argument missing.\n"); + return (1); + } + + while((c = getopt_long_only(argc, argv, "hcaifks:erl", long_options, NULL)) != EOF) + { + switch (c) + { + case 'a': opt_alpha = 1; + break; + case 'c': opt_clear = 0; + break; + case 's': opt_delay = (int) strtol(optarg, NULL, 10); + 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; + case 'l': opt_loop = 1; + break; + default: 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); + + do + { + for (int i = optind; argv[i];) + { + int r = show_image(argv[i]); + + if (!r) break; + + i += r; + if (i < optind) + i = optind; + } + } while (opt_loop != 0); + + return (0); +} diff --git a/projects/recalbox-fbv/png.c b/projects/recalbox-fbv/png.c new file mode 100644 index 0000000000000000000000000000000000000000..5be110d66c9864285afe2ffab6f4e7d9c9722e7f --- /dev/null +++ b/projects/recalbox-fbv/png.c @@ -0,0 +1,175 @@ +/* + fbv -- simple image viewer for the linux framebuffer + Copyright (C) 2000, 2001, 2003 Mateusz Golicz + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "config.h" + +#ifdef FBV_SUPPORT_PNG + + #include + #include "fbv.h" + #include + #include + #include + #include + + //#define PNG_BYTES_TO_CHECK 4 + #ifndef min + #define min(x,y) ((x) < (y) ? (x) : (y)) + #endif + +int fh_png_id(char* name) +{ + char id[4]; + int 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) +{ + (void)x; + (void)y; + png_bytep rptr[2]; + FILE* fh = NULL; + + if (!(fh = fopen(name, "rb"))) return (FH_ERROR_FILE); + + png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + if (png_ptr == NULL) return (FH_ERROR_FORMAT); + png_infop 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_jmpbuf(png_ptr))) + { + 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_uint_32 width = 0, height = 0; + int bit_depth = 0, color_type = 0, interlace_type = 0; + 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); + int trans = 0; + 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); + int 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 = NULL; + + unsigned char* rp = (unsigned char*) malloc(width * 4); + rptr[0] = (png_bytep) rp; + + *alpha = alpha_buffer; + + for (int pass = 0; pass < number_passes; pass++) + { + unsigned char* fbptr = buffer; + aptr = alpha_buffer; + + for (int i = 0; i < (int)height; i++) + { + unsigned char* trp = rp; + + png_read_rows(png_ptr, rptr, NULL, 1); + + for (int n = 0; n < (int)width; n++, fbptr += 3, trp += 4) + { + memcpy(fbptr, trp, 3); + *(aptr++) = trp[3]; + } + } + } + free(rp); + } + else + { + for (int pass = 0; pass < number_passes; pass++) + { + unsigned char* fbptr = buffer; + for (int i = 0; i < (int)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) +{ + FILE* fh = NULL; + if (!(fh = fopen(name, "rb"))) return (FH_ERROR_FILE); + + png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + if (png_ptr == NULL) return (FH_ERROR_FORMAT); + png_infop 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); + } + if (setjmp(png_jmpbuf(png_ptr))) + { + png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp) NULL); + fclose(fh); + return (FH_ERROR_FORMAT); + } + + png_init_io(png_ptr, fh); + png_read_info(png_ptr, info_ptr); + png_uint_32 width = 0, height = 0; + int bit_depth = 0, color_type = 0, interlace_type = 0; + 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 diff --git a/projects/recalbox-fbv/transforms.c b/projects/recalbox-fbv/transforms.c new file mode 100644 index 0000000000000000000000000000000000000000..06bc6679cdae703ed0406179dd774c845ff14025 --- /dev/null +++ b/projects/recalbox-fbv/transforms.c @@ -0,0 +1,116 @@ +/* + fbv -- simple image viewer for the linux framebuffer + Copyright (C) 2000, 2001, 2003 Mateusz Golicz + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include + +unsigned char* simple_resize(unsigned char* orgin, int ox, int oy, int dx, int dy) +{ + unsigned char* cr = (unsigned char*) malloc(dx * dy * 3); + assert(cr); + unsigned char* l = cr; + + // Get 16:16 floating point increment + double xStep = (double)ox / (double)dx; + int pfXStep = (int)(xStep * 65536.0); + + for (int j = 0; j < dy; j++, l += dx * 3) + { + unsigned char* p = orgin + (j * oy / dy * ox * 3); + unsigned int ip = 0; + unsigned int* li = ((unsigned int*)l); + for (int i = dx >> 2; --i >= 0; ) + { + unsigned int pip = (ip >> 16) * 3; ip += pfXStep; + unsigned p1 = p[pip] | (p[pip + 1] << 8) | (p[pip + 2] << 16); + pip = (ip >> 16) * 3; ip += pfXStep; + p1 |= (p[pip] << 24); + unsigned p2 = p[pip + 1] | (p[pip + 2] << 8); + pip = (ip >> 16) * 3; ip += pfXStep; + p2 |= (p[pip] << 16) | (p[pip + 1] << 24); + unsigned p3 = p[pip + 2]; + pip = (ip >> 16) * 3; ip += pfXStep; + p3 |= (p[pip] << 8) | (p[pip + 1] << 16) | (p[pip + 2] << 24); + li[0] = p1; + li[1] = p2; + li[2] = p3; + li += 3; + } + unsigned char* lb = ((unsigned char*)li); + for (int i = dx & 3; --i >= 0; ip += pfXStep) + { + unsigned int pip = (ip >> 16) * 3; + lb[0] = p[pip]; + lb[1] = p[pip + 1]; + lb[2] = p[pip + 2]; + lb += 3; + } + } + return (cr); +} + +unsigned char* alpha_resize(unsigned char* alpha, int ox, int oy, int dx, int dy) +{ + unsigned char* cr = (unsigned char*) malloc(dx * dy); + unsigned char* l = cr; + + for (int j = 0; j < dy; j++, l += dx) + { + unsigned char* p = alpha + (j * oy / dy * ox); + for (int 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 = (unsigned char*) malloc(dx * dy * 3); + assert(cr); + unsigned char* p = cr; + + for (int j = 0; j < dy; j++) + { + for (int i = 0; i < dx; i++, p += 3) + { + int xa = i * ox / dx; + int ya = j * oy / dy; + int xb = (i + 1) * ox / dx; + if (xb >= ox) xb = ox - 1; + int yb = (j + 1) * oy / dy; + if (yb >= oy) yb = oy - 1; + int r = 0, g = 0, b =0, sq = 0; + for (int l = ya; l <= yb; l++) + { + unsigned char* q = orgin + ((l * ox + xa) * 3); + for (int 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); +}