1
0
Fork 0
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:
Jörg Hohensohn 2004-05-18 07:16:41 +00:00
parent e3a3a55ab0
commit 363dc4b175

View file

@ -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;