summaryrefslogtreecommitdiff
path: root/apps/plugins
diff options
context:
space:
mode:
authorJörg Hohensohn <hohensoh@rockbox.org>2004-05-18 07:16:41 +0000
committerJörg Hohensohn <hohensoh@rockbox.org>2004-05-18 07:16:41 +0000
commit363dc4b175c5c7b5ff0f13e09c56d59c76d0f68d (patch)
tree974317293876dbceba6ddd26721dc7a97876ab01 /apps/plugins
parente3a3a55ab00979be080968f9a4e625cf0f94928f (diff)
downloadrockbox-363dc4b175c5c7b5ff0f13e09c56d59c76d0f68d.tar.gz
rockbox-363dc4b175c5c7b5ff0f13e09c56d59c76d0f68d.zip
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
Diffstat (limited to 'apps/plugins')
-rw-r--r--apps/plugins/jpeg.c207
1 files changed, 146 insertions, 61 deletions
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,
2872 int k_need; /* AC coefficients needed up to here */ 2872 int k_need; /* AC coefficients needed up to here */
2873 int zero_need; /* init the block with this many zeros */ 2873 int zero_need; /* init the block with this many zeros */
2874 2874
2875 int last_dc_val[4]; 2875 int last_dc_val = 0;
2876 int store_offs[4]; /* memory offsets: order of Y11 Y12 Y21 Y22 U V */ 2876 int store_offs[4]; /* memory offsets: order of Y11 Y12 Y21 Y22 U V */
2877 MEMSET(&last_dc_val, 0, sizeof(last_dc_val));
2878 2877
2879 /* pick the IDCT we want, determine how to work with coefs */ 2878 /* pick the IDCT we want, determine how to work with coefs */
2880 if (downscale == 1) 2879 if (downscale == 1)
2881 { 2880 {
2882 pf_idct = idct8x8; 2881 pf_idct = idct8x8;
2883 k_need = 63; /* all */ 2882 k_need = 64; /* all */
2884 zero_need = 63; /* all */ 2883 zero_need = 63; /* all */
2885 } 2884 }
2886 else if (downscale == 2) 2885 else if (downscale == 2)
@@ -2940,14 +2939,17 @@ int jpeg_decode(struct jpeg* p_jpeg, unsigned char* p_pixel, int downscale,
2940 struct derived_tbl* actbl = &p_jpeg->ac_derived_tbls[ti]; 2939 struct derived_tbl* actbl = &p_jpeg->ac_derived_tbls[ti];
2941 2940
2942 /* Section F.2.2.1: decode the DC coefficient difference */ 2941 /* Section F.2.2.1: decode the DC coefficient difference */
2943 last_dc_val[ci] += huff_decode_dc(&bs, dctbl); 2942 s = huff_decode_dc(&bs, dctbl);
2944 block[0] = last_dc_val[ci]; /* output it (assumes zag[0] = 0) */
2945 2943
2946 /* Section F.2.2.2: decode the AC coefficients */
2947 if (ci == 0) /* only for Y component */ 2944 if (ci == 0) /* only for Y component */
2948 { 2945 {
2946 last_dc_val += s;
2947 block[0] = last_dc_val; /* output it (assumes zag[0] = 0) */
2948
2949 /* coefficient buffer must be cleared */ 2949 /* coefficient buffer must be cleared */
2950 MEMSET(block+1, 0, zero_need*sizeof(int)); 2950 MEMSET(block+1, 0, zero_need*sizeof(int));
2951
2952 /* Section F.2.2.2: decode the AC coefficients */
2951 for (; k < k_need; k++) 2953 for (; k < k_need; k++)
2952 { 2954 {
2953 s = huff_decode_ac(&bs, actbl); 2955 s = huff_decode_ac(&bs, actbl);
@@ -3027,6 +3029,18 @@ struct t_disp
3027}; 3029};
3028 3030
3029 3031
3032/************************* Globals ***************************/
3033
3034/* decompressed image in the possible sizes (1,2,4,8), wasting the other */
3035struct t_disp disp[9];
3036
3037/* my memory pool (from the mp3 buffer) */
3038char print[32]; /* use a common snprintf() buffer */
3039unsigned char* buf; /* up to here currently used by image(s) */
3040int buf_size;
3041unsigned char* buf_root; /* the root of the images */
3042int root_size;
3043
3030/************************* Implementation ***************************/ 3044/************************* Implementation ***************************/
3031 3045
3032#define ZOOM_IN 100 // return codes for below function 3046#define ZOOM_IN 100 // return codes for below function
@@ -3148,6 +3162,7 @@ int wait_for_button(void)
3148/* callback updating a progress meter while JPEG decoding */ 3162/* callback updating a progress meter while JPEG decoding */
3149void cb_progess(int current, int total) 3163void cb_progess(int current, int total)
3150{ 3164{
3165 rb->yield(); /* be nice to the other threads */
3151 rb->progressbar(0, LCD_HEIGHT-8, LCD_WIDTH, 8, 3166 rb->progressbar(0, LCD_HEIGHT-8, LCD_WIDTH, 8,
3152 current*100/total, 0 /*Grow_Right*/); 3167 current*100/total, 0 /*Grow_Right*/);
3153 rb->lcd_update_rect(0, LCD_HEIGHT-8, LCD_WIDTH, 8); 3168 rb->lcd_update_rect(0, LCD_HEIGHT-8, LCD_WIDTH, 8);
@@ -3170,7 +3185,7 @@ int min_downscale(int x, int y, int bufsize)
3170 int downscale = 8; 3185 int downscale = 8;
3171 3186
3172 if ((x/8) * (y/8) > bufsize) 3187 if ((x/8) * (y/8) > bufsize)
3173 return 0; /* error, too large even 1:8, doesn't fit */ 3188 return 0; /* error, too large, even 1:8 doesn't fit */
3174 3189
3175 while ((x*2/downscale) * (y*2/downscale) < bufsize 3190 while ((x*2/downscale) * (y*2/downscale) < bufsize
3176 && downscale > 1) 3191 && downscale > 1)
@@ -3180,6 +3195,7 @@ int min_downscale(int x, int y, int bufsize)
3180 return downscale; 3195 return downscale;
3181} 3196}
3182 3197
3198
3183/* how far can we zoom out, to fit image into the LCD */ 3199/* how far can we zoom out, to fit image into the LCD */
3184int max_downscale(int x, int y) 3200int max_downscale(int x, int y)
3185{ 3201{
@@ -3195,6 +3211,98 @@ int max_downscale(int x, int y)
3195} 3211}
3196 3212
3197 3213
3214/* return decoded or cached image */
3215struct t_disp* get_image(struct jpeg* p_jpg, int ds)
3216{
3217 int w, h; /* used to center output */
3218 int size; /* decompressed image size */
3219 long time; /* measured ticks */
3220 int status;
3221
3222 struct t_disp* p_disp = &disp[ds]; /* short cut */
3223
3224 if (p_disp->bitmap != NULL)
3225 {
3226 return p_disp; /* we still have it */
3227 }
3228
3229 /* assign image buffer */
3230
3231 /* physical size needed for decoding */
3232 size = (p_jpg->x_phys/ds) * (p_jpg->y_phys / ds);
3233 if (buf_size <= size)
3234 { /* have to discard the current */
3235 int i;
3236 for (i=1; i<=8; i++)
3237 disp[i].bitmap = NULL; /* invalidate all bitmaps */
3238 buf = buf_root; /* start again from the beginning of the buffer */
3239 buf_size = root_size;
3240 }
3241
3242 /* size may be less when decoded (if height is not block aligned) */
3243 size = (p_jpg->x_phys/ds) * (p_jpg->y_size / ds);
3244 p_disp->bitmap = buf;
3245 buf += size;
3246 buf_size -= size;
3247
3248 rb->snprintf(print, sizeof(print), "decoding %d*%d",
3249 p_jpg->x_size/ds, p_jpg->y_size/ds);
3250 rb->lcd_puts(0, 3, print);
3251 rb->lcd_update();
3252
3253 /* update image properties */
3254 p_disp->width = p_jpg->x_size/ds;
3255 p_disp->stride = p_jpg->x_phys / ds; /* use physical size for stride */
3256 p_disp->height = p_jpg->y_size/ds;
3257
3258 /* the actual decoding */
3259 time = *rb->current_tick;
3260 status = jpeg_decode(p_jpg, p_disp->bitmap, ds, cb_progess);
3261 if (status)
3262 {
3263 rb->splash(HZ*2, true, "decode error %d", status);
3264 return NULL;
3265 }
3266 time = *rb->current_tick - time;
3267 rb->snprintf(print, sizeof(print), " %d.%02d sec ", time/HZ, time%HZ);
3268 rb->lcd_getstringsize(print, &w, &h); /* centered in progress bar */
3269 rb->lcd_putsxy((LCD_WIDTH - w)/2, LCD_HEIGHT - h, print);
3270 rb->lcd_update();
3271
3272 return p_disp;
3273}
3274
3275
3276/* set the view to the given center point, limit if necessary */
3277void set_view (struct t_disp* p_disp, int cx, int cy)
3278{
3279 int x, y;
3280
3281 /* plain center to available width/height */
3282 x = cx - MIN(LCD_WIDTH, p_disp->width) / 2;
3283 y = cy - MIN(LCD_HEIGHT, p_disp->height) / 2;
3284
3285 /* limit against upper image size */
3286 x = MIN(p_disp->width - LCD_WIDTH, x);
3287 y = MIN(p_disp->height - LCD_HEIGHT, y);
3288
3289 /* limit against negative side */
3290 x = MAX(0, x);
3291 y = MAX(0, y);
3292
3293 p_disp->x = x; /* set the values */
3294 p_disp->y = y;
3295}
3296
3297
3298/* calculate the view center based on the bitmap position */
3299void get_view(struct t_disp* p_disp, int* p_cx, int* p_cy)
3300{
3301 *p_cx = p_disp->x + MIN(LCD_WIDTH, p_disp->width) / 2;
3302 *p_cy = p_disp->y + MIN(LCD_HEIGHT, p_disp->height) / 2;
3303}
3304
3305
3198/* load, decode, display the image */ 3306/* load, decode, display the image */
3199int main(char* filename) 3307int main(char* filename)
3200{ 3308{
@@ -3202,18 +3310,12 @@ int main(char* filename)
3202 int filesize; 3310 int filesize;
3203 int grayscales; 3311 int grayscales;
3204 int graysize; // helper 3312 int graysize; // helper
3205 char print[32];
3206 unsigned char* buf;
3207 int buf_size;
3208 unsigned char* buf_jpeg; /* compressed JPEG image */ 3313 unsigned char* buf_jpeg; /* compressed JPEG image */
3209 struct t_disp disp; /* decompressed image */
3210 long time; /* measured ticks */
3211
3212 static struct jpeg jpg; /* too large for stack */ 3314 static struct jpeg jpg; /* too large for stack */
3213 int status; 3315 int status;
3214 int ds, ds_min, ds_max; /* scaling and limits */ 3316 int ds, ds_min, ds_max; /* scaling and limits */
3215 3317 struct t_disp* p_disp; /* currenly displayed image */
3216 buf = rb->plugin_get_mp3_buffer(&buf_size); 3318 int cx, cy; /* view center */
3217 3319
3218 fd = rb->open(filename, O_RDONLY); 3320 fd = rb->open(filename, O_RDONLY);
3219 if (fd < 0) 3321 if (fd < 0)
@@ -3223,6 +3325,10 @@ int main(char* filename)
3223 } 3325 }
3224 filesize = rb->filesize(fd); 3326 filesize = rb->filesize(fd);
3225 3327
3328 rb->memset(&disp, 0, sizeof(disp));
3329
3330 buf = rb->plugin_get_mp3_buffer(&buf_size); /* start munching memory */
3331
3226 3332
3227 /* initialize the grayscale buffer: 3333 /* initialize the grayscale buffer:
3228 * 112 pixels wide, 8 rows (64 pixels) high, (try to) reserve 3334 * 112 pixels wide, 8 rows (64 pixels) high, (try to) reserve
@@ -3279,6 +3385,8 @@ int main(char* filename)
3279 buf_size += filesize; 3385 buf_size += filesize;
3280 buf += jpg.words_in_buffer * sizeof(short); /* real space */ 3386 buf += jpg.words_in_buffer * sizeof(short); /* real space */
3281 buf_size -= jpg.words_in_buffer * sizeof(short); 3387 buf_size -= jpg.words_in_buffer * sizeof(short);
3388 buf_root = buf; /* we can start the images here */
3389 root_size = buf_size;
3282 3390
3283 rb->snprintf(print, sizeof(print), "image %d*%d", jpg.x_size, jpg.y_size); 3391 rb->snprintf(print, sizeof(print), "image %d*%d", jpg.x_size, jpg.y_size);
3284 rb->lcd_puts(0, 2, print); 3392 rb->lcd_puts(0, 2, print);
@@ -3294,47 +3402,30 @@ int main(char* filename)
3294 return PLUGIN_ERROR; 3402 return PLUGIN_ERROR;
3295 } 3403 }
3296 ds = ds_max; /* initials setting */ 3404 ds = ds_max; /* initials setting */
3297 3405 cx = jpg.x_size/ds/2; /* center the view */
3298 /* assign image buffer */ 3406 cy = jpg.y_size/ds/2;
3299 rb->memset(&disp, 0, sizeof(disp));
3300 disp.bitmap = buf;
3301 3407
3302 do /* loop the image prepare and decoding when zoomed */ 3408 do /* loop the image prepare and decoding when zoomed */
3303 { 3409 {
3304 int w, h; /* used to center output */ 3410 p_disp = get_image(&jpg, ds); /* decode or fetch from cache */
3305 rb->snprintf(print, sizeof(print), "decoding %d*%d", 3411 if (p_disp == NULL)
3306 jpg.x_size/ds, jpg.y_size/ds);
3307 rb->lcd_puts(0, 3, print);
3308 rb->lcd_update();
3309
3310 /* update image properties */
3311 disp.width = jpg.x_size/ds;
3312 disp.stride = jpg.x_phys / ds; /* use physical size for stride */
3313 disp.height = jpg.y_size/ds;
3314 disp.x = MAX(0, (disp.width - LCD_WIDTH) / 2); /* center view */
3315 disp.y = MAX(0, (disp.height - LCD_HEIGHT) / 2);
3316
3317 /* the actual decoding */
3318 time = *rb->current_tick;
3319 status = jpeg_decode(&jpg, disp.bitmap, ds, cb_progess);
3320 if (status)
3321 {
3322 rb->splash(HZ*2, true, "decode error %d", status);
3323 return PLUGIN_ERROR; 3412 return PLUGIN_ERROR;
3324 } 3413
3325 time = *rb->current_tick - time; 3414 set_view(p_disp, cx, cy);
3326 rb->snprintf(print, sizeof(print), " %d.%02d sec ", time/HZ, time%HZ); 3415
3327 rb->lcd_getstringsize(print, &w, &h); /* centered in progress bar */ 3416 rb->snprintf(print, sizeof(print), "showing %d*%d",
3328 rb->lcd_putsxy((LCD_WIDTH - w)/2, LCD_HEIGHT - h, print); 3417 p_disp->width, p_disp->height);
3418 rb->lcd_puts(0, 3, print);
3329 rb->lcd_update(); 3419 rb->lcd_update();
3330 3420
3331 gray_clear_display(); 3421 gray_clear_display();
3332 gray_drawgraymap( 3422 gray_drawgraymap(
3333 disp.bitmap + disp.y * disp.stride + disp.x, 3423 p_disp->bitmap + p_disp->y * p_disp->stride + p_disp->x,
3334 MAX(0, (LCD_WIDTH - disp.width) / 2), 3424 MAX(0, (LCD_WIDTH - p_disp->width) / 2),
3335 MAX(0, (LCD_HEIGHT - disp.height) / 2), 3425 MAX(0, (LCD_HEIGHT - p_disp->height) / 2),
3336 MIN(LCD_WIDTH, disp.width), MIN(LCD_HEIGHT, disp.height), 3426 MIN(LCD_WIDTH, p_disp->width),
3337 disp.stride); 3427 MIN(LCD_HEIGHT, p_disp->height),
3428 p_disp->stride);
3338 3429
3339 gray_show_display(true); /* switch on grayscale overlay */ 3430 gray_show_display(true); /* switch on grayscale overlay */
3340 3431
@@ -3343,16 +3434,15 @@ int main(char* filename)
3343 */ 3434 */
3344 while (1) 3435 while (1)
3345 { 3436 {
3346 status = scroll_bmp(&disp); 3437 status = scroll_bmp(p_disp);
3347 if (status == ZOOM_IN) 3438 if (status == ZOOM_IN)
3348 { 3439 {
3349 if (ds > ds_min) 3440 if (ds > ds_min)
3350 { 3441 {
3351 ds /= 2; /* reduce downscaling to zoom in */ 3442 ds /= 2; /* reduce downscaling to zoom in */
3352 /* FixMe: maintain center 3443 get_view(p_disp, &cx, &cy);
3353 disp.x = disp.x * 2 + LCD_WIDTH/2; 3444 cx *= 2; /* prepare the position in the new image */
3354 disp.y = disp.y * 2 + LCD_HEIGHT/2; 3445 cy *= 2;
3355 */
3356 } 3446 }
3357 else 3447 else
3358 continue; 3448 continue;
@@ -3363,14 +3453,9 @@ int main(char* filename)
3363 if (ds < ds_max) 3453 if (ds < ds_max)
3364 { 3454 {
3365 ds *= 2; /* increase downscaling to zoom out */ 3455 ds *= 2; /* increase downscaling to zoom out */
3366 /* FixMe: maintain center, if possible 3456 get_view(p_disp, &cx, &cy);
3367 disp.x = (disp.x - LCD_WIDTH/2) / 2; 3457 cx /= 2; /* prepare the position in the new image */
3368 disp.x = MIN(0, disp.x); 3458 cy /= 2;
3369 disp.x = MAX(disp.width/2 - LCD_WIDTH, disp.x);
3370 disp.y = (disp.y - LCD_HEIGHT/2) / 2;
3371 disp.y = MIN(0, disp.y);
3372 disp.y = MAX(disp.height/2 - LCD_HEIGHT, disp.y);
3373 */
3374 } 3459 }
3375 else 3460 else
3376 continue; 3461 continue;