forked from len0rd/rockbox
maintain view center when zooming, cache the previous zoom image as far as memory allows
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@4630 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
e3a3a55ab0
commit
363dc4b175
1 changed files with 146 additions and 61 deletions
|
@ -2872,15 +2872,14 @@ int jpeg_decode(struct jpeg* p_jpeg, unsigned char* p_pixel, int downscale,
|
||||||
int k_need; /* AC coefficients needed up to here */
|
int k_need; /* AC coefficients needed up to here */
|
||||||
int zero_need; /* init the block with this many zeros */
|
int zero_need; /* init the block with this many zeros */
|
||||||
|
|
||||||
int last_dc_val[4];
|
int last_dc_val = 0;
|
||||||
int store_offs[4]; /* memory offsets: order of Y11 Y12 Y21 Y22 U V */
|
int store_offs[4]; /* memory offsets: order of Y11 Y12 Y21 Y22 U V */
|
||||||
MEMSET(&last_dc_val, 0, sizeof(last_dc_val));
|
|
||||||
|
|
||||||
/* pick the IDCT we want, determine how to work with coefs */
|
/* pick the IDCT we want, determine how to work with coefs */
|
||||||
if (downscale == 1)
|
if (downscale == 1)
|
||||||
{
|
{
|
||||||
pf_idct = idct8x8;
|
pf_idct = idct8x8;
|
||||||
k_need = 63; /* all */
|
k_need = 64; /* all */
|
||||||
zero_need = 63; /* all */
|
zero_need = 63; /* all */
|
||||||
}
|
}
|
||||||
else if (downscale == 2)
|
else if (downscale == 2)
|
||||||
|
@ -2940,14 +2939,17 @@ int jpeg_decode(struct jpeg* p_jpeg, unsigned char* p_pixel, int downscale,
|
||||||
struct derived_tbl* actbl = &p_jpeg->ac_derived_tbls[ti];
|
struct derived_tbl* actbl = &p_jpeg->ac_derived_tbls[ti];
|
||||||
|
|
||||||
/* Section F.2.2.1: decode the DC coefficient difference */
|
/* Section F.2.2.1: decode the DC coefficient difference */
|
||||||
last_dc_val[ci] += huff_decode_dc(&bs, dctbl);
|
s = huff_decode_dc(&bs, dctbl);
|
||||||
block[0] = last_dc_val[ci]; /* output it (assumes zag[0] = 0) */
|
|
||||||
|
|
||||||
/* Section F.2.2.2: decode the AC coefficients */
|
|
||||||
if (ci == 0) /* only for Y component */
|
if (ci == 0) /* only for Y component */
|
||||||
{
|
{
|
||||||
|
last_dc_val += s;
|
||||||
|
block[0] = last_dc_val; /* output it (assumes zag[0] = 0) */
|
||||||
|
|
||||||
/* coefficient buffer must be cleared */
|
/* coefficient buffer must be cleared */
|
||||||
MEMSET(block+1, 0, zero_need*sizeof(int));
|
MEMSET(block+1, 0, zero_need*sizeof(int));
|
||||||
|
|
||||||
|
/* Section F.2.2.2: decode the AC coefficients */
|
||||||
for (; k < k_need; k++)
|
for (; k < k_need; k++)
|
||||||
{
|
{
|
||||||
s = huff_decode_ac(&bs, actbl);
|
s = huff_decode_ac(&bs, actbl);
|
||||||
|
@ -3027,6 +3029,18 @@ struct t_disp
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/************************* Globals ***************************/
|
||||||
|
|
||||||
|
/* decompressed image in the possible sizes (1,2,4,8), wasting the other */
|
||||||
|
struct t_disp disp[9];
|
||||||
|
|
||||||
|
/* my memory pool (from the mp3 buffer) */
|
||||||
|
char print[32]; /* use a common snprintf() buffer */
|
||||||
|
unsigned char* buf; /* up to here currently used by image(s) */
|
||||||
|
int buf_size;
|
||||||
|
unsigned char* buf_root; /* the root of the images */
|
||||||
|
int root_size;
|
||||||
|
|
||||||
/************************* Implementation ***************************/
|
/************************* Implementation ***************************/
|
||||||
|
|
||||||
#define ZOOM_IN 100 // return codes for below function
|
#define ZOOM_IN 100 // return codes for below function
|
||||||
|
@ -3148,6 +3162,7 @@ int wait_for_button(void)
|
||||||
/* callback updating a progress meter while JPEG decoding */
|
/* callback updating a progress meter while JPEG decoding */
|
||||||
void cb_progess(int current, int total)
|
void cb_progess(int current, int total)
|
||||||
{
|
{
|
||||||
|
rb->yield(); /* be nice to the other threads */
|
||||||
rb->progressbar(0, LCD_HEIGHT-8, LCD_WIDTH, 8,
|
rb->progressbar(0, LCD_HEIGHT-8, LCD_WIDTH, 8,
|
||||||
current*100/total, 0 /*Grow_Right*/);
|
current*100/total, 0 /*Grow_Right*/);
|
||||||
rb->lcd_update_rect(0, LCD_HEIGHT-8, LCD_WIDTH, 8);
|
rb->lcd_update_rect(0, LCD_HEIGHT-8, LCD_WIDTH, 8);
|
||||||
|
@ -3170,7 +3185,7 @@ int min_downscale(int x, int y, int bufsize)
|
||||||
int downscale = 8;
|
int downscale = 8;
|
||||||
|
|
||||||
if ((x/8) * (y/8) > bufsize)
|
if ((x/8) * (y/8) > bufsize)
|
||||||
return 0; /* error, too large even 1:8, doesn't fit */
|
return 0; /* error, too large, even 1:8 doesn't fit */
|
||||||
|
|
||||||
while ((x*2/downscale) * (y*2/downscale) < bufsize
|
while ((x*2/downscale) * (y*2/downscale) < bufsize
|
||||||
&& downscale > 1)
|
&& downscale > 1)
|
||||||
|
@ -3180,6 +3195,7 @@ int min_downscale(int x, int y, int bufsize)
|
||||||
return downscale;
|
return downscale;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* how far can we zoom out, to fit image into the LCD */
|
/* how far can we zoom out, to fit image into the LCD */
|
||||||
int max_downscale(int x, int y)
|
int max_downscale(int x, int y)
|
||||||
{
|
{
|
||||||
|
@ -3195,6 +3211,98 @@ int max_downscale(int x, int y)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* return decoded or cached image */
|
||||||
|
struct t_disp* get_image(struct jpeg* p_jpg, int ds)
|
||||||
|
{
|
||||||
|
int w, h; /* used to center output */
|
||||||
|
int size; /* decompressed image size */
|
||||||
|
long time; /* measured ticks */
|
||||||
|
int status;
|
||||||
|
|
||||||
|
struct t_disp* p_disp = &disp[ds]; /* short cut */
|
||||||
|
|
||||||
|
if (p_disp->bitmap != NULL)
|
||||||
|
{
|
||||||
|
return p_disp; /* we still have it */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* assign image buffer */
|
||||||
|
|
||||||
|
/* physical size needed for decoding */
|
||||||
|
size = (p_jpg->x_phys/ds) * (p_jpg->y_phys / ds);
|
||||||
|
if (buf_size <= size)
|
||||||
|
{ /* have to discard the current */
|
||||||
|
int i;
|
||||||
|
for (i=1; i<=8; i++)
|
||||||
|
disp[i].bitmap = NULL; /* invalidate all bitmaps */
|
||||||
|
buf = buf_root; /* start again from the beginning of the buffer */
|
||||||
|
buf_size = root_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* size may be less when decoded (if height is not block aligned) */
|
||||||
|
size = (p_jpg->x_phys/ds) * (p_jpg->y_size / ds);
|
||||||
|
p_disp->bitmap = buf;
|
||||||
|
buf += size;
|
||||||
|
buf_size -= size;
|
||||||
|
|
||||||
|
rb->snprintf(print, sizeof(print), "decoding %d*%d",
|
||||||
|
p_jpg->x_size/ds, p_jpg->y_size/ds);
|
||||||
|
rb->lcd_puts(0, 3, print);
|
||||||
|
rb->lcd_update();
|
||||||
|
|
||||||
|
/* update image properties */
|
||||||
|
p_disp->width = p_jpg->x_size/ds;
|
||||||
|
p_disp->stride = p_jpg->x_phys / ds; /* use physical size for stride */
|
||||||
|
p_disp->height = p_jpg->y_size/ds;
|
||||||
|
|
||||||
|
/* the actual decoding */
|
||||||
|
time = *rb->current_tick;
|
||||||
|
status = jpeg_decode(p_jpg, p_disp->bitmap, ds, cb_progess);
|
||||||
|
if (status)
|
||||||
|
{
|
||||||
|
rb->splash(HZ*2, true, "decode error %d", status);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
time = *rb->current_tick - time;
|
||||||
|
rb->snprintf(print, sizeof(print), " %d.%02d 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();
|
||||||
|
|
||||||
|
return p_disp;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* set the view to the given center point, limit if necessary */
|
||||||
|
void set_view (struct t_disp* p_disp, int cx, int cy)
|
||||||
|
{
|
||||||
|
int x, y;
|
||||||
|
|
||||||
|
/* plain center to available width/height */
|
||||||
|
x = cx - MIN(LCD_WIDTH, p_disp->width) / 2;
|
||||||
|
y = cy - MIN(LCD_HEIGHT, p_disp->height) / 2;
|
||||||
|
|
||||||
|
/* limit against upper image size */
|
||||||
|
x = MIN(p_disp->width - LCD_WIDTH, x);
|
||||||
|
y = MIN(p_disp->height - LCD_HEIGHT, y);
|
||||||
|
|
||||||
|
/* limit against negative side */
|
||||||
|
x = MAX(0, x);
|
||||||
|
y = MAX(0, y);
|
||||||
|
|
||||||
|
p_disp->x = x; /* set the values */
|
||||||
|
p_disp->y = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* calculate the view center based on the bitmap position */
|
||||||
|
void get_view(struct t_disp* p_disp, int* p_cx, int* p_cy)
|
||||||
|
{
|
||||||
|
*p_cx = p_disp->x + MIN(LCD_WIDTH, p_disp->width) / 2;
|
||||||
|
*p_cy = p_disp->y + MIN(LCD_HEIGHT, p_disp->height) / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* load, decode, display the image */
|
/* load, decode, display the image */
|
||||||
int main(char* filename)
|
int main(char* filename)
|
||||||
{
|
{
|
||||||
|
@ -3202,18 +3310,12 @@ int main(char* filename)
|
||||||
int filesize;
|
int filesize;
|
||||||
int grayscales;
|
int grayscales;
|
||||||
int graysize; // helper
|
int graysize; // helper
|
||||||
char print[32];
|
|
||||||
unsigned char* buf;
|
|
||||||
int buf_size;
|
|
||||||
unsigned char* buf_jpeg; /* compressed JPEG image */
|
unsigned char* buf_jpeg; /* compressed JPEG image */
|
||||||
struct t_disp disp; /* decompressed image */
|
|
||||||
long time; /* measured ticks */
|
|
||||||
|
|
||||||
static struct jpeg jpg; /* too large for stack */
|
static struct jpeg jpg; /* too large for stack */
|
||||||
int status;
|
int status;
|
||||||
int ds, ds_min, ds_max; /* scaling and limits */
|
int ds, ds_min, ds_max; /* scaling and limits */
|
||||||
|
struct t_disp* p_disp; /* currenly displayed image */
|
||||||
buf = rb->plugin_get_mp3_buffer(&buf_size);
|
int cx, cy; /* view center */
|
||||||
|
|
||||||
fd = rb->open(filename, O_RDONLY);
|
fd = rb->open(filename, O_RDONLY);
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
|
@ -3223,6 +3325,10 @@ int main(char* filename)
|
||||||
}
|
}
|
||||||
filesize = rb->filesize(fd);
|
filesize = rb->filesize(fd);
|
||||||
|
|
||||||
|
rb->memset(&disp, 0, sizeof(disp));
|
||||||
|
|
||||||
|
buf = rb->plugin_get_mp3_buffer(&buf_size); /* start munching memory */
|
||||||
|
|
||||||
|
|
||||||
/* initialize the grayscale buffer:
|
/* initialize the grayscale buffer:
|
||||||
* 112 pixels wide, 8 rows (64 pixels) high, (try to) reserve
|
* 112 pixels wide, 8 rows (64 pixels) high, (try to) reserve
|
||||||
|
@ -3279,6 +3385,8 @@ int main(char* filename)
|
||||||
buf_size += filesize;
|
buf_size += filesize;
|
||||||
buf += jpg.words_in_buffer * sizeof(short); /* real space */
|
buf += jpg.words_in_buffer * sizeof(short); /* real space */
|
||||||
buf_size -= jpg.words_in_buffer * sizeof(short);
|
buf_size -= jpg.words_in_buffer * sizeof(short);
|
||||||
|
buf_root = buf; /* we can start the images here */
|
||||||
|
root_size = buf_size;
|
||||||
|
|
||||||
rb->snprintf(print, sizeof(print), "image %d*%d", jpg.x_size, jpg.y_size);
|
rb->snprintf(print, sizeof(print), "image %d*%d", jpg.x_size, jpg.y_size);
|
||||||
rb->lcd_puts(0, 2, print);
|
rb->lcd_puts(0, 2, print);
|
||||||
|
@ -3294,47 +3402,30 @@ int main(char* filename)
|
||||||
return PLUGIN_ERROR;
|
return PLUGIN_ERROR;
|
||||||
}
|
}
|
||||||
ds = ds_max; /* initials setting */
|
ds = ds_max; /* initials setting */
|
||||||
|
cx = jpg.x_size/ds/2; /* center the view */
|
||||||
/* assign image buffer */
|
cy = jpg.y_size/ds/2;
|
||||||
rb->memset(&disp, 0, sizeof(disp));
|
|
||||||
disp.bitmap = buf;
|
|
||||||
|
|
||||||
do /* loop the image prepare and decoding when zoomed */
|
do /* loop the image prepare and decoding when zoomed */
|
||||||
{
|
{
|
||||||
int w, h; /* used to center output */
|
p_disp = get_image(&jpg, ds); /* decode or fetch from cache */
|
||||||
rb->snprintf(print, sizeof(print), "decoding %d*%d",
|
if (p_disp == NULL)
|
||||||
jpg.x_size/ds, jpg.y_size/ds);
|
|
||||||
rb->lcd_puts(0, 3, print);
|
|
||||||
rb->lcd_update();
|
|
||||||
|
|
||||||
/* update image properties */
|
|
||||||
disp.width = jpg.x_size/ds;
|
|
||||||
disp.stride = jpg.x_phys / ds; /* use physical size for stride */
|
|
||||||
disp.height = jpg.y_size/ds;
|
|
||||||
disp.x = MAX(0, (disp.width - LCD_WIDTH) / 2); /* center view */
|
|
||||||
disp.y = MAX(0, (disp.height - LCD_HEIGHT) / 2);
|
|
||||||
|
|
||||||
/* the actual decoding */
|
|
||||||
time = *rb->current_tick;
|
|
||||||
status = jpeg_decode(&jpg, disp.bitmap, ds, cb_progess);
|
|
||||||
if (status)
|
|
||||||
{
|
|
||||||
rb->splash(HZ*2, true, "decode error %d", status);
|
|
||||||
return PLUGIN_ERROR;
|
return PLUGIN_ERROR;
|
||||||
}
|
|
||||||
time = *rb->current_tick - time;
|
set_view(p_disp, cx, cy);
|
||||||
rb->snprintf(print, sizeof(print), " %d.%02d sec ", time/HZ, time%HZ);
|
|
||||||
rb->lcd_getstringsize(print, &w, &h); /* centered in progress bar */
|
rb->snprintf(print, sizeof(print), "showing %d*%d",
|
||||||
rb->lcd_putsxy((LCD_WIDTH - w)/2, LCD_HEIGHT - h, print);
|
p_disp->width, p_disp->height);
|
||||||
|
rb->lcd_puts(0, 3, print);
|
||||||
rb->lcd_update();
|
rb->lcd_update();
|
||||||
|
|
||||||
gray_clear_display();
|
gray_clear_display();
|
||||||
gray_drawgraymap(
|
gray_drawgraymap(
|
||||||
disp.bitmap + disp.y * disp.stride + disp.x,
|
p_disp->bitmap + p_disp->y * p_disp->stride + p_disp->x,
|
||||||
MAX(0, (LCD_WIDTH - disp.width) / 2),
|
MAX(0, (LCD_WIDTH - p_disp->width) / 2),
|
||||||
MAX(0, (LCD_HEIGHT - disp.height) / 2),
|
MAX(0, (LCD_HEIGHT - p_disp->height) / 2),
|
||||||
MIN(LCD_WIDTH, disp.width), MIN(LCD_HEIGHT, disp.height),
|
MIN(LCD_WIDTH, p_disp->width),
|
||||||
disp.stride);
|
MIN(LCD_HEIGHT, p_disp->height),
|
||||||
|
p_disp->stride);
|
||||||
|
|
||||||
gray_show_display(true); /* switch on grayscale overlay */
|
gray_show_display(true); /* switch on grayscale overlay */
|
||||||
|
|
||||||
|
@ -3343,16 +3434,15 @@ int main(char* filename)
|
||||||
*/
|
*/
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
status = scroll_bmp(&disp);
|
status = scroll_bmp(p_disp);
|
||||||
if (status == ZOOM_IN)
|
if (status == ZOOM_IN)
|
||||||
{
|
{
|
||||||
if (ds > ds_min)
|
if (ds > ds_min)
|
||||||
{
|
{
|
||||||
ds /= 2; /* reduce downscaling to zoom in */
|
ds /= 2; /* reduce downscaling to zoom in */
|
||||||
/* FixMe: maintain center
|
get_view(p_disp, &cx, &cy);
|
||||||
disp.x = disp.x * 2 + LCD_WIDTH/2;
|
cx *= 2; /* prepare the position in the new image */
|
||||||
disp.y = disp.y * 2 + LCD_HEIGHT/2;
|
cy *= 2;
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
continue;
|
continue;
|
||||||
|
@ -3363,14 +3453,9 @@ int main(char* filename)
|
||||||
if (ds < ds_max)
|
if (ds < ds_max)
|
||||||
{
|
{
|
||||||
ds *= 2; /* increase downscaling to zoom out */
|
ds *= 2; /* increase downscaling to zoom out */
|
||||||
/* FixMe: maintain center, if possible
|
get_view(p_disp, &cx, &cy);
|
||||||
disp.x = (disp.x - LCD_WIDTH/2) / 2;
|
cx /= 2; /* prepare the position in the new image */
|
||||||
disp.x = MIN(0, disp.x);
|
cy /= 2;
|
||||||
disp.x = MAX(disp.width/2 - LCD_WIDTH, disp.x);
|
|
||||||
disp.y = (disp.y - LCD_HEIGHT/2) / 2;
|
|
||||||
disp.y = MIN(0, disp.y);
|
|
||||||
disp.y = MAX(disp.height/2 - LCD_HEIGHT, disp.y);
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
continue;
|
continue;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue