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.zip
rockbox-363dc4b175c5c7b5ff0f13e09c56d59c76d0f68d.tar.gz
rockbox-363dc4b175c5c7b5ff0f13e09c56d59c76d0f68d.tar.bz2
rockbox-363dc4b175c5c7b5ff0f13e09c56d59c76d0f68d.tar.xz
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 32eedd5..002012c 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;