mirror of
https://github.com/Rockbox/rockbox.git
synced 2025-10-13 18:17:39 -04:00
imageviewer: Initial support for JPEG progressive images. Add decoder
Added jpeg decoder jpegp.c using RAINBOW lib. Currently enabled only for pictures not supported by old decoder (as old decoder more optimized for low mem targets) Someone TODO: * Old decoder has optimized downscale logic which new decoder doesn't have (it gives big difference in required memory and time for decoding). This logic should be ported/adapted if possible. * Add smooth downscaling. * Grayscale support Change-Id: Ie96bc62848b51cc6a3942f8e069ec6ab02dc1c56
This commit is contained in:
parent
64ad7354b6
commit
b8238f7b20
19 changed files with 599 additions and 22 deletions
|
@ -51,6 +51,7 @@ iriverify,viewers
|
|||
jackpot,games
|
||||
jewels,games
|
||||
jpeg,viewers
|
||||
jpegp,viewers
|
||||
keybox,apps
|
||||
keyremap,apps
|
||||
lamp,apps
|
||||
|
|
|
@ -3,5 +3,6 @@ jpeg
|
|||
png
|
||||
#ifdef HAVE_LCD_COLOR
|
||||
ppm
|
||||
jpegp
|
||||
#endif
|
||||
gif
|
||||
|
|
|
@ -25,12 +25,13 @@
|
|||
|
||||
static const char *decoder_names[MAX_IMAGE_TYPES] = {
|
||||
"bmp",
|
||||
"jpeg",
|
||||
"jpeg", // Default decoder for jpeg: Use jpeg for old decoder, jpegp for new
|
||||
"png",
|
||||
#ifdef HAVE_LCD_COLOR
|
||||
"ppm",
|
||||
#endif
|
||||
"gif"
|
||||
"gif",
|
||||
"jpegp",
|
||||
};
|
||||
|
||||
/* Check file type by magic number or file extension
|
||||
|
|
|
@ -33,6 +33,8 @@ enum image_type {
|
|||
IMAGE_PPM,
|
||||
#endif
|
||||
IMAGE_GIF,
|
||||
IMAGE_JPEG_PROGRESSIVE,
|
||||
|
||||
MAX_IMAGE_TYPES
|
||||
};
|
||||
|
||||
|
|
|
@ -853,6 +853,8 @@ static int load_and_show(char* filename, struct image_info *info)
|
|||
file_pt[curfile] = NULL;
|
||||
return change_filename(direction);
|
||||
}
|
||||
|
||||
reload_decoder:
|
||||
if (image_type != status) /* type of image is changed, load decoder. */
|
||||
{
|
||||
struct loader_info loader_info = {
|
||||
|
@ -881,6 +883,13 @@ static int load_and_show(char* filename, struct image_info *info)
|
|||
else
|
||||
status = imgdec->load_image(filename, info, buf, &remaining);
|
||||
|
||||
if (status == PLUGIN_JPEG_PROGRESSIVE)
|
||||
{
|
||||
rb->lcd_clear_display();
|
||||
status = IMAGE_JPEG_PROGRESSIVE;
|
||||
goto reload_decoder;
|
||||
}
|
||||
|
||||
if (status == PLUGIN_OUTOFMEM)
|
||||
{
|
||||
#ifdef USE_PLUG_BUF
|
||||
|
|
|
@ -55,6 +55,7 @@ enum {
|
|||
PLUGIN_OTHER = 0x200,
|
||||
PLUGIN_ABORT,
|
||||
PLUGIN_OUTOFMEM,
|
||||
PLUGIN_JPEG_PROGRESSIVE,
|
||||
|
||||
ZOOM_IN,
|
||||
ZOOM_OUT,
|
||||
|
|
|
@ -170,8 +170,12 @@ static int load_image(char *filename, struct image_info *info,
|
|||
|
||||
if (status < 0 || (status & (DQT | SOF0)) != (DQT | SOF0))
|
||||
{ /* bad format or minimum components not contained */
|
||||
#ifndef HAVE_LCD_COLOR
|
||||
rb->splashf(HZ, "unsupported %d", status);
|
||||
return PLUGIN_ERROR;
|
||||
#else
|
||||
return PLUGIN_JPEG_PROGRESSIVE;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (!(status & DHT)) /* if no Huffman table present: */
|
||||
|
|
94
apps/plugins/imageviewer/jpegp/BUFFILEGETC.c
Normal file
94
apps/plugins/imageviewer/jpegp/BUFFILEGETC.c
Normal file
|
@ -0,0 +1,94 @@
|
|||
/* Simple buffered version of file reader.
|
||||
* JPEG decoding seems to work faster with it.
|
||||
* Not fully tested. In case of any issues try FILEGETC (see SOURCES)
|
||||
* */
|
||||
#include "rb_glue.h"
|
||||
|
||||
static int fd;
|
||||
static unsigned char buff[256]; //TODO: Adjust it...
|
||||
static int length = 0;
|
||||
static int cur_buff_pos = 0;
|
||||
static int file_pos = 0;
|
||||
|
||||
extern int GETC(void)
|
||||
{
|
||||
if (cur_buff_pos >= length)
|
||||
{
|
||||
length = rb->read(fd, buff, sizeof(buff));
|
||||
file_pos += length;
|
||||
cur_buff_pos = 0;
|
||||
}
|
||||
|
||||
return buff[cur_buff_pos++];
|
||||
}
|
||||
|
||||
// multibyte readers: host-endian independent - if evaluated in right order (ie. don't optimize)
|
||||
|
||||
extern int GETWbi(void) // 16-bit big-endian
|
||||
{
|
||||
return ( GETC()<<8 ) | GETC();
|
||||
}
|
||||
|
||||
extern int GETDbi(void) // 32-bit big-endian
|
||||
{
|
||||
return ( GETC()<<24 ) | ( GETC()<<16 ) | ( GETC()<<8 ) | GETC();
|
||||
}
|
||||
|
||||
extern int GETWli(void) // 16-bit little-endian
|
||||
{
|
||||
return GETC() | ( GETC()<<8 );
|
||||
}
|
||||
|
||||
extern int GETDli(void) // 32-bit little-endian
|
||||
{
|
||||
return GETC() | ( GETC()<<8 ) | ( GETC()<<16 ) | ( GETC()<<24 );
|
||||
}
|
||||
|
||||
// seek
|
||||
|
||||
extern void SEEK(int d)
|
||||
{
|
||||
int newPos = cur_buff_pos + d;
|
||||
if (newPos < length && newPos >= 0)
|
||||
{
|
||||
cur_buff_pos = newPos;
|
||||
return;
|
||||
}
|
||||
file_pos = rb->lseek(fd, (cur_buff_pos - length) + d, SEEK_CUR);
|
||||
cur_buff_pos = length = 0;
|
||||
}
|
||||
|
||||
extern void POS(int d)
|
||||
{
|
||||
cur_buff_pos = length = 0;
|
||||
file_pos = d;
|
||||
rb->lseek(fd, d, SEEK_SET);
|
||||
}
|
||||
|
||||
extern int TELL(void)
|
||||
{
|
||||
return file_pos + cur_buff_pos - length;
|
||||
}
|
||||
|
||||
// OPEN/CLOSE file
|
||||
|
||||
extern void *OPEN(char *f)
|
||||
{
|
||||
printf("Opening %s\n", f);
|
||||
cur_buff_pos = length = file_pos = 0;
|
||||
fd = rb->open(f,O_RDONLY);
|
||||
|
||||
if ( fd < 0 )
|
||||
{
|
||||
printf("Error opening %s\n", f);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return &fd;
|
||||
}
|
||||
|
||||
extern int CLOSE(void)
|
||||
{
|
||||
cur_buff_pos = length = file_pos = 0;
|
||||
return rb->close(fd);
|
||||
}
|
71
apps/plugins/imageviewer/jpegp/FILEGETC.c
Normal file
71
apps/plugins/imageviewer/jpegp/FILEGETC.c
Normal file
|
@ -0,0 +1,71 @@
|
|||
#include "rb_glue.h"
|
||||
|
||||
static int fd;
|
||||
|
||||
extern int GETC(void)
|
||||
{
|
||||
unsigned char x;
|
||||
rb->read(fd, &x, 1);
|
||||
return x;
|
||||
}
|
||||
|
||||
// multibyte readers: host-endian independent - if evaluated in right order (ie. don't optimize)
|
||||
|
||||
extern int GETWbi(void) // 16-bit big-endian
|
||||
{
|
||||
return ( GETC()<<8 ) | GETC();
|
||||
}
|
||||
|
||||
extern int GETDbi(void) // 32-bit big-endian
|
||||
{
|
||||
return ( GETC()<<24 ) | ( GETC()<<16 ) | ( GETC()<<8 ) | GETC();
|
||||
}
|
||||
|
||||
extern int GETWli(void) // 16-bit little-endian
|
||||
{
|
||||
return GETC() | ( GETC()<<8 );
|
||||
}
|
||||
|
||||
extern int GETDli(void) // 32-bit little-endian
|
||||
{
|
||||
return GETC() | ( GETC()<<8 ) | ( GETC()<<16 ) | ( GETC()<<24 );
|
||||
}
|
||||
|
||||
// seek
|
||||
|
||||
extern void SEEK(int d)
|
||||
{
|
||||
rb->lseek(fd, d, SEEK_CUR);
|
||||
}
|
||||
|
||||
extern void POS(int d)
|
||||
{
|
||||
rb->lseek(fd, d, SEEK_SET);
|
||||
}
|
||||
|
||||
extern int TELL(void)
|
||||
{
|
||||
return rb->lseek(fd, 0, SEEK_CUR);
|
||||
}
|
||||
|
||||
// OPEN/CLOSE file
|
||||
|
||||
extern void *OPEN(char *f)
|
||||
{
|
||||
printf("Opening %s\n", f);
|
||||
|
||||
fd = rb->open(f,O_RDONLY);
|
||||
|
||||
if ( fd < 0 )
|
||||
{
|
||||
printf("Error opening %s\n", f);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return &fd;
|
||||
}
|
||||
|
||||
extern int CLOSE(void)
|
||||
{
|
||||
return rb->close(fd);
|
||||
}
|
|
@ -37,20 +37,20 @@
|
|||
|
||||
// For decoders
|
||||
|
||||
extern int GETC();
|
||||
extern int GETC(void);
|
||||
|
||||
// Multibyte helpers
|
||||
extern int GETWbi(); // read word (16-bit) big-endian
|
||||
extern int GETWli(); // little-endian
|
||||
extern int GETDbi(); // read double word (32-bit) big-endian
|
||||
extern int GETDli(); // little-endian
|
||||
extern int GETWbi(void); // read word (16-bit) big-endian
|
||||
extern int GETWli(void); // little-endian
|
||||
extern int GETDbi(void); // read double word (32-bit) big-endian
|
||||
extern int GETDli(void); // little-endian
|
||||
|
||||
// positioning
|
||||
extern void SEEK(int); // move relative to current
|
||||
extern void POS(int); // move absolute position (TIFF)
|
||||
extern int TELL(); // read actual position
|
||||
extern int TELL(void); // read actual position
|
||||
|
||||
|
||||
// For RAINBOW clients to implement outside of Rainbow Library
|
||||
extern void *OPEN(char*);
|
||||
extern void CLOSE();
|
||||
extern void CLOSE(void);
|
||||
|
|
6
apps/plugins/imageviewer/jpegp/SOURCES
Normal file
6
apps/plugins/imageviewer/jpegp/SOURCES
Normal file
|
@ -0,0 +1,6 @@
|
|||
jpegp.c
|
||||
//FILEGETC.c
|
||||
BUFFILEGETC.c
|
||||
jpeg81.c
|
||||
idct.c
|
||||
mempool.c
|
|
@ -40,12 +40,12 @@ jpeg81.c
|
|||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "GETC.h"
|
||||
#include "GETC.h"
|
||||
#include "rb_glue.h"
|
||||
#include "jpeg81.h"
|
||||
#include <malloc.h> // calloc() called once
|
||||
#include <stdio.h> // debug only
|
||||
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wunused-parameter"
|
||||
///////////////////////////////////////// LOSSLESS /////////////////////////////////////////
|
||||
|
||||
static int P1(struct COMP *C, TSAMP *samp) // Px = Ra
|
||||
|
@ -63,17 +63,17 @@ static int P3(struct COMP *C, TSAMP *samp) // Px = Rc
|
|||
return samp[-C->du_width-1];
|
||||
}
|
||||
|
||||
static int P4(struct COMP *C, TSAMP *samp) // Px = Ra + Rb – Rc
|
||||
static int P4(struct COMP *C, TSAMP *samp) // Px = Ra + Rb - Rc
|
||||
{
|
||||
return samp[-1] + samp[-C->du_width] - samp[-C->du_width-1];
|
||||
}
|
||||
|
||||
static int P5(struct COMP *C, TSAMP *samp) // Px = Ra + ((Rb – Rc)/2)
|
||||
static int P5(struct COMP *C, TSAMP *samp) // Px = Ra + ((Rb - Rc)/2)
|
||||
{
|
||||
return samp[-1] + ( (samp[-C->du_width] - samp[-C->du_width-1]) >> 1 );
|
||||
}
|
||||
|
||||
static int P6(struct COMP *C, TSAMP *samp) // Px = Rb + ((Ra – Rc)/2)
|
||||
static int P6(struct COMP *C, TSAMP *samp) // Px = Rb + ((Ra - Rc)/2)
|
||||
{
|
||||
return samp[-C->du_width] + ( (samp[-1] - samp[-C->du_width-1]) >> 1 );
|
||||
}
|
||||
|
@ -215,7 +215,7 @@ static void du_sequential_huff(struct JPEGD *j, struct COMP *sc, TCOEF *coef)
|
|||
{
|
||||
int s, k;
|
||||
dc_decode_huff(j, sc, coef);
|
||||
for (k=1; s=sc->ACS[ReadHuffmanCode(j, sc->ACB)]; k++) { // EOB?
|
||||
for (k=1; (s=sc->ACS[ReadHuffmanCode(j, sc->ACB)]); k++) { // EOB?
|
||||
k+= s>>4;
|
||||
if (s==0xf0) continue; // ZRL
|
||||
coef[k]= ReadDiff(j, s&15);
|
||||
|
@ -496,7 +496,7 @@ static void Ri(struct JPEGD *j, int n)
|
|||
printf("RST%d\n", Marker&7);
|
||||
printf("%08X: ECS\n", TELL());
|
||||
}
|
||||
else printf("STREAM ERROR: expected RSTn missing from ECS\n");
|
||||
else { printf("STREAM ERROR: expected RSTn missing from ECS\n"); }
|
||||
j->Reset_decoder(j);
|
||||
}
|
||||
}
|
||||
|
@ -832,7 +832,7 @@ extern enum JPEGENUM JPEGDecode(struct JPEGD *j)
|
|||
}
|
||||
}
|
||||
|
||||
printf(" Malloc for %d Data Units (%d bytes)\n\n", TotalDU, sizeof(DU)*TotalDU);
|
||||
printf(" Malloc for %d Data Units (%lu bytes)\n\n", TotalDU, sizeof(DU)*TotalDU);
|
||||
|
||||
if (j->SOF > 0xC8) { // DCT Arithmetic
|
||||
j->Reset_decoder= Reset_decoder_arith;
|
||||
|
@ -953,7 +953,7 @@ extern enum JPEGENUM JPEGDecode(struct JPEGD *j)
|
|||
|
||||
for (Lq-=2; Lq; Lq -= 65 + 64*Pq)
|
||||
{
|
||||
int (*get)();
|
||||
int (*get)(void);
|
||||
int T= GETC();
|
||||
int Tq= T&3;
|
||||
int *qt= j->QT[Tq];
|
||||
|
@ -993,3 +993,5 @@ extern enum JPEGENUM JPEGDecode(struct JPEGD *j)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#pragma GCC diagnostic pop
|
|
@ -144,4 +144,4 @@ struct JPEGD { // The JPEG DECODER OBJECT
|
|||
|
||||
};
|
||||
|
||||
extern int JPEGDecode(struct JPEGD *j);
|
||||
extern enum JPEGENUM JPEGDecode(struct JPEGD *j);
|
||||
|
|
260
apps/plugins/imageviewer/jpegp/jpegp.c
Normal file
260
apps/plugins/imageviewer/jpegp/jpegp.c
Normal file
|
@ -0,0 +1,260 @@
|
|||
#include "jpeg81.h"
|
||||
#include "idct.h"
|
||||
#include "GETC.h"
|
||||
#include "rb_glue.h"
|
||||
|
||||
#include "../imageviewer.h"
|
||||
|
||||
|
||||
/**************** begin Application ********************/
|
||||
|
||||
/************************* Types ***************************/
|
||||
|
||||
struct t_disp
|
||||
{
|
||||
unsigned char* bitmap;
|
||||
};
|
||||
|
||||
/************************* Globals ***************************/
|
||||
|
||||
/* decompressed image in the possible sizes (1,2,4,8), wasting the other */
|
||||
static struct t_disp disp[9];
|
||||
|
||||
static struct JPEGD jpg; /* too large for stack */
|
||||
|
||||
/************************* Implementation ***************************/
|
||||
|
||||
static 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
|
||||
rb->lcd_bitmap_part(
|
||||
(fb_data*)pdisp->bitmap, 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->bitmap, 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)
|
||||
{
|
||||
struct JPEGD* j = &jpg;
|
||||
return j->Y/ds * j->X/ds*sizeof(fb_data);
|
||||
}
|
||||
|
||||
/* my memory pool (from the mp3 buffer) */
|
||||
static char print[32]; /* use a common snprintf() buffer */
|
||||
|
||||
static void scaled_dequantization_and_idct(void)
|
||||
{
|
||||
struct JPEGD* j = &jpg;
|
||||
// The following code is based on RAINBOW lib jpeg2bmp example:
|
||||
// https://github.com/Halicery/vc_rainbow/blob/605c045a564dad8e2df84e48914eac3d2d8d4a9b/jpeg2bmp.c
|
||||
|
||||
printf("Scaled de-quantization and IDCT.. ");
|
||||
int c, i, n;
|
||||
|
||||
// Pre-scale quant-tables
|
||||
int SQ[4][64];
|
||||
for (c=0; c<4 && j->QT[c][0]; c++)
|
||||
{
|
||||
int *q= j->QT[c], *sq= SQ[c];
|
||||
for (i=0; i<64; i++) sq[i]= q[i] * SCALEM[zigzag[i]];
|
||||
}
|
||||
|
||||
// DEQUANT + IDCT
|
||||
for (c=0; c<j->Nf; c++)
|
||||
{
|
||||
struct COMP *C= j->Components+c;
|
||||
//int *q= j->QT[C->Qi];
|
||||
int *sq= SQ[C->Qi];
|
||||
|
||||
for (n=0; n < C->du_size; n++)
|
||||
{
|
||||
/*
|
||||
// <--- scaled idct
|
||||
int k, t[64];
|
||||
TCOEF *coef= du[x];
|
||||
t[0]= coef[0] * q[0] + 1024; // dequant DC and level-shift (8-bit)
|
||||
for (k=1; k<64; k++) t[zigzag[k]] = coef[k] * q[k]; // dequant AC (+zigzag)
|
||||
idct_s(t, coef);
|
||||
*/
|
||||
|
||||
// <--- scaled idct with dequant
|
||||
idct_sq( C->du[ (n / C->du_w) * C->du_width + n % C->du_w ], sq );
|
||||
}
|
||||
}
|
||||
printf("done\n");
|
||||
}
|
||||
|
||||
static int load_image(char *filename, struct image_info *info,
|
||||
unsigned char *buf, ssize_t *buf_size)
|
||||
{
|
||||
int status;
|
||||
struct JPEGD *p_jpg = &jpg;
|
||||
|
||||
memset(&disp, 0, sizeof(disp));
|
||||
memset(&jpg, 0, sizeof(jpg));
|
||||
|
||||
init_mem_pool(buf, *buf_size);
|
||||
|
||||
if (!OPEN(filename))
|
||||
{
|
||||
return PLUGIN_ERROR;
|
||||
}
|
||||
|
||||
if (!iv->running_slideshow)
|
||||
{
|
||||
rb->lcd_puts(0, 0, rb->strrchr(filename,'/')+1);
|
||||
rb->lcd_puts(0, 2, "decoding...");
|
||||
rb->lcd_update();
|
||||
}
|
||||
long time; /* measured ticks */
|
||||
|
||||
/* the actual decoding */
|
||||
time = *rb->current_tick;
|
||||
status = JPEGDecode(p_jpg);
|
||||
time = *rb->current_tick - time;
|
||||
|
||||
CLOSE();
|
||||
|
||||
if (status < 0)
|
||||
{ /* bad format or minimum components not contained */
|
||||
if (status == JPEGENUMERR_MALLOC)
|
||||
{
|
||||
return PLUGIN_OUTOFMEM;
|
||||
}
|
||||
rb->splashf(HZ, "unsupported %d", status);
|
||||
return PLUGIN_ERROR;
|
||||
}
|
||||
|
||||
if (!iv->running_slideshow)
|
||||
{
|
||||
rb->lcd_putsf(0, 2, "image %dx%d", p_jpg->X, p_jpg->Y);
|
||||
int w, h; /* used to center output */
|
||||
rb->snprintf(print, sizeof(print), "jpegp %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();
|
||||
//rb->sleep(100);
|
||||
}
|
||||
|
||||
info->x_size = p_jpg->X;
|
||||
info->y_size = p_jpg->Y;
|
||||
|
||||
#ifdef DISK_SPINDOWN
|
||||
if (iv->running_slideshow && iv->immediate_ata_off)
|
||||
{
|
||||
/* running slideshow and time is long enough: power down disk */
|
||||
rb->storage_sleep();
|
||||
}
|
||||
#endif
|
||||
|
||||
if ( 3 != p_jpg->Nf )
|
||||
return PLUGIN_ERROR;
|
||||
|
||||
scaled_dequantization_and_idct();
|
||||
|
||||
*buf_size = freeze_mem_pool();
|
||||
return PLUGIN_OK;
|
||||
}
|
||||
|
||||
static int get_image(struct image_info *info, int frame, int ds)
|
||||
{
|
||||
(void)frame;
|
||||
struct JPEGD* p_jpg = &jpg;
|
||||
struct t_disp* p_disp = &disp[ds]; /* short cut */
|
||||
|
||||
info->width = p_jpg->X / ds;
|
||||
info->height = p_jpg->Y / ds;
|
||||
info->data = p_disp;
|
||||
|
||||
if (p_disp->bitmap != NULL)
|
||||
{
|
||||
/* we still have it */
|
||||
return PLUGIN_OK;
|
||||
}
|
||||
|
||||
struct JPEGD* j = p_jpg;
|
||||
int mem = img_mem(ds);
|
||||
|
||||
p_disp->bitmap = malloc(mem);
|
||||
|
||||
if (!p_disp->bitmap)
|
||||
{
|
||||
clear_mem_pool();
|
||||
memset(&disp, 0, sizeof(disp));
|
||||
p_disp->bitmap = malloc(mem);
|
||||
if (!p_disp->bitmap)
|
||||
return PLUGIN_ERROR;
|
||||
}
|
||||
|
||||
fb_data *bmp = (fb_data *)p_disp->bitmap;
|
||||
|
||||
// The following code is based on RAINBOW lib jpeg2bmp example:
|
||||
// https://github.com/Halicery/vc_rainbow/blob/605c045a564dad8e2df84e48914eac3d2d8d4a9b/jpeg2bmp.c
|
||||
// Primitive yuv-rgb converter for all sub-sampling types, 24-bit BMP only
|
||||
printf("YUV-to-RGB conversion.. ");
|
||||
int h0 = j->Hmax / j->Components[0].Hi;
|
||||
int v0 = j->Vmax / j->Components[0].Vi;
|
||||
int h1 = j->Hmax / j->Components[1].Hi;
|
||||
int v1 = j->Vmax / j->Components[1].Vi;
|
||||
int h2 = j->Hmax / j->Components[2].Hi;
|
||||
int v2 = j->Vmax / j->Components[2].Vi;
|
||||
|
||||
int x, y;
|
||||
for (y = 0; y < j->Y; y++)
|
||||
{
|
||||
if (y%ds != 0)
|
||||
continue;
|
||||
|
||||
TCOEF *C0 =
|
||||
j->Components[0].du[j->Components[0].du_width * ((y / v0) / 8)] + 8 * ((y / v0) & 7);
|
||||
TCOEF *C1 =
|
||||
j->Components[1].du[j->Components[1].du_width * ((y / v1) / 8)] + 8 * ((y / v1) & 7);
|
||||
TCOEF *C2 =
|
||||
j->Components[2].du[j->Components[2].du_width * ((y / v2) / 8)] + 8 * ((y / v2) & 7);
|
||||
|
||||
for (x = 0; x < j->X; x++)
|
||||
{
|
||||
if (x%ds != 0)
|
||||
continue;
|
||||
|
||||
TCOEF c0 = C0[(x / h0 / 8) * 64 + ((x / h0) & 7)];
|
||||
TCOEF c1 = C1[(x / h1 / 8) * 64 + ((x / h1) & 7)];
|
||||
TCOEF c2 = C2[(x / h2 / 8) * 64 + ((x / h2) & 7)];
|
||||
|
||||
// ITU BT.601 full-range YUV-to-RGB integer approximation
|
||||
{
|
||||
int y = (c0 << 5) + 16;
|
||||
int u = c1 - 128;
|
||||
int v = c2 - 128;
|
||||
|
||||
int b = CLIP[(y + 57 * u)>>5]; // B;
|
||||
int g = CLIP[(y - 11 * u - 23 * v)>>5]; // G
|
||||
int r = CLIP[(y + 45 * v)>>5]; // R;
|
||||
*bmp++= FB_RGBPACK(r,g,b);
|
||||
}
|
||||
}
|
||||
}
|
||||
printf("done\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct image_decoder image_decoder = {
|
||||
false,
|
||||
img_mem,
|
||||
load_image,
|
||||
get_image,
|
||||
draw_image_rect,
|
||||
};
|
||||
|
||||
IMGDEC_HEADER
|
32
apps/plugins/imageviewer/jpegp/jpegp.make
Normal file
32
apps/plugins/imageviewer/jpegp/jpegp.make
Normal file
|
@ -0,0 +1,32 @@
|
|||
# __________ __ ___.
|
||||
# Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
# \/ \/ \/ \/ \/
|
||||
# $Id$
|
||||
#
|
||||
|
||||
JPEGPSRCDIR := $(IMGVSRCDIR)/jpegp
|
||||
JPEGPBUILDDIR := $(IMGVBUILDDIR)/jpegp
|
||||
|
||||
JPEGP_SRC := $(call preprocess, $(JPEGPSRCDIR)/SOURCES)
|
||||
JPEGP_OBJ := $(call c2obj, $(JPEGP_SRC))
|
||||
|
||||
OTHER_SRC += $(JPEGP_SRC)
|
||||
|
||||
ROCKS += $(JPEGPBUILDDIR)/jpegp.ovl
|
||||
|
||||
$(JPEGPBUILDDIR)/jpegp.refmap: $(JPEGP_OBJ) $(TLSFLIB)
|
||||
$(JPEGPBUILDDIR)/jpegp.link: $(PLUGIN_LDS) $(JPEGPBUILDDIR)/jpegp.refmap
|
||||
$(JPEGPBUILDDIR)/jpegp.ovl: $(JPEGP_OBJ) $(TLSFLIB)
|
||||
|
||||
JPEGPFLAGS = $(IMGDECFLAGS)
|
||||
ifndef DEBUG
|
||||
JPEGPFLAGS += -Os
|
||||
endif
|
||||
|
||||
# Compile plugin with extra flags (adapted from ZXBox)
|
||||
$(JPEGPBUILDDIR)/%.o: $(JPEGPSRCDIR)/%.c $(JPEGPSRCDIR)/jpegp.make
|
||||
$(SILENT)mkdir -p $(dir $@)
|
||||
$(call PRINTS,CC $(subst $(ROOTDIR)/,,$<))$(CC) -I$(dir $<) $(JPEGPFLAGS) -c $< -o $@
|
50
apps/plugins/imageviewer/jpegp/mempool.c
Normal file
50
apps/plugins/imageviewer/jpegp/mempool.c
Normal file
|
@ -0,0 +1,50 @@
|
|||
#include <inttypes.h>
|
||||
#include "plugin.h"
|
||||
|
||||
static unsigned char *mem_pool;
|
||||
static unsigned char *mem_pool_start;
|
||||
static size_t memory_size;
|
||||
|
||||
extern void *malloc(size_t size)
|
||||
{
|
||||
if (size > memory_size)
|
||||
return NULL;
|
||||
|
||||
memory_size -= size;
|
||||
unsigned char* ptr = mem_pool;
|
||||
|
||||
mem_pool+= size;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
extern void *calloc(size_t nelem, size_t elem_size)
|
||||
{
|
||||
unsigned char* ptr = malloc(nelem*elem_size);
|
||||
if (!ptr)
|
||||
return NULL;
|
||||
rb->memset(ptr, 0, nelem*elem_size);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
extern void init_mem_pool(const unsigned char *buf, const ssize_t buf_size)
|
||||
{
|
||||
//TODO: do we need this alignment? (copied from gif lib)
|
||||
unsigned char *memory_max;
|
||||
|
||||
/* align buffer */
|
||||
mem_pool_start = mem_pool = (unsigned char *)((intptr_t)(buf + 3) & ~3);
|
||||
memory_max = (unsigned char *)((intptr_t)(mem_pool + buf_size) & ~3);
|
||||
memory_size = memory_max - mem_pool;
|
||||
}
|
||||
|
||||
extern ssize_t freeze_mem_pool(void)
|
||||
{
|
||||
mem_pool_start = mem_pool;
|
||||
return memory_size;
|
||||
}
|
||||
|
||||
extern void clear_mem_pool(void)
|
||||
{
|
||||
memory_size += mem_pool - mem_pool_start;
|
||||
mem_pool = mem_pool_start;
|
||||
}
|
7
apps/plugins/imageviewer/jpegp/mempool.h
Normal file
7
apps/plugins/imageviewer/jpegp/mempool.h
Normal file
|
@ -0,0 +1,7 @@
|
|||
#include <inttypes.h>
|
||||
|
||||
extern void init_mem_pool(const unsigned char *buf, const ssize_t buf_size);
|
||||
extern void *malloc(size_t size);
|
||||
extern void *calloc(size_t nelem, size_t elem_size);
|
||||
extern ssize_t freeze_mem_pool(void);
|
||||
extern void clear_mem_pool(void);
|
35
apps/plugins/imageviewer/jpegp/rb_glue.h
Normal file
35
apps/plugins/imageviewer/jpegp/rb_glue.h
Normal file
|
@ -0,0 +1,35 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
* 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 "mempool.h"
|
||||
|
||||
//define from rbunicode.h clashes with jpeg81.h struct
|
||||
#undef COMP
|
||||
|
||||
#undef memset
|
||||
#define memset(a,b,c) rb->memset((a),(b),(c))
|
||||
|
||||
#if defined(DEBUG) || defined(SIMULATOR)
|
||||
#define printf rb->debugf
|
||||
#else
|
||||
#undef printf
|
||||
#define printf(...)
|
||||
#endif
|
|
@ -161,7 +161,8 @@ for JPEG images.
|
|||
\end{description}
|
||||
|
||||
\note{
|
||||
Progressive scan and other unusual JPEG files are not supported, and will
|
||||
\opt{lcd_color}{Progressive scan is supported. Unsupported JPEG files}
|
||||
\nopt{lcd_color}{Progressive scan and other unusual JPEG files are not supported, and} will
|
||||
result in various ``unsupported xx'' messages. Processing could also fail if the
|
||||
image is too big to decode which will be explained by a respective message.
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue