diff options
Diffstat (limited to 'apps/plugins/imageviewer/jpegp/jpegp.c')
-rw-r--r-- | apps/plugins/imageviewer/jpegp/jpegp.c | 260 |
1 files changed, 260 insertions, 0 deletions
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 | ||