1
0
Fork 0
forked from len0rd/rockbox
foxbox/apps/plugins/imageviewer/jpegp/jpegp.c
Roman Artiukhin b8238f7b20 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
2024-10-14 09:19:34 -04:00

260 lines
7 KiB
C

#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