diff options
-rw-r--r-- | apps/plugins/CATEGORIES | 1 | ||||
-rw-r--r-- | apps/plugins/imageviewer/SUBDIRS | 1 | ||||
-rw-r--r-- | apps/plugins/imageviewer/image_decoder.c | 5 | ||||
-rw-r--r-- | apps/plugins/imageviewer/image_decoder.h | 2 | ||||
-rw-r--r-- | apps/plugins/imageviewer/imageviewer.c | 9 | ||||
-rw-r--r-- | apps/plugins/imageviewer/imageviewer.h | 1 | ||||
-rw-r--r-- | apps/plugins/imageviewer/jpeg/jpeg.c | 4 | ||||
-rw-r--r-- | apps/plugins/imageviewer/jpegp/BUFFILEGETC.c | 94 | ||||
-rw-r--r-- | apps/plugins/imageviewer/jpegp/FILEGETC.c | 71 | ||||
-rw-r--r-- | apps/plugins/imageviewer/jpegp/GETC.h | 14 | ||||
-rw-r--r-- | apps/plugins/imageviewer/jpegp/SOURCES | 6 | ||||
-rw-r--r-- | apps/plugins/imageviewer/jpegp/jpeg81.c | 24 | ||||
-rw-r--r-- | apps/plugins/imageviewer/jpegp/jpeg81.h | 2 | ||||
-rw-r--r-- | apps/plugins/imageviewer/jpegp/jpegp.c | 260 | ||||
-rw-r--r-- | apps/plugins/imageviewer/jpegp/jpegp.make | 32 | ||||
-rw-r--r-- | apps/plugins/imageviewer/jpegp/mempool.c | 50 | ||||
-rw-r--r-- | apps/plugins/imageviewer/jpegp/mempool.h | 7 | ||||
-rw-r--r-- | apps/plugins/imageviewer/jpegp/rb_glue.h | 35 | ||||
-rw-r--r-- | manual/plugins/imageviewer.tex | 3 |
19 files changed, 599 insertions, 22 deletions
diff --git a/apps/plugins/CATEGORIES b/apps/plugins/CATEGORIES index 79186b7aed..aa7dbf38e5 100644 --- a/apps/plugins/CATEGORIES +++ b/apps/plugins/CATEGORIES | |||
@@ -51,6 +51,7 @@ iriverify,viewers | |||
51 | jackpot,games | 51 | jackpot,games |
52 | jewels,games | 52 | jewels,games |
53 | jpeg,viewers | 53 | jpeg,viewers |
54 | jpegp,viewers | ||
54 | keybox,apps | 55 | keybox,apps |
55 | keyremap,apps | 56 | keyremap,apps |
56 | lamp,apps | 57 | lamp,apps |
diff --git a/apps/plugins/imageviewer/SUBDIRS b/apps/plugins/imageviewer/SUBDIRS index 1f7b4d8b52..ea7c304218 100644 --- a/apps/plugins/imageviewer/SUBDIRS +++ b/apps/plugins/imageviewer/SUBDIRS | |||
@@ -3,5 +3,6 @@ jpeg | |||
3 | png | 3 | png |
4 | #ifdef HAVE_LCD_COLOR | 4 | #ifdef HAVE_LCD_COLOR |
5 | ppm | 5 | ppm |
6 | jpegp | ||
6 | #endif | 7 | #endif |
7 | gif | 8 | gif |
diff --git a/apps/plugins/imageviewer/image_decoder.c b/apps/plugins/imageviewer/image_decoder.c index 0c1776daaa..c481899bae 100644 --- a/apps/plugins/imageviewer/image_decoder.c +++ b/apps/plugins/imageviewer/image_decoder.c | |||
@@ -25,12 +25,13 @@ | |||
25 | 25 | ||
26 | static const char *decoder_names[MAX_IMAGE_TYPES] = { | 26 | static const char *decoder_names[MAX_IMAGE_TYPES] = { |
27 | "bmp", | 27 | "bmp", |
28 | "jpeg", | 28 | "jpeg", // Default decoder for jpeg: Use jpeg for old decoder, jpegp for new |
29 | "png", | 29 | "png", |
30 | #ifdef HAVE_LCD_COLOR | 30 | #ifdef HAVE_LCD_COLOR |
31 | "ppm", | 31 | "ppm", |
32 | #endif | 32 | #endif |
33 | "gif" | 33 | "gif", |
34 | "jpegp", | ||
34 | }; | 35 | }; |
35 | 36 | ||
36 | /* Check file type by magic number or file extension | 37 | /* Check file type by magic number or file extension |
diff --git a/apps/plugins/imageviewer/image_decoder.h b/apps/plugins/imageviewer/image_decoder.h index c27ed33e8e..7a9cd5d06c 100644 --- a/apps/plugins/imageviewer/image_decoder.h +++ b/apps/plugins/imageviewer/image_decoder.h | |||
@@ -33,6 +33,8 @@ enum image_type { | |||
33 | IMAGE_PPM, | 33 | IMAGE_PPM, |
34 | #endif | 34 | #endif |
35 | IMAGE_GIF, | 35 | IMAGE_GIF, |
36 | IMAGE_JPEG_PROGRESSIVE, | ||
37 | |||
36 | MAX_IMAGE_TYPES | 38 | MAX_IMAGE_TYPES |
37 | }; | 39 | }; |
38 | 40 | ||
diff --git a/apps/plugins/imageviewer/imageviewer.c b/apps/plugins/imageviewer/imageviewer.c index b849812508..ba5f8fec16 100644 --- a/apps/plugins/imageviewer/imageviewer.c +++ b/apps/plugins/imageviewer/imageviewer.c | |||
@@ -853,6 +853,8 @@ static int load_and_show(char* filename, struct image_info *info) | |||
853 | file_pt[curfile] = NULL; | 853 | file_pt[curfile] = NULL; |
854 | return change_filename(direction); | 854 | return change_filename(direction); |
855 | } | 855 | } |
856 | |||
857 | reload_decoder: | ||
856 | if (image_type != status) /* type of image is changed, load decoder. */ | 858 | if (image_type != status) /* type of image is changed, load decoder. */ |
857 | { | 859 | { |
858 | struct loader_info loader_info = { | 860 | struct loader_info loader_info = { |
@@ -881,6 +883,13 @@ static int load_and_show(char* filename, struct image_info *info) | |||
881 | else | 883 | else |
882 | status = imgdec->load_image(filename, info, buf, &remaining); | 884 | status = imgdec->load_image(filename, info, buf, &remaining); |
883 | 885 | ||
886 | if (status == PLUGIN_JPEG_PROGRESSIVE) | ||
887 | { | ||
888 | rb->lcd_clear_display(); | ||
889 | status = IMAGE_JPEG_PROGRESSIVE; | ||
890 | goto reload_decoder; | ||
891 | } | ||
892 | |||
884 | if (status == PLUGIN_OUTOFMEM) | 893 | if (status == PLUGIN_OUTOFMEM) |
885 | { | 894 | { |
886 | #ifdef USE_PLUG_BUF | 895 | #ifdef USE_PLUG_BUF |
diff --git a/apps/plugins/imageviewer/imageviewer.h b/apps/plugins/imageviewer/imageviewer.h index ac15df5960..44e56c0696 100644 --- a/apps/plugins/imageviewer/imageviewer.h +++ b/apps/plugins/imageviewer/imageviewer.h | |||
@@ -55,6 +55,7 @@ enum { | |||
55 | PLUGIN_OTHER = 0x200, | 55 | PLUGIN_OTHER = 0x200, |
56 | PLUGIN_ABORT, | 56 | PLUGIN_ABORT, |
57 | PLUGIN_OUTOFMEM, | 57 | PLUGIN_OUTOFMEM, |
58 | PLUGIN_JPEG_PROGRESSIVE, | ||
58 | 59 | ||
59 | ZOOM_IN, | 60 | ZOOM_IN, |
60 | ZOOM_OUT, | 61 | ZOOM_OUT, |
diff --git a/apps/plugins/imageviewer/jpeg/jpeg.c b/apps/plugins/imageviewer/jpeg/jpeg.c index 3d8c9c3ac8..c231209beb 100644 --- a/apps/plugins/imageviewer/jpeg/jpeg.c +++ b/apps/plugins/imageviewer/jpeg/jpeg.c | |||
@@ -170,8 +170,12 @@ static int load_image(char *filename, struct image_info *info, | |||
170 | 170 | ||
171 | if (status < 0 || (status & (DQT | SOF0)) != (DQT | SOF0)) | 171 | if (status < 0 || (status & (DQT | SOF0)) != (DQT | SOF0)) |
172 | { /* bad format or minimum components not contained */ | 172 | { /* bad format or minimum components not contained */ |
173 | #ifndef HAVE_LCD_COLOR | ||
173 | rb->splashf(HZ, "unsupported %d", status); | 174 | rb->splashf(HZ, "unsupported %d", status); |
174 | return PLUGIN_ERROR; | 175 | return PLUGIN_ERROR; |
176 | #else | ||
177 | return PLUGIN_JPEG_PROGRESSIVE; | ||
178 | #endif | ||
175 | } | 179 | } |
176 | 180 | ||
177 | if (!(status & DHT)) /* if no Huffman table present: */ | 181 | if (!(status & DHT)) /* if no Huffman table present: */ |
diff --git a/apps/plugins/imageviewer/jpegp/BUFFILEGETC.c b/apps/plugins/imageviewer/jpegp/BUFFILEGETC.c new file mode 100644 index 0000000000..5124636731 --- /dev/null +++ b/apps/plugins/imageviewer/jpegp/BUFFILEGETC.c | |||
@@ -0,0 +1,94 @@ | |||
1 | /* Simple buffered version of file reader. | ||
2 | * JPEG decoding seems to work faster with it. | ||
3 | * Not fully tested. In case of any issues try FILEGETC (see SOURCES) | ||
4 | * */ | ||
5 | #include "rb_glue.h" | ||
6 | |||
7 | static int fd; | ||
8 | static unsigned char buff[256]; //TODO: Adjust it... | ||
9 | static int length = 0; | ||
10 | static int cur_buff_pos = 0; | ||
11 | static int file_pos = 0; | ||
12 | |||
13 | extern int GETC(void) | ||
14 | { | ||
15 | if (cur_buff_pos >= length) | ||
16 | { | ||
17 | length = rb->read(fd, buff, sizeof(buff)); | ||
18 | file_pos += length; | ||
19 | cur_buff_pos = 0; | ||
20 | } | ||
21 | |||
22 | return buff[cur_buff_pos++]; | ||
23 | } | ||
24 | |||
25 | // multibyte readers: host-endian independent - if evaluated in right order (ie. don't optimize) | ||
26 | |||
27 | extern int GETWbi(void) // 16-bit big-endian | ||
28 | { | ||
29 | return ( GETC()<<8 ) | GETC(); | ||
30 | } | ||
31 | |||
32 | extern int GETDbi(void) // 32-bit big-endian | ||
33 | { | ||
34 | return ( GETC()<<24 ) | ( GETC()<<16 ) | ( GETC()<<8 ) | GETC(); | ||
35 | } | ||
36 | |||
37 | extern int GETWli(void) // 16-bit little-endian | ||
38 | { | ||
39 | return GETC() | ( GETC()<<8 ); | ||
40 | } | ||
41 | |||
42 | extern int GETDli(void) // 32-bit little-endian | ||
43 | { | ||
44 | return GETC() | ( GETC()<<8 ) | ( GETC()<<16 ) | ( GETC()<<24 ); | ||
45 | } | ||
46 | |||
47 | // seek | ||
48 | |||
49 | extern void SEEK(int d) | ||
50 | { | ||
51 | int newPos = cur_buff_pos + d; | ||
52 | if (newPos < length && newPos >= 0) | ||
53 | { | ||
54 | cur_buff_pos = newPos; | ||
55 | return; | ||
56 | } | ||
57 | file_pos = rb->lseek(fd, (cur_buff_pos - length) + d, SEEK_CUR); | ||
58 | cur_buff_pos = length = 0; | ||
59 | } | ||
60 | |||
61 | extern void POS(int d) | ||
62 | { | ||
63 | cur_buff_pos = length = 0; | ||
64 | file_pos = d; | ||
65 | rb->lseek(fd, d, SEEK_SET); | ||
66 | } | ||
67 | |||
68 | extern int TELL(void) | ||
69 | { | ||
70 | return file_pos + cur_buff_pos - length; | ||
71 | } | ||
72 | |||
73 | // OPEN/CLOSE file | ||
74 | |||
75 | extern void *OPEN(char *f) | ||
76 | { | ||
77 | printf("Opening %s\n", f); | ||
78 | cur_buff_pos = length = file_pos = 0; | ||
79 | fd = rb->open(f,O_RDONLY); | ||
80 | |||
81 | if ( fd < 0 ) | ||
82 | { | ||
83 | printf("Error opening %s\n", f); | ||
84 | return NULL; | ||
85 | } | ||
86 | |||
87 | return &fd; | ||
88 | } | ||
89 | |||
90 | extern int CLOSE(void) | ||
91 | { | ||
92 | cur_buff_pos = length = file_pos = 0; | ||
93 | return rb->close(fd); | ||
94 | } | ||
diff --git a/apps/plugins/imageviewer/jpegp/FILEGETC.c b/apps/plugins/imageviewer/jpegp/FILEGETC.c new file mode 100644 index 0000000000..bb7f0c485f --- /dev/null +++ b/apps/plugins/imageviewer/jpegp/FILEGETC.c | |||
@@ -0,0 +1,71 @@ | |||
1 | #include "rb_glue.h" | ||
2 | |||
3 | static int fd; | ||
4 | |||
5 | extern int GETC(void) | ||
6 | { | ||
7 | unsigned char x; | ||
8 | rb->read(fd, &x, 1); | ||
9 | return x; | ||
10 | } | ||
11 | |||
12 | // multibyte readers: host-endian independent - if evaluated in right order (ie. don't optimize) | ||
13 | |||
14 | extern int GETWbi(void) // 16-bit big-endian | ||
15 | { | ||
16 | return ( GETC()<<8 ) | GETC(); | ||
17 | } | ||
18 | |||
19 | extern int GETDbi(void) // 32-bit big-endian | ||
20 | { | ||
21 | return ( GETC()<<24 ) | ( GETC()<<16 ) | ( GETC()<<8 ) | GETC(); | ||
22 | } | ||
23 | |||
24 | extern int GETWli(void) // 16-bit little-endian | ||
25 | { | ||
26 | return GETC() | ( GETC()<<8 ); | ||
27 | } | ||
28 | |||
29 | extern int GETDli(void) // 32-bit little-endian | ||
30 | { | ||
31 | return GETC() | ( GETC()<<8 ) | ( GETC()<<16 ) | ( GETC()<<24 ); | ||
32 | } | ||
33 | |||
34 | // seek | ||
35 | |||
36 | extern void SEEK(int d) | ||
37 | { | ||
38 | rb->lseek(fd, d, SEEK_CUR); | ||
39 | } | ||
40 | |||
41 | extern void POS(int d) | ||
42 | { | ||
43 | rb->lseek(fd, d, SEEK_SET); | ||
44 | } | ||
45 | |||
46 | extern int TELL(void) | ||
47 | { | ||
48 | return rb->lseek(fd, 0, SEEK_CUR); | ||
49 | } | ||
50 | |||
51 | // OPEN/CLOSE file | ||
52 | |||
53 | extern void *OPEN(char *f) | ||
54 | { | ||
55 | printf("Opening %s\n", f); | ||
56 | |||
57 | fd = rb->open(f,O_RDONLY); | ||
58 | |||
59 | if ( fd < 0 ) | ||
60 | { | ||
61 | printf("Error opening %s\n", f); | ||
62 | return NULL; | ||
63 | } | ||
64 | |||
65 | return &fd; | ||
66 | } | ||
67 | |||
68 | extern int CLOSE(void) | ||
69 | { | ||
70 | return rb->close(fd); | ||
71 | } | ||
diff --git a/apps/plugins/imageviewer/jpegp/GETC.h b/apps/plugins/imageviewer/jpegp/GETC.h index d17cdb9857..5e8a3c6a9d 100644 --- a/apps/plugins/imageviewer/jpegp/GETC.h +++ b/apps/plugins/imageviewer/jpegp/GETC.h | |||
@@ -37,20 +37,20 @@ | |||
37 | 37 | ||
38 | // For decoders | 38 | // For decoders |
39 | 39 | ||
40 | extern int GETC(); | 40 | extern int GETC(void); |
41 | 41 | ||
42 | // Multibyte helpers | 42 | // Multibyte helpers |
43 | extern int GETWbi(); // read word (16-bit) big-endian | 43 | extern int GETWbi(void); // read word (16-bit) big-endian |
44 | extern int GETWli(); // little-endian | 44 | extern int GETWli(void); // little-endian |
45 | extern int GETDbi(); // read double word (32-bit) big-endian | 45 | extern int GETDbi(void); // read double word (32-bit) big-endian |
46 | extern int GETDli(); // little-endian | 46 | extern int GETDli(void); // little-endian |
47 | 47 | ||
48 | // positioning | 48 | // positioning |
49 | extern void SEEK(int); // move relative to current | 49 | extern void SEEK(int); // move relative to current |
50 | extern void POS(int); // move absolute position (TIFF) | 50 | extern void POS(int); // move absolute position (TIFF) |
51 | extern int TELL(); // read actual position | 51 | extern int TELL(void); // read actual position |
52 | 52 | ||
53 | 53 | ||
54 | // For RAINBOW clients to implement outside of Rainbow Library | 54 | // For RAINBOW clients to implement outside of Rainbow Library |
55 | extern void *OPEN(char*); | 55 | extern void *OPEN(char*); |
56 | extern void CLOSE(); | 56 | extern void CLOSE(void); |
diff --git a/apps/plugins/imageviewer/jpegp/SOURCES b/apps/plugins/imageviewer/jpegp/SOURCES new file mode 100644 index 0000000000..dfaf63a42f --- /dev/null +++ b/apps/plugins/imageviewer/jpegp/SOURCES | |||
@@ -0,0 +1,6 @@ | |||
1 | jpegp.c | ||
2 | //FILEGETC.c | ||
3 | BUFFILEGETC.c | ||
4 | jpeg81.c | ||
5 | idct.c | ||
6 | mempool.c \ No newline at end of file | ||
diff --git a/apps/plugins/imageviewer/jpegp/jpeg81.c b/apps/plugins/imageviewer/jpegp/jpeg81.c index 95e46dbd17..76b36ca950 100644 --- a/apps/plugins/imageviewer/jpegp/jpeg81.c +++ b/apps/plugins/imageviewer/jpegp/jpeg81.c | |||
@@ -40,12 +40,12 @@ jpeg81.c | |||
40 | * SOFTWARE. | 40 | * SOFTWARE. |
41 | */ | 41 | */ |
42 | 42 | ||
43 | #include "GETC.h" | 43 | #include "GETC.h" |
44 | #include "rb_glue.h" | ||
44 | #include "jpeg81.h" | 45 | #include "jpeg81.h" |
45 | #include <malloc.h> // calloc() called once | ||
46 | #include <stdio.h> // debug only | ||
47 | |||
48 | 46 | ||
47 | #pragma GCC diagnostic push | ||
48 | #pragma GCC diagnostic ignored "-Wunused-parameter" | ||
49 | ///////////////////////////////////////// LOSSLESS ///////////////////////////////////////// | 49 | ///////////////////////////////////////// LOSSLESS ///////////////////////////////////////// |
50 | 50 | ||
51 | static int P1(struct COMP *C, TSAMP *samp) // Px = Ra | 51 | static int P1(struct COMP *C, TSAMP *samp) // Px = Ra |
@@ -63,17 +63,17 @@ static int P3(struct COMP *C, TSAMP *samp) // Px = Rc | |||
63 | return samp[-C->du_width-1]; | 63 | return samp[-C->du_width-1]; |
64 | } | 64 | } |
65 | 65 | ||
66 | static int P4(struct COMP *C, TSAMP *samp) // Px = Ra + Rb – Rc | 66 | static int P4(struct COMP *C, TSAMP *samp) // Px = Ra + Rb - Rc |
67 | { | 67 | { |
68 | return samp[-1] + samp[-C->du_width] - samp[-C->du_width-1]; | 68 | return samp[-1] + samp[-C->du_width] - samp[-C->du_width-1]; |
69 | } | 69 | } |
70 | 70 | ||
71 | static int P5(struct COMP *C, TSAMP *samp) // Px = Ra + ((Rb – Rc)/2) | 71 | static int P5(struct COMP *C, TSAMP *samp) // Px = Ra + ((Rb - Rc)/2) |
72 | { | 72 | { |
73 | return samp[-1] + ( (samp[-C->du_width] - samp[-C->du_width-1]) >> 1 ); | 73 | return samp[-1] + ( (samp[-C->du_width] - samp[-C->du_width-1]) >> 1 ); |
74 | } | 74 | } |
75 | 75 | ||
76 | static int P6(struct COMP *C, TSAMP *samp) // Px = Rb + ((Ra – Rc)/2) | 76 | static int P6(struct COMP *C, TSAMP *samp) // Px = Rb + ((Ra - Rc)/2) |
77 | { | 77 | { |
78 | return samp[-C->du_width] + ( (samp[-1] - samp[-C->du_width-1]) >> 1 ); | 78 | return samp[-C->du_width] + ( (samp[-1] - samp[-C->du_width-1]) >> 1 ); |
79 | } | 79 | } |
@@ -215,7 +215,7 @@ static void du_sequential_huff(struct JPEGD *j, struct COMP *sc, TCOEF *coef) | |||
215 | { | 215 | { |
216 | int s, k; | 216 | int s, k; |
217 | dc_decode_huff(j, sc, coef); | 217 | dc_decode_huff(j, sc, coef); |
218 | for (k=1; s=sc->ACS[ReadHuffmanCode(j, sc->ACB)]; k++) { // EOB? | 218 | for (k=1; (s=sc->ACS[ReadHuffmanCode(j, sc->ACB)]); k++) { // EOB? |
219 | k+= s>>4; | 219 | k+= s>>4; |
220 | if (s==0xf0) continue; // ZRL | 220 | if (s==0xf0) continue; // ZRL |
221 | coef[k]= ReadDiff(j, s&15); | 221 | coef[k]= ReadDiff(j, s&15); |
@@ -496,7 +496,7 @@ static void Ri(struct JPEGD *j, int n) | |||
496 | printf("RST%d\n", Marker&7); | 496 | printf("RST%d\n", Marker&7); |
497 | printf("%08X: ECS\n", TELL()); | 497 | printf("%08X: ECS\n", TELL()); |
498 | } | 498 | } |
499 | else printf("STREAM ERROR: expected RSTn missing from ECS\n"); | 499 | else { printf("STREAM ERROR: expected RSTn missing from ECS\n"); } |
500 | j->Reset_decoder(j); | 500 | j->Reset_decoder(j); |
501 | } | 501 | } |
502 | } | 502 | } |
@@ -832,7 +832,7 @@ extern enum JPEGENUM JPEGDecode(struct JPEGD *j) | |||
832 | } | 832 | } |
833 | } | 833 | } |
834 | 834 | ||
835 | printf(" Malloc for %d Data Units (%d bytes)\n\n", TotalDU, sizeof(DU)*TotalDU); | 835 | printf(" Malloc for %d Data Units (%lu bytes)\n\n", TotalDU, sizeof(DU)*TotalDU); |
836 | 836 | ||
837 | if (j->SOF > 0xC8) { // DCT Arithmetic | 837 | if (j->SOF > 0xC8) { // DCT Arithmetic |
838 | j->Reset_decoder= Reset_decoder_arith; | 838 | j->Reset_decoder= Reset_decoder_arith; |
@@ -953,7 +953,7 @@ extern enum JPEGENUM JPEGDecode(struct JPEGD *j) | |||
953 | 953 | ||
954 | for (Lq-=2; Lq; Lq -= 65 + 64*Pq) | 954 | for (Lq-=2; Lq; Lq -= 65 + 64*Pq) |
955 | { | 955 | { |
956 | int (*get)(); | 956 | int (*get)(void); |
957 | int T= GETC(); | 957 | int T= GETC(); |
958 | int Tq= T&3; | 958 | int Tq= T&3; |
959 | int *qt= j->QT[Tq]; | 959 | int *qt= j->QT[Tq]; |
@@ -993,3 +993,5 @@ extern enum JPEGENUM JPEGDecode(struct JPEGD *j) | |||
993 | } | 993 | } |
994 | } | 994 | } |
995 | } | 995 | } |
996 | |||
997 | #pragma GCC diagnostic pop \ No newline at end of file | ||
diff --git a/apps/plugins/imageviewer/jpegp/jpeg81.h b/apps/plugins/imageviewer/jpegp/jpeg81.h index fa71b10113..e265d84926 100644 --- a/apps/plugins/imageviewer/jpegp/jpeg81.h +++ b/apps/plugins/imageviewer/jpegp/jpeg81.h | |||
@@ -144,4 +144,4 @@ struct JPEGD { // The JPEG DECODER OBJECT | |||
144 | 144 | ||
145 | }; | 145 | }; |
146 | 146 | ||
147 | extern int JPEGDecode(struct JPEGD *j); | 147 | extern enum JPEGENUM JPEGDecode(struct JPEGD *j); |
diff --git a/apps/plugins/imageviewer/jpegp/jpegp.c b/apps/plugins/imageviewer/jpegp/jpegp.c new file mode 100644 index 0000000000..bb7be314f1 --- /dev/null +++ b/apps/plugins/imageviewer/jpegp/jpegp.c | |||
@@ -0,0 +1,260 @@ | |||
1 | #include "jpeg81.h" | ||
2 | #include "idct.h" | ||
3 | #include "GETC.h" | ||
4 | #include "rb_glue.h" | ||
5 | |||
6 | #include "../imageviewer.h" | ||
7 | |||
8 | |||
9 | /**************** begin Application ********************/ | ||
10 | |||
11 | /************************* Types ***************************/ | ||
12 | |||
13 | struct t_disp | ||
14 | { | ||
15 | unsigned char* bitmap; | ||
16 | }; | ||
17 | |||
18 | /************************* Globals ***************************/ | ||
19 | |||
20 | /* decompressed image in the possible sizes (1,2,4,8), wasting the other */ | ||
21 | static struct t_disp disp[9]; | ||
22 | |||
23 | static struct JPEGD jpg; /* too large for stack */ | ||
24 | |||
25 | /************************* Implementation ***************************/ | ||
26 | |||
27 | static void draw_image_rect(struct image_info *info, | ||
28 | int x, int y, int width, int height) | ||
29 | { | ||
30 | struct t_disp* pdisp = (struct t_disp*)info->data; | ||
31 | #ifdef HAVE_LCD_COLOR | ||
32 | rb->lcd_bitmap_part( | ||
33 | (fb_data*)pdisp->bitmap, info->x + x, info->y + y, | ||
34 | STRIDE(SCREEN_MAIN, info->width, info->height), | ||
35 | x + MAX(0, (LCD_WIDTH-info->width)/2), | ||
36 | y + MAX(0, (LCD_HEIGHT-info->height)/2), | ||
37 | width, height); | ||
38 | #else | ||
39 | mylcd_ub_gray_bitmap_part( | ||
40 | pdisp->bitmap, info->x + x, info->y + y, info->width, | ||
41 | x + MAX(0, (LCD_WIDTH-info->width)/2), | ||
42 | y + MAX(0, (LCD_HEIGHT-info->height)/2), | ||
43 | width, height); | ||
44 | #endif | ||
45 | } | ||
46 | |||
47 | static int img_mem(int ds) | ||
48 | { | ||
49 | struct JPEGD* j = &jpg; | ||
50 | return j->Y/ds * j->X/ds*sizeof(fb_data); | ||
51 | } | ||
52 | |||
53 | /* my memory pool (from the mp3 buffer) */ | ||
54 | static char print[32]; /* use a common snprintf() buffer */ | ||
55 | |||
56 | static void scaled_dequantization_and_idct(void) | ||
57 | { | ||
58 | struct JPEGD* j = &jpg; | ||
59 | // The following code is based on RAINBOW lib jpeg2bmp example: | ||
60 | // https://github.com/Halicery/vc_rainbow/blob/605c045a564dad8e2df84e48914eac3d2d8d4a9b/jpeg2bmp.c | ||
61 | |||
62 | printf("Scaled de-quantization and IDCT.. "); | ||
63 | int c, i, n; | ||
64 | |||
65 | // Pre-scale quant-tables | ||
66 | int SQ[4][64]; | ||
67 | for (c=0; c<4 && j->QT[c][0]; c++) | ||
68 | { | ||
69 | int *q= j->QT[c], *sq= SQ[c]; | ||
70 | for (i=0; i<64; i++) sq[i]= q[i] * SCALEM[zigzag[i]]; | ||
71 | } | ||
72 | |||
73 | // DEQUANT + IDCT | ||
74 | for (c=0; c<j->Nf; c++) | ||
75 | { | ||
76 | struct COMP *C= j->Components+c; | ||
77 | //int *q= j->QT[C->Qi]; | ||
78 | int *sq= SQ[C->Qi]; | ||
79 | |||
80 | for (n=0; n < C->du_size; n++) | ||
81 | { | ||
82 | /* | ||
83 | // <--- scaled idct | ||
84 | int k, t[64]; | ||
85 | TCOEF *coef= du[x]; | ||
86 | t[0]= coef[0] * q[0] + 1024; // dequant DC and level-shift (8-bit) | ||
87 | for (k=1; k<64; k++) t[zigzag[k]] = coef[k] * q[k]; // dequant AC (+zigzag) | ||
88 | idct_s(t, coef); | ||
89 | */ | ||
90 | |||
91 | // <--- scaled idct with dequant | ||
92 | idct_sq( C->du[ (n / C->du_w) * C->du_width + n % C->du_w ], sq ); | ||
93 | } | ||
94 | } | ||
95 | printf("done\n"); | ||
96 | } | ||
97 | |||
98 | static int load_image(char *filename, struct image_info *info, | ||
99 | unsigned char *buf, ssize_t *buf_size) | ||
100 | { | ||
101 | int status; | ||
102 | struct JPEGD *p_jpg = &jpg; | ||
103 | |||
104 | memset(&disp, 0, sizeof(disp)); | ||
105 | memset(&jpg, 0, sizeof(jpg)); | ||
106 | |||
107 | init_mem_pool(buf, *buf_size); | ||
108 | |||
109 | if (!OPEN(filename)) | ||
110 | { | ||
111 | return PLUGIN_ERROR; | ||
112 | } | ||
113 | |||
114 | if (!iv->running_slideshow) | ||
115 | { | ||
116 | rb->lcd_puts(0, 0, rb->strrchr(filename,'/')+1); | ||
117 | rb->lcd_puts(0, 2, "decoding..."); | ||
118 | rb->lcd_update(); | ||
119 | } | ||
120 | long time; /* measured ticks */ | ||
121 | |||
122 | /* the actual decoding */ | ||
123 | time = *rb->current_tick; | ||
124 | status = JPEGDecode(p_jpg); | ||
125 | time = *rb->current_tick - time; | ||
126 | |||
127 | CLOSE(); | ||
128 | |||
129 | if (status < 0) | ||
130 | { /* bad format or minimum components not contained */ | ||
131 | if (status == JPEGENUMERR_MALLOC) | ||
132 | { | ||
133 | return PLUGIN_OUTOFMEM; | ||
134 | } | ||
135 | rb->splashf(HZ, "unsupported %d", status); | ||
136 | return PLUGIN_ERROR; | ||
137 | } | ||
138 | |||
139 | if (!iv->running_slideshow) | ||
140 | { | ||
141 | rb->lcd_putsf(0, 2, "image %dx%d", p_jpg->X, p_jpg->Y); | ||
142 | int w, h; /* used to center output */ | ||
143 | rb->snprintf(print, sizeof(print), "jpegp %ld.%02ld sec ", time/HZ, time%HZ); | ||
144 | rb->lcd_getstringsize(print, &w, &h); /* centered in progress bar */ | ||
145 | rb->lcd_putsxy((LCD_WIDTH - w)/2, LCD_HEIGHT - h, print); | ||
146 | rb->lcd_update(); | ||
147 | //rb->sleep(100); | ||
148 | } | ||
149 | |||
150 | info->x_size = p_jpg->X; | ||
151 | info->y_size = p_jpg->Y; | ||
152 | |||
153 | #ifdef DISK_SPINDOWN | ||
154 | if (iv->running_slideshow && iv->immediate_ata_off) | ||
155 | { | ||
156 | /* running slideshow and time is long enough: power down disk */ | ||
157 | rb->storage_sleep(); | ||
158 | } | ||
159 | #endif | ||
160 | |||
161 | if ( 3 != p_jpg->Nf ) | ||
162 | return PLUGIN_ERROR; | ||
163 | |||
164 | scaled_dequantization_and_idct(); | ||
165 | |||
166 | *buf_size = freeze_mem_pool(); | ||
167 | return PLUGIN_OK; | ||
168 | } | ||
169 | |||
170 | static int get_image(struct image_info *info, int frame, int ds) | ||
171 | { | ||
172 | (void)frame; | ||
173 | struct JPEGD* p_jpg = &jpg; | ||
174 | struct t_disp* p_disp = &disp[ds]; /* short cut */ | ||
175 | |||
176 | info->width = p_jpg->X / ds; | ||
177 | info->height = p_jpg->Y / ds; | ||
178 | info->data = p_disp; | ||
179 | |||
180 | if (p_disp->bitmap != NULL) | ||
181 | { | ||
182 | /* we still have it */ | ||
183 | return PLUGIN_OK; | ||
184 | } | ||
185 | |||
186 | struct JPEGD* j = p_jpg; | ||
187 | int mem = img_mem(ds); | ||
188 | |||
189 | p_disp->bitmap = malloc(mem); | ||
190 | |||
191 | if (!p_disp->bitmap) | ||
192 | { | ||
193 | clear_mem_pool(); | ||
194 | memset(&disp, 0, sizeof(disp)); | ||
195 | p_disp->bitmap = malloc(mem); | ||
196 | if (!p_disp->bitmap) | ||
197 | return PLUGIN_ERROR; | ||
198 | } | ||
199 | |||
200 | fb_data *bmp = (fb_data *)p_disp->bitmap; | ||
201 | |||
202 | // The following code is based on RAINBOW lib jpeg2bmp example: | ||
203 | // https://github.com/Halicery/vc_rainbow/blob/605c045a564dad8e2df84e48914eac3d2d8d4a9b/jpeg2bmp.c | ||
204 | // Primitive yuv-rgb converter for all sub-sampling types, 24-bit BMP only | ||
205 | printf("YUV-to-RGB conversion.. "); | ||
206 | int h0 = j->Hmax / j->Components[0].Hi; | ||
207 | int v0 = j->Vmax / j->Components[0].Vi; | ||
208 | int h1 = j->Hmax / j->Components[1].Hi; | ||
209 | int v1 = j->Vmax / j->Components[1].Vi; | ||
210 | int h2 = j->Hmax / j->Components[2].Hi; | ||
211 | int v2 = j->Vmax / j->Components[2].Vi; | ||
212 | |||
213 | int x, y; | ||
214 | for (y = 0; y < j->Y; y++) | ||
215 | { | ||
216 | if (y%ds != 0) | ||
217 | continue; | ||
218 | |||
219 | TCOEF *C0 = | ||
220 | j->Components[0].du[j->Components[0].du_width * ((y / v0) / 8)] + 8 * ((y / v0) & 7); | ||
221 | TCOEF *C1 = | ||
222 | j->Components[1].du[j->Components[1].du_width * ((y / v1) / 8)] + 8 * ((y / v1) & 7); | ||
223 | TCOEF *C2 = | ||
224 | j->Components[2].du[j->Components[2].du_width * ((y / v2) / 8)] + 8 * ((y / v2) & 7); | ||
225 | |||
226 | for (x = 0; x < j->X; x++) | ||
227 | { | ||
228 | if (x%ds != 0) | ||
229 | continue; | ||
230 | |||
231 | TCOEF c0 = C0[(x / h0 / 8) * 64 + ((x / h0) & 7)]; | ||
232 | TCOEF c1 = C1[(x / h1 / 8) * 64 + ((x / h1) & 7)]; | ||
233 | TCOEF c2 = C2[(x / h2 / 8) * 64 + ((x / h2) & 7)]; | ||
234 | |||
235 | // ITU BT.601 full-range YUV-to-RGB integer approximation | ||
236 | { | ||
237 | int y = (c0 << 5) + 16; | ||
238 | int u = c1 - 128; | ||
239 | int v = c2 - 128; | ||
240 | |||
241 | int b = CLIP[(y + 57 * u)>>5]; // B; | ||
242 | int g = CLIP[(y - 11 * u - 23 * v)>>5]; // G | ||
243 | int r = CLIP[(y + 45 * v)>>5]; // R; | ||
244 | *bmp++= FB_RGBPACK(r,g,b); | ||
245 | } | ||
246 | } | ||
247 | } | ||
248 | printf("done\n"); | ||
249 | return 0; | ||
250 | } | ||
251 | |||
252 | const struct image_decoder image_decoder = { | ||
253 | false, | ||
254 | img_mem, | ||
255 | load_image, | ||
256 | get_image, | ||
257 | draw_image_rect, | ||
258 | }; | ||
259 | |||
260 | IMGDEC_HEADER | ||
diff --git a/apps/plugins/imageviewer/jpegp/jpegp.make b/apps/plugins/imageviewer/jpegp/jpegp.make new file mode 100644 index 0000000000..8d15af3a68 --- /dev/null +++ b/apps/plugins/imageviewer/jpegp/jpegp.make | |||
@@ -0,0 +1,32 @@ | |||
1 | # __________ __ ___. | ||
2 | # Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
3 | # Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
4 | # Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
5 | # Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
6 | # \/ \/ \/ \/ \/ | ||
7 | # $Id$ | ||
8 | # | ||
9 | |||
10 | JPEGPSRCDIR := $(IMGVSRCDIR)/jpegp | ||
11 | JPEGPBUILDDIR := $(IMGVBUILDDIR)/jpegp | ||
12 | |||
13 | JPEGP_SRC := $(call preprocess, $(JPEGPSRCDIR)/SOURCES) | ||
14 | JPEGP_OBJ := $(call c2obj, $(JPEGP_SRC)) | ||
15 | |||
16 | OTHER_SRC += $(JPEGP_SRC) | ||
17 | |||
18 | ROCKS += $(JPEGPBUILDDIR)/jpegp.ovl | ||
19 | |||
20 | $(JPEGPBUILDDIR)/jpegp.refmap: $(JPEGP_OBJ) $(TLSFLIB) | ||
21 | $(JPEGPBUILDDIR)/jpegp.link: $(PLUGIN_LDS) $(JPEGPBUILDDIR)/jpegp.refmap | ||
22 | $(JPEGPBUILDDIR)/jpegp.ovl: $(JPEGP_OBJ) $(TLSFLIB) | ||
23 | |||
24 | JPEGPFLAGS = $(IMGDECFLAGS) | ||
25 | ifndef DEBUG | ||
26 | JPEGPFLAGS += -Os | ||
27 | endif | ||
28 | |||
29 | # Compile plugin with extra flags (adapted from ZXBox) | ||
30 | $(JPEGPBUILDDIR)/%.o: $(JPEGPSRCDIR)/%.c $(JPEGPSRCDIR)/jpegp.make | ||
31 | $(SILENT)mkdir -p $(dir $@) | ||
32 | $(call PRINTS,CC $(subst $(ROOTDIR)/,,$<))$(CC) -I$(dir $<) $(JPEGPFLAGS) -c $< -o $@ | ||
diff --git a/apps/plugins/imageviewer/jpegp/mempool.c b/apps/plugins/imageviewer/jpegp/mempool.c new file mode 100644 index 0000000000..f777ff230a --- /dev/null +++ b/apps/plugins/imageviewer/jpegp/mempool.c | |||
@@ -0,0 +1,50 @@ | |||
1 | #include <inttypes.h> | ||
2 | #include "plugin.h" | ||
3 | |||
4 | static unsigned char *mem_pool; | ||
5 | static unsigned char *mem_pool_start; | ||
6 | static size_t memory_size; | ||
7 | |||
8 | extern void *malloc(size_t size) | ||
9 | { | ||
10 | if (size > memory_size) | ||
11 | return NULL; | ||
12 | |||
13 | memory_size -= size; | ||
14 | unsigned char* ptr = mem_pool; | ||
15 | |||
16 | mem_pool+= size; | ||
17 | return ptr; | ||
18 | } | ||
19 | |||
20 | extern void *calloc(size_t nelem, size_t elem_size) | ||
21 | { | ||
22 | unsigned char* ptr = malloc(nelem*elem_size); | ||
23 | if (!ptr) | ||
24 | return NULL; | ||
25 | rb->memset(ptr, 0, nelem*elem_size); | ||
26 | return ptr; | ||
27 | } | ||
28 | |||
29 | extern void init_mem_pool(const unsigned char *buf, const ssize_t buf_size) | ||
30 | { | ||
31 | //TODO: do we need this alignment? (copied from gif lib) | ||
32 | unsigned char *memory_max; | ||
33 | |||
34 | /* align buffer */ | ||
35 | mem_pool_start = mem_pool = (unsigned char *)((intptr_t)(buf + 3) & ~3); | ||
36 | memory_max = (unsigned char *)((intptr_t)(mem_pool + buf_size) & ~3); | ||
37 | memory_size = memory_max - mem_pool; | ||
38 | } | ||
39 | |||
40 | extern ssize_t freeze_mem_pool(void) | ||
41 | { | ||
42 | mem_pool_start = mem_pool; | ||
43 | return memory_size; | ||
44 | } | ||
45 | |||
46 | extern void clear_mem_pool(void) | ||
47 | { | ||
48 | memory_size += mem_pool - mem_pool_start; | ||
49 | mem_pool = mem_pool_start; | ||
50 | } \ No newline at end of file | ||
diff --git a/apps/plugins/imageviewer/jpegp/mempool.h b/apps/plugins/imageviewer/jpegp/mempool.h new file mode 100644 index 0000000000..55bbdaf363 --- /dev/null +++ b/apps/plugins/imageviewer/jpegp/mempool.h | |||
@@ -0,0 +1,7 @@ | |||
1 | #include <inttypes.h> | ||
2 | |||
3 | extern void init_mem_pool(const unsigned char *buf, const ssize_t buf_size); | ||
4 | extern void *malloc(size_t size); | ||
5 | extern void *calloc(size_t nelem, size_t elem_size); | ||
6 | extern ssize_t freeze_mem_pool(void); | ||
7 | extern void clear_mem_pool(void); | ||
diff --git a/apps/plugins/imageviewer/jpegp/rb_glue.h b/apps/plugins/imageviewer/jpegp/rb_glue.h new file mode 100644 index 0000000000..ce08483deb --- /dev/null +++ b/apps/plugins/imageviewer/jpegp/rb_glue.h | |||
@@ -0,0 +1,35 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * | ||
9 | * $Id$ | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or | ||
12 | * modify it under the terms of the GNU General Public License | ||
13 | * as published by the Free Software Foundation; either version 2 | ||
14 | * of the License, or (at your option) any later version. | ||
15 | * | ||
16 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
17 | * KIND, either express or implied. | ||
18 | * | ||
19 | ****************************************************************************/ | ||
20 | |||
21 | #include "plugin.h" | ||
22 | #include "mempool.h" | ||
23 | |||
24 | //define from rbunicode.h clashes with jpeg81.h struct | ||
25 | #undef COMP | ||
26 | |||
27 | #undef memset | ||
28 | #define memset(a,b,c) rb->memset((a),(b),(c)) | ||
29 | |||
30 | #if defined(DEBUG) || defined(SIMULATOR) | ||
31 | #define printf rb->debugf | ||
32 | #else | ||
33 | #undef printf | ||
34 | #define printf(...) | ||
35 | #endif \ No newline at end of file | ||
diff --git a/manual/plugins/imageviewer.tex b/manual/plugins/imageviewer.tex index cc5b27eee4..0676f21a9f 100644 --- a/manual/plugins/imageviewer.tex +++ b/manual/plugins/imageviewer.tex | |||
@@ -161,7 +161,8 @@ for JPEG images. | |||
161 | \end{description} | 161 | \end{description} |
162 | 162 | ||
163 | \note{ | 163 | \note{ |
164 | Progressive scan and other unusual JPEG files are not supported, and will | 164 | \opt{lcd_color}{Progressive scan is supported. Unsupported JPEG files} |
165 | \nopt{lcd_color}{Progressive scan and other unusual JPEG files are not supported, and} will | ||
165 | result in various ``unsupported xx'' messages. Processing could also fail if the | 166 | result in various ``unsupported xx'' messages. Processing could also fail if the |
166 | image is too big to decode which will be explained by a respective message. | 167 | image is too big to decode which will be explained by a respective message. |
167 | 168 | ||