summaryrefslogtreecommitdiff
path: root/apps/plugins/imageviewer/jpeg/jpeg.c
diff options
context:
space:
mode:
authorTeruaki Kawashima <teru@rockbox.org>2010-01-18 12:46:19 +0000
committerTeruaki Kawashima <teru@rockbox.org>2010-01-18 12:46:19 +0000
commit5bd08237499dfc66309ba2a5a4dac75018e794ac (patch)
treefe742342707b8789ce0dbf1a18e5a8346ae2601d /apps/plugins/imageviewer/jpeg/jpeg.c
parent135d983433e741cf9658ff5d7457bdf37ef48ce0 (diff)
downloadrockbox-5bd08237499dfc66309ba2a5a4dac75018e794ac.zip
rockbox-5bd08237499dfc66309ba2a5a4dac75018e794ac.tar.gz
rockbox-5bd08237499dfc66309ba2a5a4dac75018e794ac.tar.bz2
rockbox-5bd08237499dfc66309ba2a5a4dac75018e794ac.tar.xz
jpeg,png: Merge user interface code and plugin entry point of the two plugins (part of FS#6321).
* Created new directory, imageviewer/ and moved both jpeg/ and png/ under it. - this still doesn't merge the two plugins. i.e. both jpeg.rock and png.rock will be made for color targets. - I'm thinking to merge the two plugins to single image viewer later. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@24272 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/plugins/imageviewer/jpeg/jpeg.c')
-rw-r--r--apps/plugins/imageviewer/jpeg/jpeg.c308
1 files changed, 308 insertions, 0 deletions
diff --git a/apps/plugins/imageviewer/jpeg/jpeg.c b/apps/plugins/imageviewer/jpeg/jpeg.c
new file mode 100644
index 0000000..b4ac6c0
--- /dev/null
+++ b/apps/plugins/imageviewer/jpeg/jpeg.c
@@ -0,0 +1,308 @@
+/***************************************************************************
+* __________ __ ___.
+* Open \______ \ ____ ____ | | _\_ |__ _______ ___
+* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+* \/ \/ \/ \/ \/
+* $Id$
+*
+* JPEG image viewer
+* (This is a real mess if it has to be coded in one single C file)
+*
+* File scrolling addition (C) 2005 Alexander Spyridakis
+* Copyright (C) 2004 Jörg Hohensohn aka [IDC]Dragon
+* Heavily borrowed from the IJG implementation (C) Thomas G. Lane
+* Small & fast downscaling IDCT (C) 2002 by Guido Vollbeding JPEGclub.org
+*
+* 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 "../imageviewer.h"
+#include "jpeg_decoder.h"
+
+#ifdef HAVE_LCD_COLOR
+#include "yuv2rgb.h"
+#endif
+
+/**************** begin Application ********************/
+
+/************************* Types ***************************/
+
+struct t_disp
+{
+#ifdef HAVE_LCD_COLOR
+ unsigned char* bitmap[3]; /* Y, Cr, Cb */
+ int csub_x, csub_y;
+#else
+ unsigned char* bitmap[1]; /* Y only */
+#endif
+ int stride;
+};
+
+/************************* 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;
+
+static struct jpeg jpg; /* too large for stack */
+
+/************************* Implementation ***************************/
+
+bool img_ext(const char *ext)
+{
+ if(!ext)
+ return false;
+ if(!rb->strcasecmp(ext,".jpg") ||
+ !rb->strcasecmp(ext,".jpe") ||
+ !rb->strcasecmp(ext,".jpeg"))
+ 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
+ yuv_bitmap_part(
+ pdisp->bitmap, pdisp->csub_x, pdisp->csub_y,
+ info->x + x, info->y + y, pdisp->stride,
+ x + MAX(0, (LCD_WIDTH - info->width) / 2),
+ y + MAX(0, (LCD_HEIGHT - info->height) / 2),
+ width, height,
+ settings.jpeg_colour_mode, settings.jpeg_dither_mode);
+#else
+ MYXLCD(gray_bitmap_part)(
+ pdisp->bitmap[0], info->x + x, info->y + y, pdisp->stride,
+ x + MAX(0, (LCD_WIDTH-info->width)/2),
+ y + MAX(0, (LCD_HEIGHT-info->height)/2),
+ width, height);
+#endif
+}
+
+int img_mem(int ds)
+{
+ int size;
+ struct jpeg *p_jpg = &jpg;
+
+ size = (p_jpg->x_phys/ds/p_jpg->subsample_x[0])
+ * (p_jpg->y_phys/ds/p_jpg->subsample_y[0]);
+#ifdef HAVE_LCD_COLOR
+ if (p_jpg->blocks > 1) /* colour, add requirements for chroma */
+ {
+ size += (p_jpg->x_phys/ds/p_jpg->subsample_x[1])
+ * (p_jpg->y_phys/ds/p_jpg->subsample_y[1]);
+ size += (p_jpg->x_phys/ds/p_jpg->subsample_x[2])
+ * (p_jpg->y_phys/ds/p_jpg->subsample_y[2]);
+ }
+#endif
+ return size;
+}
+
+int load_image(char *filename, struct image_info *info,
+ unsigned char *buf, ssize_t *buf_size)
+{
+ int fd;
+ int filesize;
+ unsigned char* buf_jpeg; /* compressed JPEG image */
+ int status;
+ struct jpeg *p_jpg = &jpg;
+
+ rb->memset(&disp, 0, sizeof(disp));
+ rb->memset(&jpg, 0, sizeof(jpg));
+
+ fd = rb->open(filename, O_RDONLY);
+ if (fd < 0)
+ {
+ rb->splashf(HZ, "err opening %s:%d", filename, fd);
+ return PLUGIN_ERROR;
+ }
+ filesize = rb->filesize(fd);
+
+ /* allocate JPEG buffer */
+ buf_jpeg = buf;
+
+ /* we can start the decompressed images behind it */
+ buf_images = buf_root = buf + filesize;
+ buf_images_size = root_size = *buf_size - filesize;
+
+ if (buf_images_size <= 0)
+ {
+ rb->close(fd);
+ return PLUGIN_OUTOFMEM;
+ }
+
+ if(!running_slideshow)
+ {
+ rb->snprintf(print, sizeof(print), "%s:", rb->strrchr(filename,'/')+1);
+ rb->lcd_puts(0, 0, print);
+ rb->lcd_update();
+
+ rb->snprintf(print, sizeof(print), "loading %d bytes", filesize);
+ rb->lcd_puts(0, 1, print);
+ rb->lcd_update();
+ }
+
+ rb->read(fd, buf_jpeg, filesize);
+ rb->close(fd);
+
+ if(!running_slideshow)
+ {
+ rb->snprintf(print, sizeof(print), "decoding markers");
+ rb->lcd_puts(0, 2, 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
+
+ /* process markers, unstuffing */
+ status = process_markers(buf_jpeg, filesize, p_jpg);
+
+ if (status < 0 || (status & (DQT | SOF0)) != (DQT | SOF0))
+ { /* bad format or minimum components not contained */
+ rb->splashf(HZ, "unsupported %d", status);
+ return PLUGIN_ERROR;
+ }
+
+ if (!(status & DHT)) /* if no Huffman table present: */
+ default_huff_tbl(p_jpg); /* use default */
+ build_lut(p_jpg); /* derive Huffman and other lookup-tables */
+
+ if(!running_slideshow)
+ {
+ rb->snprintf(print, sizeof(print), "image %dx%d",
+ p_jpg->x_size, p_jpg->y_size);
+ rb->lcd_puts(0, 2, print);
+ rb->lcd_update();
+ }
+
+ info->x_size = p_jpg->x_size;
+ info->y_size = p_jpg->y_size;
+ *buf_size = buf_images_size;
+ return PLUGIN_OK;
+}
+
+int get_image(struct image_info *info, int ds)
+{
+ int w, h; /* used to center output */
+ int size; /* decompressed image size */
+ long time; /* measured ticks */
+ int status;
+ struct jpeg* p_jpg = &jpg;
+ struct t_disp* p_disp = &disp[ds]; /* short cut */
+
+ info->width = p_jpg->x_size / ds;
+ info->height = p_jpg->y_size / ds;
+ info->data = p_disp;
+
+ if (p_disp->bitmap[0] != NULL)
+ {
+ /* we still have it */
+ return PLUGIN_OK;
+ }
+
+ /* assign image buffer */
+
+ /* physical size needed for decoding */
+ 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[0] = NULL; /* invalidate all bitmaps */
+ buf_images = buf_root; /* start again from the beginning of the buffer */
+ buf_images_size = root_size;
+ }
+
+#ifdef HAVE_LCD_COLOR
+ if (p_jpg->blocks > 1) /* colour jpeg */
+ {
+ int i;
+
+ for (i = 1; i < 3; i++)
+ {
+ size = (p_jpg->x_phys / ds / p_jpg->subsample_x[i])
+ * (p_jpg->y_phys / ds / p_jpg->subsample_y[i]);
+ p_disp->bitmap[i] = buf_images;
+ buf_images += size;
+ buf_images_size -= size;
+ }
+ p_disp->csub_x = p_jpg->subsample_x[1];
+ p_disp->csub_y = p_jpg->subsample_y[1];
+ }
+ else
+ {
+ p_disp->csub_x = p_disp->csub_y = 0;
+ p_disp->bitmap[1] = p_disp->bitmap[2] = buf_images;
+ }
+#endif
+ /* size may be less when decoded (if height is not block aligned) */
+ size = (p_jpg->x_phys/ds) * (p_jpg->y_size/ds);
+ p_disp->bitmap[0] = buf_images;
+ buf_images += size;
+ buf_images_size -= size;
+
+ if(!running_slideshow)
+ {
+ rb->snprintf(print, sizeof(print), "decoding %d*%d",
+ p_jpg->x_size/ds, p_jpg->y_size/ds);
+ rb->lcd_puts(0, 3, print);
+ rb->lcd_update();
+ }
+
+ /* update image properties */
+ p_disp->stride = p_jpg->x_phys / ds; /* use physical size for stride */
+
+ /* the actual decoding */
+ time = *rb->current_tick;
+#ifdef HAVE_ADJUSTABLE_CPU_FREQ
+ rb->cpu_boost(true);
+ status = jpeg_decode(p_jpg, p_disp->bitmap, ds, cb_progress);
+ rb->cpu_boost(false);
+#else
+ status = jpeg_decode(p_jpg, p_disp->bitmap, ds, cb_progress);
+#endif
+ if (status)
+ {
+ rb->splashf(HZ, "decode error %d", status);
+ return PLUGIN_ERROR;
+ }
+ time = *rb->current_tick - time;
+
+ 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();
+ }
+
+ return PLUGIN_OK;
+}