From 363dc4b175c5c7b5ff0f13e09c56d59c76d0f68d Mon Sep 17 00:00:00 2001 From: Jörg Hohensohn Date: Tue, 18 May 2004 07:16:41 +0000 Subject: 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 --- apps/plugins/jpeg.c | 207 ++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 146 insertions(+), 61 deletions(-) (limited to 'apps/plugins') diff --git a/apps/plugins/jpeg.c b/apps/plugins/jpeg.c index 32eedd5d0d..002012ca8c 100644 --- a/apps/plugins/jpeg.c +++ b/apps/plugins/jpeg.c @@ -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 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 */ - MEMSET(&last_dc_val, 0, sizeof(last_dc_val)); /* pick the IDCT we want, determine how to work with coefs */ if (downscale == 1) { pf_idct = idct8x8; - k_need = 63; /* all */ + k_need = 64; /* all */ zero_need = 63; /* all */ } 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]; /* Section F.2.2.1: decode the DC coefficient difference */ - last_dc_val[ci] += huff_decode_dc(&bs, dctbl); - block[0] = last_dc_val[ci]; /* output it (assumes zag[0] = 0) */ + s = huff_decode_dc(&bs, dctbl); - /* Section F.2.2.2: decode the AC coefficients */ 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 */ MEMSET(block+1, 0, zero_need*sizeof(int)); + + /* Section F.2.2.2: decode the AC coefficients */ for (; k < k_need; k++) { 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 ***************************/ #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 */ void cb_progess(int current, int total) { + rb->yield(); /* be nice to the other threads */ rb->progressbar(0, LCD_HEIGHT-8, LCD_WIDTH, 8, current*100/total, 0 /*Grow_Right*/); 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; 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 && downscale > 1) @@ -3180,6 +3195,7 @@ int min_downscale(int x, int y, int bufsize) return downscale; } + /* how far can we zoom out, to fit image into the LCD */ 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 */ int main(char* filename) { @@ -3202,18 +3310,12 @@ int main(char* filename) int filesize; int grayscales; int graysize; // helper - char print[32]; - unsigned char* buf; - int buf_size; 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 */ int status; int ds, ds_min, ds_max; /* scaling and limits */ - - buf = rb->plugin_get_mp3_buffer(&buf_size); + struct t_disp* p_disp; /* currenly displayed image */ + int cx, cy; /* view center */ fd = rb->open(filename, O_RDONLY); if (fd < 0) @@ -3223,6 +3325,10 @@ int main(char* filename) } 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: * 112 pixels wide, 8 rows (64 pixels) high, (try to) reserve @@ -3279,6 +3385,8 @@ int main(char* filename) buf_size += filesize; buf += jpg.words_in_buffer * sizeof(short); /* real space */ 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->lcd_puts(0, 2, print); @@ -3294,47 +3402,30 @@ int main(char* filename) return PLUGIN_ERROR; } ds = ds_max; /* initials setting */ - - /* assign image buffer */ - rb->memset(&disp, 0, sizeof(disp)); - disp.bitmap = buf; + cx = jpg.x_size/ds/2; /* center the view */ + cy = jpg.y_size/ds/2; do /* loop the image prepare and decoding when zoomed */ { - int w, h; /* used to center output */ - rb->snprintf(print, sizeof(print), "decoding %d*%d", - 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); + p_disp = get_image(&jpg, ds); /* decode or fetch from cache */ + if (p_disp == NULL) return PLUGIN_ERROR; - } - 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); + + set_view(p_disp, cx, cy); + + rb->snprintf(print, sizeof(print), "showing %d*%d", + p_disp->width, p_disp->height); + rb->lcd_puts(0, 3, print); rb->lcd_update(); gray_clear_display(); gray_drawgraymap( - disp.bitmap + disp.y * disp.stride + disp.x, - MAX(0, (LCD_WIDTH - disp.width) / 2), - MAX(0, (LCD_HEIGHT - disp.height) / 2), - MIN(LCD_WIDTH, disp.width), MIN(LCD_HEIGHT, disp.height), - disp.stride); + p_disp->bitmap + p_disp->y * p_disp->stride + p_disp->x, + MAX(0, (LCD_WIDTH - p_disp->width) / 2), + MAX(0, (LCD_HEIGHT - p_disp->height) / 2), + MIN(LCD_WIDTH, p_disp->width), + MIN(LCD_HEIGHT, p_disp->height), + p_disp->stride); gray_show_display(true); /* switch on grayscale overlay */ @@ -3343,16 +3434,15 @@ int main(char* filename) */ while (1) { - status = scroll_bmp(&disp); + status = scroll_bmp(p_disp); if (status == ZOOM_IN) { if (ds > ds_min) { ds /= 2; /* reduce downscaling to zoom in */ - /* FixMe: maintain center - disp.x = disp.x * 2 + LCD_WIDTH/2; - disp.y = disp.y * 2 + LCD_HEIGHT/2; - */ + get_view(p_disp, &cx, &cy); + cx *= 2; /* prepare the position in the new image */ + cy *= 2; } else continue; @@ -3363,14 +3453,9 @@ int main(char* filename) if (ds < ds_max) { ds *= 2; /* increase downscaling to zoom out */ - /* FixMe: maintain center, if possible - disp.x = (disp.x - LCD_WIDTH/2) / 2; - disp.x = MIN(0, disp.x); - 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); - */ + get_view(p_disp, &cx, &cy); + cx /= 2; /* prepare the position in the new image */ + cy /= 2; } else continue; -- cgit v1.2.3