mirror of
https://github.com/Rockbox/rockbox.git
synced 2025-10-14 02:27:39 -04:00
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:
parent
6d05e27d68
commit
6e3da841be
12 changed files with 574 additions and 358 deletions
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
bmp
|
bmp
|
||||||
jpeg
|
jpeg
|
||||||
png
|
png
|
||||||
|
#ifdef HAVE_LCD_COLOR
|
||||||
|
ppm
|
||||||
|
#endif
|
||||||
|
|
|
@ -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, '.');
|
||||||
|
|
|
@ -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
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
2
apps/plugins/imageviewer/ppm/SOURCES
Normal file
2
apps/plugins/imageviewer/ppm/SOURCES
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
ppm.c
|
||||||
|
ppm_decoder.c
|
233
apps/plugins/imageviewer/ppm/ppm.c
Normal file
233
apps/plugins/imageviewer/ppm/ppm.c
Normal 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
|
29
apps/plugins/imageviewer/ppm/ppm.make
Normal file
29
apps/plugins/imageviewer/ppm/ppm.make
Normal 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 $@
|
250
apps/plugins/imageviewer/ppm/ppm_decoder.c
Normal file
250
apps/plugins/imageviewer/ppm/ppm_decoder.c
Normal 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;
|
||||||
|
}
|
44
apps/plugins/imageviewer/ppm/ppm_decoder.h
Normal file
44
apps/plugins/imageviewer/ppm/ppm_decoder.h
Normal 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);
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -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,-
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue