jpeg,png: Merge user interface code and plugin entry point of the two plugins (part...
[kugel-rb.git] / apps / plugins / imageviewer / jpeg / jpeg.c
blobb4ac6c0fce16196de9b0e2e3021042dd79a1c22a
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * JPEG image viewer
11 * (This is a real mess if it has to be coded in one single C file)
13 * File scrolling addition (C) 2005 Alexander Spyridakis
14 * Copyright (C) 2004 Jörg Hohensohn aka [IDC]Dragon
15 * Heavily borrowed from the IJG implementation (C) Thomas G. Lane
16 * Small & fast downscaling IDCT (C) 2002 by Guido Vollbeding JPEGclub.org
18 * This program is free software; you can redistribute it and/or
19 * modify it under the terms of the GNU General Public License
20 * as published by the Free Software Foundation; either version 2
21 * of the License, or (at your option) any later version.
23 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
24 * KIND, either express or implied.
26 ****************************************************************************/
28 #include "plugin.h"
30 #include "../imageviewer.h"
31 #include "jpeg_decoder.h"
33 #ifdef HAVE_LCD_COLOR
34 #include "yuv2rgb.h"
35 #endif
37 /**************** begin Application ********************/
39 /************************* Types ***************************/
41 struct t_disp
43 #ifdef HAVE_LCD_COLOR
44 unsigned char* bitmap[3]; /* Y, Cr, Cb */
45 int csub_x, csub_y;
46 #else
47 unsigned char* bitmap[1]; /* Y only */
48 #endif
49 int stride;
52 /************************* Globals ***************************/
54 /* decompressed image in the possible sizes (1,2,4,8), wasting the other */
55 static struct t_disp disp[9];
57 /* my memory pool (from the mp3 buffer) */
58 static char print[32]; /* use a common snprintf() buffer */
60 /* the root of the images, hereafter are decompresed ones */
61 static unsigned char* buf_root;
62 static int root_size;
64 /* up to here currently used by image(s) */
65 static unsigned char* buf_images;
66 static ssize_t buf_images_size;
68 static struct jpeg jpg; /* too large for stack */
70 /************************* Implementation ***************************/
72 bool img_ext(const char *ext)
74 if(!ext)
75 return false;
76 if(!rb->strcasecmp(ext,".jpg") ||
77 !rb->strcasecmp(ext,".jpe") ||
78 !rb->strcasecmp(ext,".jpeg"))
79 return true;
80 else
81 return false;
84 void draw_image_rect(struct image_info *info,
85 int x, int y, int width, int height)
87 struct t_disp* pdisp = (struct t_disp*)info->data;
88 #ifdef HAVE_LCD_COLOR
89 yuv_bitmap_part(
90 pdisp->bitmap, pdisp->csub_x, pdisp->csub_y,
91 info->x + x, info->y + y, pdisp->stride,
92 x + MAX(0, (LCD_WIDTH - info->width) / 2),
93 y + MAX(0, (LCD_HEIGHT - info->height) / 2),
94 width, height,
95 settings.jpeg_colour_mode, settings.jpeg_dither_mode);
96 #else
97 MYXLCD(gray_bitmap_part)(
98 pdisp->bitmap[0], info->x + x, info->y + y, pdisp->stride,
99 x + MAX(0, (LCD_WIDTH-info->width)/2),
100 y + MAX(0, (LCD_HEIGHT-info->height)/2),
101 width, height);
102 #endif
105 int img_mem(int ds)
107 int size;
108 struct jpeg *p_jpg = &jpg;
110 size = (p_jpg->x_phys/ds/p_jpg->subsample_x[0])
111 * (p_jpg->y_phys/ds/p_jpg->subsample_y[0]);
112 #ifdef HAVE_LCD_COLOR
113 if (p_jpg->blocks > 1) /* colour, add requirements for chroma */
115 size += (p_jpg->x_phys/ds/p_jpg->subsample_x[1])
116 * (p_jpg->y_phys/ds/p_jpg->subsample_y[1]);
117 size += (p_jpg->x_phys/ds/p_jpg->subsample_x[2])
118 * (p_jpg->y_phys/ds/p_jpg->subsample_y[2]);
120 #endif
121 return size;
124 int load_image(char *filename, struct image_info *info,
125 unsigned char *buf, ssize_t *buf_size)
127 int fd;
128 int filesize;
129 unsigned char* buf_jpeg; /* compressed JPEG image */
130 int status;
131 struct jpeg *p_jpg = &jpg;
133 rb->memset(&disp, 0, sizeof(disp));
134 rb->memset(&jpg, 0, sizeof(jpg));
136 fd = rb->open(filename, O_RDONLY);
137 if (fd < 0)
139 rb->splashf(HZ, "err opening %s:%d", filename, fd);
140 return PLUGIN_ERROR;
142 filesize = rb->filesize(fd);
144 /* allocate JPEG buffer */
145 buf_jpeg = buf;
147 /* we can start the decompressed images behind it */
148 buf_images = buf_root = buf + filesize;
149 buf_images_size = root_size = *buf_size - filesize;
151 if (buf_images_size <= 0)
153 rb->close(fd);
154 return PLUGIN_OUTOFMEM;
157 if(!running_slideshow)
159 rb->snprintf(print, sizeof(print), "%s:", rb->strrchr(filename,'/')+1);
160 rb->lcd_puts(0, 0, print);
161 rb->lcd_update();
163 rb->snprintf(print, sizeof(print), "loading %d bytes", filesize);
164 rb->lcd_puts(0, 1, print);
165 rb->lcd_update();
168 rb->read(fd, buf_jpeg, filesize);
169 rb->close(fd);
171 if(!running_slideshow)
173 rb->snprintf(print, sizeof(print), "decoding markers");
174 rb->lcd_puts(0, 2, print);
175 rb->lcd_update();
177 #ifdef DISK_SPINDOWN
178 else if(immediate_ata_off)
180 /* running slideshow and time is long enough: power down disk */
181 rb->storage_sleep();
183 #endif
185 /* process markers, unstuffing */
186 status = process_markers(buf_jpeg, filesize, p_jpg);
188 if (status < 0 || (status & (DQT | SOF0)) != (DQT | SOF0))
189 { /* bad format or minimum components not contained */
190 rb->splashf(HZ, "unsupported %d", status);
191 return PLUGIN_ERROR;
194 if (!(status & DHT)) /* if no Huffman table present: */
195 default_huff_tbl(p_jpg); /* use default */
196 build_lut(p_jpg); /* derive Huffman and other lookup-tables */
198 if(!running_slideshow)
200 rb->snprintf(print, sizeof(print), "image %dx%d",
201 p_jpg->x_size, p_jpg->y_size);
202 rb->lcd_puts(0, 2, print);
203 rb->lcd_update();
206 info->x_size = p_jpg->x_size;
207 info->y_size = p_jpg->y_size;
208 *buf_size = buf_images_size;
209 return PLUGIN_OK;
212 int get_image(struct image_info *info, int ds)
214 int w, h; /* used to center output */
215 int size; /* decompressed image size */
216 long time; /* measured ticks */
217 int status;
218 struct jpeg* p_jpg = &jpg;
219 struct t_disp* p_disp = &disp[ds]; /* short cut */
221 info->width = p_jpg->x_size / ds;
222 info->height = p_jpg->y_size / ds;
223 info->data = p_disp;
225 if (p_disp->bitmap[0] != NULL)
227 /* we still have it */
228 return PLUGIN_OK;
231 /* assign image buffer */
233 /* physical size needed for decoding */
234 size = img_mem(ds);
235 if (buf_images_size <= size)
236 { /* have to discard the current */
237 int i;
238 for (i=1; i<=8; i++)
239 disp[i].bitmap[0] = NULL; /* invalidate all bitmaps */
240 buf_images = buf_root; /* start again from the beginning of the buffer */
241 buf_images_size = root_size;
244 #ifdef HAVE_LCD_COLOR
245 if (p_jpg->blocks > 1) /* colour jpeg */
247 int i;
249 for (i = 1; i < 3; i++)
251 size = (p_jpg->x_phys / ds / p_jpg->subsample_x[i])
252 * (p_jpg->y_phys / ds / p_jpg->subsample_y[i]);
253 p_disp->bitmap[i] = buf_images;
254 buf_images += size;
255 buf_images_size -= size;
257 p_disp->csub_x = p_jpg->subsample_x[1];
258 p_disp->csub_y = p_jpg->subsample_y[1];
260 else
262 p_disp->csub_x = p_disp->csub_y = 0;
263 p_disp->bitmap[1] = p_disp->bitmap[2] = buf_images;
265 #endif
266 /* size may be less when decoded (if height is not block aligned) */
267 size = (p_jpg->x_phys/ds) * (p_jpg->y_size/ds);
268 p_disp->bitmap[0] = buf_images;
269 buf_images += size;
270 buf_images_size -= size;
272 if(!running_slideshow)
274 rb->snprintf(print, sizeof(print), "decoding %d*%d",
275 p_jpg->x_size/ds, p_jpg->y_size/ds);
276 rb->lcd_puts(0, 3, print);
277 rb->lcd_update();
280 /* update image properties */
281 p_disp->stride = p_jpg->x_phys / ds; /* use physical size for stride */
283 /* the actual decoding */
284 time = *rb->current_tick;
285 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
286 rb->cpu_boost(true);
287 status = jpeg_decode(p_jpg, p_disp->bitmap, ds, cb_progress);
288 rb->cpu_boost(false);
289 #else
290 status = jpeg_decode(p_jpg, p_disp->bitmap, ds, cb_progress);
291 #endif
292 if (status)
294 rb->splashf(HZ, "decode error %d", status);
295 return PLUGIN_ERROR;
297 time = *rb->current_tick - time;
299 if(!running_slideshow)
301 rb->snprintf(print, sizeof(print), " %ld.%02ld sec ", time/HZ, time%HZ);
302 rb->lcd_getstringsize(print, &w, &h); /* centered in progress bar */
303 rb->lcd_putsxy((LCD_WIDTH - w)/2, LCD_HEIGHT - h, print);
304 rb->lcd_update();
307 return PLUGIN_OK;