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
This commit is contained in:
Marcin Bukat 2011-01-09 13:22:54 +00:00
parent 6d05e27d68
commit 6e3da841be
12 changed files with 574 additions and 358 deletions

View file

@ -71,7 +71,7 @@ pitch_detector,apps
plasma,demos plasma,demos
png,viewers png,viewers
pong,games pong,games
ppmviewer,viewers ppm,viewers
properties,viewers properties,viewers
random_folder_advance_config,apps random_folder_advance_config,apps
remote_control,apps remote_control,apps

View file

@ -182,7 +182,6 @@ plasma.c
#ifdef HAVE_LCD_COLOR #ifdef HAVE_LCD_COLOR
clix.c clix.c
ppmviewer.c
codebuster.c codebuster.c
#endif #endif

View file

@ -1,3 +1,6 @@
bmp bmp
jpeg jpeg
png png
#ifdef HAVE_LCD_COLOR
ppm
#endif

View file

@ -27,6 +27,9 @@ static const char *decoder_names[MAX_IMAGE_TYPES] = {
"bmp", "bmp",
"jpeg", "jpeg",
"png", "png",
#ifdef HAVE_LCD_COLOR
"ppm"
#endif
}; };
/* check file type by extention */ /* check file type by extention */
@ -41,6 +44,9 @@ enum image_type get_image_type(const char *name)
{ ".jpe", IMAGE_JPEG }, { ".jpe", IMAGE_JPEG },
{ ".jpeg", IMAGE_JPEG }, { ".jpeg", IMAGE_JPEG },
{ ".png", IMAGE_PNG }, { ".png", IMAGE_PNG },
#ifdef HAVE_LCD_COLOR
{ ".ppm", IMAGE_PPM },
#endif
}; };
const char *ext = rb->strrchr(name, '.'); const char *ext = rb->strrchr(name, '.');

View file

@ -29,6 +29,9 @@ enum image_type {
IMAGE_BMP = 0, IMAGE_BMP = 0,
IMAGE_JPEG, IMAGE_JPEG,
IMAGE_PNG, IMAGE_PNG,
#ifdef HAVE_LCD_COLOR
IMAGE_PPM,
#endif
MAX_IMAGE_TYPES MAX_IMAGE_TYPES
}; };

View file

@ -0,0 +1,2 @@
ppm.c
ppm_decoder.c

View file

@ -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 <lib/pluginlib_bmp.h>
#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

View file

@ -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 $@

View file

@ -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;
}

View file

@ -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);

View file

@ -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;
}

View file

@ -20,6 +20,9 @@ jpeg,viewers/test_core_jpeg,-
jpeg,viewers/test_mem_jpeg,- jpeg,viewers/test_mem_jpeg,-
jpeg,viewers/bench_mem_jpeg,- jpeg,viewers/bench_mem_jpeg,-
png,viewers/imageviewer,2 png,viewers/imageviewer,2
#ifdef HAVE_LCD_COLOR
ppm,viewers/imageviewer,2
#endif
ucl,viewers/rockbox_flash,3 ucl,viewers/rockbox_flash,3
rvf,viewers/video,4 rvf,viewers/video,4
mp3,viewers/vbrfix,5 mp3,viewers/vbrfix,5
@ -73,7 +76,6 @@ tap,viewers/zxbox,12
sna,viewers/zxbox,12 sna,viewers/zxbox,12
tzx,viewers/zxbox,12 tzx,viewers/zxbox,12
z80,viewers/zxbox,12 z80,viewers/zxbox,12
ppm,viewers/ppmviewer,2
cfg,viewers/theme_remove,- cfg,viewers/theme_remove,-
*,viewers/properties,- *,viewers/properties,-
*,viewers/shortcuts_append,- *,viewers/shortcuts_append,-