diff options
Diffstat (limited to 'apps/plugins/imageviewer/ppm/ppm.c')
-rw-r--r-- | apps/plugins/imageviewer/ppm/ppm.c | 233 |
1 files changed, 233 insertions, 0 deletions
diff --git a/apps/plugins/imageviewer/ppm/ppm.c b/apps/plugins/imageviewer/ppm/ppm.c new file mode 100644 index 0000000000..100a00ac84 --- /dev/null +++ b/apps/plugins/imageviewer/ppm/ppm.c | |||
@@ -0,0 +1,233 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2010 Marcin Bukat | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | |||
22 | #include "plugin.h" | ||
23 | #include "lcd.h" | ||
24 | #include <lib/pluginlib_bmp.h> | ||
25 | #include "../imageviewer.h" | ||
26 | #include "ppm_decoder.h" | ||
27 | #include "bmp.h" | ||
28 | |||
29 | static char print[32]; /* use a common snprintf() buffer */ | ||
30 | |||
31 | /* decompressed image in the possible sizes (1,2,4,8), wasting the other */ | ||
32 | static unsigned char *disp[9]; | ||
33 | static unsigned char *disp_buf; | ||
34 | static struct ppm_info ppm; | ||
35 | |||
36 | #if defined(HAVE_LCD_COLOR) | ||
37 | #define resize_bitmap smooth_resize_bitmap | ||
38 | #else | ||
39 | #define resize_bitmap grey_resize_bitmap | ||
40 | #endif | ||
41 | |||
42 | #if defined(USEGSLIB) && (CONFIG_PLATFORM & PLATFORM_HOSTED) | ||
43 | /* hack: fix error "undefined reference to `_grey_info'". */ | ||
44 | GREY_INFO_STRUCT | ||
45 | #endif /* USEGSLIB */ | ||
46 | |||
47 | static void draw_image_rect(struct image_info *info, | ||
48 | int x, int y, int width, int height) | ||
49 | { | ||
50 | unsigned char **pdisp = (unsigned char **)info->data; | ||
51 | |||
52 | #ifdef HAVE_LCD_COLOR | ||
53 | rb->lcd_bitmap_part((fb_data *)*pdisp, info->x + x, info->y + y, | ||
54 | STRIDE(SCREEN_MAIN, info->width, info->height), | ||
55 | x + MAX(0, (LCD_WIDTH-info->width)/2), | ||
56 | y + MAX(0, (LCD_HEIGHT-info->height)/2), | ||
57 | width, height); | ||
58 | #else | ||
59 | mylcd_ub_gray_bitmap_part(*pdisp, | ||
60 | info->x + x, info->y + y, info->width, | ||
61 | x + MAX(0, (LCD_WIDTH-info->width)/2), | ||
62 | y + MAX(0, (LCD_HEIGHT-info->height)/2), | ||
63 | width, height); | ||
64 | #endif | ||
65 | } | ||
66 | |||
67 | static int img_mem(int ds) | ||
68 | { | ||
69 | |||
70 | #ifdef USEGSLIB | ||
71 | return (ppm.x/ds) * (ppm.y/ds); | ||
72 | #else | ||
73 | return (ppm.x/ds) * (ppm.y/ds) * FB_DATA_SZ; | ||
74 | #endif | ||
75 | } | ||
76 | |||
77 | static int load_image(char *filename, struct image_info *info, | ||
78 | unsigned char *buf, ssize_t *buf_size) | ||
79 | { | ||
80 | int fd; | ||
81 | int rc = PLUGIN_OK; | ||
82 | long time = 0; /* measured ticks */ | ||
83 | int w, h; /* used to center output */ | ||
84 | |||
85 | unsigned char *memory, *memory_max; | ||
86 | size_t memory_size, file_size; | ||
87 | |||
88 | /* cleanup */ | ||
89 | memset(&disp, 0, sizeof(disp)); | ||
90 | |||
91 | /* align buffer */ | ||
92 | memory = (unsigned char *)((intptr_t)(buf + 3) & ~3); | ||
93 | memory_max = (unsigned char *)((intptr_t)(memory + *buf_size) & ~3); | ||
94 | memory_size = memory_max - memory; | ||
95 | |||
96 | fd = rb->open(filename, O_RDONLY); | ||
97 | if (fd < 0) | ||
98 | { | ||
99 | rb->splashf(HZ, "err opening %s: %d", filename, fd); | ||
100 | return PLUGIN_ERROR; | ||
101 | } | ||
102 | |||
103 | file_size = rb->filesize(fd); | ||
104 | DEBUGF("reading file '%s'\n", filename); | ||
105 | |||
106 | if (!iv->running_slideshow) | ||
107 | { | ||
108 | rb->lcd_puts(0, 0, rb->strrchr(filename,'/')+1); | ||
109 | rb->lcd_update(); | ||
110 | } | ||
111 | |||
112 | if (!iv->running_slideshow) | ||
113 | { | ||
114 | rb->lcd_putsf(0, 1, "loading %zu bytes", file_size); | ||
115 | rb->lcd_update(); | ||
116 | } | ||
117 | |||
118 | /* init decoder struct */ | ||
119 | ppm.buf = memory; | ||
120 | ppm.buf_size = memory_size; | ||
121 | |||
122 | /* the actual decoding */ | ||
123 | time = *rb->current_tick; | ||
124 | #ifdef HAVE_ADJUSTABLE_CPU_FREQ | ||
125 | rb->cpu_boost(true); | ||
126 | rc = read_ppm(fd, &ppm); | ||
127 | rb->cpu_boost(false); | ||
128 | #else | ||
129 | rc = read_ppm(fd, &ppm); | ||
130 | #endif /*HAVE_ADJUSTABLE_CPU_FREQ*/ | ||
131 | time = *rb->current_tick - time; | ||
132 | |||
133 | /* close file descriptor */ | ||
134 | rb->close(fd); | ||
135 | |||
136 | /* check return value from decoder */ | ||
137 | if ( rc == PLUGIN_ERROR ) | ||
138 | { | ||
139 | rb->splashf(HZ, "ppm decoder error"); | ||
140 | return PLUGIN_ERROR; | ||
141 | } | ||
142 | |||
143 | if (!iv->running_slideshow) | ||
144 | { | ||
145 | rb->snprintf(print, sizeof(print), " %ld.%02ld sec ", time/HZ, time%HZ); | ||
146 | rb->lcd_getstringsize(print, &w, &h); /* centered in progress bar */ | ||
147 | rb->lcd_putsxy((LCD_WIDTH - w)/2, LCD_HEIGHT - h, print); | ||
148 | rb->lcd_update(); | ||
149 | } | ||
150 | |||
151 | info->x_size = ppm.x; | ||
152 | info->y_size = ppm.y; | ||
153 | |||
154 | ppm.native_img_size = (ppm.native_img_size + 3) & ~3; | ||
155 | disp_buf = buf + ppm.native_img_size; | ||
156 | *buf_size = memory_max - disp_buf; | ||
157 | |||
158 | return PLUGIN_OK; | ||
159 | } | ||
160 | |||
161 | static int get_image(struct image_info *info, int ds) | ||
162 | { | ||
163 | unsigned char **p_disp = &disp[ds]; /* short cut */ | ||
164 | struct ppm_info *p_ppm = &ppm; | ||
165 | |||
166 | info->width = ppm.x / ds; | ||
167 | info->height = ppm.y / ds; | ||
168 | info->data = p_disp; | ||
169 | |||
170 | if (*p_disp != NULL) | ||
171 | { | ||
172 | /* we still have it */ | ||
173 | return PLUGIN_OK; | ||
174 | } | ||
175 | |||
176 | /* assign image buffer */ | ||
177 | if (ds > 1) | ||
178 | { | ||
179 | if (!iv->running_slideshow) | ||
180 | { | ||
181 | rb->lcd_putsf(0, 3, "resizing %d*%d", info->width, info->height); | ||
182 | rb->lcd_update(); | ||
183 | } | ||
184 | |||
185 | struct bitmap bmp_src, bmp_dst; | ||
186 | int size = img_mem(ds); | ||
187 | |||
188 | if (disp_buf + size >= p_ppm->buf + p_ppm->buf_size) | ||
189 | { | ||
190 | /* have to discard the current */ | ||
191 | int i; | ||
192 | for (i=1; i<=8; i++) | ||
193 | disp[i] = NULL; /* invalidate all bitmaps */ | ||
194 | |||
195 | /* start again from the beginning of the buffer */ | ||
196 | disp_buf = p_ppm->buf + p_ppm->native_img_size; | ||
197 | } | ||
198 | |||
199 | *p_disp = disp_buf; | ||
200 | disp_buf += size; | ||
201 | |||
202 | bmp_src.width = ppm.x; | ||
203 | bmp_src.height = ppm.y; | ||
204 | bmp_src.data = ppm.buf; | ||
205 | |||
206 | bmp_dst.width = info->width; | ||
207 | bmp_dst.height = info->height; | ||
208 | bmp_dst.data = *p_disp; | ||
209 | #ifdef HAVE_ADJUSTABLE_CPU_FREQ | ||
210 | rb->cpu_boost(true); | ||
211 | resize_bitmap(&bmp_src, &bmp_dst); | ||
212 | rb->cpu_boost(false); | ||
213 | #else | ||
214 | resize_bitmap(&bmp_src, &bmp_dst); | ||
215 | #endif /*HAVE_ADJUSTABLE_CPU_FREQ*/ | ||
216 | } | ||
217 | else | ||
218 | { | ||
219 | *p_disp = p_ppm->buf; | ||
220 | } | ||
221 | |||
222 | return PLUGIN_OK; | ||
223 | } | ||
224 | |||
225 | const struct image_decoder image_decoder = { | ||
226 | true, | ||
227 | img_mem, | ||
228 | load_image, | ||
229 | get_image, | ||
230 | draw_image_rect, | ||
231 | }; | ||
232 | |||
233 | IMGDEC_HEADER | ||