summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoman Artiukhin <bahusdrive@gmail.com>2024-10-09 19:39:15 +0300
committerSolomon Peachy <pizza@shaftnet.org>2024-10-14 09:19:34 -0400
commitb8238f7b20d401926640824342fe11ff92c6fcf0 (patch)
tree297b328018b7f0ab0d6cc3d4736fce4964409d99
parent64ad7354b6bbc61782935f64873afdf2c0a18bc1 (diff)
downloadrockbox-b8238f7b20d401926640824342fe11ff92c6fcf0.tar.gz
rockbox-b8238f7b20d401926640824342fe11ff92c6fcf0.zip
imageviewer: Initial support for JPEG progressive images. Add decoder
Added jpeg decoder jpegp.c using RAINBOW lib. Currently enabled only for pictures not supported by old decoder (as old decoder more optimized for low mem targets) Someone TODO: * Old decoder has optimized downscale logic which new decoder doesn't have (it gives big difference in required memory and time for decoding). This logic should be ported/adapted if possible. * Add smooth downscaling. * Grayscale support Change-Id: Ie96bc62848b51cc6a3942f8e069ec6ab02dc1c56
-rw-r--r--apps/plugins/CATEGORIES1
-rw-r--r--apps/plugins/imageviewer/SUBDIRS1
-rw-r--r--apps/plugins/imageviewer/image_decoder.c5
-rw-r--r--apps/plugins/imageviewer/image_decoder.h2
-rw-r--r--apps/plugins/imageviewer/imageviewer.c9
-rw-r--r--apps/plugins/imageviewer/imageviewer.h1
-rw-r--r--apps/plugins/imageviewer/jpeg/jpeg.c4
-rw-r--r--apps/plugins/imageviewer/jpegp/BUFFILEGETC.c94
-rw-r--r--apps/plugins/imageviewer/jpegp/FILEGETC.c71
-rw-r--r--apps/plugins/imageviewer/jpegp/GETC.h14
-rw-r--r--apps/plugins/imageviewer/jpegp/SOURCES6
-rw-r--r--apps/plugins/imageviewer/jpegp/jpeg81.c24
-rw-r--r--apps/plugins/imageviewer/jpegp/jpeg81.h2
-rw-r--r--apps/plugins/imageviewer/jpegp/jpegp.c260
-rw-r--r--apps/plugins/imageviewer/jpegp/jpegp.make32
-rw-r--r--apps/plugins/imageviewer/jpegp/mempool.c50
-rw-r--r--apps/plugins/imageviewer/jpegp/mempool.h7
-rw-r--r--apps/plugins/imageviewer/jpegp/rb_glue.h35
-rw-r--r--manual/plugins/imageviewer.tex3
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
51jackpot,games 51jackpot,games
52jewels,games 52jewels,games
53jpeg,viewers 53jpeg,viewers
54jpegp,viewers
54keybox,apps 55keybox,apps
55keyremap,apps 56keyremap,apps
56lamp,apps 57lamp,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
3png 3png
4#ifdef HAVE_LCD_COLOR 4#ifdef HAVE_LCD_COLOR
5ppm 5ppm
6jpegp
6#endif 7#endif
7gif 8gif
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
26static const char *decoder_names[MAX_IMAGE_TYPES] = { 26static 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
857reload_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
7static int fd;
8static unsigned char buff[256]; //TODO: Adjust it...
9static int length = 0;
10static int cur_buff_pos = 0;
11static int file_pos = 0;
12
13extern 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
27extern int GETWbi(void) // 16-bit big-endian
28{
29 return ( GETC()<<8 ) | GETC();
30}
31
32extern int GETDbi(void) // 32-bit big-endian
33{
34 return ( GETC()<<24 ) | ( GETC()<<16 ) | ( GETC()<<8 ) | GETC();
35}
36
37extern int GETWli(void) // 16-bit little-endian
38{
39 return GETC() | ( GETC()<<8 );
40}
41
42extern int GETDli(void) // 32-bit little-endian
43{
44 return GETC() | ( GETC()<<8 ) | ( GETC()<<16 ) | ( GETC()<<24 );
45}
46
47// seek
48
49extern 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
61extern void POS(int d)
62{
63 cur_buff_pos = length = 0;
64 file_pos = d;
65 rb->lseek(fd, d, SEEK_SET);
66}
67
68extern int TELL(void)
69{
70 return file_pos + cur_buff_pos - length;
71}
72
73// OPEN/CLOSE file
74
75extern 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
90extern 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
3static int fd;
4
5extern 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
14extern int GETWbi(void) // 16-bit big-endian
15{
16 return ( GETC()<<8 ) | GETC();
17}
18
19extern int GETDbi(void) // 32-bit big-endian
20{
21 return ( GETC()<<24 ) | ( GETC()<<16 ) | ( GETC()<<8 ) | GETC();
22}
23
24extern int GETWli(void) // 16-bit little-endian
25{
26 return GETC() | ( GETC()<<8 );
27}
28
29extern int GETDli(void) // 32-bit little-endian
30{
31 return GETC() | ( GETC()<<8 ) | ( GETC()<<16 ) | ( GETC()<<24 );
32}
33
34// seek
35
36extern void SEEK(int d)
37{
38 rb->lseek(fd, d, SEEK_CUR);
39}
40
41extern void POS(int d)
42{
43 rb->lseek(fd, d, SEEK_SET);
44}
45
46extern int TELL(void)
47{
48 return rb->lseek(fd, 0, SEEK_CUR);
49}
50
51// OPEN/CLOSE file
52
53extern 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
68extern 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
40extern int GETC(); 40extern int GETC(void);
41 41
42// Multibyte helpers 42// Multibyte helpers
43extern int GETWbi(); // read word (16-bit) big-endian 43extern int GETWbi(void); // read word (16-bit) big-endian
44extern int GETWli(); // little-endian 44extern int GETWli(void); // little-endian
45extern int GETDbi(); // read double word (32-bit) big-endian 45extern int GETDbi(void); // read double word (32-bit) big-endian
46extern int GETDli(); // little-endian 46extern int GETDli(void); // little-endian
47 47
48// positioning 48// positioning
49extern void SEEK(int); // move relative to current 49extern void SEEK(int); // move relative to current
50extern void POS(int); // move absolute position (TIFF) 50extern void POS(int); // move absolute position (TIFF)
51extern int TELL(); // read actual position 51extern 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
55extern void *OPEN(char*); 55extern void *OPEN(char*);
56extern void CLOSE(); 56extern 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 @@
1jpegp.c
2//FILEGETC.c
3BUFFILEGETC.c
4jpeg81.c
5idct.c
6mempool.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
51static int P1(struct COMP *C, TSAMP *samp) // Px = Ra 51static 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
66static int P4(struct COMP *C, TSAMP *samp) // Px = Ra + Rb Rc 66static 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
71static int P5(struct COMP *C, TSAMP *samp) // Px = Ra + ((Rb Rc)/2) 71static 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
76static int P6(struct COMP *C, TSAMP *samp) // Px = Rb + ((Ra Rc)/2) 76static 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
147extern int JPEGDecode(struct JPEGD *j); 147extern 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
13struct 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 */
21static struct t_disp disp[9];
22
23static struct JPEGD jpg; /* too large for stack */
24
25/************************* Implementation ***************************/
26
27static 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
47static 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) */
54static char print[32]; /* use a common snprintf() buffer */
55
56static 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
98static 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
170static 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
252const struct image_decoder image_decoder = {
253 false,
254 img_mem,
255 load_image,
256 get_image,
257 draw_image_rect,
258};
259
260IMGDEC_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
10JPEGPSRCDIR := $(IMGVSRCDIR)/jpegp
11JPEGPBUILDDIR := $(IMGVBUILDDIR)/jpegp
12
13JPEGP_SRC := $(call preprocess, $(JPEGPSRCDIR)/SOURCES)
14JPEGP_OBJ := $(call c2obj, $(JPEGP_SRC))
15
16OTHER_SRC += $(JPEGP_SRC)
17
18ROCKS += $(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
24JPEGPFLAGS = $(IMGDECFLAGS)
25ifndef DEBUG
26JPEGPFLAGS += -Os
27endif
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
4static unsigned char *mem_pool;
5static unsigned char *mem_pool_start;
6static size_t memory_size;
7
8extern 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
20extern 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
29extern 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
40extern ssize_t freeze_mem_pool(void)
41{
42 mem_pool_start = mem_pool;
43 return memory_size;
44}
45
46extern 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
3extern void init_mem_pool(const unsigned char *buf, const ssize_t buf_size);
4extern void *malloc(size_t size);
5extern void *calloc(size_t nelem, size_t elem_size);
6extern ssize_t freeze_mem_pool(void);
7extern 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{
164Progressive 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
165result in various ``unsupported xx'' messages. Processing could also fail if the 166result in various ``unsupported xx'' messages. Processing could also fail if the
166image is too big to decode which will be explained by a respective message. 167image is too big to decode which will be explained by a respective message.
167 168