From c4eea8f11fa2386cafb20e22fe5451106b5ade52 Mon Sep 17 00:00:00 2001 From: Teruaki Kawashima Date: Thu, 18 Feb 2010 15:10:31 +0000 Subject: FS#10535: bmp viewer plugin. * changed bmp.c so that it loads bitmap larger than LCD correctly. * removed bmp entry form inbuilt_filetypes in filetypes.c so that bmp files will be opened with bmp viewer when selected in browser. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@24754 a1c6a512-1295-4272-9138-f99709370657 --- apps/filetypes.c | 3 - apps/plugins/CATEGORIES | 1 + apps/plugins/imageviewer/SUBDIRS | 1 + apps/plugins/imageviewer/bmp/SOURCES | 2 + apps/plugins/imageviewer/bmp/bmp.c | 323 ++++++++++++++++++++++++++++++++++ apps/plugins/imageviewer/bmp/bmp.make | 21 +++ apps/plugins/imageviewer/bmp/bmp_ui.c | 5 + apps/plugins/imageviewer/jpeg/jpeg.c | 2 +- apps/plugins/imageviewer/png/png.c | 2 +- apps/plugins/viewers.config | 1 + apps/recorder/bmp.c | 46 ++++- 11 files changed, 396 insertions(+), 11 deletions(-) create mode 100644 apps/plugins/imageviewer/bmp/SOURCES create mode 100644 apps/plugins/imageviewer/bmp/bmp.c create mode 100644 apps/plugins/imageviewer/bmp/bmp.make create mode 100644 apps/plugins/imageviewer/bmp/bmp_ui.c diff --git a/apps/filetypes.c b/apps/filetypes.c index e74edff5c2..49ae4afde2 100644 --- a/apps/filetypes.c +++ b/apps/filetypes.c @@ -109,9 +109,6 @@ static const struct filetype inbuilt_filetypes[] = { #ifdef HAVE_REMOTE_LCD { "rwps",FILE_ATTR_RWPS, Icon_Wps, VOICE_EXT_RWPS }, #endif -#if LCD_DEPTH > 1 - { "bmp", FILE_ATTR_BMP, Icon_Wps, VOICE_EXT_WPS }, -#endif #if CONFIG_TUNER { "fmr", FILE_ATTR_FMR, Icon_Preset, LANG_FMR }, #endif diff --git a/apps/plugins/CATEGORIES b/apps/plugins/CATEGORIES index 218055e311..4951f0db9c 100644 --- a/apps/plugins/CATEGORIES +++ b/apps/plugins/CATEGORIES @@ -3,6 +3,7 @@ autostart,apps battery_bench,apps bench_scaler,apps blackjack,games +bmp,viewers boomshine,games bounce,demos brickmania,games diff --git a/apps/plugins/imageviewer/SUBDIRS b/apps/plugins/imageviewer/SUBDIRS index 6785e47781..ca9665a022 100644 --- a/apps/plugins/imageviewer/SUBDIRS +++ b/apps/plugins/imageviewer/SUBDIRS @@ -1,3 +1,4 @@ +bmp jpeg #ifdef HAVE_LCD_COLOR png diff --git a/apps/plugins/imageviewer/bmp/SOURCES b/apps/plugins/imageviewer/bmp/SOURCES new file mode 100644 index 0000000000..a50d245846 --- /dev/null +++ b/apps/plugins/imageviewer/bmp/SOURCES @@ -0,0 +1,2 @@ +bmp_ui.c +bmp.c diff --git a/apps/plugins/imageviewer/bmp/bmp.c b/apps/plugins/imageviewer/bmp/bmp.c new file mode 100644 index 0000000000..73a4d738ac --- /dev/null +++ b/apps/plugins/imageviewer/bmp/bmp.c @@ -0,0 +1,323 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * BMP image viewer + * + * 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 "bmp.h" +#include "resize.h" +#include +#include + +#include "../imageviewer.h" + +#ifdef HAVE_LCD_COLOR +#define resize_bitmap smooth_resize_bitmap +#elif defined(USEGSLIB) +#define resize_bitmap grey_resize_bitmap +#else +#define resize_bitmap simple_resize_bitmap +#endif + +/**************** begin Application ********************/ + + +/************************* Types ***************************/ + +struct t_disp +{ + unsigned char* bitmap; +}; + +/************************* Globals ***************************/ + +/* decompressed image in the possible sizes (1,2,4,8), wasting the other */ +static struct t_disp disp[9]; + +/* my memory pool (from the mp3 buffer) */ +static char print[32]; /* use a common snprintf() buffer */ + +/* the root of the images, hereafter are decompresed ones */ +static unsigned char* buf_root; +static int root_size; + +/* up to here currently used by image(s) */ +static unsigned char* buf_images; +static ssize_t buf_images_size; + +struct bitmap bmp; + +/************************* Implementation ***************************/ + +#ifdef USEGSLIB +/* copied & pasted from lib/pluginlib_bmp.c. */ +static void grey_resize_bitmap(struct bitmap *src, struct bitmap *dst) +{ + const int srcw = src->width; + const int srch = src->height; + const int dstw = dst->width; + const int dsth = dst->height; + unsigned char *srcd = src->data; + unsigned char *dstd = dst->data; + + const long xrstep = ((srcw-1) << 8) / (dstw-1); + const long yrstep = ((srch-1) << 8) / (dsth-1); + unsigned char *src_row, *dst_row; + long xr, yr = 0; + int src_x, src_y, dst_x, dst_y; + for (dst_y=0; dst_y < dsth; dst_y++) + { + src_y = (yr >> 8); + src_row = &srcd[src_y * srcw]; + dst_row = &dstd[dst_y * dstw]; + for (xr=0,dst_x=0; dst_x < dstw; dst_x++) + { + src_x = (xr >> 8); + dst_row[dst_x] = src_row[src_x]; + xr += xrstep; + } + yr += yrstep; + } +} +#endif /* USEGSLIB */ + +bool img_ext(const char *ext) +{ + if (!ext) + return false; + if (!rb->strcasecmp(ext,".bmp")) + return true; + else + return false; +} + +void draw_image_rect(struct image_info *info, + int x, int y, int width, int height) +{ + struct t_disp* pdisp = (struct t_disp*)info->data; +#ifdef HAVE_LCD_COLOR + rb->lcd_bitmap_part( + (fb_data*)pdisp->bitmap, 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 + MYXLCD(gray_bitmap_part)( + pdisp->bitmap, 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 +} + +int img_mem(int ds) +{ +#ifndef USEGSLIB + return (bmp.width/ds) * (bmp.height/ds) * sizeof (fb_data); +#else + return (bmp.width/ds) * (bmp.height/ds); +#endif +} + +int load_image(char *filename, struct image_info *info, + unsigned char *buf, ssize_t *buf_size) +{ + int w, h; /* used to center output */ + long time; /* measured ticks */ + int fd; + int size; + int format = FORMAT_NATIVE; +#ifdef USEGSLIB + const struct custom_format *cformat = &format_grey; +#else + const struct custom_format *cformat = &format_native; +#endif + + rb->memset(&disp, 0, sizeof(disp)); + rb->memset(&bmp, 0, sizeof(bmp)); /* clear info struct */ + + if ((intptr_t)buf & 3) + { + *buf_size -= 4-((intptr_t)buf&3); + buf += 4-((intptr_t)buf&3); + } + fd = rb->open(filename, O_RDONLY); + if (fd < 0) + { + rb->splashf(HZ, "err opening %s: %d", filename, fd); + return PLUGIN_ERROR; + } + int ds = 1; + /* check size of image needed to load image. */ + size = scaled_read_bmp_fd(fd, &bmp, 0, format | FORMAT_RETURN_SIZE, cformat); +#ifdef USE_PLUG_BUF + if (!plug_buf) +#endif + { + while (size > *buf_size && bmp.width >= 2 && bmp.height >= 2 && ds < 8) + { + /* too large for the buffer. resize on load. */ + format |= FORMAT_RESIZE|FORMAT_KEEP_ASPECT; + ds *= 2; + bmp.width /= 2; + bmp.height /= 2; + rb->lseek(fd, 0, SEEK_SET); + size = scaled_read_bmp_fd(fd, &bmp, 0, format | FORMAT_RETURN_SIZE, cformat); + } + } + if (size <= 0) + { + rb->close(fd); + rb->splashf(HZ, "read error %d", size); + return PLUGIN_ERROR; + } + + if (size > *buf_size) + { + rb->close(fd); + return PLUGIN_OUTOFMEM; + } + + if (!running_slideshow) + { + rb->lcd_puts(0, 0, rb->strrchr(filename,'/')+1); + rb->lcd_update(); + + rb->snprintf(print, sizeof(print), "loading %dx%d%s", + bmp.width, bmp.height, ds == 1?"":"(resize on load)"); + rb->lcd_puts(0, 1, print); + rb->lcd_update(); + } + + /* allocate bitmap buffer */ + bmp.data = buf; + + /* actual loading */ + time = *rb->current_tick; + rb->lseek(fd, 0, SEEK_SET); +#ifdef HAVE_ADJUSTABLE_CPU_FREQ + rb->cpu_boost(true); + size = scaled_read_bmp_fd(fd, &bmp, *buf_size, format, cformat); + rb->cpu_boost(false); +#else + size = scaled_read_bmp_fd(fd, &bmp, *buf_size, format, cformat); +#endif /*HAVE_ADJUSTABLE_CPU_FREQ*/ + rb->close(fd); + time = *rb->current_tick - time; + + if (size <= 0) + { + rb->splashf(HZ, "load error %d", size); + return PLUGIN_ERROR; + } + + if (!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(); + } +#ifdef DISK_SPINDOWN + else if (immediate_ata_off) + { + /* running slideshow and time is long enough: power down disk */ + rb->storage_sleep(); + } +#endif + + /* we can start the resized images behind it */ + buf_images = buf_root = buf + size; + buf_images_size = root_size = *buf_size - size; + + if (!running_slideshow) + { + rb->snprintf(print, sizeof(print), "image %dx%d", bmp.width, bmp.height); + rb->lcd_puts(0, 2, print); + rb->lcd_update(); + } + + info->x_size = bmp.width; + info->y_size = bmp.height; + *buf_size = buf_images_size; + return PLUGIN_OK; +} + +int get_image(struct image_info *info, int ds) +{ + struct t_disp* p_disp = &disp[ds]; /* short cut */ + + info->width = bmp.width/ds; + info->height = bmp.height/ds; + info->data = p_disp; + + if (p_disp->bitmap != NULL) + { + /* we still have it */ + return PLUGIN_OK; + } + + /* assign image buffer */ + if (ds > 1) + { + int size; /* resized image size */ + struct bitmap bmp_dst; + + size = img_mem(ds); + if (buf_images_size <= size) + { + /* have to discard the current */ + int i; + for (i=1; i<=8; i++) + disp[i].bitmap = NULL; /* invalidate all bitmaps */ + buf_images = buf_root; /* start again from the beginning of the buffer */ + buf_images_size = root_size; + } + + p_disp->bitmap = buf_images; + buf_images += size; + buf_images_size -= size; + + if (!running_slideshow) + { + rb->snprintf(print, sizeof(print), "resizing %d*%d", + info->width, info->height); + rb->lcd_puts(0, 3, print); + rb->lcd_update(); + } + + bmp_dst.width = info->width; + bmp_dst.height = info->height; + bmp_dst.data = p_disp->bitmap; +#ifdef HAVE_ADJUSTABLE_CPU_FREQ + rb->cpu_boost(true); + resize_bitmap(&bmp, &bmp_dst); + rb->cpu_boost(false); +#else + resize_bitmap(&bmp, &bmp_dst); +#endif /*HAVE_ADJUSTABLE_CPU_FREQ*/ + } + else + { + p_disp->bitmap = bmp.data; + } + + return PLUGIN_OK; +} diff --git a/apps/plugins/imageviewer/bmp/bmp.make b/apps/plugins/imageviewer/bmp/bmp.make new file mode 100644 index 0000000000..0582ba3eb3 --- /dev/null +++ b/apps/plugins/imageviewer/bmp/bmp.make @@ -0,0 +1,21 @@ +# __________ __ ___. +# Open \______ \ ____ ____ | | _\_ |__ _______ ___ +# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / +# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < +# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ +# \/ \/ \/ \/ \/ +# $Id$ +# + +BMPSRCDIR := $(IMGVSRCDIR)/bmp +BMPBUILDDIR := $(IMGVBUILDDIR)/bmp + +ROCKS += $(BMPBUILDDIR)/bmp.rock + +BMP_SRC := $(call preprocess, $(BMPSRCDIR)/SOURCES) +BMP_OBJ := $(call c2obj, $(BMP_SRC)) + +# add source files to OTHER_SRC to get automatic dependencies +OTHER_SRC += $(BMP_SRC) + +$(BMPBUILDDIR)/bmp.rock: $(BMP_OBJ) diff --git a/apps/plugins/imageviewer/bmp/bmp_ui.c b/apps/plugins/imageviewer/bmp/bmp_ui.c new file mode 100644 index 0000000000..8ff3e0c880 --- /dev/null +++ b/apps/plugins/imageviewer/bmp/bmp_ui.c @@ -0,0 +1,5 @@ +#define BMP_VIEWER +#define MENU_TITLE "BMP Menu" +#define UNSCALED_IS_AVAILABLE 1 + +#include "../imageviewer.c" diff --git a/apps/plugins/imageviewer/jpeg/jpeg.c b/apps/plugins/imageviewer/jpeg/jpeg.c index 91e0c1021f..b16ec1c4b1 100644 --- a/apps/plugins/imageviewer/jpeg/jpeg.c +++ b/apps/plugins/imageviewer/jpeg/jpeg.c @@ -136,7 +136,7 @@ int load_image(char *filename, struct image_info *info, fd = rb->open(filename, O_RDONLY); if (fd < 0) { - rb->splashf(HZ, "err opening %s:%d", filename, fd); + rb->splashf(HZ, "err opening %s: %d", filename, fd); return PLUGIN_ERROR; } filesize = rb->filesize(fd); diff --git a/apps/plugins/imageviewer/png/png.c b/apps/plugins/imageviewer/png/png.c index 958793b37d..4a7e0963d9 100644 --- a/apps/plugins/imageviewer/png/png.c +++ b/apps/plugins/imageviewer/png/png.c @@ -1338,7 +1338,7 @@ int load_image(char *filename, struct image_info *info, fd = rb->open(filename, O_RDONLY); if (fd < 0) { - rb->splashf(HZ, "err opening %s:%d", filename, fd); + rb->splashf(HZ, "err opening %s: %d", filename, fd); return PLUGIN_ERROR; } image_size = rb->filesize(fd); diff --git a/apps/plugins/viewers.config b/apps/plugins/viewers.config index 985115672d..1c70c2957f 100644 --- a/apps/plugins/viewers.config +++ b/apps/plugins/viewers.config @@ -2,6 +2,7 @@ ch8,viewers/chip8,0 txt,viewers/viewer,1 nfo,viewers/viewer,1 txt,apps/text_editor,2 +bmp,viewers/bmp,2 jpg,viewers/jpeg,2 jpe,viewers/jpeg,2 jpeg,viewers/jpeg,2 diff --git a/apps/recorder/bmp.c b/apps/recorder/bmp.c index 4e8cdd70c5..81ed8bc73b 100644 --- a/apps/recorder/bmp.c +++ b/apps/recorder/bmp.c @@ -621,6 +621,8 @@ int read_bmp_fd(int fd, defined(HAVE_BMP_SCALING) || defined(PLUGIN) if(resize) totalsize += BM_SCALED_SIZE(bm->width, 0, 0, 0); + else if (bm->width > BM_MAX_WIDTH) + totalsize += bm->width*4; #endif return totalsize; } @@ -717,9 +719,7 @@ int read_bmp_fd(int fd, #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \ defined(HAVE_BMP_SCALING) || defined(PLUGIN) -#if LCD_DEPTH > 1 && defined(HAVE_BMP_SCALING) if (resize) -#endif { if (resize_on_load(bm, dither, &src_dim, &rset, bitmap + totalsize, maxsize - totalsize, @@ -749,17 +749,51 @@ int read_bmp_fd(int fd, #endif #endif + unsigned char *buf = ba.buf; +#if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) || \ + defined(PLUGIN) + if (bm->width > BM_MAX_WIDTH) + { +#if defined(HAVE_BMP_SCALING) || defined(PLUGIN) + unsigned int len = maxsize - totalsize; + buf = bitmap + totalsize; + ALIGN_BUFFER(buf, len, sizeof(uint32_t)); + if (bm->width*4 > (int)len) +#endif + return -6; + } +#endif + int row; /* loop to read rows and put them to buffer */ for (row = rset.rowstart; row != rset.rowstop; row += rset.rowstep) { +#if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \ + defined(HAVE_BMP_SCALING) || defined(PLUGIN) + if (bm->width > BM_MAX_WIDTH) + { +#if defined(HAVE_LCD_COLOR) + struct uint8_rgb *p = (struct uint8_rgb *)buf; +#else + uint8_t* p = buf; +#endif + do { + int len = read_part_line(&ba); + if (!len) + return -9; + memcpy(p, ba.buf, len*sizeof(*p)); + p += len; + } while (ba.cur_col); + } + else +#endif if (!read_part_line(&ba)) return -9; #ifndef PLUGIN #if !defined(HAVE_LCD_COLOR) && \ (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) - uint8_t* qp = ba.buf; + uint8_t* qp = buf; #else - struct uint8_rgb *qp = (struct uint8_rgb *)ba.buf; + struct uint8_rgb *qp = (struct uint8_rgb *)buf; #endif #endif /* Convert to destination format */ @@ -798,9 +832,9 @@ int read_bmp_fd(int fd, #if LCD_DEPTH > 1 || defined(PLUGIN) { #if !defined(PLUGIN) && !defined(HAVE_JPEG) && !defined(HAVE_BMP_SCALING) - output_row_8_native(row, ba.buf, &ctx); + output_row_8_native(row, buf, &ctx); #else - output_row_8(row, ba.buf, &ctx); + output_row_8(row, buf, &ctx); #endif } #endif -- cgit v1.2.3