forked from len0rd/rockbox
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
This commit is contained in:
parent
135d983433
commit
5bd0823749
33 changed files with 1048 additions and 1995 deletions
308
apps/plugins/imageviewer/jpeg/jpeg.c
Normal file
308
apps/plugins/imageviewer/jpeg/jpeg.c
Normal file
|
|
@ -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;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue