diff options
author | Teruaki Kawashima <teru@rockbox.org> | 2010-01-18 12:46:19 +0000 |
---|---|---|
committer | Teruaki Kawashima <teru@rockbox.org> | 2010-01-18 12:46:19 +0000 |
commit | 5bd08237499dfc66309ba2a5a4dac75018e794ac (patch) | |
tree | fe742342707b8789ce0dbf1a18e5a8346ae2601d /apps/plugins/jpeg/jpeg.c | |
parent | 135d983433e741cf9658ff5d7457bdf37ef48ce0 (diff) | |
download | rockbox-5bd08237499dfc66309ba2a5a4dac75018e794ac.tar.gz rockbox-5bd08237499dfc66309ba2a5a4dac75018e794ac.zip |
jpeg,png: Merge user interface code and plugin entry point of the two plugins (part of FS#6321).
* Created new directory, imageviewer/ and moved both jpeg/ and png/ under it.
- this still doesn't merge the two plugins. i.e. both jpeg.rock and png.rock will be made for color targets.
- I'm thinking to merge the two plugins to single image viewer later.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@24272 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/plugins/jpeg/jpeg.c')
-rw-r--r-- | apps/plugins/jpeg/jpeg.c | 1218 |
1 files changed, 0 insertions, 1218 deletions
diff --git a/apps/plugins/jpeg/jpeg.c b/apps/plugins/jpeg/jpeg.c deleted file mode 100644 index 4a61f13e51..0000000000 --- a/apps/plugins/jpeg/jpeg.c +++ /dev/null | |||
@@ -1,1218 +0,0 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * JPEG image viewer | ||
11 | * (This is a real mess if it has to be coded in one single C file) | ||
12 | * | ||
13 | * File scrolling addition (C) 2005 Alexander Spyridakis | ||
14 | * Copyright (C) 2004 Jörg Hohensohn aka [IDC]Dragon | ||
15 | * Heavily borrowed from the IJG implementation (C) Thomas G. Lane | ||
16 | * Small & fast downscaling IDCT (C) 2002 by Guido Vollbeding JPEGclub.org | ||
17 | * | ||
18 | * This program is free software; you can redistribute it and/or | ||
19 | * modify it under the terms of the GNU General Public License | ||
20 | * as published by the Free Software Foundation; either version 2 | ||
21 | * of the License, or (at your option) any later version. | ||
22 | * | ||
23 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
24 | * KIND, either express or implied. | ||
25 | * | ||
26 | ****************************************************************************/ | ||
27 | |||
28 | #include "plugin.h" | ||
29 | #include <lib/playback_control.h> | ||
30 | #include <lib/helper.h> | ||
31 | #include <lib/configfile.h> | ||
32 | |||
33 | #include <lib/grey.h> | ||
34 | #include <lib/xlcd.h> | ||
35 | |||
36 | #include "jpeg.h" | ||
37 | #include "jpeg_decoder.h" | ||
38 | |||
39 | PLUGIN_HEADER | ||
40 | |||
41 | #ifdef HAVE_LCD_COLOR | ||
42 | #include "yuv2rgb.h" | ||
43 | #endif | ||
44 | |||
45 | /* different graphics libraries */ | ||
46 | #if LCD_DEPTH < 8 | ||
47 | #define USEGSLIB | ||
48 | GREY_INFO_STRUCT | ||
49 | #define MYLCD(fn) grey_ub_ ## fn | ||
50 | #define MYLCD_UPDATE() | ||
51 | #define MYXLCD(fn) grey_ub_ ## fn | ||
52 | #else | ||
53 | #define MYLCD(fn) rb->lcd_ ## fn | ||
54 | #define MYLCD_UPDATE() rb->lcd_update(); | ||
55 | #define MYXLCD(fn) xlcd_ ## fn | ||
56 | #endif | ||
57 | |||
58 | /* Min memory allowing us to use the plugin buffer | ||
59 | * and thus not stopping the music | ||
60 | * *Very* rough estimation: | ||
61 | * Max 10 000 dir entries * 4bytes/entry (char **) = 40000 bytes | ||
62 | * + 20k code size = 60 000 | ||
63 | * + 50k min for jpeg = 120 000 | ||
64 | */ | ||
65 | #define MIN_MEM 120000 | ||
66 | |||
67 | /* Headings */ | ||
68 | #define DIR_PREV 1 | ||
69 | #define DIR_NEXT -1 | ||
70 | #define DIR_NONE 0 | ||
71 | |||
72 | #define PLUGIN_OTHER 10 /* State code for output with return. */ | ||
73 | #define PLUGIN_ABORT 11 | ||
74 | #define PLUGIN_OUTOFMEM 12 | ||
75 | |||
76 | /******************************* Globals ***********************************/ | ||
77 | |||
78 | static int slideshow_enabled = false; /* run slideshow */ | ||
79 | static int running_slideshow = false; /* loading image because of slideshw */ | ||
80 | #ifndef SIMULATOR | ||
81 | static int immediate_ata_off = false; /* power down disk after loading */ | ||
82 | #endif | ||
83 | |||
84 | #ifdef HAVE_LCD_COLOR | ||
85 | fb_data rgb_linebuf[LCD_WIDTH]; /* Line buffer for scrolling when | ||
86 | DITHER_DIFFUSION is set */ | ||
87 | #endif | ||
88 | |||
89 | |||
90 | /* Persistent configuration */ | ||
91 | #define JPEG_CONFIGFILE "jpeg.cfg" | ||
92 | #define JPEG_SETTINGS_MINVERSION 1 | ||
93 | #define JPEG_SETTINGS_VERSION 2 | ||
94 | |||
95 | /* Slideshow times */ | ||
96 | #define SS_MIN_TIMEOUT 1 | ||
97 | #define SS_MAX_TIMEOUT 20 | ||
98 | #define SS_DEFAULT_TIMEOUT 5 | ||
99 | |||
100 | struct jpeg_settings | ||
101 | { | ||
102 | #ifdef HAVE_LCD_COLOR | ||
103 | int colour_mode; | ||
104 | int dither_mode; | ||
105 | #endif | ||
106 | int ss_timeout; | ||
107 | }; | ||
108 | |||
109 | static struct jpeg_settings jpeg_settings = | ||
110 | { | ||
111 | #ifdef HAVE_LCD_COLOR | ||
112 | COLOURMODE_COLOUR, | ||
113 | DITHER_NONE, | ||
114 | #endif | ||
115 | SS_DEFAULT_TIMEOUT | ||
116 | }; | ||
117 | static struct jpeg_settings old_settings; | ||
118 | |||
119 | static struct configdata jpeg_config[] = | ||
120 | { | ||
121 | #ifdef HAVE_LCD_COLOR | ||
122 | { TYPE_ENUM, 0, COLOUR_NUM_MODES, { .int_p = &jpeg_settings.colour_mode }, | ||
123 | "Colour Mode", (char *[]){ "Colour", "Grayscale" } }, | ||
124 | { TYPE_ENUM, 0, DITHER_NUM_MODES, { .int_p = &jpeg_settings.dither_mode }, | ||
125 | "Dither Mode", (char *[]){ "None", "Ordered", "Diffusion" } }, | ||
126 | #endif | ||
127 | { TYPE_INT, SS_MIN_TIMEOUT, SS_MAX_TIMEOUT, | ||
128 | { .int_p = &jpeg_settings.ss_timeout }, "Slideshow Time", NULL }, | ||
129 | }; | ||
130 | |||
131 | #if LCD_DEPTH > 1 | ||
132 | static fb_data* old_backdrop; | ||
133 | #endif | ||
134 | |||
135 | /**************** begin Application ********************/ | ||
136 | |||
137 | |||
138 | /************************* Types ***************************/ | ||
139 | |||
140 | struct t_disp | ||
141 | { | ||
142 | #ifdef HAVE_LCD_COLOR | ||
143 | unsigned char* bitmap[3]; /* Y, Cr, Cb */ | ||
144 | int csub_x, csub_y; | ||
145 | #else | ||
146 | unsigned char* bitmap[1]; /* Y only */ | ||
147 | #endif | ||
148 | int width; | ||
149 | int height; | ||
150 | int stride; | ||
151 | int x, y; | ||
152 | }; | ||
153 | |||
154 | /************************* Globals ***************************/ | ||
155 | |||
156 | /* decompressed image in the possible sizes (1,2,4,8), wasting the other */ | ||
157 | static struct t_disp disp[9]; | ||
158 | |||
159 | /* my memory pool (from the mp3 buffer) */ | ||
160 | static char print[32]; /* use a common snprintf() buffer */ | ||
161 | /* the remaining free part of the buffer for compressed+uncompressed images */ | ||
162 | static unsigned char* buf; | ||
163 | static ssize_t buf_size; | ||
164 | |||
165 | /* the root of the images, hereafter are decompresed ones */ | ||
166 | static unsigned char* buf_root; | ||
167 | static int root_size; | ||
168 | |||
169 | /* up to here currently used by image(s) */ | ||
170 | static unsigned char* buf_images; | ||
171 | static ssize_t buf_images_size; | ||
172 | |||
173 | static int ds, ds_min, ds_max; /* downscaling and limits */ | ||
174 | static struct jpeg jpg; /* too large for stack */ | ||
175 | |||
176 | static struct tree_context *tree; | ||
177 | |||
178 | /* the current full file name */ | ||
179 | static char np_file[MAX_PATH]; | ||
180 | static int curfile = 0, direction = DIR_NONE, entries = 0; | ||
181 | |||
182 | /* list of the jpeg files */ | ||
183 | static char **file_pt; | ||
184 | #if PLUGIN_BUFFER_SIZE >= MIN_MEM | ||
185 | /* are we using the plugin buffer or the audio buffer? */ | ||
186 | static bool plug_buf = true; | ||
187 | #endif | ||
188 | |||
189 | |||
190 | /************************* Implementation ***************************/ | ||
191 | |||
192 | bool jpg_ext(const char ext[]) | ||
193 | { | ||
194 | if(!ext) | ||
195 | return false; | ||
196 | if(!rb->strcasecmp(ext,".jpg") || | ||
197 | !rb->strcasecmp(ext,".jpe") || | ||
198 | !rb->strcasecmp(ext,".jpeg")) | ||
199 | return true; | ||
200 | else | ||
201 | return false; | ||
202 | } | ||
203 | |||
204 | /*Read directory contents for scrolling. */ | ||
205 | void get_pic_list(void) | ||
206 | { | ||
207 | int i; | ||
208 | struct entry *dircache; | ||
209 | char *pname; | ||
210 | tree = rb->tree_get_context(); | ||
211 | dircache = tree->dircache; | ||
212 | |||
213 | file_pt = (char **) buf; | ||
214 | |||
215 | /* Remove path and leave only the name.*/ | ||
216 | pname = rb->strrchr(np_file,'/'); | ||
217 | pname++; | ||
218 | |||
219 | for (i = 0; i < tree->filesindir; i++) | ||
220 | { | ||
221 | if (!(dircache[i].attr & ATTR_DIRECTORY) | ||
222 | && jpg_ext(rb->strrchr(dircache[i].name,'.'))) | ||
223 | { | ||
224 | file_pt[entries] = dircache[i].name; | ||
225 | /* Set Selected File. */ | ||
226 | if (!rb->strcmp(file_pt[entries], pname)) | ||
227 | curfile = entries; | ||
228 | entries++; | ||
229 | } | ||
230 | } | ||
231 | |||
232 | buf += (entries * sizeof(char**)); | ||
233 | buf_size -= (entries * sizeof(char**)); | ||
234 | } | ||
235 | |||
236 | int change_filename(int direct) | ||
237 | { | ||
238 | bool file_erased = (file_pt[curfile] == NULL); | ||
239 | direction = direct; | ||
240 | |||
241 | curfile += (direct == DIR_PREV? entries - 1: 1); | ||
242 | if (curfile >= entries) | ||
243 | curfile -= entries; | ||
244 | |||
245 | if (file_erased) | ||
246 | { | ||
247 | /* remove 'erased' file names from list. */ | ||
248 | int count, i; | ||
249 | for (count = i = 0; i < entries; i++) | ||
250 | { | ||
251 | if (curfile == i) | ||
252 | curfile = count; | ||
253 | if (file_pt[i] != NULL) | ||
254 | file_pt[count++] = file_pt[i]; | ||
255 | } | ||
256 | entries = count; | ||
257 | } | ||
258 | |||
259 | if (entries == 0) | ||
260 | { | ||
261 | rb->splash(HZ, "No supported files"); | ||
262 | return PLUGIN_ERROR; | ||
263 | } | ||
264 | |||
265 | if (rb->strlen(tree->currdir) > 1) | ||
266 | { | ||
267 | rb->strcpy(np_file, tree->currdir); | ||
268 | rb->strcat(np_file, "/"); | ||
269 | } | ||
270 | else | ||
271 | rb->strcpy(np_file, tree->currdir); | ||
272 | |||
273 | rb->strcat(np_file, file_pt[curfile]); | ||
274 | |||
275 | return PLUGIN_OTHER; | ||
276 | } | ||
277 | |||
278 | /* switch off overlay, for handling SYS_ events */ | ||
279 | void cleanup(void *parameter) | ||
280 | { | ||
281 | (void)parameter; | ||
282 | #ifdef USEGSLIB | ||
283 | grey_show(false); | ||
284 | #endif | ||
285 | } | ||
286 | |||
287 | #define VSCROLL (LCD_HEIGHT/8) | ||
288 | #define HSCROLL (LCD_WIDTH/10) | ||
289 | |||
290 | #define ZOOM_IN 100 /* return codes for below function */ | ||
291 | #define ZOOM_OUT 101 | ||
292 | |||
293 | #ifdef HAVE_LCD_COLOR | ||
294 | bool set_option_grayscale(void) | ||
295 | { | ||
296 | bool gray = jpeg_settings.colour_mode == COLOURMODE_GRAY; | ||
297 | rb->set_bool("Grayscale", &gray); | ||
298 | jpeg_settings.colour_mode = gray ? COLOURMODE_GRAY : COLOURMODE_COLOUR; | ||
299 | return false; | ||
300 | } | ||
301 | |||
302 | bool set_option_dithering(void) | ||
303 | { | ||
304 | static const struct opt_items dithering[DITHER_NUM_MODES] = { | ||
305 | [DITHER_NONE] = { "Off", -1 }, | ||
306 | [DITHER_ORDERED] = { "Ordered", -1 }, | ||
307 | [DITHER_DIFFUSION] = { "Diffusion", -1 }, | ||
308 | }; | ||
309 | |||
310 | rb->set_option("Dithering", &jpeg_settings.dither_mode, INT, | ||
311 | dithering, DITHER_NUM_MODES, NULL); | ||
312 | return false; | ||
313 | } | ||
314 | |||
315 | MENUITEM_FUNCTION(grayscale_item, 0, "Greyscale", | ||
316 | set_option_grayscale, NULL, NULL, Icon_NOICON); | ||
317 | MENUITEM_FUNCTION(dithering_item, 0, "Dithering", | ||
318 | set_option_dithering, NULL, NULL, Icon_NOICON); | ||
319 | MAKE_MENU(display_menu, "Display Options", NULL, Icon_NOICON, | ||
320 | &grayscale_item, &dithering_item); | ||
321 | |||
322 | static void display_options(void) | ||
323 | { | ||
324 | rb->do_menu(&display_menu, NULL, NULL, false); | ||
325 | } | ||
326 | #endif /* HAVE_LCD_COLOR */ | ||
327 | |||
328 | int show_menu(void) /* return 1 to quit */ | ||
329 | { | ||
330 | #if LCD_DEPTH > 1 | ||
331 | rb->lcd_set_backdrop(old_backdrop); | ||
332 | #ifdef HAVE_LCD_COLOR | ||
333 | rb->lcd_set_foreground(rb->global_settings->fg_color); | ||
334 | rb->lcd_set_background(rb->global_settings->bg_color); | ||
335 | #else | ||
336 | rb->lcd_set_foreground(LCD_BLACK); | ||
337 | rb->lcd_set_background(LCD_WHITE); | ||
338 | #endif | ||
339 | #endif | ||
340 | int result; | ||
341 | |||
342 | enum menu_id | ||
343 | { | ||
344 | MIID_RETURN = 0, | ||
345 | MIID_TOGGLE_SS_MODE, | ||
346 | MIID_CHANGE_SS_MODE, | ||
347 | #if PLUGIN_BUFFER_SIZE >= MIN_MEM | ||
348 | MIID_SHOW_PLAYBACK_MENU, | ||
349 | #endif | ||
350 | #ifdef HAVE_LCD_COLOR | ||
351 | MIID_DISPLAY_OPTIONS, | ||
352 | #endif | ||
353 | MIID_QUIT, | ||
354 | }; | ||
355 | |||
356 | MENUITEM_STRINGLIST(menu, "Jpeg Menu", NULL, | ||
357 | "Return", "Toggle Slideshow Mode", | ||
358 | "Change Slideshow Time", | ||
359 | #if PLUGIN_BUFFER_SIZE >= MIN_MEM | ||
360 | "Show Playback Menu", | ||
361 | #endif | ||
362 | #ifdef HAVE_LCD_COLOR | ||
363 | "Display Options", | ||
364 | #endif | ||
365 | "Quit"); | ||
366 | |||
367 | static const struct opt_items slideshow[2] = { | ||
368 | { "Disable", -1 }, | ||
369 | { "Enable", -1 }, | ||
370 | }; | ||
371 | |||
372 | result=rb->do_menu(&menu, NULL, NULL, false); | ||
373 | |||
374 | switch (result) | ||
375 | { | ||
376 | case MIID_RETURN: | ||
377 | break; | ||
378 | case MIID_TOGGLE_SS_MODE: | ||
379 | rb->set_option("Toggle Slideshow", &slideshow_enabled, INT, | ||
380 | slideshow , 2, NULL); | ||
381 | break; | ||
382 | case MIID_CHANGE_SS_MODE: | ||
383 | rb->set_int("Slideshow Time", "s", UNIT_SEC, | ||
384 | &jpeg_settings.ss_timeout, NULL, 1, | ||
385 | SS_MIN_TIMEOUT, SS_MAX_TIMEOUT, NULL); | ||
386 | break; | ||
387 | |||
388 | #if PLUGIN_BUFFER_SIZE >= MIN_MEM | ||
389 | case MIID_SHOW_PLAYBACK_MENU: | ||
390 | if (plug_buf) | ||
391 | { | ||
392 | playback_control(NULL); | ||
393 | } | ||
394 | else | ||
395 | { | ||
396 | rb->splash(HZ, "Cannot restart playback"); | ||
397 | } | ||
398 | break; | ||
399 | #endif | ||
400 | #ifdef HAVE_LCD_COLOR | ||
401 | case MIID_DISPLAY_OPTIONS: | ||
402 | display_options(); | ||
403 | break; | ||
404 | #endif | ||
405 | case MIID_QUIT: | ||
406 | return 1; | ||
407 | break; | ||
408 | } | ||
409 | |||
410 | #if !defined(SIMULATOR) && defined(HAVE_DISK_STORAGE) | ||
411 | /* change ata spindown time based on slideshow time setting */ | ||
412 | immediate_ata_off = false; | ||
413 | rb->storage_spindown(rb->global_settings->disk_spindown); | ||
414 | |||
415 | if (slideshow_enabled) | ||
416 | { | ||
417 | if(jpeg_settings.ss_timeout < 10) | ||
418 | { | ||
419 | /* slideshow times < 10s keep disk spinning */ | ||
420 | rb->storage_spindown(0); | ||
421 | } | ||
422 | else if (!rb->mp3_is_playing()) | ||
423 | { | ||
424 | /* slideshow times > 10s and not playing: ata_off after load */ | ||
425 | immediate_ata_off = true; | ||
426 | } | ||
427 | } | ||
428 | #endif | ||
429 | #if LCD_DEPTH > 1 | ||
430 | rb->lcd_set_backdrop(NULL); | ||
431 | rb->lcd_set_foreground(LCD_WHITE); | ||
432 | rb->lcd_set_background(LCD_BLACK); | ||
433 | #endif | ||
434 | rb->lcd_clear_display(); | ||
435 | return 0; | ||
436 | } | ||
437 | |||
438 | void draw_image_rect(struct t_disp* pdisp, int x, int y, int width, int height) | ||
439 | { | ||
440 | #ifdef HAVE_LCD_COLOR | ||
441 | yuv_bitmap_part( | ||
442 | pdisp->bitmap, pdisp->csub_x, pdisp->csub_y, | ||
443 | pdisp->x + x, pdisp->y + y, pdisp->stride, | ||
444 | x + MAX(0, (LCD_WIDTH - pdisp->width) / 2), | ||
445 | y + MAX(0, (LCD_HEIGHT - pdisp->height) / 2), | ||
446 | width, height, | ||
447 | jpeg_settings.colour_mode, jpeg_settings.dither_mode); | ||
448 | #else | ||
449 | MYXLCD(gray_bitmap_part)( | ||
450 | pdisp->bitmap[0], pdisp->x + x, pdisp->y + y, pdisp->stride, | ||
451 | x + MAX(0, (LCD_WIDTH-pdisp->width)/2), | ||
452 | y + MAX(0, (LCD_HEIGHT-pdisp->height)/2), | ||
453 | width, height); | ||
454 | #endif | ||
455 | } | ||
456 | |||
457 | /* Pan the viewing window right - move image to the left and fill in | ||
458 | the right-hand side */ | ||
459 | static void pan_view_right(struct t_disp* pdisp) | ||
460 | { | ||
461 | int move; | ||
462 | |||
463 | move = MIN(HSCROLL, pdisp->width - pdisp->x - LCD_WIDTH); | ||
464 | if (move > 0) | ||
465 | { | ||
466 | MYXLCD(scroll_left)(move); /* scroll left */ | ||
467 | pdisp->x += move; | ||
468 | draw_image_rect(pdisp, LCD_WIDTH - move, 0, move, pdisp->height-pdisp->y); | ||
469 | MYLCD_UPDATE(); | ||
470 | } | ||
471 | } | ||
472 | |||
473 | /* Pan the viewing window left - move image to the right and fill in | ||
474 | the left-hand side */ | ||
475 | static void pan_view_left(struct t_disp* pdisp) | ||
476 | { | ||
477 | int move; | ||
478 | |||
479 | move = MIN(HSCROLL, pdisp->x); | ||
480 | if (move > 0) | ||
481 | { | ||
482 | MYXLCD(scroll_right)(move); /* scroll right */ | ||
483 | pdisp->x -= move; | ||
484 | draw_image_rect(pdisp, 0, 0, move, pdisp->height-pdisp->y); | ||
485 | MYLCD_UPDATE(); | ||
486 | } | ||
487 | } | ||
488 | |||
489 | /* Pan the viewing window up - move image down and fill in | ||
490 | the top */ | ||
491 | static void pan_view_up(struct t_disp* pdisp) | ||
492 | { | ||
493 | int move; | ||
494 | |||
495 | move = MIN(VSCROLL, pdisp->y); | ||
496 | if (move > 0) | ||
497 | { | ||
498 | MYXLCD(scroll_down)(move); /* scroll down */ | ||
499 | pdisp->y -= move; | ||
500 | #ifdef HAVE_LCD_COLOR | ||
501 | if (jpeg_settings.dither_mode == DITHER_DIFFUSION) | ||
502 | { | ||
503 | /* Draw over the band at the top of the last update | ||
504 | caused by lack of error history on line zero. */ | ||
505 | move = MIN(move + 1, pdisp->y + pdisp->height); | ||
506 | } | ||
507 | #endif | ||
508 | draw_image_rect(pdisp, 0, 0, pdisp->width-pdisp->x, move); | ||
509 | MYLCD_UPDATE(); | ||
510 | } | ||
511 | } | ||
512 | |||
513 | /* Pan the viewing window down - move image up and fill in | ||
514 | the bottom */ | ||
515 | static void pan_view_down(struct t_disp* pdisp) | ||
516 | { | ||
517 | int move; | ||
518 | |||
519 | move = MIN(VSCROLL, pdisp->height - pdisp->y - LCD_HEIGHT); | ||
520 | if (move > 0) | ||
521 | { | ||
522 | MYXLCD(scroll_up)(move); /* scroll up */ | ||
523 | pdisp->y += move; | ||
524 | #ifdef HAVE_LCD_COLOR | ||
525 | if (jpeg_settings.dither_mode == DITHER_DIFFUSION) | ||
526 | { | ||
527 | /* Save the line that was on the last line of the display | ||
528 | and draw one extra line above then recover the line with | ||
529 | image data that had an error history when it was drawn. | ||
530 | */ | ||
531 | move++, pdisp->y--; | ||
532 | rb->memcpy(rgb_linebuf, | ||
533 | rb->lcd_framebuffer + (LCD_HEIGHT - move)*LCD_WIDTH, | ||
534 | LCD_WIDTH*sizeof (fb_data)); | ||
535 | } | ||
536 | #endif | ||
537 | |||
538 | draw_image_rect(pdisp, 0, LCD_HEIGHT - move, pdisp->width-pdisp->x, move); | ||
539 | |||
540 | #ifdef HAVE_LCD_COLOR | ||
541 | if (jpeg_settings.dither_mode == DITHER_DIFFUSION) | ||
542 | { | ||
543 | /* Cover the first row drawn with previous image data. */ | ||
544 | rb->memcpy(rb->lcd_framebuffer + (LCD_HEIGHT - move)*LCD_WIDTH, | ||
545 | rgb_linebuf, LCD_WIDTH*sizeof (fb_data)); | ||
546 | pdisp->y++; | ||
547 | } | ||
548 | #endif | ||
549 | MYLCD_UPDATE(); | ||
550 | } | ||
551 | } | ||
552 | |||
553 | /* interactively scroll around the image */ | ||
554 | int scroll_bmp(struct t_disp* pdisp) | ||
555 | { | ||
556 | int button; | ||
557 | int lastbutton = 0; | ||
558 | |||
559 | while (true) | ||
560 | { | ||
561 | if (slideshow_enabled) | ||
562 | button = rb->button_get_w_tmo(jpeg_settings.ss_timeout * HZ); | ||
563 | else | ||
564 | button = rb->button_get(true); | ||
565 | |||
566 | running_slideshow = false; | ||
567 | |||
568 | switch(button) | ||
569 | { | ||
570 | case JPEG_LEFT: | ||
571 | if (entries > 1 && pdisp->width <= LCD_WIDTH | ||
572 | && pdisp->height <= LCD_HEIGHT) | ||
573 | return change_filename(DIR_PREV); | ||
574 | case JPEG_LEFT | BUTTON_REPEAT: | ||
575 | pan_view_left(pdisp); | ||
576 | break; | ||
577 | |||
578 | case JPEG_RIGHT: | ||
579 | if (entries > 1 && pdisp->width <= LCD_WIDTH | ||
580 | && pdisp->height <= LCD_HEIGHT) | ||
581 | return change_filename(DIR_NEXT); | ||
582 | case JPEG_RIGHT | BUTTON_REPEAT: | ||
583 | pan_view_right(pdisp); | ||
584 | break; | ||
585 | |||
586 | case JPEG_UP: | ||
587 | case JPEG_UP | BUTTON_REPEAT: | ||
588 | pan_view_up(pdisp); | ||
589 | break; | ||
590 | |||
591 | case JPEG_DOWN: | ||
592 | case JPEG_DOWN | BUTTON_REPEAT: | ||
593 | pan_view_down(pdisp); | ||
594 | break; | ||
595 | |||
596 | case BUTTON_NONE: | ||
597 | if (!slideshow_enabled) | ||
598 | break; | ||
599 | running_slideshow = true; | ||
600 | if (entries > 1) | ||
601 | return change_filename(DIR_NEXT); | ||
602 | break; | ||
603 | |||
604 | #ifdef JPEG_SLIDE_SHOW | ||
605 | case JPEG_SLIDE_SHOW: | ||
606 | slideshow_enabled = !slideshow_enabled; | ||
607 | running_slideshow = slideshow_enabled; | ||
608 | break; | ||
609 | #endif | ||
610 | |||
611 | #ifdef JPEG_NEXT_REPEAT | ||
612 | case JPEG_NEXT_REPEAT: | ||
613 | #endif | ||
614 | case JPEG_NEXT: | ||
615 | if (entries > 1) | ||
616 | return change_filename(DIR_NEXT); | ||
617 | break; | ||
618 | |||
619 | #ifdef JPEG_PREVIOUS_REPEAT | ||
620 | case JPEG_PREVIOUS_REPEAT: | ||
621 | #endif | ||
622 | case JPEG_PREVIOUS: | ||
623 | if (entries > 1) | ||
624 | return change_filename(DIR_PREV); | ||
625 | break; | ||
626 | |||
627 | case JPEG_ZOOM_IN: | ||
628 | #ifdef JPEG_ZOOM_PRE | ||
629 | if (lastbutton != JPEG_ZOOM_PRE) | ||
630 | break; | ||
631 | #endif | ||
632 | return ZOOM_IN; | ||
633 | break; | ||
634 | |||
635 | case JPEG_ZOOM_OUT: | ||
636 | #ifdef JPEG_ZOOM_PRE | ||
637 | if (lastbutton != JPEG_ZOOM_PRE) | ||
638 | break; | ||
639 | #endif | ||
640 | return ZOOM_OUT; | ||
641 | break; | ||
642 | #ifdef JPEG_RC_MENU | ||
643 | case JPEG_RC_MENU: | ||
644 | #endif | ||
645 | case JPEG_MENU: | ||
646 | #ifdef USEGSLIB | ||
647 | grey_show(false); /* switch off greyscale overlay */ | ||
648 | #endif | ||
649 | if (show_menu() == 1) | ||
650 | return PLUGIN_OK; | ||
651 | |||
652 | #ifdef USEGSLIB | ||
653 | grey_show(true); /* switch on greyscale overlay */ | ||
654 | #else | ||
655 | draw_image_rect(pdisp, 0, 0, | ||
656 | pdisp->width-pdisp->x, pdisp->height-pdisp->y); | ||
657 | MYLCD_UPDATE(); | ||
658 | #endif | ||
659 | break; | ||
660 | default: | ||
661 | if (rb->default_event_handler_ex(button, cleanup, NULL) | ||
662 | == SYS_USB_CONNECTED) | ||
663 | return PLUGIN_USB_CONNECTED; | ||
664 | break; | ||
665 | |||
666 | } /* switch */ | ||
667 | |||
668 | if (button != BUTTON_NONE) | ||
669 | lastbutton = button; | ||
670 | } /* while (true) */ | ||
671 | } | ||
672 | |||
673 | /********************* main function *************************/ | ||
674 | |||
675 | /* callback updating a progress meter while JPEG decoding */ | ||
676 | void cb_progress(int current, int total) | ||
677 | { | ||
678 | rb->yield(); /* be nice to the other threads */ | ||
679 | if(!running_slideshow) | ||
680 | { | ||
681 | rb->gui_scrollbar_draw(rb->screens[SCREEN_MAIN], | ||
682 | 0, LCD_HEIGHT-8, LCD_WIDTH, 8, | ||
683 | total, 0, current, HORIZONTAL); | ||
684 | rb->lcd_update_rect(0, LCD_HEIGHT-8, LCD_WIDTH, 8); | ||
685 | } | ||
686 | #ifndef USEGSLIB | ||
687 | else | ||
688 | { | ||
689 | /* in slideshow mode, keep gui interference to a minimum */ | ||
690 | rb->gui_scrollbar_draw(rb->screens[SCREEN_MAIN], | ||
691 | 0, LCD_HEIGHT-4, LCD_WIDTH, 4, | ||
692 | total, 0, current, HORIZONTAL); | ||
693 | rb->lcd_update_rect(0, LCD_HEIGHT-4, LCD_WIDTH, 4); | ||
694 | } | ||
695 | #endif | ||
696 | } | ||
697 | |||
698 | int jpegmem(struct jpeg *p_jpg, int ds) | ||
699 | { | ||
700 | int size; | ||
701 | |||
702 | size = (p_jpg->x_phys/ds/p_jpg->subsample_x[0]) | ||
703 | * (p_jpg->y_phys/ds/p_jpg->subsample_y[0]); | ||
704 | #ifdef HAVE_LCD_COLOR | ||
705 | if (p_jpg->blocks > 1) /* colour, add requirements for chroma */ | ||
706 | { | ||
707 | size += (p_jpg->x_phys/ds/p_jpg->subsample_x[1]) | ||
708 | * (p_jpg->y_phys/ds/p_jpg->subsample_y[1]); | ||
709 | size += (p_jpg->x_phys/ds/p_jpg->subsample_x[2]) | ||
710 | * (p_jpg->y_phys/ds/p_jpg->subsample_y[2]); | ||
711 | } | ||
712 | #endif | ||
713 | return size; | ||
714 | } | ||
715 | |||
716 | /* how far can we zoom in without running out of memory */ | ||
717 | int min_downscale(struct jpeg *p_jpg, int bufsize) | ||
718 | { | ||
719 | int downscale = 8; | ||
720 | |||
721 | if (jpegmem(p_jpg, 8) > bufsize) | ||
722 | return 0; /* error, too large, even 1:8 doesn't fit */ | ||
723 | |||
724 | while (downscale > 1 && jpegmem(p_jpg, downscale/2) <= bufsize) | ||
725 | downscale /= 2; | ||
726 | |||
727 | return downscale; | ||
728 | } | ||
729 | |||
730 | /* how far can we zoom out, to fit image into the LCD */ | ||
731 | int max_downscale(struct jpeg *p_jpg) | ||
732 | { | ||
733 | int downscale = 1; | ||
734 | |||
735 | while (downscale < 8 && (p_jpg->x_size/downscale > LCD_WIDTH | ||
736 | || p_jpg->y_size/downscale > LCD_HEIGHT)) | ||
737 | { | ||
738 | downscale *= 2; | ||
739 | } | ||
740 | |||
741 | return downscale; | ||
742 | } | ||
743 | |||
744 | /* load image from filename. */ | ||
745 | int load_image(char* filename, struct jpeg *p_jpg) | ||
746 | { | ||
747 | int fd; | ||
748 | int filesize; | ||
749 | unsigned char* buf_jpeg; /* compressed JPEG image */ | ||
750 | int status; | ||
751 | |||
752 | fd = rb->open(filename, O_RDONLY); | ||
753 | if (fd < 0) | ||
754 | { | ||
755 | rb->splashf(HZ, "err opening %s:%d", filename, fd); | ||
756 | return PLUGIN_ERROR; | ||
757 | } | ||
758 | filesize = rb->filesize(fd); | ||
759 | |||
760 | /* allocate JPEG buffer */ | ||
761 | buf_jpeg = buf; | ||
762 | |||
763 | /* we can start the decompressed images behind it */ | ||
764 | buf_images = buf_root = buf + filesize; | ||
765 | buf_images_size = root_size = buf_size - filesize; | ||
766 | |||
767 | if (buf_images_size <= 0) | ||
768 | { | ||
769 | rb->close(fd); | ||
770 | return PLUGIN_OUTOFMEM; | ||
771 | } | ||
772 | |||
773 | if(!running_slideshow) | ||
774 | { | ||
775 | rb->snprintf(print, sizeof(print), "%s:", rb->strrchr(filename,'/')+1); | ||
776 | rb->lcd_puts(0, 0, print); | ||
777 | rb->lcd_update(); | ||
778 | |||
779 | rb->snprintf(print, sizeof(print), "loading %d bytes", filesize); | ||
780 | rb->lcd_puts(0, 1, print); | ||
781 | rb->lcd_update(); | ||
782 | } | ||
783 | |||
784 | rb->read(fd, buf_jpeg, filesize); | ||
785 | rb->close(fd); | ||
786 | |||
787 | if(!running_slideshow) | ||
788 | { | ||
789 | rb->snprintf(print, sizeof(print), "decoding markers"); | ||
790 | rb->lcd_puts(0, 2, print); | ||
791 | rb->lcd_update(); | ||
792 | } | ||
793 | #ifndef SIMULATOR | ||
794 | else if(immediate_ata_off) | ||
795 | { | ||
796 | /* running slideshow and time is long enough: power down disk */ | ||
797 | rb->storage_sleep(); | ||
798 | } | ||
799 | #endif | ||
800 | |||
801 | /* process markers, unstuffing */ | ||
802 | status = process_markers(buf_jpeg, filesize, p_jpg); | ||
803 | |||
804 | if (status < 0 || (status & (DQT | SOF0)) != (DQT | SOF0)) | ||
805 | { /* bad format or minimum components not contained */ | ||
806 | rb->splashf(HZ, "unsupported %d", status); | ||
807 | return PLUGIN_ERROR; | ||
808 | } | ||
809 | |||
810 | if (!(status & DHT)) /* if no Huffman table present: */ | ||
811 | default_huff_tbl(p_jpg); /* use default */ | ||
812 | build_lut(p_jpg); /* derive Huffman and other lookup-tables */ | ||
813 | |||
814 | if(!running_slideshow) | ||
815 | { | ||
816 | rb->snprintf(print, sizeof(print), "image %dx%d", | ||
817 | p_jpg->x_size, p_jpg->y_size); | ||
818 | rb->lcd_puts(0, 2, print); | ||
819 | rb->lcd_update(); | ||
820 | } | ||
821 | |||
822 | return PLUGIN_OK; | ||
823 | } | ||
824 | |||
825 | /* return decoded or cached image */ | ||
826 | struct t_disp* get_image(struct jpeg* p_jpg, int ds) | ||
827 | { | ||
828 | int w, h; /* used to center output */ | ||
829 | int size; /* decompressed image size */ | ||
830 | long time; /* measured ticks */ | ||
831 | int status; | ||
832 | |||
833 | struct t_disp* p_disp = &disp[ds]; /* short cut */ | ||
834 | |||
835 | if (p_disp->bitmap[0] != NULL) | ||
836 | { | ||
837 | return p_disp; /* we still have it */ | ||
838 | } | ||
839 | |||
840 | /* assign image buffer */ | ||
841 | |||
842 | /* physical size needed for decoding */ | ||
843 | size = jpegmem(p_jpg, ds); | ||
844 | if (buf_images_size <= size) | ||
845 | { /* have to discard the current */ | ||
846 | int i; | ||
847 | for (i=1; i<=8; i++) | ||
848 | disp[i].bitmap[0] = NULL; /* invalidate all bitmaps */ | ||
849 | buf_images = buf_root; /* start again from the beginning of the buffer */ | ||
850 | buf_images_size = root_size; | ||
851 | } | ||
852 | |||
853 | #ifdef HAVE_LCD_COLOR | ||
854 | if (p_jpg->blocks > 1) /* colour jpeg */ | ||
855 | { | ||
856 | int i; | ||
857 | |||
858 | for (i = 1; i < 3; i++) | ||
859 | { | ||
860 | size = (p_jpg->x_phys / ds / p_jpg->subsample_x[i]) | ||
861 | * (p_jpg->y_phys / ds / p_jpg->subsample_y[i]); | ||
862 | p_disp->bitmap[i] = buf_images; | ||
863 | buf_images += size; | ||
864 | buf_images_size -= size; | ||
865 | } | ||
866 | p_disp->csub_x = p_jpg->subsample_x[1]; | ||
867 | p_disp->csub_y = p_jpg->subsample_y[1]; | ||
868 | } | ||
869 | else | ||
870 | { | ||
871 | p_disp->csub_x = p_disp->csub_y = 0; | ||
872 | p_disp->bitmap[1] = p_disp->bitmap[2] = buf_images; | ||
873 | } | ||
874 | #endif | ||
875 | /* size may be less when decoded (if height is not block aligned) */ | ||
876 | size = (p_jpg->x_phys/ds) * (p_jpg->y_size / ds); | ||
877 | p_disp->bitmap[0] = buf_images; | ||
878 | buf_images += size; | ||
879 | buf_images_size -= size; | ||
880 | |||
881 | if(!running_slideshow) | ||
882 | { | ||
883 | rb->snprintf(print, sizeof(print), "decoding %d*%d", | ||
884 | p_jpg->x_size/ds, p_jpg->y_size/ds); | ||
885 | rb->lcd_puts(0, 3, print); | ||
886 | rb->lcd_update(); | ||
887 | } | ||
888 | |||
889 | /* update image properties */ | ||
890 | p_disp->width = p_jpg->x_size / ds; | ||
891 | p_disp->stride = p_jpg->x_phys / ds; /* use physical size for stride */ | ||
892 | p_disp->height = p_jpg->y_size / ds; | ||
893 | |||
894 | /* the actual decoding */ | ||
895 | time = *rb->current_tick; | ||
896 | #ifdef HAVE_ADJUSTABLE_CPU_FREQ | ||
897 | rb->cpu_boost(true); | ||
898 | status = jpeg_decode(p_jpg, p_disp->bitmap, ds, cb_progress); | ||
899 | rb->cpu_boost(false); | ||
900 | #else | ||
901 | status = jpeg_decode(p_jpg, p_disp->bitmap, ds, cb_progress); | ||
902 | #endif | ||
903 | if (status) | ||
904 | { | ||
905 | rb->splashf(HZ, "decode error %d", status); | ||
906 | return NULL; | ||
907 | } | ||
908 | time = *rb->current_tick - time; | ||
909 | |||
910 | if(!running_slideshow) | ||
911 | { | ||
912 | rb->snprintf(print, sizeof(print), " %ld.%02ld sec ", time/HZ, time%HZ); | ||
913 | rb->lcd_getstringsize(print, &w, &h); /* centered in progress bar */ | ||
914 | rb->lcd_putsxy((LCD_WIDTH - w)/2, LCD_HEIGHT - h, print); | ||
915 | rb->lcd_update(); | ||
916 | } | ||
917 | |||
918 | return p_disp; | ||
919 | } | ||
920 | |||
921 | |||
922 | /* set the view to the given center point, limit if necessary */ | ||
923 | void set_view (struct t_disp* p_disp, int cx, int cy) | ||
924 | { | ||
925 | int x, y; | ||
926 | |||
927 | /* plain center to available width/height */ | ||
928 | x = cx - MIN(LCD_WIDTH, p_disp->width) / 2; | ||
929 | y = cy - MIN(LCD_HEIGHT, p_disp->height) / 2; | ||
930 | |||
931 | /* limit against upper image size */ | ||
932 | x = MIN(p_disp->width - LCD_WIDTH, x); | ||
933 | y = MIN(p_disp->height - LCD_HEIGHT, y); | ||
934 | |||
935 | /* limit against negative side */ | ||
936 | x = MAX(0, x); | ||
937 | y = MAX(0, y); | ||
938 | |||
939 | p_disp->x = x; /* set the values */ | ||
940 | p_disp->y = y; | ||
941 | } | ||
942 | |||
943 | /* calculate the view center based on the bitmap position */ | ||
944 | void get_view(struct t_disp* p_disp, int* p_cx, int* p_cy) | ||
945 | { | ||
946 | *p_cx = p_disp->x + MIN(LCD_WIDTH, p_disp->width) / 2; | ||
947 | *p_cy = p_disp->y + MIN(LCD_HEIGHT, p_disp->height) / 2; | ||
948 | } | ||
949 | |||
950 | /* load, decode, display the image */ | ||
951 | int load_and_show(char* filename) | ||
952 | { | ||
953 | int status; | ||
954 | struct t_disp* p_disp; /* currenly displayed image */ | ||
955 | int cx, cy; /* view center */ | ||
956 | |||
957 | #if LCD_DEPTH > 1 | ||
958 | rb->lcd_set_foreground(LCD_WHITE); | ||
959 | rb->lcd_set_background(LCD_BLACK); | ||
960 | rb->lcd_set_backdrop(NULL); | ||
961 | #endif | ||
962 | rb->lcd_clear_display(); | ||
963 | |||
964 | rb->memset(&disp, 0, sizeof(disp)); | ||
965 | rb->memset(&jpg, 0, sizeof(jpg)); /* clear info struct */ | ||
966 | |||
967 | if (rb->button_get(false) == JPEG_MENU) | ||
968 | status = PLUGIN_ABORT; | ||
969 | else | ||
970 | status = load_image(filename, &jpg); | ||
971 | |||
972 | if (status == PLUGIN_OUTOFMEM) | ||
973 | { | ||
974 | #if PLUGIN_BUFFER_SIZE >= MIN_MEM | ||
975 | if(plug_buf) | ||
976 | { | ||
977 | rb->lcd_setfont(FONT_SYSFIXED); | ||
978 | rb->lcd_clear_display(); | ||
979 | rb->snprintf(print,sizeof(print),"%s:",rb->strrchr(filename,'/')+1); | ||
980 | rb->lcd_puts(0,0,print); | ||
981 | rb->lcd_puts(0,1,"Not enough plugin memory!"); | ||
982 | rb->lcd_puts(0,2,"Zoom In: Stop playback."); | ||
983 | if(entries>1) | ||
984 | rb->lcd_puts(0,3,"Left/Right: Skip File."); | ||
985 | rb->lcd_puts(0,4,"Show Menu: Quit."); | ||
986 | rb->lcd_update(); | ||
987 | rb->lcd_setfont(FONT_UI); | ||
988 | |||
989 | rb->button_clear_queue(); | ||
990 | |||
991 | while (1) | ||
992 | { | ||
993 | int button = rb->button_get(true); | ||
994 | switch(button) | ||
995 | { | ||
996 | case JPEG_ZOOM_IN: | ||
997 | plug_buf = false; | ||
998 | buf = rb->plugin_get_audio_buffer((size_t *)&buf_size); | ||
999 | /*try again this file, now using the audio buffer */ | ||
1000 | return PLUGIN_OTHER; | ||
1001 | #ifdef JPEG_RC_MENU | ||
1002 | case JPEG_RC_MENU: | ||
1003 | #endif | ||
1004 | case JPEG_MENU: | ||
1005 | return PLUGIN_OK; | ||
1006 | |||
1007 | case JPEG_LEFT: | ||
1008 | if(entries>1) | ||
1009 | { | ||
1010 | rb->lcd_clear_display(); | ||
1011 | return change_filename(DIR_PREV); | ||
1012 | } | ||
1013 | break; | ||
1014 | |||
1015 | case JPEG_RIGHT: | ||
1016 | if(entries>1) | ||
1017 | { | ||
1018 | rb->lcd_clear_display(); | ||
1019 | return change_filename(DIR_NEXT); | ||
1020 | } | ||
1021 | break; | ||
1022 | default: | ||
1023 | if(rb->default_event_handler_ex(button, cleanup, NULL) | ||
1024 | == SYS_USB_CONNECTED) | ||
1025 | return PLUGIN_USB_CONNECTED; | ||
1026 | |||
1027 | } | ||
1028 | } | ||
1029 | } | ||
1030 | else | ||
1031 | #endif | ||
1032 | { | ||
1033 | rb->splash(HZ, "Out of Memory"); | ||
1034 | file_pt[curfile] = NULL; | ||
1035 | return change_filename(direction); | ||
1036 | } | ||
1037 | } | ||
1038 | else if (status == PLUGIN_ERROR) | ||
1039 | { | ||
1040 | file_pt[curfile] = NULL; | ||
1041 | return change_filename(direction); | ||
1042 | } | ||
1043 | else if (status == PLUGIN_ABORT) { | ||
1044 | rb->splash(HZ, "aborted"); | ||
1045 | return PLUGIN_OK; | ||
1046 | } | ||
1047 | |||
1048 | ds_max = max_downscale(&jpg); /* check display constraint */ | ||
1049 | ds_min = min_downscale(&jpg, buf_images_size); /* check memory constraint */ | ||
1050 | if (ds_min == 0) | ||
1051 | { | ||
1052 | rb->splash(HZ, "too large"); | ||
1053 | file_pt[curfile] = NULL; | ||
1054 | return change_filename(direction); | ||
1055 | } | ||
1056 | else if (ds_max < ds_min) | ||
1057 | ds_max = ds_min; | ||
1058 | |||
1059 | ds = ds_max; /* initialize setting */ | ||
1060 | cx = jpg.x_size/ds/2; /* center the view */ | ||
1061 | cy = jpg.y_size/ds/2; | ||
1062 | |||
1063 | do /* loop the image prepare and decoding when zoomed */ | ||
1064 | { | ||
1065 | p_disp = get_image(&jpg, ds); /* decode or fetch from cache */ | ||
1066 | if (p_disp == NULL) | ||
1067 | { | ||
1068 | file_pt[curfile] = NULL; | ||
1069 | return change_filename(direction); | ||
1070 | } | ||
1071 | |||
1072 | set_view(p_disp, cx, cy); | ||
1073 | |||
1074 | if(!running_slideshow) | ||
1075 | { | ||
1076 | rb->snprintf(print, sizeof(print), "showing %dx%d", | ||
1077 | p_disp->width, p_disp->height); | ||
1078 | rb->lcd_puts(0, 3, print); | ||
1079 | rb->lcd_update(); | ||
1080 | } | ||
1081 | |||
1082 | MYLCD(clear_display)(); | ||
1083 | draw_image_rect(p_disp, 0, 0, | ||
1084 | p_disp->width-p_disp->x, p_disp->height-p_disp->y); | ||
1085 | MYLCD_UPDATE(); | ||
1086 | |||
1087 | #ifdef USEGSLIB | ||
1088 | grey_show(true); /* switch on greyscale overlay */ | ||
1089 | #endif | ||
1090 | |||
1091 | /* drawing is now finished, play around with scrolling | ||
1092 | * until you press OFF or connect USB | ||
1093 | */ | ||
1094 | while (1) | ||
1095 | { | ||
1096 | status = scroll_bmp(p_disp); | ||
1097 | if (status == ZOOM_IN) | ||
1098 | { | ||
1099 | if (ds > ds_min) | ||
1100 | { | ||
1101 | ds /= 2; /* reduce downscaling to zoom in */ | ||
1102 | get_view(p_disp, &cx, &cy); | ||
1103 | cx *= 2; /* prepare the position in the new image */ | ||
1104 | cy *= 2; | ||
1105 | } | ||
1106 | else | ||
1107 | continue; | ||
1108 | } | ||
1109 | |||
1110 | if (status == ZOOM_OUT) | ||
1111 | { | ||
1112 | if (ds < ds_max) | ||
1113 | { | ||
1114 | ds *= 2; /* increase downscaling to zoom out */ | ||
1115 | get_view(p_disp, &cx, &cy); | ||
1116 | cx /= 2; /* prepare the position in the new image */ | ||
1117 | cy /= 2; | ||
1118 | } | ||
1119 | else | ||
1120 | continue; | ||
1121 | } | ||
1122 | break; | ||
1123 | } | ||
1124 | |||
1125 | #ifdef USEGSLIB | ||
1126 | grey_show(false); /* switch off overlay */ | ||
1127 | #endif | ||
1128 | rb->lcd_clear_display(); | ||
1129 | } | ||
1130 | while (status != PLUGIN_OK && status != PLUGIN_USB_CONNECTED | ||
1131 | && status != PLUGIN_OTHER); | ||
1132 | #ifdef USEGSLIB | ||
1133 | rb->lcd_update(); | ||
1134 | #endif | ||
1135 | return status; | ||
1136 | } | ||
1137 | |||
1138 | /******************** Plugin entry point *********************/ | ||
1139 | |||
1140 | enum plugin_status plugin_start(const void* parameter) | ||
1141 | { | ||
1142 | int condition; | ||
1143 | #ifdef USEGSLIB | ||
1144 | long greysize; /* helper */ | ||
1145 | #endif | ||
1146 | #if LCD_DEPTH > 1 | ||
1147 | old_backdrop = rb->lcd_get_backdrop(); | ||
1148 | #endif | ||
1149 | |||
1150 | if(!parameter) return PLUGIN_ERROR; | ||
1151 | |||
1152 | #if PLUGIN_BUFFER_SIZE >= MIN_MEM | ||
1153 | buf = rb->plugin_get_buffer((size_t *)&buf_size); | ||
1154 | #else | ||
1155 | buf = rb->plugin_get_audio_buffer((size_t *)&buf_size); | ||
1156 | #endif | ||
1157 | |||
1158 | rb->strcpy(np_file, parameter); | ||
1159 | get_pic_list(); | ||
1160 | |||
1161 | if(!entries) return PLUGIN_ERROR; | ||
1162 | |||
1163 | #if (PLUGIN_BUFFER_SIZE >= MIN_MEM) && !defined(SIMULATOR) | ||
1164 | if(!rb->audio_status()) | ||
1165 | { | ||
1166 | plug_buf = false; | ||
1167 | buf = rb->plugin_get_audio_buffer((size_t *)&buf_size); | ||
1168 | } | ||
1169 | #endif | ||
1170 | |||
1171 | #ifdef USEGSLIB | ||
1172 | if (!grey_init(buf, buf_size, GREY_ON_COP, | ||
1173 | LCD_WIDTH, LCD_HEIGHT, &greysize)) | ||
1174 | { | ||
1175 | rb->splash(HZ, "grey buf error"); | ||
1176 | return PLUGIN_ERROR; | ||
1177 | } | ||
1178 | buf += greysize; | ||
1179 | buf_size -= greysize; | ||
1180 | #endif | ||
1181 | |||
1182 | /* should be ok to just load settings since the plugin itself has | ||
1183 | just been loaded from disk and the drive should be spinning */ | ||
1184 | configfile_load(JPEG_CONFIGFILE, jpeg_config, | ||
1185 | ARRAYLEN(jpeg_config), JPEG_SETTINGS_MINVERSION); | ||
1186 | old_settings = jpeg_settings; | ||
1187 | |||
1188 | /* Turn off backlight timeout */ | ||
1189 | backlight_force_on(); /* backlight control in lib/helper.c */ | ||
1190 | |||
1191 | do | ||
1192 | { | ||
1193 | condition = load_and_show(np_file); | ||
1194 | } while (condition != PLUGIN_OK && condition != PLUGIN_USB_CONNECTED | ||
1195 | && condition != PLUGIN_ERROR); | ||
1196 | |||
1197 | if (rb->memcmp(&jpeg_settings, &old_settings, sizeof (jpeg_settings))) | ||
1198 | { | ||
1199 | /* Just in case drive has to spin, keep it from looking locked */ | ||
1200 | rb->splash(0, "Saving Settings"); | ||
1201 | configfile_save(JPEG_CONFIGFILE, jpeg_config, | ||
1202 | ARRAYLEN(jpeg_config), JPEG_SETTINGS_VERSION); | ||
1203 | } | ||
1204 | |||
1205 | #if !defined(SIMULATOR) && defined(HAVE_DISK_STORAGE) | ||
1206 | /* set back ata spindown time in case we changed it */ | ||
1207 | rb->storage_spindown(rb->global_settings->disk_spindown); | ||
1208 | #endif | ||
1209 | |||
1210 | /* Turn on backlight timeout (revert to settings) */ | ||
1211 | backlight_use_settings(); /* backlight control in lib/helper.c */ | ||
1212 | |||
1213 | #ifdef USEGSLIB | ||
1214 | grey_release(); /* deinitialize */ | ||
1215 | #endif | ||
1216 | |||
1217 | return condition; | ||
1218 | } | ||