summaryrefslogtreecommitdiffstats
path: root/apps/plugins/imageviewer/imageviewer.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/imageviewer/imageviewer.c')
-rw-r--r--apps/plugins/imageviewer/imageviewer.c219
1 files changed, 131 insertions, 88 deletions
diff --git a/apps/plugins/imageviewer/imageviewer.c b/apps/plugins/imageviewer/imageviewer.c
index e3c72ae291..01b9f31be1 100644
--- a/apps/plugins/imageviewer/imageviewer.c
+++ b/apps/plugins/imageviewer/imageviewer.c
@@ -7,7 +7,7 @@
* \/ \/ \/ \/ \/
* $Id$
*
- * user intereface of image viewers (jpeg, png, etc.)
+ * user intereface of image viewer
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -19,11 +19,16 @@
*
****************************************************************************/
+/*
+ * TODO:
+ * - check magick value in file header to determine image type.
+ */
#include "plugin.h"
#include <lib/playback_control.h>
#include <lib/helper.h>
#include <lib/configfile.h>
#include "imageviewer.h"
+#include "image_decoder.h"
@@ -38,16 +43,6 @@ GREY_INFO_STRUCT
/******************************* Globals ***********************************/
-bool slideshow_enabled = false; /* run slideshow */
-bool running_slideshow = false; /* loading image because of slideshow */
-#ifdef DISK_SPINDOWN
-bool immediate_ata_off = false; /* power down disk after loading */
-#endif
-#ifdef USE_PLUG_BUF
-/* are we using the plugin buffer or the audio buffer? */
-bool plug_buf = true;
-#endif
-
/* Persistent configuration */
#define IMGVIEW_CONFIGFILE "imageviewer.cfg"
#define IMGVIEW_SETTINGS_MINVERSION 1
@@ -63,8 +58,7 @@ bool plug_buf = true;
#include "jpeg/yuv2rgb.h"
#endif
-/* jpeg use this */
-struct imgview_settings settings =
+static struct imgview_settings settings =
{
#ifdef HAVE_LCD_COLOR
COLOURMODE_COLOUR,
@@ -86,17 +80,39 @@ static struct configdata config[] =
{ .int_p = &settings.ss_timeout }, "Slideshow Time", NULL },
};
+static void cb_progress(int current, int total);
+
+static struct imgdec_api iv_api = {
+ .settings = &settings,
+ .slideshow_enabled = false,
+ .running_slideshow = false,
+#ifdef DISK_SPINDOWN
+ .immediate_ata_off = false,
+#endif
+#ifdef USE_PLUG_BUF
+ .plug_buf = true,
+#endif
+
+ .cb_progress = cb_progress,
+
+#ifdef USEGSLIB
+ .gray_bitmap_part = myxlcd_ub_(gray_bitmap_part),
+#endif
+};
+
/**************** begin Application ********************/
/************************* Globals ***************************/
-#if defined(HAVE_LCD_COLOR) && defined(JPEG_VIEWER)
+#ifdef HAVE_LCD_COLOR
static fb_data rgb_linebuf[LCD_WIDTH]; /* Line buffer for scrolling when
DITHER_DIFFUSION is set */
#endif
-/* my memory pool (from the mp3 buffer) */
+/* buffer to load image decoder */
+static unsigned char* decoder_buf;
+static size_t decoder_buf_size;
/* the remaining free part of the buffer for loaded+resized images */
static unsigned char* buf;
static size_t buf_size;
@@ -106,11 +122,14 @@ static struct image_info image_info;
/* the current full file name */
static char np_file[MAX_PATH];
-static int curfile = 0, direction = DIR_NEXT, entries = 0;
+static int curfile = -1, direction = DIR_NEXT, entries = 0;
/* list of the supported image files */
static char **file_pt;
+static const struct image_decoder *imgdec = NULL;
+static enum image_type image_type = IMAGE_UNKNOWN;
+
/************************* Implementation ***************************/
/* Read directory contents for scrolling. */
@@ -130,7 +149,7 @@ static void get_pic_list(void)
for (i = 0; i < tree->filesindir && buf_size > sizeof(char**); i++)
{
if (!(dircache[i].attr & ATTR_DIRECTORY)
- && img_ext(rb->strrchr(dircache[i].name,'.')))
+ && get_image_type(dircache[i].name) != IMAGE_UNKNOWN)
{
file_pt[entries] = dircache[i].name;
/* Set Selected File. */
@@ -187,11 +206,11 @@ static void cleanup(void *parameter)
#endif
}
-#if defined(HAVE_LCD_COLOR) && defined(JPEG_VIEWER)
+#ifdef HAVE_LCD_COLOR
static bool set_option_grayscale(void)
{
bool gray = settings.jpeg_colour_mode == COLOURMODE_GRAY;
- rb->set_bool("Grayscale", &gray);
+ rb->set_bool("Grayscale (Jpeg)", &gray);
settings.jpeg_colour_mode = gray ? COLOURMODE_GRAY : COLOURMODE_COLOUR;
return false;
}
@@ -204,14 +223,14 @@ static bool set_option_dithering(void)
[DITHER_DIFFUSION] = { "Diffusion", -1 },
};
- rb->set_option("Dithering", &settings.jpeg_dither_mode, INT,
+ rb->set_option("Dithering (Jpeg)", &settings.jpeg_dither_mode, INT,
dithering, DITHER_NUM_MODES, NULL);
return false;
}
-MENUITEM_FUNCTION(grayscale_item, 0, "Greyscale",
+MENUITEM_FUNCTION(grayscale_item, 0, "Greyscale (Jpeg)",
set_option_grayscale, NULL, NULL, Icon_NOICON);
-MENUITEM_FUNCTION(dithering_item, 0, "Dithering",
+MENUITEM_FUNCTION(dithering_item, 0, "Dithering (Jpeg)",
set_option_dithering, NULL, NULL, Icon_NOICON);
MAKE_MENU(display_menu, "Display Options", NULL, Icon_NOICON,
&grayscale_item, &dithering_item);
@@ -220,7 +239,7 @@ static void display_options(void)
{
rb->do_menu(&display_menu, NULL, NULL, false);
}
-#endif /* defined(HAVE_LCD_COLOR) && defined(JPEG_VIEWER) */
+#endif /* HAVE_LCD_COLOR */
static int show_menu(void) /* return 1 to quit */
{
@@ -234,19 +253,19 @@ static int show_menu(void) /* return 1 to quit */
#ifdef USE_PLUG_BUF
MIID_SHOW_PLAYBACK_MENU,
#endif
-#if defined(HAVE_LCD_COLOR) && defined(JPEG_VIEWER)
+#ifdef HAVE_LCD_COLOR
MIID_DISPLAY_OPTIONS,
#endif
MIID_QUIT,
};
- MENUITEM_STRINGLIST(menu, MENU_TITLE, NULL,
+ MENUITEM_STRINGLIST(menu, "Image Viewer Menu", NULL,
"Return", "Toggle Slideshow Mode",
"Change Slideshow Time",
#ifdef USE_PLUG_BUF
"Show Playback Menu",
#endif
-#if defined(HAVE_LCD_COLOR) && defined(JPEG_VIEWER)
+#ifdef HAVE_LCD_COLOR
"Display Options",
#endif
"Quit");
@@ -263,7 +282,7 @@ static int show_menu(void) /* return 1 to quit */
case MIID_RETURN:
break;
case MIID_TOGGLE_SS_MODE:
- rb->set_option("Toggle Slideshow", &slideshow_enabled, BOOL,
+ rb->set_option("Toggle Slideshow", &iv_api.slideshow_enabled, BOOL,
slideshow , 2, NULL);
break;
case MIID_CHANGE_SS_MODE:
@@ -274,7 +293,7 @@ static int show_menu(void) /* return 1 to quit */
#ifdef USE_PLUG_BUF
case MIID_SHOW_PLAYBACK_MENU:
- if (plug_buf)
+ if (iv_api.plug_buf)
{
playback_control(NULL);
}
@@ -284,7 +303,7 @@ static int show_menu(void) /* return 1 to quit */
}
break;
#endif
-#if defined(HAVE_LCD_COLOR) && defined(JPEG_VIEWER)
+#ifdef HAVE_LCD_COLOR
case MIID_DISPLAY_OPTIONS:
display_options();
break;
@@ -296,10 +315,10 @@ static int show_menu(void) /* return 1 to quit */
#ifdef DISK_SPINDOWN
/* change ata spindown time based on slideshow time setting */
- immediate_ata_off = false;
+ iv_api.immediate_ata_off = false;
rb->storage_spindown(rb->global_settings->disk_spindown);
- if (slideshow_enabled)
+ if (iv_api.slideshow_enabled)
{
if(settings.ss_timeout < 10)
{
@@ -309,7 +328,7 @@ static int show_menu(void) /* return 1 to quit */
else if (!rb->mp3_is_playing())
{
/* slideshow times > 10s and not playing: ata_off after load */
- immediate_ata_off = true;
+ iv_api.immediate_ata_off = true;
}
}
#endif
@@ -344,7 +363,7 @@ static int ask_and_get_audio_buffer(const char *filename)
switch(button)
{
case IMGVIEW_ZOOM_IN:
- plug_buf = false;
+ iv_api.plug_buf = false;
buf = rb->plugin_get_audio_buffer(&buf_size);
/*try again this file, now using the audio buffer */
return PLUGIN_OTHER;
@@ -382,15 +401,15 @@ static int ask_and_get_audio_buffer(const char *filename)
#endif /* USE_PLUG_BUF */
/* callback updating a progress meter while image decoding */
-void cb_progress(int current, int total)
+static void cb_progress(int current, int total)
{
rb->yield(); /* be nice to the other threads */
#ifndef USEGSLIB
/* in slideshow mode, keep gui interference to a minimum */
- const int size = (!running_slideshow ? 8 : 4);
+ const int size = (!iv_api.running_slideshow ? 8 : 4);
#else
const int size = 8;
- if(!running_slideshow)
+ if(!iv_api.running_slideshow)
#endif
{
rb->gui_scrollbar_draw(rb->screens[SCREEN_MAIN],
@@ -414,7 +433,8 @@ static void pan_view_right(struct image_info *info)
{
mylcd_ub_scroll_left(move); /* scroll left */
info->x += move;
- draw_image_rect(info, LCD_WIDTH - move, 0, move, info->height-info->y);
+ imgdec->draw_image_rect(info, LCD_WIDTH - move, 0,
+ move, info->height-info->y);
mylcd_ub_update();
}
}
@@ -430,7 +450,7 @@ static void pan_view_left(struct image_info *info)
{
mylcd_ub_scroll_right(move); /* scroll right */
info->x -= move;
- draw_image_rect(info, 0, 0, move, info->height-info->y);
+ imgdec->draw_image_rect(info, 0, 0, move, info->height-info->y);
mylcd_ub_update();
}
}
@@ -446,15 +466,16 @@ static void pan_view_up(struct image_info *info)
{
mylcd_ub_scroll_down(move); /* scroll down */
info->y -= move;
-#if defined(HAVE_LCD_COLOR) && defined(JPEG_VIEWER)
- if (settings.jpeg_dither_mode == DITHER_DIFFUSION)
+#ifdef HAVE_LCD_COLOR
+ if (image_type == IMAGE_JPEG
+ && settings.jpeg_dither_mode == DITHER_DIFFUSION)
{
/* Draw over the band at the top of the last update
caused by lack of error history on line zero. */
move = MIN(move + 1, info->y + info->height);
}
#endif
- draw_image_rect(info, 0, 0, info->width-info->x, move);
+ imgdec->draw_image_rect(info, 0, 0, info->width-info->x, move);
mylcd_ub_update();
}
}
@@ -470,8 +491,9 @@ static void pan_view_down(struct image_info *info)
{
mylcd_ub_scroll_up(move); /* scroll up */
info->y += move;
-#if defined(HAVE_LCD_COLOR) && defined(JPEG_VIEWER)
- if (settings.jpeg_dither_mode == DITHER_DIFFUSION)
+#ifdef HAVE_LCD_COLOR
+ if (image_type == IMAGE_JPEG
+ && settings.jpeg_dither_mode == DITHER_DIFFUSION)
{
/* Save the line that was on the last line of the display
and draw one extra line above then recover the line with
@@ -484,10 +506,12 @@ static void pan_view_down(struct image_info *info)
}
#endif
- draw_image_rect(info, 0, LCD_HEIGHT - move, info->width-info->x, move);
+ imgdec->draw_image_rect(info, 0, LCD_HEIGHT - move,
+ info->width-info->x, move);
-#if defined(HAVE_LCD_COLOR) && defined(JPEG_VIEWER)
- if (settings.jpeg_dither_mode == DITHER_DIFFUSION)
+#ifdef HAVE_LCD_COLOR
+ if (image_type == IMAGE_JPEG
+ && settings.jpeg_dither_mode == DITHER_DIFFUSION)
{
/* Cover the first row drawn with previous image data. */
rb->memcpy(rb->lcd_framebuffer + (LCD_HEIGHT - move)*LCD_WIDTH,
@@ -507,12 +531,12 @@ static int scroll_bmp(struct image_info *info)
while (true)
{
- if (slideshow_enabled)
+ if (iv_api.slideshow_enabled)
button = rb->button_get_w_tmo(settings.ss_timeout * HZ);
else
button = rb->button_get(true);
- running_slideshow = false;
+ iv_api.running_slideshow = false;
switch(button)
{
@@ -543,16 +567,16 @@ static int scroll_bmp(struct image_info *info)
break;
case BUTTON_NONE:
- if (slideshow_enabled && entries > 1)
+ if (iv_api.slideshow_enabled && entries > 1)
{
- running_slideshow = true;
+ iv_api.running_slideshow = true;
return change_filename(DIR_NEXT);
}
break;
#ifdef IMGVIEW_SLIDE_SHOW
case IMGVIEW_SLIDE_SHOW:
- slideshow_enabled = !slideshow_enabled;
+ iv_api.slideshow_enabled = !iv_api.slideshow_enabled;
break;
#endif
@@ -605,7 +629,7 @@ static int scroll_bmp(struct image_info *info)
#ifdef USEGSLIB
grey_show(true); /* switch on greyscale overlay */
#else
- draw_image_rect(info, 0, 0,
+ imgdec->draw_image_rect(info, 0, 0,
info->width-info->x, info->height-info->y);
mylcd_ub_update();
#endif
@@ -637,10 +661,10 @@ static int min_downscale(int bufsize)
{
int downscale = 8;
- if (img_mem(8) > bufsize)
+ if (imgdec->img_mem(8) > bufsize)
return 0; /* error, too large, even 1:8 doesn't fit */
- while (downscale > 1 && img_mem(downscale/2) <= bufsize)
+ while (downscale > 1 && imgdec->img_mem(downscale/2) <= bufsize)
downscale /= 2;
return downscale;
@@ -697,18 +721,39 @@ static int load_and_show(char* filename, struct image_info *info)
rb->lcd_clear_display();
+ status = get_image_type(filename);
+ if (image_type != status) /* type of image is changed, load decoder. */
+ {
+ struct loader_info loader_info = {
+ status, &iv_api, decoder_buf, decoder_buf_size,
+ };
+ image_type = status;
+ imgdec = load_decoder(&loader_info);
+ if (imgdec == NULL)
+ {
+ /* something is wrong */
+ return PLUGIN_ERROR;
+ }
+#ifdef USE_PLUG_BUF
+ if(iv_api.plug_buf)
+ {
+ buf = loader_info.buffer;
+ buf_size = loader_info.size;
+ }
+#endif
+ }
rb->memset(info, 0, sizeof(*info));
remaining = buf_size;
if (rb->button_get(false) == IMGVIEW_MENU)
status = PLUGIN_ABORT;
else
- status = load_image(filename, info, buf, &remaining);
+ status = imgdec->load_image(filename, info, buf, &remaining);
if (status == PLUGIN_OUTOFMEM)
{
#ifdef USE_PLUG_BUF
- if(plug_buf)
+ if(iv_api.plug_buf)
{
return ask_and_get_audio_buffer(filename);
}
@@ -734,13 +779,14 @@ static int load_and_show(char* filename, struct image_info *info)
ds_min = min_downscale(remaining); /* check memory constraint */
if (ds_min == 0)
{
-#if UNSCALED_IS_AVAILABLE
- /* Can not resize the image but original one is available, so use it. */
- ds_min = ds_max = 1;
-#else
- /* not enough memory to decode image. */
+ if (imgdec->unscaled_avail)
+ {
+ /* Can not resize the image but original one is available, so use it. */
+ ds_min = ds_max = 1;
+ }
+ else
#ifdef USE_PLUG_BUF
- if(plug_buf)
+ if (iv_api.plug_buf)
{
return ask_and_get_audio_buffer(filename);
}
@@ -751,7 +797,6 @@ static int load_and_show(char* filename, struct image_info *info)
file_pt[curfile] = NULL;
return change_filename(direction);
}
-#endif
}
else if (ds_max < ds_min)
ds_max = ds_min;
@@ -762,7 +807,7 @@ static int load_and_show(char* filename, struct image_info *info)
do /* loop the image prepare and decoding when zoomed */
{
- status = get_image(info, ds); /* decode or fetch from cache */
+ status = imgdec->get_image(info, ds); /* decode or fetch from cache */
if (status == PLUGIN_ERROR)
{
file_pt[curfile] = NULL;
@@ -771,14 +816,14 @@ static int load_and_show(char* filename, struct image_info *info)
set_view(info, cx, cy);
- if(!running_slideshow)
+ if(!iv_api.running_slideshow)
{
rb->lcd_putsf(0, 3, "showing %dx%d", info->width, info->height);
rb->lcd_update();
}
mylcd_ub_clear_display();
- draw_image_rect(info, 0, 0,
+ imgdec->draw_image_rect(info, 0, 0,
info->width-info->x, info->height-info->y);
mylcd_ub_update();
@@ -794,18 +839,10 @@ static int load_and_show(char* filename, struct image_info *info)
status = scroll_bmp(info);
if (status == ZOOM_IN)
{
-#if UNSCALED_IS_AVAILABLE
- if (ds > 1)
-#else
- if (ds > ds_min)
-#endif
+ if (ds > ds_min || (imgdec->unscaled_avail && ds > 1))
{
-#if UNSCALED_IS_AVAILABLE
/* if 1/1 is always available, jump ds from ds_min to 1. */
int zoom = (ds == ds_min)? ds_min: 2;
-#else
- const int zoom = 2;
-#endif
ds /= zoom; /* reduce downscaling to zoom in */
get_view(info, &cx, &cy);
cx *= zoom; /* prepare the position in the new image */
@@ -819,12 +856,8 @@ static int load_and_show(char* filename, struct image_info *info)
{
if (ds < ds_max)
{
-#if UNSCALED_IS_AVAILABLE
/* if ds is 1 and ds_min is > 1, jump ds to ds_min. */
int zoom = (ds < ds_min)? ds_min: 2;
-#else
- const int zoom = 2;
-#endif
ds *= zoom; /* increase downscaling to zoom out */
get_view(info, &cx, &cy);
cx /= zoom; /* prepare the position in the new image */
@@ -859,25 +892,24 @@ enum plugin_status plugin_start(const void* parameter)
if(!parameter) return PLUGIN_ERROR;
+ rb->strcpy(np_file, parameter);
+ if (get_image_type(np_file) == IMAGE_UNKNOWN)
+ {
+ rb->splash(HZ*2, "Unsupported file");
+ return PLUGIN_ERROR;
+ }
+
#ifdef USE_PLUG_BUF
buf = rb->plugin_get_buffer(&buf_size);
#else
+ decoder_buf = rb->plugin_get_buffer(&decoder_buf_size);
buf = rb->plugin_get_audio_buffer(&buf_size);
#endif
- rb->strcpy(np_file, parameter);
get_pic_list();
if(!entries) return PLUGIN_ERROR;
-#ifdef USE_PLUG_BUF
- if(!rb->audio_status())
- {
- plug_buf = false;
- buf = rb->plugin_get_audio_buffer(&buf_size);
- }
-#endif
-
#ifdef USEGSLIB
if (!grey_init(buf, buf_size, GREY_ON_COP,
LCD_WIDTH, LCD_HEIGHT, &greysize))
@@ -889,6 +921,16 @@ enum plugin_status plugin_start(const void* parameter)
buf_size -= greysize;
#endif
+#ifdef USE_PLUG_BUF
+ decoder_buf = buf;
+ decoder_buf_size = buf_size;
+ if(!rb->audio_status())
+ {
+ iv_api.plug_buf = false;
+ buf = rb->plugin_get_audio_buffer(&buf_size);
+ }
+#endif
+
/* should be ok to just load settings since the plugin itself has
just been loaded from disk and the drive should be spinning */
configfile_load(IMGVIEW_CONFIGFILE, config,
@@ -908,6 +950,7 @@ enum plugin_status plugin_start(const void* parameter)
{
condition = load_and_show(np_file, &image_info);
} while (condition >= PLUGIN_OTHER);
+ release_decoder();
if (rb->memcmp(&settings, &old_settings, sizeof (settings)))
{