diff options
author | Jörg Hohensohn <hohensoh@rockbox.org> | 2004-05-12 22:56:32 +0000 |
---|---|---|
committer | Jörg Hohensohn <hohensoh@rockbox.org> | 2004-05-12 22:56:32 +0000 |
commit | efea9e6b2de7a2127bc281a8851627b579731afb (patch) | |
tree | 20b8c21d9c08ddb03f3bb30671d8df812517cea5 | |
parent | 1f55909081b86e560e43234a1e49e9ffe1ada4af (diff) | |
download | rockbox-efea9e6b2de7a2127bc281a8851627b579731afb.tar.gz rockbox-efea9e6b2de7a2127bc281a8851627b579731afb.zip |
jpeg viewer: use Play to zoom in, On to zoom out, arrows to scroll
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@4613 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r-- | apps/plugins/jpeg.c | 3026 |
1 files changed, 3026 insertions, 0 deletions
diff --git a/apps/plugins/jpeg.c b/apps/plugins/jpeg.c new file mode 100644 index 0000000000..ee6fb83f66 --- /dev/null +++ b/apps/plugins/jpeg.c | |||
@@ -0,0 +1,3026 @@ | |||
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 | * Copyright (C) 2004 Jörg Hohensohn aka [IDC]Dragon | ||
14 | * Grayscale framework (c) 2004 Jens Arnold | ||
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 | * All files in this archive are subject to the GNU General Public License. | ||
19 | * See the file COPYING in the source tree root for full license agreement. | ||
20 | * | ||
21 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
22 | * KIND, either express or implied. | ||
23 | * | ||
24 | ****************************************************************************/ | ||
25 | |||
26 | #ifndef SIMULATOR /* not for simulator by now */ | ||
27 | #include "plugin.h" | ||
28 | |||
29 | #ifdef HAVE_LCD_BITMAP /* and also not for the Player */ | ||
30 | |||
31 | /******************************* Globals ***********************************/ | ||
32 | |||
33 | static struct plugin_api* rb; | ||
34 | |||
35 | /*********************** Begin grayscale framework *************************/ | ||
36 | |||
37 | /* This is a generic framework to use grayscale display within rockbox | ||
38 | * plugins. It obviously does not work for the player. | ||
39 | * | ||
40 | * If you want to use grayscale display within a plugin, copy this section | ||
41 | * (up to "End grayscale framework") into your source and you are able to use | ||
42 | * it. For detailed documentation look at the head of each public function. | ||
43 | * | ||
44 | * It requires a global Rockbox api pointer in "rb" and uses the rockbox | ||
45 | * timer api so you cannot use that timer for other purposes while | ||
46 | * displaying grayscale. | ||
47 | * | ||
48 | * The framework consists of 3 sections: | ||
49 | * | ||
50 | * - internal core functions and definitions | ||
51 | * - public core functions | ||
52 | * - public optional functions | ||
53 | * | ||
54 | * Usually you will use functions from the latter two sections in your code. | ||
55 | * You can cut out functions from the third section that you do not need in | ||
56 | * order to not waste space. Don't forget to cut the prototype as well. | ||
57 | */ | ||
58 | |||
59 | /**** internal core functions and definitions ****/ | ||
60 | |||
61 | /* You do not want to touch these if you don't know exactly what you're | ||
62 | * doing. */ | ||
63 | |||
64 | #define GRAY_RUNNING 0x0001 /* grayscale overlay is running */ | ||
65 | #define GRAY_DEFERRED_UPDATE 0x0002 /* lcd_update() requested */ | ||
66 | |||
67 | typedef struct | ||
68 | { | ||
69 | int x; | ||
70 | int by; /* 8-pixel units */ | ||
71 | int width; | ||
72 | int height; | ||
73 | int bheight; /* 8-pixel units */ | ||
74 | int plane_size; | ||
75 | int depth; /* number_of_bitplanes = (number_of_grayscales - 1) */ | ||
76 | int cur_plane; /* for the timer isr */ | ||
77 | unsigned long randmask; /* mask for random value in graypixel() */ | ||
78 | unsigned long flags; /* various flags, see #defines */ | ||
79 | unsigned char *data; /* pointer to start of bitplane data */ | ||
80 | unsigned long *bitpattern; /* pointer to start of pattern table */ | ||
81 | } tGraybuf; | ||
82 | |||
83 | static tGraybuf *graybuf = NULL; | ||
84 | |||
85 | /** prototypes **/ | ||
86 | |||
87 | void timer_isr(void); | ||
88 | void graypixel(int x, int y, unsigned long pattern); | ||
89 | void grayinvertmasked(int x, int yb, unsigned char mask); | ||
90 | |||
91 | /** implementation **/ | ||
92 | |||
93 | /* timer interrupt handler: display next bitplane */ | ||
94 | void timer_isr(void) | ||
95 | { | ||
96 | rb->lcd_blit(graybuf->data + (graybuf->plane_size * graybuf->cur_plane), | ||
97 | graybuf->x, graybuf->by, graybuf->width, graybuf->bheight, | ||
98 | graybuf->width); | ||
99 | |||
100 | if (++graybuf->cur_plane >= graybuf->depth) | ||
101 | graybuf->cur_plane = 0; | ||
102 | |||
103 | if (graybuf->flags & GRAY_DEFERRED_UPDATE) /* lcd_update() requested? */ | ||
104 | { | ||
105 | int x1 = MAX(graybuf->x, 0); | ||
106 | int x2 = MIN(graybuf->x + graybuf->width, LCD_WIDTH); | ||
107 | int y1 = MAX(graybuf->by << 3, 0); | ||
108 | int y2 = MIN((graybuf->by + graybuf->bheight) << 3, LCD_HEIGHT); | ||
109 | |||
110 | if (y1 > 0) /* refresh part above overlay, full width */ | ||
111 | rb->lcd_update_rect(0, 0, LCD_WIDTH, y1); | ||
112 | |||
113 | if (y2 < LCD_HEIGHT) /* refresh part below overlay, full width */ | ||
114 | rb->lcd_update_rect(0, y2, LCD_WIDTH, LCD_HEIGHT - y2); | ||
115 | |||
116 | if (x1 > 0) /* refresh part to the left of overlay */ | ||
117 | rb->lcd_update_rect(0, y1, x1, y2 - y1); | ||
118 | |||
119 | if (x2 < LCD_WIDTH) /* refresh part to the right of overlay */ | ||
120 | rb->lcd_update_rect(x2, y1, LCD_WIDTH - x2, y2 - y1); | ||
121 | |||
122 | graybuf->flags &= ~GRAY_DEFERRED_UPDATE; /* clear request */ | ||
123 | } | ||
124 | } | ||
125 | |||
126 | /* Set a pixel to a specific bit pattern | ||
127 | * This is the fundamental graphics primitive, asm optimized */ | ||
128 | void graypixel(int x, int y, unsigned long pattern) | ||
129 | { | ||
130 | static short random_buffer; | ||
131 | register long address, mask, random; | ||
132 | |||
133 | /* Some (pseudo-)random function must be used here to shift the bit | ||
134 | * pattern randomly, otherwise you would get flicker and/or moire. | ||
135 | * Since rand() is relatively slow, I've implemented a simple, but very | ||
136 | * fast pseudo-random generator based on linear congruency in assembler. | ||
137 | * It delivers 16 pseudo-random bits in each iteration. */ | ||
138 | |||
139 | /* simple but fast pseudo-random generator */ | ||
140 | asm( | ||
141 | "mov.w @%1,%0 \n" /* load last value */ | ||
142 | "mov #75,r1 \n" | ||
143 | "mulu %0,r1 \n" /* multiply by 75 */ | ||
144 | "sts macl,%0 \n" /* get result */ | ||
145 | "add #74,%0 \n" /* add another 74 */ | ||
146 | "mov.w %0,@%1 \n" /* store new value */ | ||
147 | /* Since the lower bits are not very random: */ | ||
148 | "shlr8 %0 \n" /* get bits 8..15 (need max. 5) */ | ||
149 | "and %2,%0 \n" /* mask out unneeded bits */ | ||
150 | : /* outputs */ | ||
151 | /* %0 */ "=&r"(random) | ||
152 | : /* inputs */ | ||
153 | /* %1 */ "r"(&random_buffer), | ||
154 | /* %2 */ "r"(graybuf->randmask) | ||
155 | : /* clobbers */ | ||
156 | "r1","macl" | ||
157 | ); | ||
158 | |||
159 | /* precalculate mask and byte address in first bitplane */ | ||
160 | asm( | ||
161 | "mov %3,%0 \n" /* take y as base for address offset */ | ||
162 | "shlr2 %0 \n" /* shift right by 3 (= divide by 8) */ | ||
163 | "shlr %0 \n" | ||
164 | "mulu %0,%2 \n" /* multiply with width */ | ||
165 | "and #7,%3 \n" /* get lower 3 bits of y */ | ||
166 | "sts macl,%0 \n" /* get mulu result */ | ||
167 | "add %4,%0 \n" /* add base + x to get final address */ | ||
168 | |||
169 | "mov %3,%1 \n" /* move lower 3 bits of y out of r0 */ | ||
170 | "mova .pp_table,%3 \n" /* get address of mask table in r0 */ | ||
171 | "bra .pp_end \n" /* skip the table */ | ||
172 | "mov.b @(%3,%1),%1 \n" /* get entry from mask table */ | ||
173 | |||
174 | ".align 2 \n" | ||
175 | ".pp_table: \n" /* mask table */ | ||
176 | ".byte 0x01 \n" | ||
177 | ".byte 0x02 \n" | ||
178 | ".byte 0x04 \n" | ||
179 | ".byte 0x08 \n" | ||
180 | ".byte 0x10 \n" | ||
181 | ".byte 0x20 \n" | ||
182 | ".byte 0x40 \n" | ||
183 | ".byte 0x80 \n" | ||
184 | |||
185 | ".pp_end: \n" | ||
186 | : /* outputs */ | ||
187 | /* %0 */ "=&r"(address), | ||
188 | /* %1 */ "=&r"(mask) | ||
189 | : /* inputs */ | ||
190 | /* %2 */ "r"(graybuf->width), | ||
191 | /* %3 = r0 */ "z"(y), | ||
192 | /* %4 */ "r"(graybuf->data + x) | ||
193 | : /* clobbers */ | ||
194 | "macl" | ||
195 | ); | ||
196 | |||
197 | /* the hard part: set bits in all bitplanes according to pattern */ | ||
198 | asm( | ||
199 | "cmp/hs %1,%5 \n" /* random >= depth ? */ | ||
200 | "bf .p_ntrim \n" | ||
201 | "sub %1,%5 \n" /* yes: random -= depth */ | ||
202 | /* it's sufficient to do this once, since the mask guarantees | ||
203 | * random < 2 * depth */ | ||
204 | ".p_ntrim: \n" | ||
205 | |||
206 | /* calculate some addresses */ | ||
207 | "mulu %4,%1 \n" /* end address offset */ | ||
208 | "not %3,r1 \n" /* get inverse mask (for "and") */ | ||
209 | "sts macl,%1 \n" /* result of mulu */ | ||
210 | "mulu %4,%5 \n" /* address offset of <random>'th plane */ | ||
211 | "add %2,%1 \n" /* end offset -> end address */ | ||
212 | "sts macl,%5 \n" /* result of mulu */ | ||
213 | "add %2,%5 \n" /* address of <random>'th plane */ | ||
214 | "bra .p_start1 \n" | ||
215 | "mov %5,r2 \n" /* copy address */ | ||
216 | |||
217 | /* first loop: set bits from <random>'th bitplane to last */ | ||
218 | ".p_loop1: \n" | ||
219 | "mov.b @r2,r3 \n" /* get data byte */ | ||
220 | "shlr %0 \n" /* shift bit mask, sets t bit */ | ||
221 | "and r1,r3 \n" /* reset bit (-> "white") */ | ||
222 | "bf .p_white1 \n" /* t=0? -> "white" bit */ | ||
223 | "or %3,r3 \n" /* set bit ("black" bit) */ | ||
224 | ".p_white1: \n" | ||
225 | "mov.b r3,@r2 \n" /* store data byte */ | ||
226 | "add %4,r2 \n" /* advance address to next bitplane */ | ||
227 | ".p_start1: \n" | ||
228 | "cmp/hi r2,%1 \n" /* address < end address ? */ | ||
229 | "bt .p_loop1 \n" | ||
230 | |||
231 | "bra .p_start2 \n" | ||
232 | "nop \n" | ||
233 | |||
234 | /* second loop: set bits from first to <random-1>'th bitplane | ||
235 | * Bit setting works the other way round here to equalize average | ||
236 | * execution times for bright and dark pixels */ | ||
237 | ".p_loop2: \n" | ||
238 | "mov.b @%2,r3 \n" /* get data byte */ | ||
239 | "shlr %0 \n" /* shift bit mask, sets t bit */ | ||
240 | "or %3,r3 \n" /* set bit (-> "black") */ | ||
241 | "bt .p_black2 \n" /* t=1? -> "black" bit */ | ||
242 | "and r1,r3 \n" /* reset bit ("white" bit) */ | ||
243 | ".p_black2: \n" | ||
244 | "mov.b r3,@%2 \n" /* store data byte */ | ||
245 | "add %4,%2 \n" /* advance address to next bitplane */ | ||
246 | ".p_start2: \n" | ||
247 | "cmp/hi %2,%5 \n" /* address < <random>'th address ? */ | ||
248 | "bt .p_loop2 \n" | ||
249 | : /* outputs */ | ||
250 | : /* inputs */ | ||
251 | /* %0 */ "r"(pattern), | ||
252 | /* %1 */ "r"(graybuf->depth), | ||
253 | /* %2 */ "r"(address), | ||
254 | /* %3 */ "r"(mask), | ||
255 | /* %4 */ "r"(graybuf->plane_size), | ||
256 | /* %5 */ "r"(random) | ||
257 | : /* clobbers */ | ||
258 | "r1", "r2", "r3", "macl" | ||
259 | ); | ||
260 | } | ||
261 | |||
262 | /* Invert the bits for 1-8 pixels within the buffer */ | ||
263 | void grayinvertmasked(int x, int by, unsigned char mask) | ||
264 | { | ||
265 | asm( | ||
266 | "mulu %4,%5 \n" /* width * by (offset of row) */ | ||
267 | "mov #0,r1 \n" /* current_plane = 0 */ | ||
268 | "sts macl,r2 \n" /* get mulu result */ | ||
269 | "add r2,%1 \n" /* -> address in 1st bitplane */ | ||
270 | |||
271 | ".i_loop: \n" | ||
272 | "mov.b @%1,r2 \n" /* get data byte */ | ||
273 | "add #1,r1 \n" /* current_plane++; */ | ||
274 | "xor %2,r2 \n" /* invert bits */ | ||
275 | "mov.b r2,@%1 \n" /* store data byte */ | ||
276 | "add %3,%1 \n" /* advance address to next bitplane */ | ||
277 | "cmp/hi r1,%0 \n" /* current_plane < depth ? */ | ||
278 | "bt .i_loop \n" | ||
279 | : /* outputs */ | ||
280 | : /* inputs */ | ||
281 | /* %0 */ "r"(graybuf->depth), | ||
282 | /* %1 */ "r"(graybuf->data + x), | ||
283 | /* %2 */ "r"(mask), | ||
284 | /* %3 */ "r"(graybuf->plane_size), | ||
285 | /* %4 */ "r"(graybuf->width), | ||
286 | /* %5 */ "r"(by) | ||
287 | : /* clobbers */ | ||
288 | "r1", "r2", "macl" | ||
289 | ); | ||
290 | } | ||
291 | |||
292 | /*** public core functions ***/ | ||
293 | |||
294 | /** prototypes **/ | ||
295 | |||
296 | int gray_init_buffer(unsigned char *gbuf, int gbuf_size, int width, | ||
297 | int bheight, int depth); | ||
298 | void gray_release_buffer(void); | ||
299 | void gray_position_display(int x, int by); | ||
300 | void gray_show_display(bool enable); | ||
301 | |||
302 | /** implementation **/ | ||
303 | |||
304 | /* Prepare the grayscale display buffer | ||
305 | * | ||
306 | * arguments: | ||
307 | * gbuf = pointer to the memory area to use (e.g. plugin buffer) | ||
308 | * gbuf_size = max usable size of the buffer | ||
309 | * width = width in pixels (1..112) | ||
310 | * bheight = height in 8-pixel units (1..8) | ||
311 | * depth = desired number of shades - 1 (1..32) | ||
312 | * | ||
313 | * result: | ||
314 | * = depth if there was enough memory | ||
315 | * < depth if there wasn't enough memory. The number of displayable | ||
316 | * shades is smaller than desired, but it still works | ||
317 | * = 0 if there wasn't even enough memory for 1 bitplane (black & white) | ||
318 | * | ||
319 | * You can request any depth from 1 to 32, not just powers of 2. The routine | ||
320 | * performs "graceful degradation" if the memory is not sufficient for the | ||
321 | * desired depth. As long as there is at least enough memory for 1 bitplane, | ||
322 | * it creates as many bitplanes as fit into memory, although 1 bitplane will | ||
323 | * only deliver black & white display. | ||
324 | * | ||
325 | * The total memory needed can be calculated as follows: | ||
326 | * total_mem = | ||
327 | * sizeof(tGraymap) (= 48 bytes currently) | ||
328 | * + sizeof(long) (= 4 bytes) | ||
329 | * + (width * bheight + sizeof(long)) * depth | ||
330 | * + 0..3 (longword alignment of grayscale display buffer) | ||
331 | */ | ||
332 | int gray_init_buffer(unsigned char *gbuf, int gbuf_size, int width, | ||
333 | int bheight, int depth) | ||
334 | { | ||
335 | int possible_depth, plane_size; | ||
336 | int i, j; | ||
337 | |||
338 | if (width > LCD_WIDTH || bheight > (LCD_HEIGHT >> 3) || depth < 1) | ||
339 | return 0; | ||
340 | |||
341 | while ((unsigned long)gbuf & 3) /* the buffer has to be long aligned */ | ||
342 | { | ||
343 | gbuf++; | ||
344 | gbuf_size--; | ||
345 | } | ||
346 | |||
347 | plane_size = width * bheight; | ||
348 | possible_depth = (gbuf_size - sizeof(tGraybuf) - sizeof(unsigned long)) | ||
349 | / (plane_size + sizeof(unsigned long)); | ||
350 | |||
351 | if (possible_depth < 1) | ||
352 | return 0; | ||
353 | |||
354 | depth = MIN(depth, 32); | ||
355 | depth = MIN(depth, possible_depth); | ||
356 | |||
357 | graybuf = (tGraybuf *) gbuf; /* global pointer to buffer structure */ | ||
358 | |||
359 | graybuf->x = 0; | ||
360 | graybuf->by = 0; | ||
361 | graybuf->width = width; | ||
362 | graybuf->height = bheight << 3; | ||
363 | graybuf->bheight = bheight; | ||
364 | graybuf->plane_size = plane_size; | ||
365 | graybuf->depth = depth; | ||
366 | graybuf->cur_plane = 0; | ||
367 | graybuf->flags = 0; | ||
368 | graybuf->data = gbuf + sizeof(tGraybuf); | ||
369 | graybuf->bitpattern = (unsigned long *) (graybuf->data | ||
370 | + depth * plane_size); | ||
371 | |||
372 | i = depth; | ||
373 | j = 8; | ||
374 | while (i != 0) | ||
375 | { | ||
376 | i >>= 1; | ||
377 | j--; | ||
378 | } | ||
379 | graybuf->randmask = 0xFF >> j; | ||
380 | |||
381 | /* initial state is all white */ | ||
382 | rb->memset(graybuf->data, 0, depth * plane_size); | ||
383 | |||
384 | /* Precalculate the bit patterns for all possible pixel values */ | ||
385 | for (i = 0; i <= depth; i++) | ||
386 | { | ||
387 | unsigned long pattern = 0; | ||
388 | int value = 0; | ||
389 | |||
390 | for (j = 0; j < depth; j++) | ||
391 | { | ||
392 | pattern <<= 1; | ||
393 | value += i; | ||
394 | |||
395 | if (value >= depth) | ||
396 | value -= depth; /* "white" bit */ | ||
397 | else | ||
398 | pattern |= 1; /* "black" bit */ | ||
399 | } | ||
400 | /* now the lower <depth> bits contain the pattern */ | ||
401 | |||
402 | graybuf->bitpattern[i] = pattern; | ||
403 | } | ||
404 | |||
405 | return depth; | ||
406 | } | ||
407 | |||
408 | /* Release the grayscale display buffer | ||
409 | * | ||
410 | * Switches the grayscale overlay off at first if it is still running, | ||
411 | * then sets the pointer to NULL. | ||
412 | * DO CALL either this function or at least gray_show_display(false) | ||
413 | * before you exit, otherwise nasty things may happen. | ||
414 | */ | ||
415 | void gray_release_buffer(void) | ||
416 | { | ||
417 | gray_show_display(false); | ||
418 | graybuf = NULL; | ||
419 | } | ||
420 | |||
421 | /* Set position of the top left corner of the grayscale overlay | ||
422 | * | ||
423 | * arguments: | ||
424 | * x = left margin in pixels | ||
425 | * by = top margin in 8-pixel units | ||
426 | * | ||
427 | * You may set this in a way that the overlay spills across the right or | ||
428 | * bottom display border. In this case it will simply be clipped by the | ||
429 | * LCD controller. You can even set negative values, this will clip at the | ||
430 | * left or top border. I did not test it, but the limits may be +127 / -128 | ||
431 | * | ||
432 | * If you use this while the grayscale overlay is running, the now-freed area | ||
433 | * will be restored. | ||
434 | */ | ||
435 | void gray_position_display(int x, int by) | ||
436 | { | ||
437 | if (graybuf == NULL) | ||
438 | return; | ||
439 | |||
440 | graybuf->x = x; | ||
441 | graybuf->by = by; | ||
442 | |||
443 | if (graybuf->flags & GRAY_RUNNING) | ||
444 | graybuf->flags |= GRAY_DEFERRED_UPDATE; | ||
445 | } | ||
446 | |||
447 | /* Switch the grayscale overlay on or off | ||
448 | * | ||
449 | * arguments: | ||
450 | * enable = true: the grayscale overlay is switched on if initialized | ||
451 | * = false: the grayscale overlay is switched off and the regular lcd | ||
452 | * content is restored | ||
453 | * | ||
454 | * DO NOT call lcd_update() or any other api function that directly accesses | ||
455 | * the lcd while the grayscale overlay is running! If you need to do | ||
456 | * lcd_update() to update something outside the grayscale overlay area, use | ||
457 | * gray_deferred_update() instead. | ||
458 | * | ||
459 | * Other functions to avoid are: | ||
460 | * lcd_blit() (obviously), lcd_update_rect(), lcd_set_contrast(), | ||
461 | * lcd_set_invert_display(), lcd_set_flip(), lcd_roll() | ||
462 | * | ||
463 | * The grayscale display consumes ~50 % CPU power (for a full screen overlay, | ||
464 | * less if the overlay is smaller) when switched on. You can switch the overlay | ||
465 | * on and off as many times as you want. | ||
466 | */ | ||
467 | void gray_show_display(bool enable) | ||
468 | { | ||
469 | if (graybuf == NULL) | ||
470 | return; | ||
471 | |||
472 | if (enable) | ||
473 | { | ||
474 | graybuf->flags |= GRAY_RUNNING; | ||
475 | rb->plugin_register_timer(FREQ / 67, 1, timer_isr); | ||
476 | } | ||
477 | else | ||
478 | { | ||
479 | rb->plugin_unregister_timer(); | ||
480 | graybuf->flags &= ~GRAY_RUNNING; | ||
481 | rb->lcd_update(); /* restore whatever there was before */ | ||
482 | } | ||
483 | } | ||
484 | |||
485 | /*** public optional functions ***/ | ||
486 | |||
487 | /* Here are the various graphics primitives. Cut out functions you do not | ||
488 | * need in order to keep plugin code size down. | ||
489 | */ | ||
490 | |||
491 | /** prototypes **/ | ||
492 | |||
493 | /* functions affecting the whole display */ | ||
494 | void gray_clear_display(void); | ||
495 | void gray_black_display(void); | ||
496 | void gray_deferred_update(void); | ||
497 | |||
498 | /* scrolling functions */ | ||
499 | void gray_scroll_left(int count, bool black_border); | ||
500 | void gray_scroll_right(int count, bool black_border); | ||
501 | void gray_scroll_up8(bool black_border); | ||
502 | void gray_scroll_down8(bool black_border); | ||
503 | void gray_scroll_up1(bool black_border); | ||
504 | void gray_scroll_down1(bool black_border); | ||
505 | |||
506 | /* pixel functions */ | ||
507 | void gray_drawpixel(int x, int y, int brightness); | ||
508 | void gray_invertpixel(int x, int y); | ||
509 | |||
510 | /* line functions */ | ||
511 | void gray_drawline(int x1, int y1, int x2, int y2, int brightness); | ||
512 | void gray_invertline(int x1, int y1, int x2, int y2); | ||
513 | |||
514 | /* rectangle functions */ | ||
515 | void gray_drawrect(int x1, int y1, int x2, int y2, int brightness); | ||
516 | void gray_fillrect(int x1, int y1, int x2, int y2, int brightness); | ||
517 | void gray_invertrect(int x1, int y1, int x2, int y2); | ||
518 | |||
519 | /* bitmap functions */ | ||
520 | void gray_drawgraymap(unsigned char *src, int x, int y, int nx, int ny, | ||
521 | int stride); | ||
522 | void gray_drawbitmap(unsigned char *src, int x, int y, int nx, int ny, | ||
523 | int stride, bool draw_bg, int fg_brightness, | ||
524 | int bg_brightness); | ||
525 | |||
526 | /** implementation **/ | ||
527 | |||
528 | /* Clear the grayscale display (sets all pixels to white) | ||
529 | */ | ||
530 | void gray_clear_display(void) | ||
531 | { | ||
532 | if (graybuf == NULL) | ||
533 | return; | ||
534 | |||
535 | rb->memset(graybuf->data, 0, graybuf->depth * graybuf->plane_size); | ||
536 | } | ||
537 | |||
538 | /* Set the grayscale display to all black | ||
539 | */ | ||
540 | void gray_black_display(void) | ||
541 | { | ||
542 | if (graybuf == NULL) | ||
543 | return; | ||
544 | |||
545 | rb->memset(graybuf->data, 0xFF, graybuf->depth * graybuf->plane_size); | ||
546 | } | ||
547 | |||
548 | /* Do a lcd_update() to show changes done by rb->lcd_xxx() functions (in areas | ||
549 | * of the screen not covered by the grayscale overlay). If the grayscale | ||
550 | * overlay is running, the update will be done in the next call of the | ||
551 | * interrupt routine, otherwise it will be performed right away. See also | ||
552 | * comment for the gray_show_display() function. | ||
553 | */ | ||
554 | void gray_deferred_update(void) | ||
555 | { | ||
556 | if (graybuf != NULL && (graybuf->flags & GRAY_RUNNING)) | ||
557 | graybuf->flags |= GRAY_DEFERRED_UPDATE; | ||
558 | else | ||
559 | rb->lcd_update(); | ||
560 | } | ||
561 | |||
562 | /* Scroll the whole grayscale buffer left by <count> pixels | ||
563 | * | ||
564 | * black_border determines if the pixels scrolled in at the right are black | ||
565 | * or white | ||
566 | */ | ||
567 | void gray_scroll_left(int count, bool black_border) | ||
568 | { | ||
569 | int x, by, d; | ||
570 | unsigned char *src, *dest; | ||
571 | unsigned char filler; | ||
572 | |||
573 | if (graybuf == NULL || count >= graybuf->width) | ||
574 | return; | ||
575 | |||
576 | if (black_border) | ||
577 | filler = 0xFF; | ||
578 | else | ||
579 | filler = 0; | ||
580 | |||
581 | /* Scroll row by row to minimize flicker (byte rows = 8 pixels each) */ | ||
582 | for (by = 0; by < graybuf->bheight; by++) | ||
583 | { | ||
584 | for (d = 0; d < graybuf->depth; d++) | ||
585 | { | ||
586 | dest = graybuf->data + graybuf->plane_size * d | ||
587 | + graybuf->width * by; | ||
588 | src = dest + count; | ||
589 | |||
590 | for (x = count; x < graybuf->width; x++) | ||
591 | *dest++ = *src++; | ||
592 | |||
593 | for (x = 0; x < count; x++) | ||
594 | *dest++ = filler; | ||
595 | } | ||
596 | } | ||
597 | } | ||
598 | |||
599 | /* Scroll the whole grayscale buffer right by <count> pixels | ||
600 | * | ||
601 | * black_border determines if the pixels scrolled in at the left are black | ||
602 | * or white | ||
603 | */ | ||
604 | void gray_scroll_right(int count, bool black_border) | ||
605 | { | ||
606 | int x, by, d; | ||
607 | unsigned char *src, *dest; | ||
608 | unsigned char filler; | ||
609 | |||
610 | if (graybuf == NULL || count >= graybuf->width) | ||
611 | return; | ||
612 | |||
613 | if (black_border) | ||
614 | filler = 0xFF; | ||
615 | else | ||
616 | filler = 0; | ||
617 | |||
618 | /* Scroll row by row to minimize flicker (byte rows = 8 pixels each) */ | ||
619 | for (by = 0; by < graybuf->bheight; by++) | ||
620 | { | ||
621 | for (d = 0; d < graybuf->depth; d++) | ||
622 | { | ||
623 | dest = graybuf->data + graybuf->plane_size * d | ||
624 | + graybuf->width * (by + 1) - 1; | ||
625 | src = dest - count; | ||
626 | |||
627 | for (x = count; x < graybuf->width; x++) | ||
628 | *dest-- = *src--; | ||
629 | |||
630 | for (x = 0; x < count; x++) | ||
631 | *dest-- = filler; | ||
632 | } | ||
633 | } | ||
634 | } | ||
635 | |||
636 | /* Scroll the whole grayscale buffer up by 8 pixels | ||
637 | * | ||
638 | * black_border determines if the pixels scrolled in at the bottom are black | ||
639 | * or white | ||
640 | */ | ||
641 | void gray_scroll_up8(bool black_border) | ||
642 | { | ||
643 | int by, d; | ||
644 | unsigned char *src; | ||
645 | unsigned char filler; | ||
646 | |||
647 | if (graybuf == NULL) | ||
648 | return; | ||
649 | |||
650 | if (black_border) | ||
651 | filler = 0xFF; | ||
652 | else | ||
653 | filler = 0; | ||
654 | |||
655 | /* Scroll row by row to minimize flicker (byte rows = 8 pixels each) */ | ||
656 | for (by = 1; by < graybuf->bheight; by++) | ||
657 | { | ||
658 | for (d = 0; d < graybuf->depth; d++) | ||
659 | { | ||
660 | src = graybuf->data + graybuf->plane_size * d | ||
661 | + graybuf->width * by; | ||
662 | |||
663 | rb->memcpy(src - graybuf->width, src, graybuf->width); | ||
664 | } | ||
665 | } | ||
666 | for (d = 0; d < graybuf->depth; d++) /* fill last row */ | ||
667 | { | ||
668 | rb->memset(graybuf->data + graybuf->plane_size * (d + 1) | ||
669 | - graybuf->width, filler, graybuf->width); | ||
670 | } | ||
671 | } | ||
672 | |||
673 | /* Scroll the whole grayscale buffer down by 8 pixels | ||
674 | * | ||
675 | * black_border determines if the pixels scrolled in at the top are black | ||
676 | * or white | ||
677 | */ | ||
678 | void gray_scroll_down8(bool black_border) | ||
679 | { | ||
680 | int by, d; | ||
681 | unsigned char *dest; | ||
682 | unsigned char filler; | ||
683 | |||
684 | if (graybuf == NULL) | ||
685 | return; | ||
686 | |||
687 | if (black_border) | ||
688 | filler = 0xFF; | ||
689 | else | ||
690 | filler = 0; | ||
691 | |||
692 | /* Scroll row by row to minimize flicker (byte rows = 8 pixels each) */ | ||
693 | for (by = graybuf->bheight - 1; by > 0; by--) | ||
694 | { | ||
695 | for (d = 0; d < graybuf->depth; d++) | ||
696 | { | ||
697 | dest = graybuf->data + graybuf->plane_size * d | ||
698 | + graybuf->width * by; | ||
699 | |||
700 | rb->memcpy(dest, dest - graybuf->width, graybuf->width); | ||
701 | } | ||
702 | } | ||
703 | for (d = 0; d < graybuf->depth; d++) /* fill first row */ | ||
704 | { | ||
705 | rb->memset(graybuf->data + graybuf->plane_size * d, filler, | ||
706 | graybuf->width); | ||
707 | } | ||
708 | } | ||
709 | |||
710 | /* Scroll the whole grayscale buffer up by 1 pixel | ||
711 | * | ||
712 | * black_border determines if the pixels scrolled in at the bottom are black | ||
713 | * or white | ||
714 | * | ||
715 | * Scrolling up/down pixel-wise is significantly slower than scrolling | ||
716 | * left/right or scrolling up/down byte-wise because it involves bit | ||
717 | * shifting. That's why it is asm optimized. | ||
718 | */ | ||
719 | void gray_scroll_up1(bool black_border) | ||
720 | { | ||
721 | int filler; | ||
722 | |||
723 | if (graybuf == NULL) | ||
724 | return; | ||
725 | |||
726 | if (black_border) | ||
727 | filler = 1; | ||
728 | else | ||
729 | filler = 0; | ||
730 | |||
731 | /* scroll column by column to minimize flicker */ | ||
732 | asm( | ||
733 | "mov #0,r6 \n" /* x = 0; */ | ||
734 | |||
735 | ".su_cloop: \n" /* repeat for every column */ | ||
736 | "mov %1,r7 \n" /* get start address */ | ||
737 | "mov #0,r1 \n" /* current_plane = 0 */ | ||
738 | |||
739 | ".su_oloop: \n" /* repeat for every bitplane */ | ||
740 | "mov r7,r2 \n" /* get start address */ | ||
741 | "mov #0,r3 \n" /* current_row = 0 */ | ||
742 | "mov %5,r5 \n" /* get filler bit (bit 0) */ | ||
743 | |||
744 | ".su_iloop: \n" /* repeat for all rows */ | ||
745 | "sub %2,r2 \n" /* address -= width; */ | ||
746 | "mov.b @r2,r4 \n" /* get new byte */ | ||
747 | "shll8 r5 \n" /* shift old lsb to bit 8 */ | ||
748 | "extu.b r4,r4 \n" /* extend byte unsigned */ | ||
749 | "or r5,r4 \n" /* merge old lsb */ | ||
750 | "shlr r4 \n" /* shift right */ | ||
751 | "movt r5 \n" /* save new lsb */ | ||
752 | "mov.b r4,@r2 \n" /* store byte */ | ||
753 | "add #1,r3 \n" /* current_row++; */ | ||
754 | "cmp/hi r3,%3 \n" /* cuurent_row < bheight ? */ | ||
755 | "bt .su_iloop \n" | ||
756 | |||
757 | "add %4,r7 \n" /* start_address += plane_size; */ | ||
758 | "add #1,r1 \n" /* current_plane++; */ | ||
759 | "cmp/hi r1,%0 \n" /* current_plane < depth ? */ | ||
760 | "bt .su_oloop \n" | ||
761 | |||
762 | "add #1,%1 \n" /* start_address++; */ | ||
763 | "add #1,r6 \n" /* x++; */ | ||
764 | "cmp/hi r6,%2 \n" /* x < width ? */ | ||
765 | "bt .su_cloop \n" | ||
766 | : /* outputs */ | ||
767 | : /* inputs */ | ||
768 | /* %0 */ "r"(graybuf->depth), | ||
769 | /* %1 */ "r"(graybuf->data + graybuf->plane_size), | ||
770 | /* %2 */ "r"(graybuf->width), | ||
771 | /* %3 */ "r"(graybuf->bheight), | ||
772 | /* %4 */ "r"(graybuf->plane_size), | ||
773 | /* %5 */ "r"(filler) | ||
774 | : /* clobbers */ | ||
775 | "r1", "r2", "r3", "r4", "r5", "r6", "r7" | ||
776 | ); | ||
777 | } | ||
778 | |||
779 | /* Scroll the whole grayscale buffer down by 1 pixel | ||
780 | * | ||
781 | * black_border determines if the pixels scrolled in at the top are black | ||
782 | * or white | ||
783 | * | ||
784 | * Scrolling up/down pixel-wise is significantly slower than scrolling | ||
785 | * left/right or scrolling up/down byte-wise because it involves bit | ||
786 | * shifting. That's why it is asm optimized. Scrolling down is a bit | ||
787 | * faster than scrolling up, though. | ||
788 | */ | ||
789 | void gray_scroll_down1(bool black_border) | ||
790 | { | ||
791 | int filler; | ||
792 | |||
793 | if (graybuf == NULL) | ||
794 | return; | ||
795 | |||
796 | if (black_border) | ||
797 | filler = -1; /* sets bit 31 */ | ||
798 | else | ||
799 | filler = 0; | ||
800 | |||
801 | /* scroll column by column to minimize flicker */ | ||
802 | asm( | ||
803 | "mov #0,r5 \n" /* x = 0; */ | ||
804 | |||
805 | ".sd_cloop: \n" /* repeat for every column */ | ||
806 | "mov %1,r6 \n" /* get start address */ | ||
807 | "mov #0,r1 \n" /* current_plane = 0 */ | ||
808 | |||
809 | ".sd_oloop: \n" /* repeat for every bitplane */ | ||
810 | "mov r6,r2 \n" /* get start address */ | ||
811 | "mov #0,r3 \n" /* current_row = 0 */ | ||
812 | "mov %5,r4 \n" /* get filler bit (bit 31) */ | ||
813 | |||
814 | ".sd_iloop: \n" /* repeat for all rows */ | ||
815 | "shll r4 \n" /* get old msb (again) */ | ||
816 | /* This is possible because the sh1 loads byte data sign-extended, | ||
817 | * so the upper 25 bits of the register are all identical */ | ||
818 | "mov.b @r2,r4 \n" /* get new byte */ | ||
819 | "add #1,r3 \n" /* current_row++; */ | ||
820 | "rotcl r4 \n" /* rotate left, merges previous msb */ | ||
821 | "mov.b r4,@r2 \n" /* store byte */ | ||
822 | "add %2,r2 \n" /* address += width; */ | ||
823 | "cmp/hi r3,%3 \n" /* cuurent_row < bheight ? */ | ||
824 | "bt .sd_iloop \n" | ||
825 | |||
826 | "add %4,r6 \n" /* start_address += plane_size; */ | ||
827 | "add #1,r1 \n" /* current_plane++; */ | ||
828 | "cmp/hi r1,%0 \n" /* current_plane < depth ? */ | ||
829 | "bt .sd_oloop \n" | ||
830 | |||
831 | "add #1,%1 \n" /* start_address++; */ | ||
832 | "add #1,r5 \n" /* x++ */ | ||
833 | "cmp/hi r5,%2 \n" /* x < width ? */ | ||
834 | "bt .sd_cloop \n" | ||
835 | : /* outputs */ | ||
836 | : /* inputs */ | ||
837 | /* %0 */ "r"(graybuf->depth), | ||
838 | /* %1 */ "r"(graybuf->data), | ||
839 | /* %2 */ "r"(graybuf->width), | ||
840 | /* %3 */ "r"(graybuf->bheight), | ||
841 | /* %4 */ "r"(graybuf->plane_size), | ||
842 | /* %5 */ "r"(filler) | ||
843 | : /* clobbers */ | ||
844 | "r1", "r2", "r3", "r4", "r5", "r6" | ||
845 | ); | ||
846 | } | ||
847 | |||
848 | /* Set a pixel to a specific gray value | ||
849 | * | ||
850 | * brightness is 0..255 (black to white) regardless of real bit depth | ||
851 | */ | ||
852 | void gray_drawpixel(int x, int y, int brightness) | ||
853 | { | ||
854 | if (graybuf == NULL || x >= graybuf->width || y >= graybuf->height | ||
855 | || brightness > 255) | ||
856 | return; | ||
857 | |||
858 | graypixel(x, y, graybuf->bitpattern[(brightness | ||
859 | * (graybuf->depth + 1)) >> 8]); | ||
860 | } | ||
861 | |||
862 | /* Invert a pixel | ||
863 | * | ||
864 | * The bit pattern for that pixel in the buffer is inverted, so white becomes | ||
865 | * black, light gray becomes dark gray etc. | ||
866 | */ | ||
867 | void gray_invertpixel(int x, int y) | ||
868 | { | ||
869 | if (graybuf == NULL || x >= graybuf->width || y >= graybuf->height) | ||
870 | return; | ||
871 | |||
872 | grayinvertmasked(x, (y >> 3), 1 << (y & 7)); | ||
873 | } | ||
874 | |||
875 | /* Draw a line from (x1, y1) to (x2, y2) with a specific gray value | ||
876 | * | ||
877 | * brightness is 0..255 (black to white) regardless of real bit depth | ||
878 | */ | ||
879 | void gray_drawline(int x1, int y1, int x2, int y2, int brightness) | ||
880 | { | ||
881 | int numpixels; | ||
882 | int i; | ||
883 | int deltax, deltay; | ||
884 | int d, dinc1, dinc2; | ||
885 | int x, xinc1, xinc2; | ||
886 | int y, yinc1, yinc2; | ||
887 | unsigned long pattern; | ||
888 | |||
889 | if (graybuf == NULL || x1 >= graybuf->width || y1 >= graybuf->height | ||
890 | || x2 >= graybuf->width || y2 >= graybuf->height|| brightness > 255) | ||
891 | return; | ||
892 | |||
893 | pattern = graybuf->bitpattern[(brightness * (graybuf->depth + 1)) >> 8]; | ||
894 | |||
895 | deltax = abs(x2 - x1); | ||
896 | deltay = abs(y2 - y1); | ||
897 | |||
898 | if (deltax >= deltay) | ||
899 | { | ||
900 | numpixels = deltax; | ||
901 | d = 2 * deltay - deltax; | ||
902 | dinc1 = deltay * 2; | ||
903 | dinc2 = (deltay - deltax) * 2; | ||
904 | xinc1 = 1; | ||
905 | xinc2 = 1; | ||
906 | yinc1 = 0; | ||
907 | yinc2 = 1; | ||
908 | } | ||
909 | else | ||
910 | { | ||
911 | numpixels = deltay; | ||
912 | d = 2 * deltax - deltay; | ||
913 | dinc1 = deltax * 2; | ||
914 | dinc2 = (deltax - deltay) * 2; | ||
915 | xinc1 = 0; | ||
916 | xinc2 = 1; | ||
917 | yinc1 = 1; | ||
918 | yinc2 = 1; | ||
919 | } | ||
920 | numpixels++; /* include endpoints */ | ||
921 | |||
922 | if (x1 > x2) | ||
923 | { | ||
924 | xinc1 = -xinc1; | ||
925 | xinc2 = -xinc2; | ||
926 | } | ||
927 | |||
928 | if (y1 > y2) | ||
929 | { | ||
930 | yinc1 = -yinc1; | ||
931 | yinc2 = -yinc2; | ||
932 | } | ||
933 | |||
934 | x = x1; | ||
935 | y = y1; | ||
936 | |||
937 | for (i=0; i<numpixels; i++) | ||
938 | { | ||
939 | graypixel(x, y, pattern); | ||
940 | |||
941 | if (d < 0) | ||
942 | { | ||
943 | d += dinc1; | ||
944 | x += xinc1; | ||
945 | y += yinc1; | ||
946 | } | ||
947 | else | ||
948 | { | ||
949 | d += dinc2; | ||
950 | x += xinc2; | ||
951 | y += yinc2; | ||
952 | } | ||
953 | } | ||
954 | } | ||
955 | |||
956 | /* Invert a line from (x1, y1) to (x2, y2) | ||
957 | * | ||
958 | * The bit patterns for the pixels of the line are inverted, so white becomes | ||
959 | * black, light gray becomes dark gray etc. | ||
960 | */ | ||
961 | void gray_invertline(int x1, int y1, int x2, int y2) | ||
962 | { | ||
963 | int numpixels; | ||
964 | int i; | ||
965 | int deltax, deltay; | ||
966 | int d, dinc1, dinc2; | ||
967 | int x, xinc1, xinc2; | ||
968 | int y, yinc1, yinc2; | ||
969 | |||
970 | if (graybuf == NULL || x1 >= graybuf->width || y1 >= graybuf->height | ||
971 | || x2 >= graybuf->width || y2 >= graybuf->height) | ||
972 | return; | ||
973 | |||
974 | deltax = abs(x2 - x1); | ||
975 | deltay = abs(y2 - y1); | ||
976 | |||
977 | if (deltax >= deltay) | ||
978 | { | ||
979 | numpixels = deltax; | ||
980 | d = 2 * deltay - deltax; | ||
981 | dinc1 = deltay * 2; | ||
982 | dinc2 = (deltay - deltax) * 2; | ||
983 | xinc1 = 1; | ||
984 | xinc2 = 1; | ||
985 | yinc1 = 0; | ||
986 | yinc2 = 1; | ||
987 | } | ||
988 | else | ||
989 | { | ||
990 | numpixels = deltay; | ||
991 | d = 2 * deltax - deltay; | ||
992 | dinc1 = deltax * 2; | ||
993 | dinc2 = (deltax - deltay) * 2; | ||
994 | xinc1 = 0; | ||
995 | xinc2 = 1; | ||
996 | yinc1 = 1; | ||
997 | yinc2 = 1; | ||
998 | } | ||
999 | numpixels++; /* include endpoints */ | ||
1000 | |||
1001 | if (x1 > x2) | ||
1002 | { | ||
1003 | xinc1 = -xinc1; | ||
1004 | xinc2 = -xinc2; | ||
1005 | } | ||
1006 | |||
1007 | if (y1 > y2) | ||
1008 | { | ||
1009 | yinc1 = -yinc1; | ||
1010 | yinc2 = -yinc2; | ||
1011 | } | ||
1012 | |||
1013 | x = x1; | ||
1014 | y = y1; | ||
1015 | |||
1016 | for (i=0; i<numpixels; i++) | ||
1017 | { | ||
1018 | grayinvertmasked(x, (y >> 3), 1 << (y & 7)); | ||
1019 | |||
1020 | if (d < 0) | ||
1021 | { | ||
1022 | d += dinc1; | ||
1023 | x += xinc1; | ||
1024 | y += yinc1; | ||
1025 | } | ||
1026 | else | ||
1027 | { | ||
1028 | d += dinc2; | ||
1029 | x += xinc2; | ||
1030 | y += yinc2; | ||
1031 | } | ||
1032 | } | ||
1033 | } | ||
1034 | |||
1035 | /* Draw a (hollow) rectangle with a specific gray value, | ||
1036 | * corners are (x1, y1) and (x2, y2) | ||
1037 | * | ||
1038 | * brightness is 0..255 (black to white) regardless of real bit depth | ||
1039 | */ | ||
1040 | void gray_drawrect(int x1, int y1, int x2, int y2, int brightness) | ||
1041 | { | ||
1042 | int x, y; | ||
1043 | unsigned long pattern; | ||
1044 | |||
1045 | if (graybuf == NULL || x1 >= graybuf->width || y1 >= graybuf->height | ||
1046 | || x2 >= graybuf->width || y2 >= graybuf->height|| brightness > 255) | ||
1047 | return; | ||
1048 | |||
1049 | pattern = graybuf->bitpattern[(brightness * (graybuf->depth + 1)) >> 8]; | ||
1050 | |||
1051 | if (y1 > y2) | ||
1052 | { | ||
1053 | y = y1; | ||
1054 | y1 = y2; | ||
1055 | y2 = y; | ||
1056 | } | ||
1057 | if (x1 > x2) | ||
1058 | { | ||
1059 | x = x1; | ||
1060 | x1 = x2; | ||
1061 | x2 = x; | ||
1062 | } | ||
1063 | |||
1064 | for (x = x1; x <= x2; x++) | ||
1065 | { | ||
1066 | graypixel(x, y1, pattern); | ||
1067 | graypixel(x, y2, pattern); | ||
1068 | } | ||
1069 | for (y = y1; y <= y2; y++) | ||
1070 | { | ||
1071 | graypixel(x1, y, pattern); | ||
1072 | graypixel(x2, y, pattern); | ||
1073 | } | ||
1074 | } | ||
1075 | |||
1076 | /* Fill a rectangle with a specific gray value | ||
1077 | * corners are (x1, y1) and (x2, y2) | ||
1078 | * | ||
1079 | * brightness is 0..255 (black to white) regardless of real bit depth | ||
1080 | */ | ||
1081 | void gray_fillrect(int x1, int y1, int x2, int y2, int brightness) | ||
1082 | { | ||
1083 | int x, y; | ||
1084 | unsigned long pattern; | ||
1085 | |||
1086 | if (graybuf == NULL || x1 >= graybuf->width || y1 >= graybuf->height | ||
1087 | || x2 >= graybuf->width || y2 >= graybuf->height || brightness > 255) | ||
1088 | return; | ||
1089 | |||
1090 | if (y1 > y2) | ||
1091 | { | ||
1092 | y = y1; | ||
1093 | y1 = y2; | ||
1094 | y2 = y; | ||
1095 | } | ||
1096 | if (x1 > x2) | ||
1097 | { | ||
1098 | x = x1; | ||
1099 | x1 = x2; | ||
1100 | x2 = x; | ||
1101 | } | ||
1102 | |||
1103 | pattern = graybuf->bitpattern[(brightness * (graybuf->depth + 1)) >> 8]; | ||
1104 | |||
1105 | for (y = y1; y <= y2; y++) | ||
1106 | { | ||
1107 | for (x = x1; x <= x2; x++) | ||
1108 | { | ||
1109 | graypixel(x, y, pattern); | ||
1110 | } | ||
1111 | } | ||
1112 | } | ||
1113 | |||
1114 | /* Invert a (solid) rectangle, corners are (x1, y1) and (x2, y2) | ||
1115 | * | ||
1116 | * The bit patterns for all pixels of the rectangle are inverted, so white | ||
1117 | * becomes black, light gray becomes dark gray etc. This is the fastest of | ||
1118 | * all gray_xxxrect() functions! Perfectly suited for cursors. | ||
1119 | */ | ||
1120 | void gray_invertrect(int x1, int y1, int x2, int y2) | ||
1121 | { | ||
1122 | int x, yb, yb1, yb2; | ||
1123 | unsigned char mask; | ||
1124 | |||
1125 | if (graybuf == NULL || x1 >= graybuf->width || y1 >= graybuf->height | ||
1126 | || x2 >= graybuf->width || y2 >= graybuf->height) | ||
1127 | return; | ||
1128 | |||
1129 | if (y1 > y2) | ||
1130 | { | ||
1131 | yb = y1; | ||
1132 | y1 = y2; | ||
1133 | y2 = yb; | ||
1134 | } | ||
1135 | if (x1 > x2) | ||
1136 | { | ||
1137 | x = x1; | ||
1138 | x1 = x2; | ||
1139 | x2 = x; | ||
1140 | } | ||
1141 | |||
1142 | yb1 = y1 >> 3; | ||
1143 | yb2 = y2 >> 3; | ||
1144 | |||
1145 | if (yb1 == yb2) | ||
1146 | { | ||
1147 | mask = 0xFF << (y1 & 7); | ||
1148 | mask &= 0xFF >> (7 - (y2 & 7)); | ||
1149 | |||
1150 | for (x = x1; x <= x2; x++) | ||
1151 | grayinvertmasked(x, yb1, mask); | ||
1152 | } | ||
1153 | else | ||
1154 | { | ||
1155 | mask = 0xFF << (y1 & 7); | ||
1156 | |||
1157 | for (x = x1; x <= x2; x++) | ||
1158 | grayinvertmasked(x, yb1, mask); | ||
1159 | |||
1160 | for (yb = yb1 + 1; yb < yb2; yb++) | ||
1161 | { | ||
1162 | for (x = x1; x <= x2; x++) | ||
1163 | grayinvertmasked(x, yb, 0xFF); | ||
1164 | } | ||
1165 | |||
1166 | mask = 0xFF >> (7 - (y2 & 7)); | ||
1167 | |||
1168 | for (x = x1; x <= x2; x++) | ||
1169 | grayinvertmasked(x, yb2, mask); | ||
1170 | } | ||
1171 | } | ||
1172 | |||
1173 | /* Copy a grayscale bitmap into the display | ||
1174 | * | ||
1175 | * A grayscale bitmap contains one byte for every pixel that defines the | ||
1176 | * brightness of the pixel (0..255). Bytes are read in row-major order. | ||
1177 | * The <stride> parameter is useful if you want to show only a part of a | ||
1178 | * bitmap. It should always be set to the "line length" of the bitmap, so | ||
1179 | * for displaying the whole bitmap, nx == stride. | ||
1180 | */ | ||
1181 | void gray_drawgraymap(unsigned char *src, int x, int y, int nx, int ny, | ||
1182 | int stride) | ||
1183 | { | ||
1184 | int xi, yi; | ||
1185 | unsigned char *row; | ||
1186 | |||
1187 | if (graybuf == NULL || x >= graybuf->width || y >= graybuf->height) | ||
1188 | return; | ||
1189 | |||
1190 | if ((y + ny) >= graybuf->height) /* clip bottom */ | ||
1191 | ny = graybuf->height - y; | ||
1192 | |||
1193 | if ((x + nx) >= graybuf->width) /* clip right */ | ||
1194 | nx = graybuf->width - x; | ||
1195 | |||
1196 | for (yi = y; yi < y + ny; yi++) | ||
1197 | { | ||
1198 | row = src; | ||
1199 | src += stride; | ||
1200 | for (xi = x; xi < x + nx; xi++) | ||
1201 | { | ||
1202 | graypixel(xi, yi, graybuf->bitpattern[((int)(*row++) | ||
1203 | * (graybuf->depth + 1)) >> 8]); | ||
1204 | } | ||
1205 | } | ||
1206 | } | ||
1207 | |||
1208 | /* Display a bitmap with specific foreground and background gray values | ||
1209 | * | ||
1210 | * A bitmap contains one bit for every pixel that defines if that pixel is | ||
1211 | * foreground (1) or background (0). Bytes are read in row-major order, MSB | ||
1212 | * first. A row consists of an integer number of bytes, extra bits past the | ||
1213 | * right margin are ignored. | ||
1214 | * The <stride> parameter is useful if you want to show only a part of a | ||
1215 | * bitmap. It should always be set to the "line length" of the bitmap. | ||
1216 | * Beware that this is counted in bytes, so nx == 8 * stride for the whole | ||
1217 | * bitmap. | ||
1218 | * | ||
1219 | * If draw_bg is false, only foreground pixels are drawn, so the background | ||
1220 | * is transparent. In this case bg_brightness is ignored. | ||
1221 | */ | ||
1222 | void gray_drawbitmap(unsigned char *src, int x, int y, int nx, int ny, | ||
1223 | int stride, bool draw_bg, int fg_brightness, | ||
1224 | int bg_brightness) | ||
1225 | { | ||
1226 | int xi, yi, i; | ||
1227 | unsigned long fg_pattern, bg_pattern; | ||
1228 | unsigned long bits = 0; /* Have to initialize to prevent warning */ | ||
1229 | unsigned char *row; | ||
1230 | |||
1231 | if (graybuf == NULL || x >= graybuf->width || y >= graybuf->height | ||
1232 | || fg_brightness > 255 || bg_brightness > 255) | ||
1233 | return; | ||
1234 | |||
1235 | if ((y + ny) >= graybuf->height) /* clip bottom */ | ||
1236 | ny = graybuf->height - y; | ||
1237 | |||
1238 | if ((x + nx) >= graybuf->width) /* clip right */ | ||
1239 | nx = graybuf->width - x; | ||
1240 | |||
1241 | fg_pattern = graybuf->bitpattern[(fg_brightness | ||
1242 | * (graybuf->depth + 1)) >> 8]; | ||
1243 | |||
1244 | bg_pattern = graybuf->bitpattern[(bg_brightness | ||
1245 | * (graybuf->depth + 1)) >> 8]; | ||
1246 | |||
1247 | for (yi = y; yi < y + ny; yi++) | ||
1248 | { | ||
1249 | i = 0; | ||
1250 | row = src; | ||
1251 | src += stride; | ||
1252 | for (xi = x; xi < x + nx; xi++) | ||
1253 | { | ||
1254 | if (i == 0) /* get next 8 bits */ | ||
1255 | bits = (unsigned long)(*row++); | ||
1256 | |||
1257 | if (bits & 0x80) | ||
1258 | graypixel(xi, yi, fg_pattern); | ||
1259 | else | ||
1260 | if (draw_bg) | ||
1261 | graypixel(xi, yi, bg_pattern); | ||
1262 | |||
1263 | bits <<= 1; | ||
1264 | i++; | ||
1265 | i &= 7; | ||
1266 | } | ||
1267 | } | ||
1268 | } | ||
1269 | |||
1270 | /**************** end grayscale framework ********************/ | ||
1271 | |||
1272 | #define MEMSET(p,v,c) rb->memset(p,v,c) // for portability of below | ||
1273 | #define INLINE static inline | ||
1274 | |||
1275 | /**************** begin JPEG code ********************/ | ||
1276 | |||
1277 | /* LUT for IDCT, this could also be used for gamma correction */ | ||
1278 | const unsigned char range_limit[1024] = { | ||
1279 | 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, | ||
1280 | 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159, | ||
1281 | 160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175, | ||
1282 | 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191, | ||
1283 | 192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207, | ||
1284 | 208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223, | ||
1285 | 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239, | ||
1286 | 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255, | ||
1287 | |||
1288 | 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, | ||
1289 | 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, | ||
1290 | 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, | ||
1291 | 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, | ||
1292 | 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, | ||
1293 | 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, | ||
1294 | 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, | ||
1295 | 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, | ||
1296 | 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, | ||
1297 | 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, | ||
1298 | 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, | ||
1299 | 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, | ||
1300 | 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, | ||
1301 | 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, | ||
1302 | 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, | ||
1303 | 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, | ||
1304 | 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, | ||
1305 | 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, | ||
1306 | 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, | ||
1307 | 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, | ||
1308 | 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, | ||
1309 | 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, | ||
1310 | 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, | ||
1311 | 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, | ||
1312 | |||
1313 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | ||
1314 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | ||
1315 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | ||
1316 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | ||
1317 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | ||
1318 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | ||
1319 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | ||
1320 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | ||
1321 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | ||
1322 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | ||
1323 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | ||
1324 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | ||
1325 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | ||
1326 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | ||
1327 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | ||
1328 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | ||
1329 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | ||
1330 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | ||
1331 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | ||
1332 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | ||
1333 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | ||
1334 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | ||
1335 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | ||
1336 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | ||
1337 | |||
1338 | 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, | ||
1339 | 16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31, | ||
1340 | 32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47, | ||
1341 | 48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63, | ||
1342 | 64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79, | ||
1343 | 80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95, | ||
1344 | 96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111, | ||
1345 | 112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127 | ||
1346 | }; | ||
1347 | |||
1348 | |||
1349 | /* IDCT implementation */ | ||
1350 | |||
1351 | |||
1352 | #define CONST_BITS 13 | ||
1353 | #define PASS1_BITS 2 | ||
1354 | |||
1355 | |||
1356 | /* Some C compilers fail to reduce "FIX(constant)" at compile time, thus | ||
1357 | * causing a lot of useless floating-point operations at run time. | ||
1358 | * To get around this we use the following pre-calculated constants. | ||
1359 | * If you change CONST_BITS you may want to add appropriate values. | ||
1360 | * (With a reasonable C compiler, you can just rely on the FIX() macro...) | ||
1361 | */ | ||
1362 | #define FIX_0_298631336 2446 /* FIX(0.298631336) */ | ||
1363 | #define FIX_0_390180644 3196 /* FIX(0.390180644) */ | ||
1364 | #define FIX_0_541196100 4433 /* FIX(0.541196100) */ | ||
1365 | #define FIX_0_765366865 6270 /* FIX(0.765366865) */ | ||
1366 | #define FIX_0_899976223 7373 /* FIX(0.899976223) */ | ||
1367 | #define FIX_1_175875602 9633 /* FIX(1.175875602) */ | ||
1368 | #define FIX_1_501321110 12299 /* FIX(1.501321110) */ | ||
1369 | #define FIX_1_847759065 15137 /* FIX(1.847759065) */ | ||
1370 | #define FIX_1_961570560 16069 /* FIX(1.961570560) */ | ||
1371 | #define FIX_2_053119869 16819 /* FIX(2.053119869) */ | ||
1372 | #define FIX_2_562915447 20995 /* FIX(2.562915447) */ | ||
1373 | #define FIX_3_072711026 25172 /* FIX(3.072711026) */ | ||
1374 | |||
1375 | |||
1376 | |||
1377 | /* Multiply an long variable by an long constant to yield an long result. | ||
1378 | * For 8-bit samples with the recommended scaling, all the variable | ||
1379 | * and constant values involved are no more than 16 bits wide, so a | ||
1380 | * 16x16->32 bit multiply can be used instead of a full 32x32 multiply. | ||
1381 | * For 12-bit samples, a full 32-bit multiplication will be needed. | ||
1382 | */ | ||
1383 | #define MULTIPLY16(var,const) (((short) (var)) * ((short) (const))) | ||
1384 | |||
1385 | |||
1386 | /* Dequantize a coefficient by multiplying it by the multiplier-table | ||
1387 | * entry; produce an int result. In this module, both inputs and result | ||
1388 | * are 16 bits or less, so either int or short multiply will work. | ||
1389 | */ | ||
1390 | /* #define DEQUANTIZE(coef,quantval) (((int) (coef)) * (quantval)) */ | ||
1391 | #define DEQUANTIZE MULTIPLY16 | ||
1392 | |||
1393 | /* Descale and correctly round an int value that's scaled by N bits. | ||
1394 | * We assume RIGHT_SHIFT rounds towards minus infinity, so adding | ||
1395 | * the fudge factor is correct for either sign of X. | ||
1396 | */ | ||
1397 | #define DESCALE(x,n) (((x) + (1l << ((n)-1))) >> (n)) | ||
1398 | |||
1399 | #define RANGE_MASK (255 * 4 + 3) /* 2 bits wider than legal samples */ | ||
1400 | |||
1401 | |||
1402 | |||
1403 | /* | ||
1404 | * Perform dequantization and inverse DCT on one block of coefficients, | ||
1405 | * producing a reduced-size 1x1 output block. | ||
1406 | */ | ||
1407 | void idct1x1(unsigned char* p_byte, int* inptr, int* quantptr, int skip_line) | ||
1408 | { | ||
1409 | (void)skip_line; /* unused */ | ||
1410 | *p_byte = range_limit[(inptr[0] * quantptr[0] >> 3) & RANGE_MASK]; | ||
1411 | } | ||
1412 | |||
1413 | |||
1414 | |||
1415 | /* | ||
1416 | * Perform dequantization and inverse DCT on one block of coefficients, | ||
1417 | * producing a reduced-size 2x2 output block. | ||
1418 | */ | ||
1419 | void idct2x2(unsigned char* p_byte, int* inptr, int* quantptr, int skip_line) | ||
1420 | { | ||
1421 | int tmp0, tmp1, tmp2, tmp3, tmp4, tmp5; | ||
1422 | unsigned char* outptr; | ||
1423 | |||
1424 | /* Pass 1: process columns from input, store into work array. */ | ||
1425 | |||
1426 | /* Column 0 */ | ||
1427 | tmp4 = DEQUANTIZE(inptr[8*0], quantptr[8*0]); | ||
1428 | tmp5 = DEQUANTIZE(inptr[8*1], quantptr[8*1]); | ||
1429 | |||
1430 | tmp0 = tmp4 + tmp5; | ||
1431 | tmp2 = tmp4 - tmp5; | ||
1432 | |||
1433 | /* Column 1 */ | ||
1434 | tmp4 = DEQUANTIZE(inptr[8*0+1], quantptr[8*0+1]); | ||
1435 | tmp5 = DEQUANTIZE(inptr[8*1+1], quantptr[8*1+1]); | ||
1436 | |||
1437 | tmp1 = tmp4 + tmp5; | ||
1438 | tmp3 = tmp4 - tmp5; | ||
1439 | |||
1440 | /* Pass 2: process 2 rows, store into output array. */ | ||
1441 | |||
1442 | /* Row 0 */ | ||
1443 | outptr = p_byte; | ||
1444 | |||
1445 | outptr[0] = range_limit[(int) DESCALE(tmp0 + tmp1, 3) | ||
1446 | & RANGE_MASK]; | ||
1447 | outptr[1] = range_limit[(int) DESCALE(tmp0 - tmp1, 3) | ||
1448 | & RANGE_MASK]; | ||
1449 | |||
1450 | /* Row 1 */ | ||
1451 | outptr = p_byte + skip_line; | ||
1452 | |||
1453 | outptr[0] = range_limit[(int) DESCALE(tmp2 + tmp3, 3) | ||
1454 | & RANGE_MASK]; | ||
1455 | outptr[1] = range_limit[(int) DESCALE(tmp2 - tmp3, 3) | ||
1456 | & RANGE_MASK]; | ||
1457 | } | ||
1458 | |||
1459 | |||
1460 | |||
1461 | /* | ||
1462 | * Perform dequantization and inverse DCT on one block of coefficients, | ||
1463 | * producing a reduced-size 4x4 output block. | ||
1464 | */ | ||
1465 | void idct4x4(unsigned char* p_byte, int* inptr, int* quantptr, int skip_line) | ||
1466 | { | ||
1467 | int tmp0, tmp2, tmp10, tmp12; | ||
1468 | int z1, z2, z3; | ||
1469 | int * wsptr; | ||
1470 | unsigned char* outptr; | ||
1471 | int ctr; | ||
1472 | int workspace[4*4]; /* buffers data between passes */ | ||
1473 | |||
1474 | /* Pass 1: process columns from input, store into work array. */ | ||
1475 | |||
1476 | wsptr = workspace; | ||
1477 | for (ctr = 0; ctr < 4; ctr++, inptr++, quantptr++, wsptr++) | ||
1478 | { | ||
1479 | /* Even part */ | ||
1480 | |||
1481 | tmp0 = DEQUANTIZE(inptr[8*0], quantptr[8*0]); | ||
1482 | tmp2 = DEQUANTIZE(inptr[8*2], quantptr[8*2]); | ||
1483 | |||
1484 | tmp10 = (tmp0 + tmp2) << PASS1_BITS; | ||
1485 | tmp12 = (tmp0 - tmp2) << PASS1_BITS; | ||
1486 | |||
1487 | /* Odd part */ | ||
1488 | /* Same rotation as in the even part of the 8x8 LL&M IDCT */ | ||
1489 | |||
1490 | z2 = DEQUANTIZE(inptr[8*1], quantptr[8*1]); | ||
1491 | z3 = DEQUANTIZE(inptr[8*3], quantptr[8*3]); | ||
1492 | |||
1493 | z1 = MULTIPLY16(z2 + z3, FIX_0_541196100); | ||
1494 | tmp0 = DESCALE(z1 + MULTIPLY16(z3, - FIX_1_847759065), CONST_BITS-PASS1_BITS); | ||
1495 | tmp2 = DESCALE(z1 + MULTIPLY16(z2, FIX_0_765366865), CONST_BITS-PASS1_BITS); | ||
1496 | |||
1497 | /* Final output stage */ | ||
1498 | |||
1499 | wsptr[4*0] = (int) (tmp10 + tmp2); | ||
1500 | wsptr[4*3] = (int) (tmp10 - tmp2); | ||
1501 | wsptr[4*1] = (int) (tmp12 + tmp0); | ||
1502 | wsptr[4*2] = (int) (tmp12 - tmp0); | ||
1503 | } | ||
1504 | |||
1505 | /* Pass 2: process 4 rows from work array, store into output array. */ | ||
1506 | |||
1507 | wsptr = workspace; | ||
1508 | for (ctr = 0; ctr < 4; ctr++) | ||
1509 | { | ||
1510 | outptr = p_byte + (ctr*skip_line); | ||
1511 | /* Even part */ | ||
1512 | |||
1513 | tmp0 = (int) wsptr[0]; | ||
1514 | tmp2 = (int) wsptr[2]; | ||
1515 | |||
1516 | tmp10 = (tmp0 + tmp2) << CONST_BITS; | ||
1517 | tmp12 = (tmp0 - tmp2) << CONST_BITS; | ||
1518 | |||
1519 | /* Odd part */ | ||
1520 | /* Same rotation as in the even part of the 8x8 LL&M IDCT */ | ||
1521 | |||
1522 | z2 = (int) wsptr[1]; | ||
1523 | z3 = (int) wsptr[3]; | ||
1524 | |||
1525 | z1 = MULTIPLY16(z2 + z3, FIX_0_541196100); | ||
1526 | tmp0 = z1 + MULTIPLY16(z3, - FIX_1_847759065); | ||
1527 | tmp2 = z1 + MULTIPLY16(z2, FIX_0_765366865); | ||
1528 | |||
1529 | /* Final output stage */ | ||
1530 | |||
1531 | outptr[0] = range_limit[(int) DESCALE(tmp10 + tmp2, | ||
1532 | CONST_BITS+PASS1_BITS+3) | ||
1533 | & RANGE_MASK]; | ||
1534 | outptr[3] = range_limit[(int) DESCALE(tmp10 - tmp2, | ||
1535 | CONST_BITS+PASS1_BITS+3) | ||
1536 | & RANGE_MASK]; | ||
1537 | outptr[1] = range_limit[(int) DESCALE(tmp12 + tmp0, | ||
1538 | CONST_BITS+PASS1_BITS+3) | ||
1539 | & RANGE_MASK]; | ||
1540 | outptr[2] = range_limit[(int) DESCALE(tmp12 - tmp0, | ||
1541 | CONST_BITS+PASS1_BITS+3) | ||
1542 | & RANGE_MASK]; | ||
1543 | |||
1544 | wsptr += 4; /* advance pointer to next row */ | ||
1545 | } | ||
1546 | } | ||
1547 | |||
1548 | |||
1549 | |||
1550 | /* | ||
1551 | * Perform dequantization and inverse DCT on one block of coefficients. | ||
1552 | */ | ||
1553 | void idct8x8(unsigned char* p_byte, int* inptr, int* quantptr, int skip_line) | ||
1554 | { | ||
1555 | long tmp0, tmp1, tmp2, tmp3; | ||
1556 | long tmp10, tmp11, tmp12, tmp13; | ||
1557 | long z1, z2, z3, z4, z5; | ||
1558 | int * wsptr; | ||
1559 | unsigned char* outptr; | ||
1560 | int ctr; | ||
1561 | static int workspace[64]; /* buffers data between passes */ | ||
1562 | |||
1563 | /* Pass 1: process columns from input, store into work array. */ | ||
1564 | /* Note results are scaled up by sqrt(8) compared to a true IDCT; */ | ||
1565 | /* furthermore, we scale the results by 2**PASS1_BITS. */ | ||
1566 | |||
1567 | wsptr = workspace; | ||
1568 | for (ctr = 8; ctr > 0; ctr--) | ||
1569 | { | ||
1570 | /* Due to quantization, we will usually find that many of the input | ||
1571 | * coefficients are zero, especially the AC terms. We can exploit this | ||
1572 | * by short-circuiting the IDCT calculation for any column in which all | ||
1573 | * the AC terms are zero. In that case each output is equal to the | ||
1574 | * DC coefficient (with scale factor as needed). | ||
1575 | * With typical images and quantization tables, half or more of the | ||
1576 | * column DCT calculations can be simplified this way. | ||
1577 | */ | ||
1578 | |||
1579 | if ((inptr[8*1] | inptr[8*2] | inptr[8*3] | ||
1580 | | inptr[8*4] | inptr[8*5] | inptr[8*6] | inptr[8*7]) == 0) | ||
1581 | { | ||
1582 | /* AC terms all zero */ | ||
1583 | int dcval = DEQUANTIZE(inptr[8*0], quantptr[8*0]) << PASS1_BITS; | ||
1584 | |||
1585 | wsptr[8*0] = wsptr[8*1] = wsptr[8*2] = wsptr[8*3] = wsptr[8*4] | ||
1586 | = wsptr[8*5] = wsptr[8*6] = wsptr[8*7] = dcval; | ||
1587 | inptr++; /* advance pointers to next column */ | ||
1588 | quantptr++; | ||
1589 | wsptr++; | ||
1590 | continue; | ||
1591 | } | ||
1592 | |||
1593 | /* Even part: reverse the even part of the forward DCT. */ | ||
1594 | /* The rotator is sqrt(2)*c(-6). */ | ||
1595 | |||
1596 | z2 = DEQUANTIZE(inptr[8*2], quantptr[8*2]); | ||
1597 | z3 = DEQUANTIZE(inptr[8*6], quantptr[8*6]); | ||
1598 | |||
1599 | z1 = MULTIPLY16(z2 + z3, FIX_0_541196100); | ||
1600 | tmp2 = z1 + MULTIPLY16(z3, - FIX_1_847759065); | ||
1601 | tmp3 = z1 + MULTIPLY16(z2, FIX_0_765366865); | ||
1602 | |||
1603 | z2 = DEQUANTIZE(inptr[8*0], quantptr[8*0]); | ||
1604 | z3 = DEQUANTIZE(inptr[8*4], quantptr[8*4]); | ||
1605 | |||
1606 | tmp0 = (z2 + z3) << CONST_BITS; | ||
1607 | tmp1 = (z2 - z3) << CONST_BITS; | ||
1608 | |||
1609 | tmp10 = tmp0 + tmp3; | ||
1610 | tmp13 = tmp0 - tmp3; | ||
1611 | tmp11 = tmp1 + tmp2; | ||
1612 | tmp12 = tmp1 - tmp2; | ||
1613 | |||
1614 | /* Odd part per figure 8; the matrix is unitary and hence its | ||
1615 | transpose is its inverse. i0..i3 are y7,y5,y3,y1 respectively. */ | ||
1616 | |||
1617 | tmp0 = DEQUANTIZE(inptr[8*7], quantptr[8*7]); | ||
1618 | tmp1 = DEQUANTIZE(inptr[8*5], quantptr[8*5]); | ||
1619 | tmp2 = DEQUANTIZE(inptr[8*3], quantptr[8*3]); | ||
1620 | tmp3 = DEQUANTIZE(inptr[8*1], quantptr[8*1]); | ||
1621 | |||
1622 | z1 = tmp0 + tmp3; | ||
1623 | z2 = tmp1 + tmp2; | ||
1624 | z3 = tmp0 + tmp2; | ||
1625 | z4 = tmp1 + tmp3; | ||
1626 | z5 = MULTIPLY16(z3 + z4, FIX_1_175875602); /* sqrt(2) * c3 */ | ||
1627 | |||
1628 | tmp0 = MULTIPLY16(tmp0, FIX_0_298631336); /* sqrt(2) * (-c1+c3+c5-c7) */ | ||
1629 | tmp1 = MULTIPLY16(tmp1, FIX_2_053119869); /* sqrt(2) * ( c1+c3-c5+c7) */ | ||
1630 | tmp2 = MULTIPLY16(tmp2, FIX_3_072711026); /* sqrt(2) * ( c1+c3+c5-c7) */ | ||
1631 | tmp3 = MULTIPLY16(tmp3, FIX_1_501321110); /* sqrt(2) * ( c1+c3-c5-c7) */ | ||
1632 | z1 = MULTIPLY16(z1, - FIX_0_899976223); /* sqrt(2) * (c7-c3) */ | ||
1633 | z2 = MULTIPLY16(z2, - FIX_2_562915447); /* sqrt(2) * (-c1-c3) */ | ||
1634 | z3 = MULTIPLY16(z3, - FIX_1_961570560); /* sqrt(2) * (-c3-c5) */ | ||
1635 | z4 = MULTIPLY16(z4, - FIX_0_390180644); /* sqrt(2) * (c5-c3) */ | ||
1636 | |||
1637 | z3 += z5; | ||
1638 | z4 += z5; | ||
1639 | |||
1640 | tmp0 += z1 + z3; | ||
1641 | tmp1 += z2 + z4; | ||
1642 | tmp2 += z2 + z3; | ||
1643 | tmp3 += z1 + z4; | ||
1644 | |||
1645 | /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */ | ||
1646 | |||
1647 | wsptr[8*0] = (int) DESCALE(tmp10 + tmp3, CONST_BITS-PASS1_BITS); | ||
1648 | wsptr[8*7] = (int) DESCALE(tmp10 - tmp3, CONST_BITS-PASS1_BITS); | ||
1649 | wsptr[8*1] = (int) DESCALE(tmp11 + tmp2, CONST_BITS-PASS1_BITS); | ||
1650 | wsptr[8*6] = (int) DESCALE(tmp11 - tmp2, CONST_BITS-PASS1_BITS); | ||
1651 | wsptr[8*2] = (int) DESCALE(tmp12 + tmp1, CONST_BITS-PASS1_BITS); | ||
1652 | wsptr[8*5] = (int) DESCALE(tmp12 - tmp1, CONST_BITS-PASS1_BITS); | ||
1653 | wsptr[8*3] = (int) DESCALE(tmp13 + tmp0, CONST_BITS-PASS1_BITS); | ||
1654 | wsptr[8*4] = (int) DESCALE(tmp13 - tmp0, CONST_BITS-PASS1_BITS); | ||
1655 | |||
1656 | inptr++; /* advance pointers to next column */ | ||
1657 | quantptr++; | ||
1658 | wsptr++; | ||
1659 | } | ||
1660 | |||
1661 | /* Pass 2: process rows from work array, store into output array. */ | ||
1662 | /* Note that we must descale the results by a factor of 8 == 2**3, */ | ||
1663 | /* and also undo the PASS1_BITS scaling. */ | ||
1664 | |||
1665 | wsptr = workspace; | ||
1666 | for (ctr = 0; ctr < 8; ctr++) { | ||
1667 | outptr = p_byte + (ctr*skip_line); | ||
1668 | /* Rows of zeroes can be exploited in the same way as we did with columns. | ||
1669 | * However, the column calculation has created many nonzero AC terms, so | ||
1670 | * the simplification applies less often (typically 5% to 10% of the time). | ||
1671 | * On machines with very fast multiplication, it's possible that the | ||
1672 | * test takes more time than it's worth. In that case this section | ||
1673 | * may be commented out. | ||
1674 | */ | ||
1675 | |||
1676 | #ifndef NO_ZERO_ROW_TEST | ||
1677 | if ((wsptr[1] | wsptr[2] | wsptr[3] | ||
1678 | | wsptr[4] | wsptr[5] | wsptr[6] | wsptr[7]) == 0) | ||
1679 | { | ||
1680 | /* AC terms all zero */ | ||
1681 | unsigned char dcval = range_limit[(int) DESCALE((long) wsptr[0], | ||
1682 | PASS1_BITS+3) & RANGE_MASK]; | ||
1683 | |||
1684 | outptr[0] = dcval; | ||
1685 | outptr[1] = dcval; | ||
1686 | outptr[2] = dcval; | ||
1687 | outptr[3] = dcval; | ||
1688 | outptr[4] = dcval; | ||
1689 | outptr[5] = dcval; | ||
1690 | outptr[6] = dcval; | ||
1691 | outptr[7] = dcval; | ||
1692 | |||
1693 | wsptr += 8; /* advance pointer to next row */ | ||
1694 | continue; | ||
1695 | } | ||
1696 | #endif | ||
1697 | |||
1698 | /* Even part: reverse the even part of the forward DCT. */ | ||
1699 | /* The rotator is sqrt(2)*c(-6). */ | ||
1700 | |||
1701 | z2 = (long) wsptr[2]; | ||
1702 | z3 = (long) wsptr[6]; | ||
1703 | |||
1704 | z1 = MULTIPLY16(z2 + z3, FIX_0_541196100); | ||
1705 | tmp2 = z1 + MULTIPLY16(z3, - FIX_1_847759065); | ||
1706 | tmp3 = z1 + MULTIPLY16(z2, FIX_0_765366865); | ||
1707 | |||
1708 | tmp0 = ((long) wsptr[0] + (long) wsptr[4]) << CONST_BITS; | ||
1709 | tmp1 = ((long) wsptr[0] - (long) wsptr[4]) << CONST_BITS; | ||
1710 | |||
1711 | tmp10 = tmp0 + tmp3; | ||
1712 | tmp13 = tmp0 - tmp3; | ||
1713 | tmp11 = tmp1 + tmp2; | ||
1714 | tmp12 = tmp1 - tmp2; | ||
1715 | |||
1716 | /* Odd part per figure 8; the matrix is unitary and hence its | ||
1717 | * transpose is its inverse. i0..i3 are y7,y5,y3,y1 respectively. */ | ||
1718 | |||
1719 | tmp0 = (long) wsptr[7]; | ||
1720 | tmp1 = (long) wsptr[5]; | ||
1721 | tmp2 = (long) wsptr[3]; | ||
1722 | tmp3 = (long) wsptr[1]; | ||
1723 | |||
1724 | z1 = tmp0 + tmp3; | ||
1725 | z2 = tmp1 + tmp2; | ||
1726 | z3 = tmp0 + tmp2; | ||
1727 | z4 = tmp1 + tmp3; | ||
1728 | z5 = MULTIPLY16(z3 + z4, FIX_1_175875602); /* sqrt(2) * c3 */ | ||
1729 | |||
1730 | tmp0 = MULTIPLY16(tmp0, FIX_0_298631336); /* sqrt(2) * (-c1+c3+c5-c7) */ | ||
1731 | tmp1 = MULTIPLY16(tmp1, FIX_2_053119869); /* sqrt(2) * ( c1+c3-c5+c7) */ | ||
1732 | tmp2 = MULTIPLY16(tmp2, FIX_3_072711026); /* sqrt(2) * ( c1+c3+c5-c7) */ | ||
1733 | tmp3 = MULTIPLY16(tmp3, FIX_1_501321110); /* sqrt(2) * ( c1+c3-c5-c7) */ | ||
1734 | z1 = MULTIPLY16(z1, - FIX_0_899976223); /* sqrt(2) * (c7-c3) */ | ||
1735 | z2 = MULTIPLY16(z2, - FIX_2_562915447); /* sqrt(2) * (-c1-c3) */ | ||
1736 | z3 = MULTIPLY16(z3, - FIX_1_961570560); /* sqrt(2) * (-c3-c5) */ | ||
1737 | z4 = MULTIPLY16(z4, - FIX_0_390180644); /* sqrt(2) * (c5-c3) */ | ||
1738 | |||
1739 | z3 += z5; | ||
1740 | z4 += z5; | ||
1741 | |||
1742 | tmp0 += z1 + z3; | ||
1743 | tmp1 += z2 + z4; | ||
1744 | tmp2 += z2 + z3; | ||
1745 | tmp3 += z1 + z4; | ||
1746 | |||
1747 | /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */ | ||
1748 | |||
1749 | outptr[0] = range_limit[(int) DESCALE(tmp10 + tmp3, | ||
1750 | CONST_BITS+PASS1_BITS+3) & RANGE_MASK]; | ||
1751 | outptr[7] = range_limit[(int) DESCALE(tmp10 - tmp3, | ||
1752 | CONST_BITS+PASS1_BITS+3) & RANGE_MASK]; | ||
1753 | outptr[1] = range_limit[(int) DESCALE(tmp11 + tmp2, | ||
1754 | CONST_BITS+PASS1_BITS+3) & RANGE_MASK]; | ||
1755 | outptr[6] = range_limit[(int) DESCALE(tmp11 - tmp2, | ||
1756 | CONST_BITS+PASS1_BITS+3) & RANGE_MASK]; | ||
1757 | outptr[2] = range_limit[(int) DESCALE(tmp12 + tmp1, | ||
1758 | CONST_BITS+PASS1_BITS+3) & RANGE_MASK]; | ||
1759 | outptr[5] = range_limit[(int) DESCALE(tmp12 - tmp1, | ||
1760 | CONST_BITS+PASS1_BITS+3) & RANGE_MASK]; | ||
1761 | outptr[3] = range_limit[(int) DESCALE(tmp13 + tmp0, | ||
1762 | CONST_BITS+PASS1_BITS+3) & RANGE_MASK]; | ||
1763 | outptr[4] = range_limit[(int) DESCALE(tmp13 - tmp0, | ||
1764 | CONST_BITS+PASS1_BITS+3) & RANGE_MASK]; | ||
1765 | |||
1766 | wsptr += 8; /* advance pointer to next row */ | ||
1767 | } | ||
1768 | } | ||
1769 | |||
1770 | |||
1771 | |||
1772 | /* JPEG decoder implementation */ | ||
1773 | |||
1774 | |||
1775 | #define HUFF_LOOKAHEAD 8 /* # of bits of lookahead */ | ||
1776 | |||
1777 | struct derived_tbl | ||
1778 | { | ||
1779 | /* Basic tables: (element [0] of each array is unused) */ | ||
1780 | long mincode[17]; /* smallest code of length k */ | ||
1781 | long maxcode[18]; /* largest code of length k (-1 if none) */ | ||
1782 | /* (maxcode[17] is a sentinel to ensure huff_DECODE terminates) */ | ||
1783 | int valptr[17]; /* huffval[] index of 1st symbol of length k */ | ||
1784 | |||
1785 | /* Back link to public Huffman table (needed only in slow_DECODE) */ | ||
1786 | int* pub; | ||
1787 | |||
1788 | /* Lookahead tables: indexed by the next HUFF_LOOKAHEAD bits of | ||
1789 | the input data stream. If the next Huffman code is no more | ||
1790 | than HUFF_LOOKAHEAD bits long, we can obtain its length and | ||
1791 | the corresponding symbol directly from these tables. */ | ||
1792 | int look_nbits[1<<HUFF_LOOKAHEAD]; /* # bits, or 0 if too long */ | ||
1793 | unsigned char look_sym[1<<HUFF_LOOKAHEAD]; /* symbol, or unused */ | ||
1794 | }; | ||
1795 | |||
1796 | #define QUANT_TABLE_LENGTH 64 | ||
1797 | |||
1798 | /* for type of Huffman table */ | ||
1799 | #define DC_LEN 28 | ||
1800 | #define AC_LEN 178 | ||
1801 | |||
1802 | struct huffman_table | ||
1803 | { /* length and code according to JFIF format */ | ||
1804 | int huffmancodes_dc[DC_LEN]; | ||
1805 | int huffmancodes_ac[AC_LEN]; | ||
1806 | }; | ||
1807 | |||
1808 | struct frame_component | ||
1809 | { | ||
1810 | int ID; | ||
1811 | int horizontal_sampling; | ||
1812 | int vertical_sampling; | ||
1813 | int quanttable_select; | ||
1814 | }; | ||
1815 | |||
1816 | struct scan_component | ||
1817 | { | ||
1818 | int ID; | ||
1819 | int DC_select; | ||
1820 | int AC_select; | ||
1821 | }; | ||
1822 | |||
1823 | struct bitstream | ||
1824 | { | ||
1825 | unsigned long get_buffer; /* current bit-extraction buffer */ | ||
1826 | int bits_left; /* # of unused bits in it */ | ||
1827 | unsigned short* next_input_word; | ||
1828 | long words_left; /* # of words remaining in source buffer */ | ||
1829 | }; | ||
1830 | |||
1831 | struct jpeg | ||
1832 | { | ||
1833 | int x_size, y_size; /* size of image (can be less than block boundary) */ | ||
1834 | int x_phys, y_phys; /* physical size, block aligned */ | ||
1835 | int x_mbl; /* x dimension of MBL */ | ||
1836 | int y_mbl; /* y dimension of MBL */ | ||
1837 | int blocks; /* blocks per MBL */ | ||
1838 | |||
1839 | unsigned short* p_entropy_data; | ||
1840 | long words_in_buffer; /* # of valid words in source buffer */ | ||
1841 | |||
1842 | int quanttable[4][QUANT_TABLE_LENGTH]; /* raw quantization tables 0-3 */ | ||
1843 | int qt_idct[2][QUANT_TABLE_LENGTH]; /* quantization tables for IDCT */ | ||
1844 | |||
1845 | struct huffman_table hufftable[2]; /* Huffman tables */ | ||
1846 | struct derived_tbl dc_derived_tbls[2]; /* Huffman-LUTs */ | ||
1847 | struct derived_tbl ac_derived_tbls[2]; | ||
1848 | |||
1849 | struct frame_component frameheader[3]; /* Component descriptor */ | ||
1850 | struct scan_component scanheader[3]; /* currently not used */ | ||
1851 | |||
1852 | int mcu_membership[6]; /* info per block */ | ||
1853 | int tab_membership[6]; | ||
1854 | }; | ||
1855 | |||
1856 | |||
1857 | /* possible return flags for process_markers() */ | ||
1858 | #define HUFFTAB 0x0001 /* with huffman table */ | ||
1859 | #define QUANTTAB 0x0002 /* with quantization table */ | ||
1860 | #define APP0_JFIF 0x0004 /* with APP0 segment following JFIF standard */ | ||
1861 | #define FILL_FF 0x0008 /* with 0xFF padding bytes at begin/end */ | ||
1862 | #define SOF0 0x0010 /* with SOF0-Segment */ | ||
1863 | #define DHT 0x0020 /* with Definition of huffman tables */ | ||
1864 | #define SOS 0x0040 /* with Start-of-Scan segment */ | ||
1865 | #define DQT 0x0080 /* with definition of quantization table */ | ||
1866 | |||
1867 | /* Preprocess the JPEG JFIF file */ | ||
1868 | int process_markers(unsigned char* p_bytes, long size, struct jpeg* p_jpeg) | ||
1869 | { | ||
1870 | unsigned char* p_src = p_bytes; | ||
1871 | unsigned char* p_temp; | ||
1872 | |||
1873 | /* write without markers nor stuffing in same buffer */ | ||
1874 | unsigned short* p_dest = (unsigned short*) p_bytes; | ||
1875 | int marker_size; /* variable length of marker segment */ | ||
1876 | int i, j, n; | ||
1877 | unsigned char highbyte, lowbyte; | ||
1878 | int ret = 0; /* returned flags */ | ||
1879 | |||
1880 | /* memory location for later decompress */ | ||
1881 | p_jpeg->p_entropy_data = (unsigned short*)p_bytes; | ||
1882 | |||
1883 | while (p_src < p_bytes + size) | ||
1884 | { | ||
1885 | if (*p_src++ != 0xFF) /* no marker? */ | ||
1886 | { | ||
1887 | p_src--; /* it's image data, put it back */ | ||
1888 | break; /* exit marker processing */ | ||
1889 | } | ||
1890 | |||
1891 | switch (*p_src++) | ||
1892 | { | ||
1893 | case 0xFF: /* Fill byte */ | ||
1894 | ret |= FILL_FF; | ||
1895 | case 0x00: /* Zero stuffed byte - entropy data */ | ||
1896 | p_src--; /* put it back */ | ||
1897 | continue; | ||
1898 | |||
1899 | case 0xC0: /* SOF Huff - Baseline DCT */ | ||
1900 | { | ||
1901 | ret |= SOF0; | ||
1902 | marker_size = *p_src++ << 8; /* Highbyte */ | ||
1903 | marker_size |= *p_src++; /* Lowbyte */ | ||
1904 | n = *p_src++; /* sample precision (= 8 or 12) */ | ||
1905 | if (n != 8) | ||
1906 | { | ||
1907 | return(-1); /* Unsupported sample precision */ | ||
1908 | } | ||
1909 | p_jpeg->y_size = *p_src++ << 8; /* Highbyte */ | ||
1910 | p_jpeg->y_size |= *p_src++; /* Lowbyte */ | ||
1911 | p_jpeg->x_size = *p_src++ << 8; /* Highbyte */ | ||
1912 | p_jpeg->x_size |= *p_src++; /* Lowbyte */ | ||
1913 | |||
1914 | n = (marker_size-2-6)/3; | ||
1915 | if (*p_src++ != n || (n != 1 && n != 3)) | ||
1916 | { | ||
1917 | return(-2); /* Unsupported SOF0 component specification */ | ||
1918 | } | ||
1919 | for (i=0; i<n; i++) | ||
1920 | { | ||
1921 | p_jpeg->frameheader[i].ID = *p_src++; /* Component info */ | ||
1922 | p_jpeg->frameheader[i].horizontal_sampling = *p_src >> 4; | ||
1923 | p_jpeg->frameheader[i].vertical_sampling = *p_src++ & 0x0F; | ||
1924 | p_jpeg->frameheader[i].quanttable_select = *p_src++; | ||
1925 | } | ||
1926 | |||
1927 | /* assignments for the decoding of blocks */ | ||
1928 | if (p_jpeg->frameheader[0].horizontal_sampling == 2 | ||
1929 | && p_jpeg->frameheader[0].vertical_sampling == 1) | ||
1930 | { /* 4:2:2 */ | ||
1931 | p_jpeg->blocks = 4; | ||
1932 | p_jpeg->x_mbl = (p_jpeg->x_size+15) / 16; | ||
1933 | p_jpeg->x_phys = p_jpeg->x_mbl * 16; | ||
1934 | p_jpeg->y_mbl = (p_jpeg->y_size+7) / 8; | ||
1935 | p_jpeg->y_phys = p_jpeg->y_mbl * 8; | ||
1936 | p_jpeg->mcu_membership[0] = 0; /* Y1=Y2=0, U=2, V=3 */ | ||
1937 | p_jpeg->mcu_membership[1] = 0; | ||
1938 | p_jpeg->mcu_membership[2] = 2; | ||
1939 | p_jpeg->mcu_membership[3] = 3; | ||
1940 | p_jpeg->tab_membership[0] = 0; /* DC, DC, AC, AC */ | ||
1941 | p_jpeg->tab_membership[1] = 0; | ||
1942 | p_jpeg->tab_membership[2] = 1; | ||
1943 | p_jpeg->tab_membership[3] = 1; | ||
1944 | } | ||
1945 | else if (p_jpeg->frameheader[0].horizontal_sampling == 2 | ||
1946 | && p_jpeg->frameheader[0].vertical_sampling == 2) | ||
1947 | { /* 4:2:0 */ | ||
1948 | p_jpeg->blocks = 6; | ||
1949 | p_jpeg->x_mbl = (p_jpeg->x_size+15) / 16; | ||
1950 | p_jpeg->x_phys = p_jpeg->x_mbl * 16; | ||
1951 | p_jpeg->y_mbl = (p_jpeg->y_size+15) / 16; | ||
1952 | p_jpeg->y_phys = p_jpeg->y_mbl * 16; | ||
1953 | p_jpeg->mcu_membership[0] = 0; | ||
1954 | p_jpeg->mcu_membership[1] = 0; | ||
1955 | p_jpeg->mcu_membership[2] = 0; | ||
1956 | p_jpeg->mcu_membership[3] = 0; | ||
1957 | p_jpeg->mcu_membership[4] = 2; | ||
1958 | p_jpeg->mcu_membership[5] = 3; | ||
1959 | p_jpeg->tab_membership[0] = 0; | ||
1960 | p_jpeg->tab_membership[1] = 0; | ||
1961 | p_jpeg->tab_membership[2] = 0; | ||
1962 | p_jpeg->tab_membership[3] = 0; | ||
1963 | p_jpeg->tab_membership[4] = 1; | ||
1964 | p_jpeg->tab_membership[5] = 1; | ||
1965 | } | ||
1966 | else if (p_jpeg->frameheader[0].horizontal_sampling == 1 | ||
1967 | && p_jpeg->frameheader[0].vertical_sampling == 1) | ||
1968 | { /* 4:4:4 */ | ||
1969 | p_jpeg->blocks = n; | ||
1970 | p_jpeg->x_mbl = (p_jpeg->x_size+7) / 8; | ||
1971 | p_jpeg->x_phys = p_jpeg->x_mbl * 8; | ||
1972 | p_jpeg->y_mbl = (p_jpeg->y_size+7) / 8; | ||
1973 | p_jpeg->y_phys = p_jpeg->y_mbl * 8; | ||
1974 | p_jpeg->mcu_membership[0] = 0; | ||
1975 | p_jpeg->mcu_membership[1] = 2; | ||
1976 | p_jpeg->mcu_membership[2] = 3; | ||
1977 | p_jpeg->tab_membership[0] = 0; | ||
1978 | p_jpeg->tab_membership[1] = 1; | ||
1979 | p_jpeg->tab_membership[2] = 1; | ||
1980 | } | ||
1981 | else | ||
1982 | { | ||
1983 | return(-3); /* Unsupported SOF0 subsampling */ | ||
1984 | } | ||
1985 | |||
1986 | } | ||
1987 | break; | ||
1988 | |||
1989 | case 0xC1: /* SOF Huff - Extended sequential DCT*/ | ||
1990 | case 0xC2: /* SOF Huff - Progressive DCT*/ | ||
1991 | case 0xC3: /* SOF Huff - Spatial (sequential) lossless*/ | ||
1992 | case 0xC5: /* SOF Huff - Differential sequential DCT*/ | ||
1993 | case 0xC6: /* SOF Huff - Differential progressive DCT*/ | ||
1994 | case 0xC7: /* SOF Huff - Differential spatial*/ | ||
1995 | case 0xC8: /* SOF Arith - Reserved for JPEG extensions*/ | ||
1996 | case 0xC9: /* SOF Arith - Extended sequential DCT*/ | ||
1997 | case 0xCA: /* SOF Arith - Progressive DCT*/ | ||
1998 | case 0xCB: /* SOF Arith - Spatial (sequential) lossless*/ | ||
1999 | case 0xCD: /* SOF Arith - Differential sequential DCT*/ | ||
2000 | case 0xCE: /* SOF Arith - Differential progressive DCT*/ | ||
2001 | case 0xCF: /* SOF Arith - Differential spatial*/ | ||
2002 | { | ||
2003 | return (-4); /* other DCT model than baseline not implemented */ | ||
2004 | } | ||
2005 | |||
2006 | case 0xC4: /* Define Huffman Table(s) */ | ||
2007 | { | ||
2008 | ret |= DHT; | ||
2009 | marker_size = *p_src++ << 8; /* Highbyte */ | ||
2010 | marker_size |= *p_src++; /* Lowbyte */ | ||
2011 | |||
2012 | p_temp = p_src; | ||
2013 | while (p_src < p_temp+marker_size-2) /* another table */ | ||
2014 | { | ||
2015 | i = *p_src & 0x0F; /* table index */ | ||
2016 | if (i > 1) | ||
2017 | { | ||
2018 | return (-5); /* Huffman table index out of range */ | ||
2019 | } | ||
2020 | if (*p_src++ & 0xF0) /* AC table */ | ||
2021 | { | ||
2022 | for (j=0; j<AC_LEN; j++) | ||
2023 | p_jpeg->hufftable[i].huffmancodes_ac[j] = *p_src++; | ||
2024 | } | ||
2025 | else /* DC table */ | ||
2026 | { | ||
2027 | for (j=0; j<DC_LEN; j++) | ||
2028 | p_jpeg->hufftable[i].huffmancodes_dc[j] = *p_src++; | ||
2029 | } | ||
2030 | } /* while */ | ||
2031 | } | ||
2032 | break; | ||
2033 | |||
2034 | case 0xCC: /* Define Arithmetic coding conditioning(s) */ | ||
2035 | return(-6); /* Arithmetic coding not supported */ | ||
2036 | |||
2037 | case 0xD0: /* Restart with modulo 8 count 0 */ | ||
2038 | case 0xD1: /* Restart with modulo 8 count 1 */ | ||
2039 | case 0xD2: /* Restart with modulo 8 count 2 */ | ||
2040 | case 0xD3: /* Restart with modulo 8 count 3 */ | ||
2041 | case 0xD4: /* Restart with modulo 8 count 4 */ | ||
2042 | case 0xD5: /* Restart with modulo 8 count 5 */ | ||
2043 | case 0xD6: /* Restart with modulo 8 count 6 */ | ||
2044 | case 0xD7: /* Restart with modulo 8 count 7 */ | ||
2045 | case 0xD8: /* Start of Image */ | ||
2046 | case 0xD9: /* End of Image */ | ||
2047 | case 0x01: /* for temp private use arith code */ | ||
2048 | break; /* skip parameterless marker */ | ||
2049 | |||
2050 | |||
2051 | case 0xDA: /* Start of Scan */ | ||
2052 | { | ||
2053 | ret |= SOS; | ||
2054 | marker_size = *p_src++ << 8; /* Highbyte */ | ||
2055 | marker_size |= *p_src++; /* Lowbyte */ | ||
2056 | |||
2057 | n = (marker_size-2-1-3)/2; | ||
2058 | if (*p_src++ != n || (n != 1 && n != 3)) | ||
2059 | { | ||
2060 | return (-7); /* Unsupported SOS component specification */ | ||
2061 | } | ||
2062 | for (i=0; i<n; i++) | ||
2063 | { | ||
2064 | p_jpeg->scanheader[i].ID = *p_src++; | ||
2065 | p_jpeg->scanheader[i].DC_select = *p_src >> 4; | ||
2066 | p_jpeg->scanheader[i].AC_select = *p_src++ & 0x0F; | ||
2067 | } | ||
2068 | p_src += 3; /* skip spectral information */ | ||
2069 | } | ||
2070 | break; | ||
2071 | |||
2072 | case 0xDB: /* Define quantization Table(s) */ | ||
2073 | { | ||
2074 | ret |= DQT; | ||
2075 | marker_size = *p_src++ << 8; /* Highbyte */ | ||
2076 | marker_size |= *p_src++; /* Lowbyte */ | ||
2077 | n = (marker_size-2)/(QUANT_TABLE_LENGTH+1); /* # of tables */ | ||
2078 | for (i=0; i<n; i++) | ||
2079 | { | ||
2080 | int id = *p_src++; /* ID */ | ||
2081 | if (id >= 4) | ||
2082 | { | ||
2083 | return (-8); /* Unsupported quantization table */ | ||
2084 | } | ||
2085 | /* Read Quantisation table: */ | ||
2086 | for (j=0; j<QUANT_TABLE_LENGTH; j++) | ||
2087 | p_jpeg->quanttable[id][j] = *p_src++; | ||
2088 | } | ||
2089 | } | ||
2090 | break; | ||
2091 | |||
2092 | case 0xDC: /* Define Number of Lines */ | ||
2093 | case 0xDD: /* Define Restart Interval */ | ||
2094 | case 0xDE: /* Define Hierarchical progression */ | ||
2095 | case 0xDF: /* Expand Reference Component(s) */ | ||
2096 | case 0xE0: /* Application Field 0*/ | ||
2097 | case 0xE1: /* Application Field 1*/ | ||
2098 | case 0xE2: /* Application Field 2*/ | ||
2099 | case 0xE3: /* Application Field 3*/ | ||
2100 | case 0xE4: /* Application Field 4*/ | ||
2101 | case 0xE5: /* Application Field 5*/ | ||
2102 | case 0xE6: /* Application Field 6*/ | ||
2103 | case 0xE7: /* Application Field 7*/ | ||
2104 | case 0xFE: /* Comment */ | ||
2105 | { | ||
2106 | marker_size = *p_src++ << 8; /* Highbyte */ | ||
2107 | marker_size |= *p_src++; /* Lowbyte */ | ||
2108 | p_src += marker_size-2; /* skip segment */ | ||
2109 | } | ||
2110 | break; | ||
2111 | |||
2112 | case 0xF0: /* Reserved for JPEG extensions */ | ||
2113 | case 0xF1: /* Reserved for JPEG extensions */ | ||
2114 | case 0xF2: /* Reserved for JPEG extensions */ | ||
2115 | case 0xF3: /* Reserved for JPEG extensions */ | ||
2116 | case 0xF4: /* Reserved for JPEG extensions */ | ||
2117 | case 0xF5: /* Reserved for JPEG extensions */ | ||
2118 | case 0xF6: /* Reserved for JPEG extensions */ | ||
2119 | case 0xF7: /* Reserved for JPEG extensions */ | ||
2120 | case 0xF8: /* Reserved for JPEG extensions */ | ||
2121 | case 0xF9: /* Reserved for JPEG extensions */ | ||
2122 | case 0xFA: /* Reserved for JPEG extensions */ | ||
2123 | case 0xFB: /* Reserved for JPEG extensions */ | ||
2124 | case 0xFC: /* Reserved for JPEG extensions */ | ||
2125 | case 0xFD: /* Reserved for JPEG extensions */ | ||
2126 | case 0x02: /* Reserved */ | ||
2127 | default: | ||
2128 | return (-9); /* Unknown marker */ | ||
2129 | } /* switch */ | ||
2130 | } /* while */ | ||
2131 | |||
2132 | /* undo byte stuffing, endian conversion */ | ||
2133 | /* ToDo: remove restart markers, if present */ | ||
2134 | while (p_src < p_bytes + size) | ||
2135 | { | ||
2136 | highbyte = *p_src++; | ||
2137 | if (highbyte==0xFF && *p_src++) break; /* end on marker */ | ||
2138 | lowbyte = *p_src++; | ||
2139 | if (lowbyte==0xFF && *p_src++) | ||
2140 | { | ||
2141 | *p_dest++ = highbyte<<8; /* write remaining */ | ||
2142 | break; /* end on marker */ | ||
2143 | } | ||
2144 | *p_dest++ = highbyte<<8 | lowbyte; | ||
2145 | } | ||
2146 | MEMSET(p_dest, 0, size-((unsigned char*)p_dest-p_bytes)); /* fill tail with zeros */ | ||
2147 | p_jpeg->words_in_buffer = p_dest-(unsigned short*)p_bytes; | ||
2148 | return (ret); /* return flags with seen markers */ | ||
2149 | } | ||
2150 | |||
2151 | |||
2152 | void default_huff_tbl(struct jpeg* p_jpeg) | ||
2153 | { | ||
2154 | static const struct huffman_table luma_table = | ||
2155 | { | ||
2156 | { | ||
2157 | 0x00,0x01,0x05,0x01,0x01,0x01,0x01,0x01,0x01,0x00,0x00,0x00,0x00,0x00, | ||
2158 | 0x00,0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B | ||
2159 | }, | ||
2160 | { | ||
2161 | 0x00,0x02,0x01,0x03,0x03,0x02,0x04,0x03,0x05,0x05,0x04,0x04,0x00,0x00,0x01,0x7D, | ||
2162 | 0x01,0x02,0x03,0x00,0x04,0x11,0x05,0x12,0x21,0x31,0x41,0x06,0x13,0x51,0x61,0x07, | ||
2163 | 0x22,0x71,0x14,0x32,0x81,0x91,0xA1,0x08,0x23,0x42,0xB1,0xC1,0x15,0x52,0xD1,0xF0, | ||
2164 | 0x24,0x33,0x62,0x72,0x82,0x09,0x0A,0x16,0x17,0x18,0x19,0x1A,0x25,0x26,0x27,0x28, | ||
2165 | 0x29,0x2A,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x43,0x44,0x45,0x46,0x47,0x48,0x49, | ||
2166 | 0x4A,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0x63,0x64,0x65,0x66,0x67,0x68,0x69, | ||
2167 | 0x6A,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0x83,0x84,0x85,0x86,0x87,0x88,0x89, | ||
2168 | 0x8A,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7, | ||
2169 | 0xA8,0xA9,0xAA,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xC2,0xC3,0xC4,0xC5, | ||
2170 | 0xC6,0xC7,0xC8,0xC9,0xCA,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xE1,0xE2, | ||
2171 | 0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8, | ||
2172 | 0xF9,0xFA | ||
2173 | } | ||
2174 | }; | ||
2175 | |||
2176 | static const struct huffman_table chroma_table = | ||
2177 | { | ||
2178 | { | ||
2179 | 0x00,0x03,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x00,0x00,0x00, | ||
2180 | 0x00,0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B | ||
2181 | }, | ||
2182 | { | ||
2183 | 0x00,0x02,0x01,0x02,0x04,0x04,0x03,0x04,0x07,0x05,0x04,0x04,0x00,0x01,0x02,0x77, | ||
2184 | 0x00,0x01,0x02,0x03,0x11,0x04,0x05,0x21,0x31,0x06,0x12,0x41,0x51,0x07,0x61,0x71, | ||
2185 | 0x13,0x22,0x32,0x81,0x08,0x14,0x42,0x91,0xA1,0xB1,0xC1,0x09,0x23,0x33,0x52,0xF0, | ||
2186 | 0x15,0x62,0x72,0xD1,0x0A,0x16,0x24,0x34,0xE1,0x25,0xF1,0x17,0x18,0x19,0x1A,0x26, | ||
2187 | 0x27,0x28,0x29,0x2A,0x35,0x36,0x37,0x38,0x39,0x3A,0x43,0x44,0x45,0x46,0x47,0x48, | ||
2188 | 0x49,0x4A,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0x63,0x64,0x65,0x66,0x67,0x68, | ||
2189 | 0x69,0x6A,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0x82,0x83,0x84,0x85,0x86,0x87, | ||
2190 | 0x88,0x89,0x8A,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0xA2,0xA3,0xA4,0xA5, | ||
2191 | 0xA6,0xA7,0xA8,0xA9,0xAA,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xC2,0xC3, | ||
2192 | 0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA, | ||
2193 | 0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8, | ||
2194 | 0xF9,0xFA | ||
2195 | } | ||
2196 | }; | ||
2197 | |||
2198 | p_jpeg->hufftable[0] = luma_table; | ||
2199 | p_jpeg->hufftable[1] = chroma_table; | ||
2200 | |||
2201 | return; | ||
2202 | } | ||
2203 | |||
2204 | /* Compute the derived values for a Huffman table */ | ||
2205 | void fix_huff_tbl(int* htbl, struct derived_tbl* dtbl) | ||
2206 | { | ||
2207 | int p, i, l, si; | ||
2208 | int lookbits, ctr; | ||
2209 | char huffsize[257]; | ||
2210 | unsigned int huffcode[257]; | ||
2211 | unsigned int code; | ||
2212 | |||
2213 | dtbl->pub = htbl; /* fill in back link */ | ||
2214 | |||
2215 | /* Figure C.1: make table of Huffman code length for each symbol */ | ||
2216 | /* Note that this is in code-length order. */ | ||
2217 | |||
2218 | p = 0; | ||
2219 | for (l = 1; l <= 16; l++) | ||
2220 | { /* all possible code length */ | ||
2221 | for (i = 1; i <= (int) htbl[l-1]; i++) /* all codes per length */ | ||
2222 | huffsize[p++] = (char) l; | ||
2223 | } | ||
2224 | huffsize[p] = 0; | ||
2225 | |||
2226 | /* Figure C.2: generate the codes themselves */ | ||
2227 | /* Note that this is in code-length order. */ | ||
2228 | |||
2229 | code = 0; | ||
2230 | si = huffsize[0]; | ||
2231 | p = 0; | ||
2232 | while (huffsize[p]) | ||
2233 | { | ||
2234 | while (((int) huffsize[p]) == si) | ||
2235 | { | ||
2236 | huffcode[p++] = code; | ||
2237 | code++; | ||
2238 | } | ||
2239 | code <<= 1; | ||
2240 | si++; | ||
2241 | } | ||
2242 | |||
2243 | /* Figure F.15: generate decoding tables for bit-sequential decoding */ | ||
2244 | |||
2245 | p = 0; | ||
2246 | for (l = 1; l <= 16; l++) | ||
2247 | { | ||
2248 | if (htbl[l-1]) | ||
2249 | { | ||
2250 | dtbl->valptr[l] = p; /* huffval[] index of 1st symbol of code length l */ | ||
2251 | dtbl->mincode[l] = huffcode[p]; /* minimum code of length l */ | ||
2252 | p += htbl[l-1]; | ||
2253 | dtbl->maxcode[l] = huffcode[p-1]; /* maximum code of length l */ | ||
2254 | } | ||
2255 | else | ||
2256 | { | ||
2257 | dtbl->maxcode[l] = -1; /* -1 if no codes of this length */ | ||
2258 | } | ||
2259 | } | ||
2260 | dtbl->maxcode[17] = 0xFFFFFL; /* ensures huff_DECODE terminates */ | ||
2261 | |||
2262 | /* Compute lookahead tables to speed up decoding. | ||
2263 | * First we set all the table entries to 0, indicating "too long"; | ||
2264 | * then we iterate through the Huffman codes that are short enough and | ||
2265 | * fill in all the entries that correspond to bit sequences starting | ||
2266 | * with that code. | ||
2267 | */ | ||
2268 | |||
2269 | MEMSET(dtbl->look_nbits, 0, sizeof(dtbl->look_nbits)); | ||
2270 | |||
2271 | p = 0; | ||
2272 | for (l = 1; l <= HUFF_LOOKAHEAD; l++) | ||
2273 | { | ||
2274 | for (i = 1; i <= (int) htbl[l-1]; i++, p++) | ||
2275 | { | ||
2276 | /* l = current code's length, p = its index in huffcode[] & huffval[]. */ | ||
2277 | /* Generate left-justified code followed by all possible bit sequences */ | ||
2278 | lookbits = huffcode[p] << (HUFF_LOOKAHEAD-l); | ||
2279 | for (ctr = 1 << (HUFF_LOOKAHEAD-l); ctr > 0; ctr--) | ||
2280 | { | ||
2281 | dtbl->look_nbits[lookbits] = l; | ||
2282 | dtbl->look_sym[lookbits] = htbl[16+p]; | ||
2283 | lookbits++; | ||
2284 | } | ||
2285 | } | ||
2286 | } | ||
2287 | } | ||
2288 | |||
2289 | |||
2290 | /* zag[i] is the natural-order position of the i'th element of zigzag order. | ||
2291 | * If the incoming data is corrupted, decode_mcu could attempt to | ||
2292 | * reference values beyond the end of the array. To avoid a wild store, | ||
2293 | * we put some extra zeroes after the real entries. | ||
2294 | */ | ||
2295 | static const int zag[] = { | ||
2296 | 0, 1, 8, 16, 9, 2, 3, 10, | ||
2297 | 17, 24, 32, 25, 18, 11, 4, 5, | ||
2298 | 12, 19, 26, 33, 40, 48, 41, 34, | ||
2299 | 27, 20, 13, 6, 7, 14, 21, 28, | ||
2300 | 35, 42, 49, 56, 57, 50, 43, 36, | ||
2301 | 29, 22, 15, 23, 30, 37, 44, 51, | ||
2302 | 58, 59, 52, 45, 38, 31, 39, 46, | ||
2303 | 53, 60, 61, 54, 47, 55, 62, 63, | ||
2304 | 0, 0, 0, 0, 0, 0, 0, 0, /* extra entries in case k>63 below */ | ||
2305 | 0, 0, 0, 0, 0, 0, 0, 0 | ||
2306 | }; | ||
2307 | |||
2308 | void build_lut(struct jpeg* p_jpeg) | ||
2309 | { | ||
2310 | int i; | ||
2311 | fix_huff_tbl(p_jpeg->hufftable[0].huffmancodes_dc, | ||
2312 | &p_jpeg->dc_derived_tbls[0]); | ||
2313 | fix_huff_tbl(p_jpeg->hufftable[0].huffmancodes_ac, | ||
2314 | &p_jpeg->ac_derived_tbls[0]); | ||
2315 | fix_huff_tbl(p_jpeg->hufftable[1].huffmancodes_dc, | ||
2316 | &p_jpeg->dc_derived_tbls[1]); | ||
2317 | fix_huff_tbl(p_jpeg->hufftable[1].huffmancodes_ac, | ||
2318 | &p_jpeg->ac_derived_tbls[1]); | ||
2319 | |||
2320 | /* build the dequantization tables for the IDCT (De-ZiZagged) */ | ||
2321 | for (i=0; i<64; i++) | ||
2322 | { | ||
2323 | p_jpeg->qt_idct[0][zag[i]] = p_jpeg->quanttable[0][i]; | ||
2324 | p_jpeg->qt_idct[1][zag[i]] = p_jpeg->quanttable[1][i]; | ||
2325 | } | ||
2326 | } | ||
2327 | |||
2328 | |||
2329 | /* | ||
2330 | * These functions/macros provide the in-line portion of bit fetching. | ||
2331 | * Use check_bit_buffer to ensure there are N bits in get_buffer | ||
2332 | * before using get_bits, peek_bits, or drop_bits. | ||
2333 | * check_bit_buffer(state,n,action); | ||
2334 | * Ensure there are N bits in get_buffer; if suspend, take action. | ||
2335 | * val = get_bits(n); | ||
2336 | * Fetch next N bits. | ||
2337 | * val = peek_bits(n); | ||
2338 | * Fetch next N bits without removing them from the buffer. | ||
2339 | * drop_bits(n); | ||
2340 | * Discard next N bits. | ||
2341 | * The value N should be a simple variable, not an expression, because it | ||
2342 | * is evaluated multiple times. | ||
2343 | */ | ||
2344 | |||
2345 | INLINE void check_bit_buffer(struct bitstream* pb, int nbits) | ||
2346 | { | ||
2347 | if (pb->bits_left < nbits) | ||
2348 | { | ||
2349 | pb->words_left--; | ||
2350 | pb->get_buffer = (pb->get_buffer << 16) | *pb->next_input_word++; | ||
2351 | pb->bits_left += 16; | ||
2352 | } | ||
2353 | } | ||
2354 | |||
2355 | INLINE int get_bits(struct bitstream* pb, int nbits) | ||
2356 | { | ||
2357 | return ((int) (pb->get_buffer >> (pb->bits_left -= nbits))) & ((1<<nbits)-1); | ||
2358 | } | ||
2359 | |||
2360 | INLINE int peek_bits(struct bitstream* pb, int nbits) | ||
2361 | { | ||
2362 | return ((int) (pb->get_buffer >> (pb->bits_left - nbits))) & ((1<<nbits)-1); | ||
2363 | } | ||
2364 | |||
2365 | INLINE void drop_bits(struct bitstream* pb, int nbits) | ||
2366 | { | ||
2367 | pb->bits_left -= nbits; | ||
2368 | } | ||
2369 | |||
2370 | /* Figure F.12: extend sign bit. */ | ||
2371 | #define HUFF_EXTEND(x,s) ((x) < extend_test[s] ? (x) + extend_offset[s] : (x)) | ||
2372 | |||
2373 | static const int extend_test[16] = /* entry n is 2**(n-1) */ | ||
2374 | { | ||
2375 | 0, 0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080, | ||
2376 | 0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000 | ||
2377 | }; | ||
2378 | |||
2379 | static const int extend_offset[16] = /* entry n is (-1 << n) + 1 */ | ||
2380 | { | ||
2381 | 0, ((-1)<<1) + 1, ((-1)<<2) + 1, ((-1)<<3) + 1, ((-1)<<4) + 1, | ||
2382 | ((-1)<<5) + 1, ((-1)<<6) + 1, ((-1)<<7) + 1, ((-1)<<8) + 1, | ||
2383 | ((-1)<<9) + 1, ((-1)<<10) + 1, ((-1)<<11) + 1, ((-1)<<12) + 1, | ||
2384 | ((-1)<<13) + 1, ((-1)<<14) + 1, ((-1)<<15) + 1 | ||
2385 | }; | ||
2386 | |||
2387 | /* Decode a single value */ | ||
2388 | INLINE int huff_decode_dc(struct bitstream* bs, struct derived_tbl* tbl) | ||
2389 | { | ||
2390 | int nb, look, s, r; | ||
2391 | |||
2392 | check_bit_buffer(bs, HUFF_LOOKAHEAD); | ||
2393 | look = peek_bits(bs, HUFF_LOOKAHEAD); | ||
2394 | if ((nb = tbl->look_nbits[look]) != 0) | ||
2395 | { | ||
2396 | drop_bits(bs, nb); | ||
2397 | s = tbl->look_sym[look]; | ||
2398 | check_bit_buffer(bs, s); | ||
2399 | r = get_bits(bs, s); | ||
2400 | s = HUFF_EXTEND(r, s); | ||
2401 | } | ||
2402 | else | ||
2403 | { /* slow_DECODE(s, HUFF_LOOKAHEAD+1)) < 0); */ | ||
2404 | long code; | ||
2405 | nb=HUFF_LOOKAHEAD+1; | ||
2406 | check_bit_buffer(bs, nb); | ||
2407 | code = get_bits(bs, nb); | ||
2408 | while (code > tbl->maxcode[nb]) | ||
2409 | { | ||
2410 | code <<= 1; | ||
2411 | check_bit_buffer(bs, 1); | ||
2412 | code |= get_bits(bs, 1); | ||
2413 | nb++; | ||
2414 | } | ||
2415 | if (nb > 16) /* error in Huffman */ | ||
2416 | { | ||
2417 | s=0; /* fake a zero, this is most safe */ | ||
2418 | } | ||
2419 | else | ||
2420 | { | ||
2421 | s = tbl->pub[16 + tbl->valptr[nb] + ((int) (code - tbl->mincode[nb])) ]; | ||
2422 | check_bit_buffer(bs, s); | ||
2423 | r = get_bits(bs, s); | ||
2424 | s = HUFF_EXTEND(r, s); | ||
2425 | } | ||
2426 | } /* end slow decode */ | ||
2427 | return s; | ||
2428 | } | ||
2429 | |||
2430 | INLINE int huff_decode_ac(struct bitstream* bs, struct derived_tbl* tbl) | ||
2431 | { | ||
2432 | int nb, look, s; | ||
2433 | |||
2434 | check_bit_buffer(bs, HUFF_LOOKAHEAD); | ||
2435 | look = peek_bits(bs, HUFF_LOOKAHEAD); | ||
2436 | if ((nb = tbl->look_nbits[look]) != 0) | ||
2437 | { | ||
2438 | drop_bits(bs, nb); | ||
2439 | s = tbl->look_sym[look]; | ||
2440 | } | ||
2441 | else | ||
2442 | { /* slow_DECODE(s, HUFF_LOOKAHEAD+1)) < 0); */ | ||
2443 | long code; | ||
2444 | nb=HUFF_LOOKAHEAD+1; | ||
2445 | check_bit_buffer(bs, nb); | ||
2446 | code = get_bits(bs, nb); | ||
2447 | while (code > tbl->maxcode[nb]) | ||
2448 | { | ||
2449 | code <<= 1; | ||
2450 | check_bit_buffer(bs, 1); | ||
2451 | code |= get_bits(bs, 1); | ||
2452 | nb++; | ||
2453 | } | ||
2454 | if (nb > 16) /* error in Huffman */ | ||
2455 | { | ||
2456 | s=0; /* fake a zero, this is most safe */ | ||
2457 | } | ||
2458 | else | ||
2459 | { | ||
2460 | s = tbl->pub[16 + tbl->valptr[nb] + ((int) (code - tbl->mincode[nb])) ]; | ||
2461 | } | ||
2462 | } /* end slow decode */ | ||
2463 | return s; | ||
2464 | } | ||
2465 | |||
2466 | |||
2467 | /* a JPEG decoder specialized in decoding only the luminance (b&w) */ | ||
2468 | int jpeg_decode(struct jpeg* p_jpeg, unsigned char* p_pixel, int downscale, | ||
2469 | void (*pf_progress)(int current, int total)) | ||
2470 | { | ||
2471 | struct bitstream bs; /* bitstream "object" */ | ||
2472 | static int block[64]; /* decoded DCT coefficients */ | ||
2473 | |||
2474 | int width, height; | ||
2475 | int skip_line; /* bytes from one line to the next (skip_line) */ | ||
2476 | int skip_strip, skip_mcu; /* bytes to next DCT row / column */ | ||
2477 | |||
2478 | int x, y; /* loop counter */ | ||
2479 | |||
2480 | unsigned char* p_byte; /* bitmap pointer */ | ||
2481 | |||
2482 | void (*pf_idct)(unsigned char*, int*, int*, int); /* selected IDCT */ | ||
2483 | int k_need; /* AC coefficients needed up to here */ | ||
2484 | int zero_need; /* init the block with this many zeros */ | ||
2485 | |||
2486 | int last_dc_val[4]; | ||
2487 | int store_offs[4]; /* memory offsets: order of Y11 Y12 Y21 Y22 U V */ | ||
2488 | MEMSET(&last_dc_val, 0, sizeof(last_dc_val)); | ||
2489 | |||
2490 | /* pick the IDCT we want, determine how to work with coefs */ | ||
2491 | if (downscale == 1) | ||
2492 | { | ||
2493 | pf_idct = idct8x8; | ||
2494 | k_need = 63; /* all */ | ||
2495 | zero_need = 63; /* all */ | ||
2496 | } | ||
2497 | else if (downscale == 2) | ||
2498 | { | ||
2499 | pf_idct = idct4x4; | ||
2500 | k_need = 25; /* this far in zig-zag to cover 4*4 */ | ||
2501 | zero_need = 27; /* clear this far in linear order */ | ||
2502 | } | ||
2503 | else if (downscale == 4) | ||
2504 | { | ||
2505 | pf_idct = idct2x2; | ||
2506 | k_need = 5; /* this far in zig-zag to cover 2*2 */ | ||
2507 | zero_need = 9; /* clear this far in linear order */ | ||
2508 | } | ||
2509 | else if (downscale == 8) | ||
2510 | { | ||
2511 | pf_idct = idct1x1; | ||
2512 | k_need = 0; /* no AC, not needed */ | ||
2513 | zero_need = 0; /* no AC, not needed */ | ||
2514 | } | ||
2515 | else return -1; /* not supported */ | ||
2516 | |||
2517 | /* init bitstream */ | ||
2518 | bs.bits_left = 0; | ||
2519 | bs.next_input_word = p_jpeg->p_entropy_data; | ||
2520 | bs.words_left = p_jpeg->words_in_buffer; | ||
2521 | |||
2522 | width = p_jpeg->x_phys / downscale; | ||
2523 | height = p_jpeg->y_phys / downscale; | ||
2524 | skip_line = width; | ||
2525 | skip_strip = skip_line * (height / p_jpeg->y_mbl); | ||
2526 | skip_mcu = (width/p_jpeg->x_mbl); | ||
2527 | |||
2528 | /* prepare offsets about where to store the different blocks */ | ||
2529 | store_offs[0] = 0; | ||
2530 | store_offs[1] = 8 / downscale; /* to the right */ | ||
2531 | store_offs[2] = width * 8 / downscale; /* below */ | ||
2532 | store_offs[3] = store_offs[1] + store_offs[2]; /* right+below */ | ||
2533 | |||
2534 | for(y=0; y<p_jpeg->y_mbl; y++) | ||
2535 | { | ||
2536 | p_byte = p_pixel; | ||
2537 | p_pixel += skip_strip; | ||
2538 | for (x=0; x<p_jpeg->x_mbl; x++) | ||
2539 | { | ||
2540 | int blkn; | ||
2541 | |||
2542 | /* Outer loop handles each block in the MCU */ | ||
2543 | |||
2544 | for (blkn = 0; blkn < p_jpeg->blocks && bs.words_left>=0; blkn++) | ||
2545 | { /* Decode a single block's worth of coefficients */ | ||
2546 | int k = 1; /* coefficient index */ | ||
2547 | int s, r; /* huffman values */ | ||
2548 | int ci = p_jpeg->mcu_membership[blkn]; /* component index */ | ||
2549 | int ti = p_jpeg->tab_membership[blkn]; /* table index */ | ||
2550 | struct derived_tbl* dctbl = &p_jpeg->dc_derived_tbls[ti]; | ||
2551 | struct derived_tbl* actbl = &p_jpeg->ac_derived_tbls[ti]; | ||
2552 | |||
2553 | /* Section F.2.2.1: decode the DC coefficient difference */ | ||
2554 | last_dc_val[ci] += huff_decode_dc(&bs, dctbl); | ||
2555 | block[0] = last_dc_val[ci]; /* output it (assumes zag[0] = 0) */ | ||
2556 | |||
2557 | /* Section F.2.2.2: decode the AC coefficients */ | ||
2558 | if (ci == 0) /* only for Y component */ | ||
2559 | { | ||
2560 | /* coefficient buffer must be cleared */ | ||
2561 | MEMSET(block+1, 0, zero_need*sizeof(int)); | ||
2562 | for (; k < k_need; k++) | ||
2563 | { | ||
2564 | s = huff_decode_ac(&bs, actbl); | ||
2565 | r = s >> 4; | ||
2566 | s &= 15; | ||
2567 | |||
2568 | if (s) | ||
2569 | { | ||
2570 | k += r; | ||
2571 | check_bit_buffer(&bs, s); | ||
2572 | r = get_bits(&bs, s); | ||
2573 | block[zag[k]] = HUFF_EXTEND(r, s); | ||
2574 | } | ||
2575 | else | ||
2576 | { | ||
2577 | if (r != 15) | ||
2578 | { | ||
2579 | k = 64; | ||
2580 | break; | ||
2581 | } | ||
2582 | k += r; | ||
2583 | } | ||
2584 | } /* for k */ | ||
2585 | } | ||
2586 | /* In this path we just discard the values */ | ||
2587 | for (; k < 64; k++) | ||
2588 | { | ||
2589 | s = huff_decode_ac(&bs, actbl); | ||
2590 | r = s >> 4; | ||
2591 | s &= 15; | ||
2592 | |||
2593 | if (s) | ||
2594 | { | ||
2595 | k += r; | ||
2596 | check_bit_buffer(&bs, s); | ||
2597 | drop_bits(&bs, s); | ||
2598 | } | ||
2599 | else | ||
2600 | { | ||
2601 | if (r != 15) | ||
2602 | break; | ||
2603 | k += r; | ||
2604 | } | ||
2605 | } /* for k */ | ||
2606 | |||
2607 | if (ci == 0) | ||
2608 | { /* only for Y component */ | ||
2609 | pf_idct(p_byte+store_offs[blkn], block, p_jpeg->qt_idct[ti], | ||
2610 | skip_line); | ||
2611 | } | ||
2612 | } /* for blkn */ | ||
2613 | p_byte += skip_mcu; | ||
2614 | } /* for x */ | ||
2615 | if (pf_progress != NULL) | ||
2616 | pf_progress(y, p_jpeg->y_mbl-1); /* notify about decoding progress */ | ||
2617 | } /* for y */ | ||
2618 | |||
2619 | return 0; /* success */ | ||
2620 | } | ||
2621 | |||
2622 | |||
2623 | /**************** end JPEG code ********************/ | ||
2624 | |||
2625 | |||
2626 | /**************** begin Application ********************/ | ||
2627 | |||
2628 | |||
2629 | /************************* Types ***************************/ | ||
2630 | |||
2631 | struct t_disp | ||
2632 | { | ||
2633 | unsigned char* bitmap; | ||
2634 | int width; | ||
2635 | int height; | ||
2636 | int stride; | ||
2637 | int x, y; | ||
2638 | }; | ||
2639 | |||
2640 | |||
2641 | /************************* Implementation ***************************/ | ||
2642 | |||
2643 | #define ZOOM_IN 100 // return codes for below function | ||
2644 | #define ZOOM_OUT 101 | ||
2645 | |||
2646 | /* interactively scroll around the image */ | ||
2647 | int scroll_bmp(struct t_disp* pdisp) | ||
2648 | { | ||
2649 | while (true) | ||
2650 | { | ||
2651 | int button; | ||
2652 | int move; | ||
2653 | int i; | ||
2654 | |||
2655 | /* we're unfortunately slower than key repeat, | ||
2656 | so empty the button queue, to avoid post-scroll */ | ||
2657 | while(rb->button_get(false) != BUTTON_NONE); | ||
2658 | |||
2659 | button = rb->button_get(true); | ||
2660 | |||
2661 | if (button == SYS_USB_CONNECTED) | ||
2662 | { | ||
2663 | gray_release_buffer(); /* switch off overlay and deinitialize */ | ||
2664 | return PLUGIN_USB_CONNECTED; | ||
2665 | } | ||
2666 | |||
2667 | switch(button & ~(BUTTON_REPEAT)) | ||
2668 | { | ||
2669 | case BUTTON_LEFT: | ||
2670 | move = MIN(10, pdisp->x); | ||
2671 | if (move > 0) | ||
2672 | { | ||
2673 | gray_scroll_right(move, false); /* scroll right */ | ||
2674 | pdisp->x -= move; | ||
2675 | gray_drawgraymap( | ||
2676 | pdisp->bitmap + pdisp->y * pdisp->stride + pdisp->x, | ||
2677 | 0, MAX(0, (LCD_HEIGHT-pdisp->height)/2), // x, y | ||
2678 | move, MIN(LCD_HEIGHT, pdisp->height), // w, h | ||
2679 | pdisp->stride); | ||
2680 | } | ||
2681 | break; | ||
2682 | |||
2683 | case BUTTON_RIGHT: | ||
2684 | move = MIN(10, pdisp->width - pdisp->x - LCD_WIDTH); | ||
2685 | if (move > 0) | ||
2686 | { | ||
2687 | gray_scroll_left(move, false); /* scroll left */ | ||
2688 | pdisp->x += move; | ||
2689 | gray_drawgraymap( | ||
2690 | pdisp->bitmap + pdisp->y * pdisp->stride + pdisp->x + LCD_WIDTH - move, | ||
2691 | LCD_WIDTH - move, MAX(0, (LCD_HEIGHT-pdisp->height)/2), /* x, y */ | ||
2692 | move, MIN(LCD_HEIGHT, pdisp->height), /* w, h */ | ||
2693 | pdisp->stride); | ||
2694 | } | ||
2695 | break; | ||
2696 | |||
2697 | case BUTTON_UP: | ||
2698 | move = MIN(8, pdisp->y); | ||
2699 | if (move > 0) | ||
2700 | { | ||
2701 | if (move == 8) | ||
2702 | gray_scroll_down8(false); /* scroll down by 8 pixel */ | ||
2703 | else | ||
2704 | for (i=0; i<move; i++) | ||
2705 | gray_scroll_down1(false); /* n times one pixel */ | ||
2706 | pdisp->y -= move; | ||
2707 | gray_drawgraymap( | ||
2708 | pdisp->bitmap + pdisp->y * pdisp->stride + pdisp->x, | ||
2709 | MAX(0, (LCD_WIDTH-pdisp->width)/2), 0, /* x, y */ | ||
2710 | MIN(LCD_WIDTH, pdisp->width), move, /* w, h */ | ||
2711 | pdisp->stride); | ||
2712 | } | ||
2713 | break; | ||
2714 | |||
2715 | case BUTTON_DOWN: | ||
2716 | move = MIN(8, pdisp->height - pdisp->y - LCD_HEIGHT); | ||
2717 | if (move > 0) | ||
2718 | { | ||
2719 | if (move == 8) | ||
2720 | gray_scroll_up8(false); /* scroll up by 8 pixel */ | ||
2721 | else | ||
2722 | for (i=0; i<move; i++) | ||
2723 | gray_scroll_up1(false); /* n times one pixel */ | ||
2724 | pdisp->y += move; | ||
2725 | gray_drawgraymap( | ||
2726 | pdisp->bitmap + (pdisp->y + LCD_HEIGHT - move) * pdisp->stride + pdisp->x, | ||
2727 | MAX(0, (LCD_WIDTH-pdisp->width)/2), LCD_HEIGHT - move, /* x, y */ | ||
2728 | MIN(LCD_WIDTH, pdisp->width), move, /* w, h */ | ||
2729 | pdisp->stride); | ||
2730 | } | ||
2731 | break; | ||
2732 | |||
2733 | case BUTTON_PLAY: | ||
2734 | return ZOOM_IN; | ||
2735 | break; | ||
2736 | |||
2737 | case BUTTON_ON: | ||
2738 | return ZOOM_OUT; | ||
2739 | break; | ||
2740 | |||
2741 | case BUTTON_OFF: | ||
2742 | return PLUGIN_OK; | ||
2743 | } /* switch */ | ||
2744 | } /* while (true) */ | ||
2745 | } | ||
2746 | |||
2747 | /********************* main function *************************/ | ||
2748 | |||
2749 | /* debug function */ | ||
2750 | int wait_for_button(void) | ||
2751 | { | ||
2752 | int button; | ||
2753 | |||
2754 | do | ||
2755 | { | ||
2756 | button = rb->button_get(true); | ||
2757 | } while ((button & BUTTON_REL) && button != SYS_USB_CONNECTED); | ||
2758 | |||
2759 | return button; | ||
2760 | } | ||
2761 | |||
2762 | /* callback updating a progress meter while JPEG decoding */ | ||
2763 | void cb_progess(int current, int total) | ||
2764 | { | ||
2765 | rb->progressbar(0, LCD_HEIGHT-8, LCD_WIDTH, 8, | ||
2766 | current*100/total, 0 /*Grow_Right*/); | ||
2767 | rb->lcd_update_rect(0, LCD_HEIGHT-8, LCD_WIDTH, 8); | ||
2768 | } | ||
2769 | |||
2770 | /* helper to align a buffer to a given power of two */ | ||
2771 | void align(unsigned char** ppbuf, int* plen, int align) | ||
2772 | { | ||
2773 | unsigned int orig = (unsigned int)*ppbuf; | ||
2774 | unsigned int aligned = (orig + (align-1)) & ~(align-1); | ||
2775 | |||
2776 | *plen -= aligned - orig; | ||
2777 | *ppbuf = (unsigned char*)aligned; | ||
2778 | } | ||
2779 | |||
2780 | |||
2781 | /* how far can we zoom in without running out of memory */ | ||
2782 | int min_downscale(int x, int y, int bufsize) | ||
2783 | { | ||
2784 | int downscale = 8; | ||
2785 | |||
2786 | if ((x/8) * (y/8) > bufsize) | ||
2787 | return 0; /* error, too large even 1:8, doesn't fit */ | ||
2788 | |||
2789 | while ((x*2/downscale) * (y*2/downscale) < bufsize | ||
2790 | && downscale > 1) | ||
2791 | { | ||
2792 | downscale /= 2; | ||
2793 | } | ||
2794 | return downscale; | ||
2795 | } | ||
2796 | |||
2797 | /* how far can we zoom out, to fit image into the LCD */ | ||
2798 | int max_downscale(int x, int y) | ||
2799 | { | ||
2800 | int downscale = 1; | ||
2801 | |||
2802 | while ((x/downscale > LCD_WIDTH || y/downscale > LCD_HEIGHT) | ||
2803 | && downscale < 8) | ||
2804 | { | ||
2805 | downscale *= 2; | ||
2806 | } | ||
2807 | |||
2808 | return downscale; | ||
2809 | } | ||
2810 | |||
2811 | |||
2812 | /* load, decode, display the image */ | ||
2813 | int main(char* filename) | ||
2814 | { | ||
2815 | int fd; | ||
2816 | int filesize; | ||
2817 | int grayscales; | ||
2818 | int graysize; // helper | ||
2819 | char print[32]; | ||
2820 | unsigned char* buf; | ||
2821 | int buf_size; | ||
2822 | unsigned char* buf_jpeg; /* compressed JPEG image */ | ||
2823 | struct t_disp disp; /* decompressed image */ | ||
2824 | long time; /* measured ticks */ | ||
2825 | |||
2826 | static struct jpeg jpg; /* too large for stack */ | ||
2827 | int status; | ||
2828 | int ds, ds_min, ds_max; /* scaling and limits */ | ||
2829 | |||
2830 | buf = rb->plugin_get_mp3_buffer(&buf_size); | ||
2831 | |||
2832 | fd = rb->open(filename, O_RDONLY); | ||
2833 | if (fd < 0) | ||
2834 | { | ||
2835 | rb->splash(HZ*2, true, "fopen err"); | ||
2836 | return PLUGIN_ERROR; | ||
2837 | } | ||
2838 | filesize = rb->filesize(fd); | ||
2839 | |||
2840 | |||
2841 | /* initialize the grayscale buffer: | ||
2842 | * 112 pixels wide, 8 rows (64 pixels) high, (try to) reserve | ||
2843 | * 32 bitplanes for 33 shades of gray. (uses 28856 bytes)*/ | ||
2844 | align(&buf, &buf_size, 4); // 32 bit align | ||
2845 | graysize = sizeof(tGraybuf) + sizeof(long) + (112 * 8 + sizeof(long)) * 32; | ||
2846 | grayscales = gray_init_buffer(buf, graysize, 112, 8, 32) + 1; | ||
2847 | buf += graysize; | ||
2848 | buf_size -= graysize; | ||
2849 | if (grayscales < 33 || buf_size <= 0) | ||
2850 | { | ||
2851 | rb->splash(HZ*2, true, "gray buf error"); | ||
2852 | return PLUGIN_ERROR; | ||
2853 | } | ||
2854 | |||
2855 | |||
2856 | /* allocate JPEG buffer */ | ||
2857 | align(&buf, &buf_size, 2); /* 16 bit align */ | ||
2858 | buf_jpeg = (unsigned char*)(((int)buf + 1) & ~1); | ||
2859 | buf += filesize; | ||
2860 | buf_size -= filesize; | ||
2861 | if (buf_size <= 0) | ||
2862 | { | ||
2863 | rb->splash(HZ*2, true, "out of memory"); | ||
2864 | rb->close(fd); | ||
2865 | return PLUGIN_ERROR; | ||
2866 | } | ||
2867 | |||
2868 | rb->snprintf(print, sizeof(print), "loading %d bytes", filesize); | ||
2869 | rb->lcd_puts(0, 0, print); | ||
2870 | rb->lcd_update(); | ||
2871 | |||
2872 | rb->read(fd, buf_jpeg, filesize); | ||
2873 | rb->close(fd); | ||
2874 | |||
2875 | rb->snprintf(print, sizeof(print), "decoding markers"); | ||
2876 | rb->lcd_puts(0, 1, print); | ||
2877 | rb->lcd_update(); | ||
2878 | |||
2879 | rb->memset(&jpg, 0, sizeof(jpg)); /* clear info struct */ | ||
2880 | /* process markers, unstuffing */ | ||
2881 | status = process_markers(buf_jpeg, filesize, &jpg); | ||
2882 | if (status < 0 || (status & (DQT | SOF0)) != (DQT | SOF0)) | ||
2883 | { /* bad format or minimum components not contained */ | ||
2884 | rb->splash(HZ*2, true, "unsupported format %d", status); | ||
2885 | return PLUGIN_ERROR; | ||
2886 | } | ||
2887 | if (!(status & DHT)) /* if no Huffman table present: */ | ||
2888 | default_huff_tbl(&jpg); /* use default */ | ||
2889 | build_lut(&jpg); /* derive Huffman and other lookup-tables */ | ||
2890 | |||
2891 | /* I can correct the buffer now, re-gain what the removed markers took */ | ||
2892 | buf -= filesize; /* back to before */ | ||
2893 | buf_size += filesize; | ||
2894 | buf += jpg.words_in_buffer * sizeof(short); /* real space */ | ||
2895 | buf_size -= jpg.words_in_buffer * sizeof(short); | ||
2896 | |||
2897 | rb->snprintf(print, sizeof(print), "image %d*%d", jpg.x_size, jpg.y_size); | ||
2898 | rb->lcd_puts(0, 2, print); | ||
2899 | rb->lcd_update(); | ||
2900 | |||
2901 | /* check display constraint */ | ||
2902 | ds_max = max_downscale(jpg.x_size, jpg.y_size); | ||
2903 | /* check memory constraint */ | ||
2904 | ds_min = min_downscale(jpg.x_phys, jpg.y_phys, buf_size); | ||
2905 | if (ds_min == 0) | ||
2906 | { | ||
2907 | rb->splash(HZ*2, true, "too large"); | ||
2908 | return PLUGIN_ERROR; | ||
2909 | } | ||
2910 | ds = ds_max; /* initials setting */ | ||
2911 | |||
2912 | /* assign image buffer */ | ||
2913 | rb->memset(&disp, 0, sizeof(disp)); | ||
2914 | disp.bitmap = buf; | ||
2915 | |||
2916 | do /* loop the image prepare and decoding when zoomed */ | ||
2917 | { | ||
2918 | int w, h; /* used to center output */ | ||
2919 | rb->snprintf(print, sizeof(print), "decoding %d*%d", | ||
2920 | jpg.x_size/ds, jpg.y_size/ds); | ||
2921 | rb->lcd_puts(0, 3, print); | ||
2922 | rb->lcd_update(); | ||
2923 | |||
2924 | /* update image properties */ | ||
2925 | disp.width = jpg.x_size/ds; | ||
2926 | disp.stride = jpg.x_phys / ds; /* use physical size for stride */ | ||
2927 | disp.height = jpg.y_size/ds; | ||
2928 | disp.x = MAX(0, (disp.width - LCD_WIDTH) / 2); /* center view */ | ||
2929 | disp.y = MAX(0, (disp.height - LCD_HEIGHT) / 2); | ||
2930 | |||
2931 | /* the actual decoding */ | ||
2932 | time = *rb->current_tick; | ||
2933 | status = jpeg_decode(&jpg, disp.bitmap, ds, cb_progess); | ||
2934 | if (status) | ||
2935 | { | ||
2936 | rb->splash(HZ*2, true, "decode error %d", status); | ||
2937 | return PLUGIN_ERROR; | ||
2938 | } | ||
2939 | time = *rb->current_tick - time; | ||
2940 | rb->snprintf(print, sizeof(print), " %d.%02d sec ", time/HZ, time%HZ); | ||
2941 | rb->lcd_getstringsize(print, &w, &h); /* centered in progress bar */ | ||
2942 | rb->lcd_putsxy((LCD_WIDTH - w)/2, LCD_HEIGHT - h, print); | ||
2943 | rb->lcd_update(); | ||
2944 | |||
2945 | gray_clear_display(); | ||
2946 | gray_drawgraymap( | ||
2947 | disp.bitmap + disp.y * disp.stride + disp.x, | ||
2948 | MAX(0, (LCD_WIDTH - disp.width) / 2), | ||
2949 | MAX(0, (LCD_HEIGHT - disp.height) / 2), | ||
2950 | MIN(LCD_WIDTH, disp.width), MIN(LCD_HEIGHT, disp.height), | ||
2951 | disp.stride); | ||
2952 | |||
2953 | gray_show_display(true); /* switch on grayscale overlay */ | ||
2954 | |||
2955 | /* drawing is now finished, play around with scrolling | ||
2956 | * until you press OFF or connect USB | ||
2957 | */ | ||
2958 | while (1) | ||
2959 | { | ||
2960 | status = scroll_bmp(&disp); | ||
2961 | if (status == ZOOM_IN) | ||
2962 | { | ||
2963 | if (ds > ds_min) | ||
2964 | { | ||
2965 | ds /= 2; /* reduce downscaling to zoom in */ | ||
2966 | /* FixMe: maintain center | ||
2967 | disp.x = disp.x * 2 + LCD_WIDTH/2; | ||
2968 | disp.y = disp.y * 2 + LCD_HEIGHT/2; | ||
2969 | */ | ||
2970 | } | ||
2971 | else | ||
2972 | continue; | ||
2973 | } | ||
2974 | |||
2975 | if (status == ZOOM_OUT) | ||
2976 | { | ||
2977 | if (ds < ds_max) | ||
2978 | { | ||
2979 | ds *= 2; /* increase downscaling to zoom out */ | ||
2980 | /* FixMe: maintain center, if possible | ||
2981 | disp.x = (disp.x - LCD_WIDTH/2) / 2; | ||
2982 | disp.x = MIN(0, disp.x); | ||
2983 | disp.x = MAX(disp.width/2 - LCD_WIDTH, disp.x); | ||
2984 | disp.y = (disp.y - LCD_HEIGHT/2) / 2; | ||
2985 | disp.y = MIN(0, disp.y); | ||
2986 | disp.y = MAX(disp.height/2 - LCD_HEIGHT, disp.y); | ||
2987 | */ | ||
2988 | } | ||
2989 | else | ||
2990 | continue; | ||
2991 | } | ||
2992 | break; | ||
2993 | } | ||
2994 | |||
2995 | gray_show_display(false); /* switch off overlay */ | ||
2996 | |||
2997 | } | ||
2998 | while (status > 0 && status != SYS_USB_CONNECTED); | ||
2999 | |||
3000 | gray_release_buffer(); /* deinitialize */ | ||
3001 | |||
3002 | return status; | ||
3003 | } | ||
3004 | |||
3005 | /******************** Plugin entry point *********************/ | ||
3006 | |||
3007 | enum plugin_status plugin_start(struct plugin_api* api, void* parameter) | ||
3008 | { | ||
3009 | int ret; | ||
3010 | /* this macro should be called as the first thing you do in the plugin. | ||
3011 | it test that the api version and model the plugin was compiled for | ||
3012 | matches the machine it is running on */ | ||
3013 | TEST_PLUGIN_API(api); | ||
3014 | |||
3015 | rb = api; /* copy to global api pointer */ | ||
3016 | |||
3017 | ret = main((char*)parameter); | ||
3018 | |||
3019 | if (ret == PLUGIN_USB_CONNECTED) | ||
3020 | rb->usb_screen(); | ||
3021 | return ret; | ||
3022 | } | ||
3023 | |||
3024 | #endif /* #ifdef HAVE_LCD_BITMAP */ | ||
3025 | #endif /* #ifndef SIMULATOR */ | ||
3026 | |||