rockbox/apps/plugins/imageviewer/jpegp/jpegp.c
Christian Soffke f4dc4d89dc plugins: imageviewer: Hide info by default when loading file
Looks nicer, especially when the "View Album Art"
option is used.

Add delay to progress bar, so it only appears when
250ms have passed.

Change-Id: I183c839f1ab206385cd01327922933b544c4b78b
2026-04-16 07:58:27 -04:00

292 lines
8.5 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 offset, int filesize)
{
(void)filesize;
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 (offset)
{
POS(offset);
}
if (!iv->settings->hide_info &&
!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->settings->hide_info &&
!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;
int max_y = info->height * ds;
int max_x = info->width * ds;
for (y = 0; y < max_y; y += ds)
{
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 < max_x; x += ds)
{
int c0, c1, c2;
if (ds == 1)
{
c0 = C0[(x / h0 / 8) * 64 + ((x / h0) & 7)];
c1 = C1[(x / h1 / 8) * 64 + ((x / h1) & 7)];
c2 = C2[(x / h2 / 8) * 64 + ((x / h2) & 7)];
}
else
{
/* Box filter downsampling (area averaging):
Average a ds*ds block of Y/U/V samples per output pixel
for simple anti-aliasing without extra buffers */
int sumY = 0, sumU = 0, sumV = 0;
int dx, dy;
int area = ds * ds;
for (dy = 0; dy < ds; dy++)
{
TCOEF *C0_dy = j->Components[0].du[j->Components[0].du_width * (((y + dy) / v0) / 8)] + 8 * (((y + dy) / v0) & 7);
TCOEF *C1_dy = j->Components[1].du[j->Components[1].du_width * (((y + dy) / v1) / 8)] + 8 * (((y + dy) / v1) & 7);
TCOEF *C2_dy = j->Components[2].du[j->Components[2].du_width * (((y + dy) / v2) / 8)] + 8 * (((y + dy) / v2) & 7);
for (dx = 0; dx < ds; dx++)
{
int sx = x + dx;
sumY += C0_dy[((sx / h0 / 8) * 64) + ((sx / h0) & 7)];
sumU += C1_dy[((sx / h1 / 8) * 64) + ((sx / h1) & 7)];
sumV += C2_dy[((sx / h2 / 8) * 64) + ((sx / h2) & 7)];
}
}
c0 = (sumY + area/2) / area;
c1 = (sumU + area/2) / area;
c2 = (sumV + area/2) / area;
}
// 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