diff options
author | Marcin Bukat <marcin.bukat@gmail.com> | 2012-11-02 13:03:58 +0100 |
---|---|---|
committer | Marcin Bukat <marcin.bukat@gmail.com> | 2012-11-13 18:13:10 +0100 |
commit | 0ceaff2b65c50b75ad8cc5b2d12e7b3f864092e5 (patch) | |
tree | 49d8d297cbba93902bc612a9aa4ded1b6e2d46e5 /apps/plugins/imageviewer/gif/gif.c | |
parent | b35f82c91ff050b4405b19a3e56e9d031bf940e2 (diff) | |
download | rockbox-0ceaff2b65c50b75ad8cc5b2d12e7b3f864092e5.tar.gz rockbox-0ceaff2b65c50b75ad8cc5b2d12e7b3f864092e5.zip |
imageviewer: gif viewer based on giflib-5.0.2
This adds ability to view gif images in rockbox.
Works both on color and gray/monochrome targets (greylib).
Aspect correction is supported as well.
Limitations:
- animated gifs are restricted to 32 frames
- animated gifs loop always (loopcount is ignored)
- plain text extension is not supported
- animated gifs with interframe delay = 0 are treated as still
images (web browsers usually treat delay 0 as 100ms to prevent
exhaustive CPU load by such images)
Change-Id: I61501f801ddcd403410e38d83e6bddc9883e7ede
Diffstat (limited to 'apps/plugins/imageviewer/gif/gif.c')
-rw-r--r-- | apps/plugins/imageviewer/gif/gif.c | 241 |
1 files changed, 241 insertions, 0 deletions
diff --git a/apps/plugins/imageviewer/gif/gif.c b/apps/plugins/imageviewer/gif/gif.c new file mode 100644 index 0000000000..672735af94 --- /dev/null +++ b/apps/plugins/imageviewer/gif/gif.c | |||
@@ -0,0 +1,241 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * | ||
9 | * Copyright (c) 2012 Marcin Bukat | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or | ||
12 | * modify it under the terms of the GNU General Public License | ||
13 | * as published by the Free Software Foundation; either version 2 | ||
14 | * of the License, or (at your option) any later version. | ||
15 | * | ||
16 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
17 | * KIND, either express or implied. | ||
18 | * | ||
19 | ****************************************************************************/ | ||
20 | |||
21 | #include "plugin.h" | ||
22 | #include "lcd.h" | ||
23 | #include <lib/pluginlib_bmp.h> | ||
24 | #include "../imageviewer.h" | ||
25 | #include "bmp.h" | ||
26 | #include "gif_decoder.h" | ||
27 | #include "gif_lib.h" | ||
28 | |||
29 | /* decoder context struct */ | ||
30 | static struct gif_decoder decoder; | ||
31 | |||
32 | static char print[32]; /* use a common snprintf() buffer */ | ||
33 | |||
34 | /* decompressed image in the possible sizes (1,2,4,8), wasting the other */ | ||
35 | /* max 32 frames */ | ||
36 | static unsigned char *disp[GIF_MAX_FRAMES][9]; | ||
37 | static unsigned char *disp_buf; | ||
38 | |||
39 | #if defined(HAVE_LCD_COLOR) | ||
40 | #define resize_bitmap smooth_resize_bitmap | ||
41 | #else | ||
42 | #define resize_bitmap grey_resize_bitmap | ||
43 | #endif | ||
44 | |||
45 | #if defined(USEGSLIB) && (CONFIG_PLATFORM & PLATFORM_HOSTED) | ||
46 | /* hack: fix error "undefined reference to `_grey_info'". */ | ||
47 | GREY_INFO_STRUCT | ||
48 | #endif /* USEGSLIB */ | ||
49 | |||
50 | static void draw_image_rect(struct image_info *info, | ||
51 | int x, int y, int width, int height) | ||
52 | { | ||
53 | unsigned char **pdisp = (unsigned char **)info->data; | ||
54 | |||
55 | #ifdef HAVE_LCD_COLOR | ||
56 | rb->lcd_bitmap_part((fb_data *)*pdisp, info->x + x, info->y + y, | ||
57 | STRIDE(SCREEN_MAIN, info->width, info->height), | ||
58 | x + MAX(0, (LCD_WIDTH-info->width)/2), | ||
59 | y + MAX(0, (LCD_HEIGHT-info->height)/2), | ||
60 | width, height); | ||
61 | #else | ||
62 | mylcd_ub_gray_bitmap_part(*pdisp, | ||
63 | info->x + x, info->y + y, info->width, | ||
64 | x + MAX(0, (LCD_WIDTH-info->width)/2), | ||
65 | y + MAX(0, (LCD_HEIGHT-info->height)/2), | ||
66 | width, height); | ||
67 | #endif | ||
68 | } | ||
69 | |||
70 | static int img_mem(int ds) | ||
71 | { | ||
72 | struct gif_decoder *p_decoder = &decoder; | ||
73 | return p_decoder->native_img_size/ds; | ||
74 | } | ||
75 | |||
76 | static int load_image(char *filename, struct image_info *info, | ||
77 | unsigned char *buf, ssize_t *buf_size) | ||
78 | { | ||
79 | int w, h; | ||
80 | long time = 0; /* measured ticks */ | ||
81 | struct gif_decoder *p_decoder = &decoder; | ||
82 | |||
83 | unsigned char *memory, *memory_max; | ||
84 | size_t memory_size; | ||
85 | |||
86 | /* cleanup */ | ||
87 | memset(&disp, 0, sizeof(disp)); | ||
88 | |||
89 | /* align buffer */ | ||
90 | memory = (unsigned char *)((intptr_t)(buf + 3) & ~3); | ||
91 | memory_max = (unsigned char *)((intptr_t)(memory + *buf_size) & ~3); | ||
92 | memory_size = memory_max - memory; | ||
93 | |||
94 | #ifdef DISK_SPINDOWN | ||
95 | if (iv->running_slideshow && iv->immediate_ata_off) { | ||
96 | /* running slideshow and time is long enough: power down disk */ | ||
97 | rb->storage_sleep(); | ||
98 | } | ||
99 | #endif | ||
100 | |||
101 | /* initialize decoder context struct, set buffer decoder is free | ||
102 | * to use. | ||
103 | */ | ||
104 | gif_decoder_init(p_decoder, memory, memory_size); | ||
105 | |||
106 | /* populate internal data from gif file control structs */ | ||
107 | gif_open(filename, p_decoder); | ||
108 | |||
109 | if (!p_decoder->error) | ||
110 | { | ||
111 | |||
112 | if (!iv->running_slideshow) | ||
113 | { | ||
114 | rb->lcd_putsf(0, 2, "image %dx%d", | ||
115 | p_decoder->width, | ||
116 | p_decoder->height); | ||
117 | rb->lcd_putsf(0, 3, "decoding %d*%d", | ||
118 | p_decoder->width, | ||
119 | p_decoder->height); | ||
120 | rb->lcd_update(); | ||
121 | } | ||
122 | |||
123 | /* the actual decoding */ | ||
124 | time = *rb->current_tick; | ||
125 | |||
126 | #ifdef HAVE_ADJUSTABLE_CPU_FREQ | ||
127 | rb->cpu_boost(true); | ||
128 | #endif | ||
129 | gif_decode(p_decoder, iv->cb_progress); | ||
130 | |||
131 | #ifdef HAVE_ADJUSTABLE_CPU_FREQ | ||
132 | rb->cpu_boost(false); | ||
133 | #endif | ||
134 | time = *rb->current_tick - time; | ||
135 | } | ||
136 | |||
137 | if (!iv->running_slideshow && !p_decoder->error) | ||
138 | { | ||
139 | rb->snprintf(print, sizeof(print), " %ld.%02ld sec ", time/HZ, time%HZ); | ||
140 | rb->lcd_getstringsize(print, &w, &h); /* centered in progress bar */ | ||
141 | rb->lcd_putsxy((LCD_WIDTH - w)/2, LCD_HEIGHT - h, print); | ||
142 | rb->lcd_update(); | ||
143 | } | ||
144 | |||
145 | if (p_decoder->error) | ||
146 | { | ||
147 | rb->splashf(HZ, "%s", GifErrorString(p_decoder->error)); | ||
148 | return PLUGIN_ERROR; | ||
149 | } | ||
150 | |||
151 | info->x_size = p_decoder->width; | ||
152 | info->y_size = p_decoder->height; | ||
153 | info->frames_count = p_decoder->frames_count; | ||
154 | info->delay = p_decoder->delay; | ||
155 | |||
156 | //p_decoder->native_img_size = (p_decoder->native_img_size + 3) & ~3; | ||
157 | disp_buf = p_decoder->mem + | ||
158 | ((p_decoder->native_img_size*p_decoder->frames_count + 3) & ~3); | ||
159 | |||
160 | *buf_size = memory_max - disp_buf; | ||
161 | |||
162 | return PLUGIN_OK; | ||
163 | } | ||
164 | |||
165 | static int get_image(struct image_info *info, int frame, int ds) | ||
166 | { | ||
167 | unsigned char **p_disp = &disp[frame][ds]; /* short cut */ | ||
168 | struct gif_decoder *p_decoder = &decoder; | ||
169 | |||
170 | info->width = p_decoder->width / ds; | ||
171 | info->height = p_decoder->height / ds; | ||
172 | info->data = p_disp; | ||
173 | |||
174 | if (*p_disp != NULL) | ||
175 | { | ||
176 | /* we still have it */ | ||
177 | return PLUGIN_OK; | ||
178 | } | ||
179 | |||
180 | /* assign image buffer */ | ||
181 | if (ds > 1) | ||
182 | { | ||
183 | if (!iv->running_slideshow) | ||
184 | { | ||
185 | rb->lcd_putsf(0, 3, "resizing %d*%d", info->width, info->height); | ||
186 | rb->lcd_update(); | ||
187 | } | ||
188 | struct bitmap bmp_src, bmp_dst; | ||
189 | |||
190 | /* size of the scalled image */ | ||
191 | int size = img_mem(ds); | ||
192 | |||
193 | if (disp_buf + size >= p_decoder->mem + p_decoder->mem_size) | ||
194 | { | ||
195 | /* have to discard the current */ | ||
196 | int i; | ||
197 | for (i=1; i<=8; i++) | ||
198 | disp[frame][i] = NULL; /* invalidate all bitmaps */ | ||
199 | |||
200 | /* start again from the beginning of the buffer */ | ||
201 | disp_buf = p_decoder->mem + | ||
202 | p_decoder->native_img_size*p_decoder->frames_count; | ||
203 | } | ||
204 | |||
205 | *p_disp = disp_buf; | ||
206 | disp_buf += size; | ||
207 | |||
208 | bmp_src.width = p_decoder->width; | ||
209 | bmp_src.height = p_decoder->height; | ||
210 | bmp_src.data = p_decoder->mem + p_decoder->native_img_size*frame; | ||
211 | |||
212 | bmp_dst.width = info->width; | ||
213 | bmp_dst.height = info->height; | ||
214 | bmp_dst.data = *p_disp; | ||
215 | |||
216 | #ifdef HAVE_ADJUSTABLE_CPU_FREQ | ||
217 | rb->cpu_boost(true); | ||
218 | #endif | ||
219 | resize_bitmap(&bmp_src, &bmp_dst); | ||
220 | |||
221 | #ifdef HAVE_ADJUSTABLE_CPU_FREQ | ||
222 | rb->cpu_boost(false); | ||
223 | #endif | ||
224 | } | ||
225 | else | ||
226 | { | ||
227 | *p_disp = p_decoder->mem + p_decoder->native_img_size*frame; | ||
228 | } | ||
229 | |||
230 | return PLUGIN_OK; | ||
231 | } | ||
232 | |||
233 | const struct image_decoder image_decoder = { | ||
234 | true, | ||
235 | img_mem, | ||
236 | load_image, | ||
237 | get_image, | ||
238 | draw_image_rect, | ||
239 | }; | ||
240 | |||
241 | IMGDEC_HEADER | ||