From 6e3da841be4f0c7eda5d0daec19fc4919bd56d9f Mon Sep 17 00:00:00 2001 From: Marcin Bukat Date: Sun, 9 Jan 2011 13:22:54 +0000 Subject: Rework ppmviewer to fit our shiny new imageviewer framework. FS#11818 by me. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@29012 a1c6a512-1295-4272-9138-f99709370657 --- apps/plugins/CATEGORIES | 2 +- apps/plugins/SOURCES | 1 - apps/plugins/imageviewer/SUBDIRS | 3 + apps/plugins/imageviewer/image_decoder.c | 6 + apps/plugins/imageviewer/image_decoder.h | 3 + apps/plugins/imageviewer/ppm/SOURCES | 2 + apps/plugins/imageviewer/ppm/ppm.c | 233 +++++++++++++++++++ apps/plugins/imageviewer/ppm/ppm.make | 29 +++ apps/plugins/imageviewer/ppm/ppm_decoder.c | 250 ++++++++++++++++++++ apps/plugins/imageviewer/ppm/ppm_decoder.h | 44 ++++ apps/plugins/ppmviewer.c | 355 ----------------------------- apps/plugins/viewers.config | 4 +- 12 files changed, 574 insertions(+), 358 deletions(-) create mode 100644 apps/plugins/imageviewer/ppm/SOURCES create mode 100644 apps/plugins/imageviewer/ppm/ppm.c create mode 100644 apps/plugins/imageviewer/ppm/ppm.make create mode 100644 apps/plugins/imageviewer/ppm/ppm_decoder.c create mode 100644 apps/plugins/imageviewer/ppm/ppm_decoder.h delete mode 100644 apps/plugins/ppmviewer.c diff --git a/apps/plugins/CATEGORIES b/apps/plugins/CATEGORIES index c310a2cdb8..66b6f5e4ab 100644 --- a/apps/plugins/CATEGORIES +++ b/apps/plugins/CATEGORIES @@ -71,7 +71,7 @@ pitch_detector,apps plasma,demos png,viewers pong,games -ppmviewer,viewers +ppm,viewers properties,viewers random_folder_advance_config,apps remote_control,apps diff --git a/apps/plugins/SOURCES b/apps/plugins/SOURCES index 3c4e9e131d..7afd97309f 100644 --- a/apps/plugins/SOURCES +++ b/apps/plugins/SOURCES @@ -182,7 +182,6 @@ plasma.c #ifdef HAVE_LCD_COLOR clix.c -ppmviewer.c codebuster.c #endif diff --git a/apps/plugins/imageviewer/SUBDIRS b/apps/plugins/imageviewer/SUBDIRS index 9d8da7d53b..0f8d953939 100644 --- a/apps/plugins/imageviewer/SUBDIRS +++ b/apps/plugins/imageviewer/SUBDIRS @@ -1,3 +1,6 @@ bmp jpeg png +#ifdef HAVE_LCD_COLOR +ppm +#endif diff --git a/apps/plugins/imageviewer/image_decoder.c b/apps/plugins/imageviewer/image_decoder.c index b4fa27e425..553632e559 100644 --- a/apps/plugins/imageviewer/image_decoder.c +++ b/apps/plugins/imageviewer/image_decoder.c @@ -27,6 +27,9 @@ static const char *decoder_names[MAX_IMAGE_TYPES] = { "bmp", "jpeg", "png", +#ifdef HAVE_LCD_COLOR + "ppm" +#endif }; /* check file type by extention */ @@ -41,6 +44,9 @@ enum image_type get_image_type(const char *name) { ".jpe", IMAGE_JPEG }, { ".jpeg", IMAGE_JPEG }, { ".png", IMAGE_PNG }, +#ifdef HAVE_LCD_COLOR + { ".ppm", IMAGE_PPM }, +#endif }; const char *ext = rb->strrchr(name, '.'); diff --git a/apps/plugins/imageviewer/image_decoder.h b/apps/plugins/imageviewer/image_decoder.h index 93608b1b9a..1ccf9cabf2 100644 --- a/apps/plugins/imageviewer/image_decoder.h +++ b/apps/plugins/imageviewer/image_decoder.h @@ -29,6 +29,9 @@ enum image_type { IMAGE_BMP = 0, IMAGE_JPEG, IMAGE_PNG, +#ifdef HAVE_LCD_COLOR + IMAGE_PPM, +#endif MAX_IMAGE_TYPES }; diff --git a/apps/plugins/imageviewer/ppm/SOURCES b/apps/plugins/imageviewer/ppm/SOURCES new file mode 100644 index 0000000000..492cca3ae2 --- /dev/null +++ b/apps/plugins/imageviewer/ppm/SOURCES @@ -0,0 +1,2 @@ +ppm.c +ppm_decoder.c diff --git a/apps/plugins/imageviewer/ppm/ppm.c b/apps/plugins/imageviewer/ppm/ppm.c new file mode 100644 index 0000000000..100a00ac84 --- /dev/null +++ b/apps/plugins/imageviewer/ppm/ppm.c @@ -0,0 +1,233 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2010 Marcin Bukat + * + * 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 software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#include "plugin.h" +#include "lcd.h" +#include +#include "../imageviewer.h" +#include "ppm_decoder.h" +#include "bmp.h" + +static char print[32]; /* use a common snprintf() buffer */ + +/* decompressed image in the possible sizes (1,2,4,8), wasting the other */ +static unsigned char *disp[9]; +static unsigned char *disp_buf; +static struct ppm_info ppm; + +#if defined(HAVE_LCD_COLOR) +#define resize_bitmap smooth_resize_bitmap +#else +#define resize_bitmap grey_resize_bitmap +#endif + +#if defined(USEGSLIB) && (CONFIG_PLATFORM & PLATFORM_HOSTED) +/* hack: fix error "undefined reference to `_grey_info'". */ +GREY_INFO_STRUCT +#endif /* USEGSLIB */ + +static void draw_image_rect(struct image_info *info, + int x, int y, int width, int height) +{ + unsigned char **pdisp = (unsigned char **)info->data; + +#ifdef HAVE_LCD_COLOR + rb->lcd_bitmap_part((fb_data *)*pdisp, info->x + x, info->y + y, + STRIDE(SCREEN_MAIN, info->width, info->height), + x + MAX(0, (LCD_WIDTH-info->width)/2), + y + MAX(0, (LCD_HEIGHT-info->height)/2), + width, height); +#else + mylcd_ub_gray_bitmap_part(*pdisp, + info->x + x, info->y + y, info->width, + x + MAX(0, (LCD_WIDTH-info->width)/2), + y + MAX(0, (LCD_HEIGHT-info->height)/2), + width, height); +#endif +} + +static int img_mem(int ds) +{ + +#ifdef USEGSLIB + return (ppm.x/ds) * (ppm.y/ds); +#else + return (ppm.x/ds) * (ppm.y/ds) * FB_DATA_SZ; +#endif +} + +static int load_image(char *filename, struct image_info *info, + unsigned char *buf, ssize_t *buf_size) +{ + int fd; + int rc = PLUGIN_OK; + long time = 0; /* measured ticks */ + int w, h; /* used to center output */ + + unsigned char *memory, *memory_max; + size_t memory_size, file_size; + + /* cleanup */ + memset(&disp, 0, sizeof(disp)); + + /* align buffer */ + memory = (unsigned char *)((intptr_t)(buf + 3) & ~3); + memory_max = (unsigned char *)((intptr_t)(memory + *buf_size) & ~3); + memory_size = memory_max - memory; + + fd = rb->open(filename, O_RDONLY); + if (fd < 0) + { + rb->splashf(HZ, "err opening %s: %d", filename, fd); + return PLUGIN_ERROR; + } + + file_size = rb->filesize(fd); + DEBUGF("reading file '%s'\n", filename); + + if (!iv->running_slideshow) + { + rb->lcd_puts(0, 0, rb->strrchr(filename,'/')+1); + rb->lcd_update(); + } + + if (!iv->running_slideshow) + { + rb->lcd_putsf(0, 1, "loading %zu bytes", file_size); + rb->lcd_update(); + } + + /* init decoder struct */ + ppm.buf = memory; + ppm.buf_size = memory_size; + + /* the actual decoding */ + time = *rb->current_tick; +#ifdef HAVE_ADJUSTABLE_CPU_FREQ + rb->cpu_boost(true); + rc = read_ppm(fd, &ppm); + rb->cpu_boost(false); +#else + rc = read_ppm(fd, &ppm); +#endif /*HAVE_ADJUSTABLE_CPU_FREQ*/ + time = *rb->current_tick - time; + + /* close file descriptor */ + rb->close(fd); + + /* check return value from decoder */ + if ( rc == PLUGIN_ERROR ) + { + rb->splashf(HZ, "ppm decoder error"); + return PLUGIN_ERROR; + } + + if (!iv->running_slideshow) + { + rb->snprintf(print, sizeof(print), " %ld.%02ld sec ", time/HZ, time%HZ); + rb->lcd_getstringsize(print, &w, &h); /* centered in progress bar */ + rb->lcd_putsxy((LCD_WIDTH - w)/2, LCD_HEIGHT - h, print); + rb->lcd_update(); + } + + info->x_size = ppm.x; + info->y_size = ppm.y; + + ppm.native_img_size = (ppm.native_img_size + 3) & ~3; + disp_buf = buf + ppm.native_img_size; + *buf_size = memory_max - disp_buf; + + return PLUGIN_OK; +} + +static int get_image(struct image_info *info, int ds) +{ + unsigned char **p_disp = &disp[ds]; /* short cut */ + struct ppm_info *p_ppm = &ppm; + + info->width = ppm.x / ds; + info->height = ppm.y / ds; + info->data = p_disp; + + if (*p_disp != NULL) + { + /* we still have it */ + return PLUGIN_OK; + } + + /* assign image buffer */ + if (ds > 1) + { + if (!iv->running_slideshow) + { + rb->lcd_putsf(0, 3, "resizing %d*%d", info->width, info->height); + rb->lcd_update(); + } + + struct bitmap bmp_src, bmp_dst; + int size = img_mem(ds); + + if (disp_buf + size >= p_ppm->buf + p_ppm->buf_size) + { + /* have to discard the current */ + int i; + for (i=1; i<=8; i++) + disp[i] = NULL; /* invalidate all bitmaps */ + + /* start again from the beginning of the buffer */ + disp_buf = p_ppm->buf + p_ppm->native_img_size; + } + + *p_disp = disp_buf; + disp_buf += size; + + bmp_src.width = ppm.x; + bmp_src.height = ppm.y; + bmp_src.data = ppm.buf; + + bmp_dst.width = info->width; + bmp_dst.height = info->height; + bmp_dst.data = *p_disp; +#ifdef HAVE_ADJUSTABLE_CPU_FREQ + rb->cpu_boost(true); + resize_bitmap(&bmp_src, &bmp_dst); + rb->cpu_boost(false); +#else + resize_bitmap(&bmp_src, &bmp_dst); +#endif /*HAVE_ADJUSTABLE_CPU_FREQ*/ + } + else + { + *p_disp = p_ppm->buf; + } + + return PLUGIN_OK; +} + +const struct image_decoder image_decoder = { + true, + img_mem, + load_image, + get_image, + draw_image_rect, +}; + +IMGDEC_HEADER diff --git a/apps/plugins/imageviewer/ppm/ppm.make b/apps/plugins/imageviewer/ppm/ppm.make new file mode 100644 index 0000000000..e77f282723 --- /dev/null +++ b/apps/plugins/imageviewer/ppm/ppm.make @@ -0,0 +1,29 @@ +# __________ __ ___. +# Open \______ \ ____ ____ | | _\_ |__ _______ ___ +# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / +# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < +# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ +# \/ \/ \/ \/ \/ +# $Id$ +# + +PPMSRCDIR := $(IMGVSRCDIR)/ppm +PPMBUILDDIR := $(IMGVBUILDDIR)/ppm + +PPM_SRC := $(call preprocess, $(PPMSRCDIR)/SOURCES) +PPM_OBJ := $(call c2obj, $(PPM_SRC)) + +OTHER_SRC += $(PPM_SRC) + +ROCKS += $(PPMBUILDDIR)/ppm.ovl + +$(PPMBUILDDIR)/ppm.refmap: $(PPM_OBJ) +$(PPMBUILDDIR)/ppm.link: $(PPM_OBJ) $(PPMBUILDDIR)/ppm.refmap +$(PPMBUILDDIR)/ppm.ovl: $(PPM_OBJ) + +PPMFLAGS = $(IMGDECFLAGS) -Os + +# Compile PPM plugin with extra flags (adapted from ZXBox) +$(PPMBUILDDIR)/%.o: $(PPMSRCDIR)/%.c $(PPMSRCDIR)/ppm.make + $(SILENT)mkdir -p $(dir $@) + $(call PRINTS,CC $(subst $(ROOTDIR)/,,$<))$(CC) -I$(dir $<) $(PPMFLAGS) -c $< -o $@ diff --git a/apps/plugins/imageviewer/ppm/ppm_decoder.c b/apps/plugins/imageviewer/ppm/ppm_decoder.c new file mode 100644 index 0000000000..44c4f9232e --- /dev/null +++ b/apps/plugins/imageviewer/ppm/ppm_decoder.c @@ -0,0 +1,250 @@ +/***************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// __ \_/ ___\| |/ /| __ \ / __ \ \/ / + * Jukebox | | ( (__) ) \___| ( | \_\ ( (__) ) ( + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2008 Alexander Papst + * + * 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 software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#include "plugin.h" +#include "lib/pluginlib_bmp.h" +#include "ppm_decoder.h" + +static int ppm_read_magic_number(int fd) +{ + char i1, i2; + if(!rb->read(fd, &i1, 1) || !rb->read(fd, &i2, 1)) + { + ppm_error( "Error reading magic number from ppm image stream. "\ + "Most often, this means your input file is empty." ); + return PLUGIN_ERROR; + } + return i1 * 256 + i2; +} + +static char ppm_getc(int fd) +{ + char ch; + + if (!rb->read(fd, &ch, 1)) { + ppm_error("EOF. Read error reading a byte"); + return PLUGIN_ERROR; + } + + if (ch == '#') { + do { + if (!rb->read(fd, &ch, 1)) { + ppm_error("EOF. Read error reading a byte"); + return PLUGIN_ERROR; + } + } while (ch != '\n' && ch != '\r'); + } + return ch; +} + +static int ppm_getuint(int fd) +{ + char ch; + int i; + int digitVal; + + do { + ch = ppm_getc(fd); + } while (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r'); + + if (ch < '0' || ch > '9') { + ppm_error("Junk (%c) in file where an integer should be.", ch); + return PLUGIN_ERROR; + } + + i = 0; + + do { + digitVal = ch - '0'; + + if (i > INT_MAX/10 - digitVal) { + ppm_error("ASCII decimal integer in file is "\ + "too large to be processed."); + return PLUGIN_ERROR; + } + + i = i * 10 + digitVal; + ch = ppm_getc(fd); + + } while (ch >= '0' && ch <= '9'); + + return i; +} + +static int ppm_getrawbyte(int fd) +{ + unsigned char by; + + if (!rb->read(fd, &by, 1)) { + ppm_error("EOF. Read error while reading a one-byte sample."); + return PLUGIN_ERROR; + } + + return (int)by; +} + +static int ppm_getrawsample(int fd, int const maxval) +{ + if (maxval < 256) { + /* The sample is just one byte. Read it. */ + return(ppm_getrawbyte(fd)); + } else { + /* The sample is two bytes. Read both. */ + unsigned char byte_pair[2]; + + if (!rb->read(fd, byte_pair, 2)) { + ppm_error("EOF. Read error while reading a long sample."); + return PLUGIN_ERROR; + } + return((byte_pair[0]<<8) | byte_pair[1]); + } +} + +/* Read from the file header dimensions as well as max + * int value used + */ +static int read_ppm_init_rest(int fd, struct ppm_info *ppm) +{ + /* Read size. */ + ppm->x = ppm_getuint(fd); + ppm->y = ppm_getuint(fd); + +#ifdef HAVE_LCD_COLOR + ppm->native_img_size = ppm->x * ppm->y * FB_DATA_SZ; +#endif + + if (ppm->native_img_size > ppm->buf_size) { + ppm_error("Imagesize (%ld pixels) is too large. "\ + "The maximum allowed is %ld.", + (long)ppm->native_img_size, + (long)ppm->buf_size); + return PLUGIN_ERROR; + } + + /* Read maxval. */ + ppm->maxval = ppm_getuint(fd); + + if (ppm->maxval > PPM_OVERALLMAXVAL) { + ppm_error("maxval of input image (%u) is too large. "\ + "The maximum allowed by the PPM is %u.", + ppm->maxval, PPM_OVERALLMAXVAL); + return PLUGIN_ERROR; + } + if (ppm->maxval == 0) { + ppm_error("maxval of input image is zero."); + return PLUGIN_ERROR; + } + return 1; +} + +static void read_ppm_init(int fd, struct ppm_info *ppm) +{ + /* Check magic number. */ + ppm->format = ppm_read_magic_number( fd ); + + if (ppm->format == PLUGIN_ERROR) return; + switch (ppm->format) { + case PPM_FORMAT: + case RPPM_FORMAT: + if(read_ppm_init_rest(fd, ppm) == PLUGIN_ERROR) { + ppm->format = PLUGIN_ERROR; + } + break; + + default: + ppm_error( "Bad magic number - not a ppm or rppm file." ); + ppm->format = PLUGIN_ERROR; + } +} + +#if defined(LCD_STRIDEFORMAT) && LCD_STRIDEFORMAT == VERTICAL_STRIDE +#define BUFADDR(x, y, width, height) ( ppm->buf + (height*(x) + (y))*FB_DATA_SZ) +#else +#define BUFADDR(x, y, width, height) ( ppm->buf + (width*(y) + (x))*FB_DATA_SZ) +#endif + +static int read_ppm_row(int fd, struct ppm_info *ppm, int row) +{ + + int col; + int r, g, b; + switch (ppm->format) { + case PPM_FORMAT: + for (col = 0; col < ppm->x; ++col) { + r = ppm_getuint(fd); + g = ppm_getuint(fd); + b = ppm_getuint(fd); + + if (r == PLUGIN_ERROR || g == PLUGIN_ERROR || + b == PLUGIN_ERROR) + { + return PLUGIN_ERROR; + } + *(fb_data *)BUFADDR(col, row, ppm->x, ppm->y) = LCD_RGBPACK( + (255 * r)/ppm->maxval, + (255 * g)/ppm->maxval, + (255 * b)/ppm->maxval); + } + break; + + case RPPM_FORMAT: + for (col = 0; col < ppm->x; ++col) { + r = ppm_getrawsample(fd, ppm->maxval); + g = ppm_getrawsample(fd, ppm->maxval); + b = ppm_getrawsample(fd, ppm->maxval); + + if (r == PLUGIN_ERROR || g == PLUGIN_ERROR || + b == PLUGIN_ERROR) + { + return PLUGIN_ERROR; + } + *(fb_data *)BUFADDR(col, row, ppm->x, ppm->y) = LCD_RGBPACK( + (255 * r)/ppm->maxval, + (255 * g)/ppm->maxval, + (255 * b)/ppm->maxval); + } + break; + + default: + ppm_error("What?!"); + return PLUGIN_ERROR; + } + return 1; +} + +/* public */ +int read_ppm(int fd, struct ppm_info *ppm) +{ + int row; + + read_ppm_init(fd, ppm); + + if(ppm->format == PLUGIN_ERROR) { + return PLUGIN_ERROR; + } + + for (row = 0; row < ppm->y; ++row) { + if( read_ppm_row(fd, ppm, row) == PLUGIN_ERROR) { + return PLUGIN_ERROR; + } + } + return 1; +} diff --git a/apps/plugins/imageviewer/ppm/ppm_decoder.h b/apps/plugins/imageviewer/ppm/ppm_decoder.h new file mode 100644 index 0000000000..edd1bcba55 --- /dev/null +++ b/apps/plugins/imageviewer/ppm/ppm_decoder.h @@ -0,0 +1,44 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2010 Marcin Bukat + * + * 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 software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +/* Magic constants. */ +#define PPM_MAGIC1 'P' +#define PPM_MAGIC2 '3' +#define RPPM_MAGIC2 '6' +#define PPM_FORMAT (PPM_MAGIC1 * 256 + PPM_MAGIC2) +#define RPPM_FORMAT (PPM_MAGIC1 * 256 + RPPM_MAGIC2) + +#define PPM_OVERALLMAXVAL 65535 + +#define ppm_error(...) rb->splashf(HZ*2, __VA_ARGS__ ) + +struct ppm_info { + int x; + int y; + int maxval; + int format; + unsigned char *buf; + size_t buf_size; + unsigned int native_img_size; +}; + +/* public prototype */ +int read_ppm(int fd, struct ppm_info *ppm); diff --git a/apps/plugins/ppmviewer.c b/apps/plugins/ppmviewer.c deleted file mode 100644 index e138692aef..0000000000 --- a/apps/plugins/ppmviewer.c +++ /dev/null @@ -1,355 +0,0 @@ -/***************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// __ \_/ ___\| |/ /| __ \ / __ \ \/ / - * Jukebox | | ( (__) ) \___| ( | \_\ ( (__) ) ( - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Copyright (C) 2008 Alexander Papst - * - * 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 software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ - -#include "plugin.h" -#include "lib/pluginlib_bmp.h" - -/* Magic constants. */ -#define PPM_MAGIC1 'P' -#define PPM_MAGIC2 '3' -#define RPPM_MAGIC2 '6' -#define PPM_FORMAT (PPM_MAGIC1 * 256 + PPM_MAGIC2) -#define RPPM_FORMAT (PPM_MAGIC1 * 256 + RPPM_MAGIC2) - -#define PPM_OVERALLMAXVAL 65535 -#define PPM_MAXSIZE (300*1024)/sizeof(fb_data) - -#define ppm_error(...) rb->splashf(HZ*2, __VA_ARGS__ ) - -static fb_data *buffer, *lcd_buf; - -int ppm_read_magic_number(int fd) -{ - char i1, i2; - if(!rb->read(fd, &i1, 1) || !rb->read(fd, &i2, 1)) - { - ppm_error( "Error reading magic number from ppm image stream. "\ - "Most often, this means your input file is empty." ); - return PLUGIN_ERROR; - } - return i1 * 256 + i2; -} - -char ppm_getc(int fd) -{ - char ch; - - if (!rb->read(fd, &ch, 1)) { - ppm_error("EOF. Read error reading a byte"); - return PLUGIN_ERROR; - } - - if (ch == '#') { - do { - if (!rb->read(fd, &ch, 1)) { - ppm_error("EOF. Read error reading a byte"); - return PLUGIN_ERROR; - } - } while (ch != '\n' && ch != '\r'); - } - return ch; -} - -int ppm_getuint(int fd) -{ - char ch; - int i; - int digitVal; - - do { - ch = ppm_getc(fd); - } while (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r'); - - if (ch < '0' || ch > '9') { - ppm_error("Junk (%c) in file where an integer should be.", ch); - return PLUGIN_ERROR; - } - - i = 0; - - do { - digitVal = ch - '0'; - - if (i > INT_MAX/10 - digitVal) { - ppm_error("ASCII decimal integer in file is "\ - "too large to be processed."); - return PLUGIN_ERROR; - } - - i = i * 10 + digitVal; - ch = ppm_getc(fd); - - } while (ch >= '0' && ch <= '9'); - - return i; -} - -int ppm_getrawbyte(int fd) -{ - unsigned char by; - - if (!rb->read(fd, &by, 1)) { - ppm_error("EOF. Read error while reading a one-byte sample."); - return PLUGIN_ERROR; - } - - return (int)by; -} - -int ppm_getrawsample(int fd, int const maxval) -{ - if (maxval < 256) { - /* The sample is just one byte. Read it. */ - return(ppm_getrawbyte(fd)); - } else { - /* The sample is two bytes. Read both. */ - unsigned char byte_pair[2]; - - if (!rb->read(fd, byte_pair, 2)) { - ppm_error("EOF. Read error while reading a long sample."); - return PLUGIN_ERROR; - } - return((byte_pair[0]<<8) | byte_pair[1]); - } -} - -int read_ppm_init_rest(int fd, - int * const cols, - int * const rows, - int * const maxval) -{ - /* Read size. */ - *cols = ppm_getuint(fd); - *rows = ppm_getuint(fd); - - if ((long unsigned int)(*cols * *rows) > PPM_MAXSIZE) { - ppm_error("Imagesize (%ld pixels) is too large. "\ - "The maximum allowed is %ld.", - (long unsigned int)(*cols * *rows), - (long unsigned int)PPM_MAXSIZE); - return PLUGIN_ERROR; - } - - /* Read maxval. */ - *maxval = ppm_getuint(fd); - - if (*maxval > PPM_OVERALLMAXVAL) { - ppm_error("maxval of input image (%u) is too large. "\ - "The maximum allowed by the PPM is %u.", - *maxval, PPM_OVERALLMAXVAL); - return PLUGIN_ERROR; - } - if (*maxval == 0) { - ppm_error("maxval of input image is zero."); - return PLUGIN_ERROR; - } - return 1; -} - -void read_ppm_init(int fd, - int * const cols, - int * const rows, - int * const maxval, - int * const format) -{ - /* Check magic number. */ - *format = ppm_read_magic_number( fd ); - - if (*format == PLUGIN_ERROR) return; - switch (*format) { - case PPM_FORMAT: - case RPPM_FORMAT: - if(read_ppm_init_rest(fd, cols, rows, maxval) == PLUGIN_ERROR) { - *format = PLUGIN_ERROR; - } - break; - - default: - ppm_error( "Bad magic number - not a ppm or rppm file." ); - *format = PLUGIN_ERROR; - } -} - -#if defined(LCD_STRIDEFORMAT) && LCD_STRIDEFORMAT == VERTICAL_STRIDE -#define BUFADDR(x, y, width, height) ( buffer + height*(x) + (y)) -#else -#define BUFADDR(x, y, width, height) ( buffer + width*(y) + (x)) -#endif - -int read_ppm_row(int fd, - int const row, - int const cols, - int const rows, - int const maxval, - int const format) -{ -#if !(defined(LCD_STRIDEFORMAT) && LCD_STRIDEFORMAT == VERTICAL_STRIDE) - (void) rows; -#endif - - int col; - int r, g, b; - switch (format) { - case PPM_FORMAT: - for (col = 0; col < cols; ++col) { - r = ppm_getuint(fd); - g = ppm_getuint(fd); - b = ppm_getuint(fd); - - if (r == PLUGIN_ERROR || g == PLUGIN_ERROR || - b == PLUGIN_ERROR) - { - return PLUGIN_ERROR; - } - *BUFADDR(col, row, cols, rows) = LCD_RGBPACK( - (255 / maxval) * r, - (255 / maxval) * g, - (255 / maxval) * b); - } - break; - - case RPPM_FORMAT: - for (col = 0; col < cols; ++col) { - r = ppm_getrawsample(fd, maxval); - g = ppm_getrawsample(fd, maxval); - b = ppm_getrawsample(fd, maxval); - - if (r == PLUGIN_ERROR || g == PLUGIN_ERROR || - b == PLUGIN_ERROR) - { - return PLUGIN_ERROR; - } - *BUFADDR(col, row, cols, rows) = LCD_RGBPACK( - (255 / maxval) * r, - (255 / maxval) * g, - (255 / maxval) * b); - } - break; - - default: - ppm_error("What?!"); - return PLUGIN_ERROR; - } - return 1; -} - -int read_ppm(int fd, - int * const cols, - int * const rows, - int * const maxval) -{ - int row; - int format; - - read_ppm_init(fd, cols, rows, maxval, &format); - - if(format == PLUGIN_ERROR) { - return PLUGIN_ERROR; - } - - for (row = 0; row < *rows; ++row) { - if( read_ppm_row(fd, row, *cols, *rows, *maxval, format) == PLUGIN_ERROR) { - return PLUGIN_ERROR; - } - } - return 1; -} - -/* this is the plugin entry point */ -enum plugin_status plugin_start(const void* parameter) -{ - static char filename[MAX_PATH]; - int fd; - - int cols; - int rows; - int maxval; - - int result; - - struct bitmap small_bitmap, orig_bitmap; - - if(!parameter) return PLUGIN_ERROR; - - size_t buffer_size; - char *audiobuf = rb->plugin_get_buffer(&buffer_size); - if (buffer_size < PPM_MAXSIZE + LCD_WIDTH * LCD_HEIGHT + 1) - { - /* steal from audiobuffer if plugin buffer is too small */ - audiobuf = rb->plugin_get_audio_buffer(&buffer_size); - - if (buffer_size < PPM_MAXSIZE + LCD_WIDTH * LCD_HEIGHT + 1) - { - rb->splash(HZ, "Not enough memory"); - return PLUGIN_ERROR; - } - } - - /* align on 16 bits */ - audiobuf = (char *)(((uintptr_t)audiobuf + 1) & ~1); - buffer = (fb_data *)audiobuf; - lcd_buf = (fb_data*) (audiobuf + PPM_MAXSIZE); - - rb->strcpy(filename, parameter); - - fd = rb->open(filename, O_RDONLY); - if (fd < 0) - { - ppm_error("Couldnt open file: %s, %d", filename, fd); - return PLUGIN_ERROR; - } - - result = read_ppm(fd, &cols, &rows, &maxval); - - rb->close(fd); - if(result == PLUGIN_ERROR) return PLUGIN_ERROR; - - orig_bitmap.width = cols; - orig_bitmap.height = rows; - orig_bitmap.data = (char*)buffer; - - if (cols > LCD_WIDTH || rows > LCD_HEIGHT) - { - if (cols > LCD_WIDTH) { - small_bitmap.width = LCD_WIDTH; - small_bitmap.height = - (int)(((float)LCD_WIDTH / (float)cols) * (float)rows); - - } else { /* rows > LCD_HEIGHT */ - - small_bitmap.width = - (int)(((float)LCD_HEIGHT / (float)rows) * (float)cols); - small_bitmap.height = LCD_HEIGHT; - } - small_bitmap.data = (char*)lcd_buf; - - smooth_resize_bitmap( &orig_bitmap, &small_bitmap ); - - rb->lcd_bitmap((fb_data*)small_bitmap.data, 0, 0, - small_bitmap.width, small_bitmap.height); - } else { - rb->lcd_bitmap((fb_data*)orig_bitmap.data, 0, 0, cols, rows); - } - rb->lcd_update(); - rb->button_get(true); - - return PLUGIN_OK; -} diff --git a/apps/plugins/viewers.config b/apps/plugins/viewers.config index 0170883817..ed2f68aaf7 100644 --- a/apps/plugins/viewers.config +++ b/apps/plugins/viewers.config @@ -20,6 +20,9 @@ jpeg,viewers/test_core_jpeg,- jpeg,viewers/test_mem_jpeg,- jpeg,viewers/bench_mem_jpeg,- png,viewers/imageviewer,2 +#ifdef HAVE_LCD_COLOR +ppm,viewers/imageviewer,2 +#endif ucl,viewers/rockbox_flash,3 rvf,viewers/video,4 mp3,viewers/vbrfix,5 @@ -73,7 +76,6 @@ tap,viewers/zxbox,12 sna,viewers/zxbox,12 tzx,viewers/zxbox,12 z80,viewers/zxbox,12 -ppm,viewers/ppmviewer,2 cfg,viewers/theme_remove,- *,viewers/properties,- *,viewers/shortcuts_append,- -- cgit v1.2.3