Rearange menu of mpegplayer. Add new menu with "settings" and "quit", and remove...
[kugel-rb.git] / apps / plugins / jpeg / yuv2rgb.c
blobed88d5416a1de87fbcdbf1b275d0e7816d36ef06
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"
29 #include "yuv2rgb.h"
32 * Conversion of full 0-255 range YCrCb to RGB:
33 * |R| |1.000000 -0.000001 1.402000| |Y'|
34 * |G| = |1.000000 -0.334136 -0.714136| |Pb|
35 * |B| |1.000000 1.772000 0.000000| |Pr|
36 * Scaled (yields s15-bit output):
37 * |R| |128 0 179| |Y |
38 * |G| = |128 -43 -91| |Cb - 128|
39 * |B| |128 227 0| |Cr - 128|
41 #define YFAC 128
42 #define RVFAC 179
43 #define GUFAC (-43)
44 #define GVFAC (-91)
45 #define BUFAC 227
46 #define YUV_WHITE (255*YFAC)
47 #define NODITHER_DELTA (127*YFAC)
48 #define COMPONENT_SHIFT 15
49 #define MATRIX_SHIFT 7
51 static inline int clamp_component_bits(int x, int bits)
53 if ((unsigned)x > (1u << bits) - 1)
54 x = x < 0 ? 0 : (1 << bits) - 1;
55 return x;
58 static inline int component_to_lcd(int x, int bits, int delta)
60 /* Formula used in core bitmap loader. */
61 return (((1 << bits) - 1)*x + (x >> (8 - bits)) + delta) >> COMPONENT_SHIFT;
64 static inline int lcd_to_component(int x, int bits, int delta)
66 /* Reasonable, approximate reversal to get a full range back from the
67 quantized value. */
68 return YUV_WHITE*x / ((1 << bits) - 1);
69 (void)delta;
72 #define RED 0
73 #define GRN 1
74 #define BLU 2
76 struct rgb_err
78 int16_t errbuf[LCD_WIDTH+2]; /* Error record for line below */
79 } rgb_err_buffers[3];
81 struct rgb_pixel
83 int r, g, b; /* Current pixel components in s16.0 */
84 int inc; /* Current line increment (-1 or 1) */
85 int row; /* Current row in source image */
86 int col; /* Current column in source image */
87 int ce[3]; /* Errors to apply to current pixel */
88 struct rgb_err *e; /* RED, GRN, BLU */
89 int epos; /* Current position in error record */
92 struct rgb_pixel *pixel;
94 /** round and truncate to lcd depth **/
95 static fb_data pixel_to_lcd_colour(void)
97 struct rgb_pixel *p = pixel;
98 int r, g, b;
100 r = component_to_lcd(p->r, LCD_RED_BITS, NODITHER_DELTA);
101 r = clamp_component_bits(r, LCD_RED_BITS);
103 g = component_to_lcd(p->g, LCD_GREEN_BITS, NODITHER_DELTA);
104 g = clamp_component_bits(g, LCD_GREEN_BITS);
106 b = component_to_lcd(p->b, LCD_BLUE_BITS, NODITHER_DELTA);
107 b = clamp_component_bits(b, LCD_BLUE_BITS);
109 return LCD_RGBPACK_LCD(r, g, b);
112 /** write a monochrome pixel to the colour LCD **/
113 static fb_data pixel_to_lcd_gray(void)
115 int r, g, b;
117 g = clamp_component(pixel->g);
118 r = component_to_lcd(g, LCD_RED_BITS, NODITHER_DELTA);
119 b = component_to_lcd(g, LCD_BLUE_BITS, NODITHER_DELTA);
120 g = component_to_lcd(g, LCD_GREEN_BITS, NODITHER_DELTA);
122 return LCD_RGBPACK_LCD(r, g, b);
126 * Bayer ordered dithering - swiped from the core bitmap loader.
128 static fb_data pixel_odither_to_lcd(void)
130 /* canonical ordered dither matrix */
131 static const unsigned char dither_matrix[16][16] = {
132 { 0,192, 48,240, 12,204, 60,252, 3,195, 51,243, 15,207, 63,255 },
133 { 128, 64,176,112,140, 76,188,124,131, 67,179,115,143, 79,191,127 },
134 { 32,224, 16,208, 44,236, 28,220, 35,227, 19,211, 47,239, 31,223 },
135 { 160, 96,144, 80,172,108,156, 92,163, 99,147, 83,175,111,159, 95 },
136 { 8,200, 56,248, 4,196, 52,244, 11,203, 59,251, 7,199, 55,247 },
137 { 136, 72,184,120,132, 68,180,116,139, 75,187,123,135, 71,183,119 },
138 { 40,232, 24,216, 36,228, 20,212, 43,235, 27,219, 39,231, 23,215 },
139 { 168,104,152, 88,164,100,148, 84,171,107,155, 91,167,103,151, 87 },
140 { 2,194, 50,242, 14,206, 62,254, 1,193, 49,241, 13,205, 61,253 },
141 { 130, 66,178,114,142, 78,190,126,129, 65,177,113,141, 77,189,125 },
142 { 34,226, 18,210, 46,238, 30,222, 33,225, 17,209, 45,237, 29,221 },
143 { 162, 98,146, 82,174,110,158, 94,161, 97,145, 81,173,109,157, 93 },
144 { 10,202, 58,250, 6,198, 54,246, 9,201, 57,249, 5,197, 53,245 },
145 { 138, 74,186,122,134, 70,182,118,137, 73,185,121,133, 69,181,117 },
146 { 42,234, 26,218, 38,230, 22,214, 41,233, 25,217, 37,229, 21,213 },
147 { 170,106,154, 90,166,102,150, 86,169,105,153, 89,165,101,149, 85 }
150 struct rgb_pixel *p = pixel;
151 int r, g, b, delta;
153 delta = dither_matrix[p->col & 15][p->row & 15] << MATRIX_SHIFT;
155 r = component_to_lcd(p->r, LCD_RED_BITS, delta);
156 r = clamp_component_bits(r, LCD_RED_BITS);
158 g = component_to_lcd(p->g, LCD_GREEN_BITS, delta);
159 g = clamp_component_bits(g, LCD_GREEN_BITS);
161 b = component_to_lcd(p->b, LCD_BLUE_BITS, delta);
162 b = clamp_component_bits(b, LCD_BLUE_BITS);
164 p->col += p->inc;
166 return LCD_RGBPACK_LCD(r, g, b);
170 * Floyd/Steinberg dither to lcd depth.
172 * Apply filter to each component in serpentine pattern. Kernel shown for
173 * L->R scan. Kernel is reversed for R->L.
174 * * 7
175 * 3 5 1 (1/16)
177 static inline void distribute_error(int *ce, struct rgb_err *e,
178 int err, int epos, int inc)
180 *ce = (7*err >> 4) + e->errbuf[epos+inc];
181 e->errbuf[epos+inc] = err >> 4;
182 e->errbuf[epos] += 5*err >> 4;
183 e->errbuf[epos-inc] += 3*err >> 4;
186 static fb_data pixel_fsdither_to_lcd(void)
188 struct rgb_pixel *p = pixel;
189 int rc, gc, bc, r, g, b;
190 int inc, epos;
192 /* Full components with error terms */
193 rc = p->r + p->ce[RED];
194 r = component_to_lcd(rc, LCD_RED_BITS, 0);
195 r = clamp_component_bits(r, LCD_RED_BITS);
197 gc = p->g + p->ce[GRN];
198 g = component_to_lcd(gc, LCD_GREEN_BITS, 0);
199 g = clamp_component_bits(g, LCD_GREEN_BITS);
201 bc = p->b + p->ce[BLU];
202 b = component_to_lcd(bc, LCD_BLUE_BITS, 0);
203 b = clamp_component_bits(b, LCD_BLUE_BITS);
205 /* Get pixel errors */
206 rc -= lcd_to_component(r, LCD_RED_BITS, 0);
207 gc -= lcd_to_component(g, LCD_GREEN_BITS, 0);
208 bc -= lcd_to_component(b, LCD_BLUE_BITS, 0);
210 /* Spead error to surrounding pixels. */
211 inc = p->inc;
212 epos = p->epos;
213 p->epos += inc;
215 distribute_error(&p->ce[RED], &p->e[RED], rc, epos, inc);
216 distribute_error(&p->ce[GRN], &p->e[GRN], gc, epos, inc);
217 distribute_error(&p->ce[BLU], &p->e[BLU], bc, epos, inc);
219 /* Pack and return pixel */
220 return LCD_RGBPACK_LCD(r, g, b);
223 /* Functions for each output mode, colour then grayscale. */
224 static fb_data (* const pixel_funcs[COLOUR_NUM_MODES][DITHER_NUM_MODES])(void) =
226 [COLOURMODE_COLOUR] =
228 [DITHER_NONE] = pixel_to_lcd_colour,
229 [DITHER_ORDERED] = pixel_odither_to_lcd,
230 [DITHER_DIFFUSION] = pixel_fsdither_to_lcd,
232 [COLOURMODE_GRAY] =
234 [DITHER_NONE] = pixel_to_lcd_gray,
235 [DITHER_ORDERED] = pixel_odither_to_lcd,
236 [DITHER_DIFFUSION] = pixel_fsdither_to_lcd,
241 * Draw a partial YUV colour bitmap
243 * Runs serpentine pattern when dithering is DITHER_DIFFUSION, else scan is
244 * always L->R.
246 void yuv_bitmap_part(unsigned char *src[3], int csub_x, int csub_y,
247 int src_x, int src_y, int stride,
248 int x, int y, int width, int height,
249 int colour_mode, int dither_mode)
251 fb_data *dst, *dst_end;
252 fb_data (*pixel_func)(void);
253 struct rgb_pixel px;
255 if (x + width > LCD_WIDTH)
256 width = LCD_WIDTH - x; /* Clip right */
257 if (x < 0)
258 width += x, x = 0; /* Clip left */
259 if (width <= 0)
260 return; /* nothing left to do */
262 if (y + height > LCD_HEIGHT)
263 height = LCD_HEIGHT - y; /* Clip bottom */
264 if (y < 0)
265 height += y, y = 0; /* Clip top */
266 if (height <= 0)
267 return; /* nothing left to do */
269 pixel = &px;
271 dst = rb->lcd_framebuffer + LCD_WIDTH * y + x;
272 dst_end = dst + LCD_WIDTH * height;
274 if (colour_mode == COLOURMODE_GRAY)
275 csub_y = 0; /* Ignore Cb, Cr */
277 pixel_func = pixel_funcs[colour_mode]
278 [dither_mode];
280 if (dither_mode == DITHER_DIFFUSION)
282 /* Reset error terms. */
283 px.e = rgb_err_buffers;
284 px.ce[RED] = px.ce[GRN] = px.ce[BLU] = 0;
285 rb->memset(px.e, 0, 3*sizeof (struct rgb_err));
290 fb_data *dst_row, *row_end;
291 const unsigned char *ysrc;
292 px.inc = 1;
294 if (dither_mode == DITHER_DIFFUSION)
296 /* Use R->L scan on odd lines */
297 px.inc -= (src_y & 1) << 1;
298 px.epos = x + 1;
300 if (px.inc < 0)
301 px.epos += width - 1;
304 if (px.inc == 1)
306 /* Scan is L->R */
307 dst_row = dst;
308 row_end = dst_row + width;
309 px.col = src_x;
311 else
313 /* Scan is R->L */
314 row_end = dst - 1;
315 dst_row = row_end + width;
316 px.col = src_x + width - 1;
319 ysrc = src[0] + stride * src_y + px.col;
320 px.row = src_y;
322 /* Do one row of pixels */
323 if (csub_y) /* colour */
325 /* upsampling, YUV->RGB conversion and reduction to RGB565 in one go */
326 const unsigned char *usrc, *vsrc;
328 usrc = src[1] + (stride/csub_x) * (src_y/csub_y)
329 + (px.col/csub_x);
330 vsrc = src[2] + (stride/csub_x) * (src_y/csub_y)
331 + (px.col/csub_x);
332 int xphase = px.col % csub_x;
333 int xphase_reset = px.inc * csub_x;
334 int y, v, u, rv, guv, bu;
336 v = *vsrc - 128;
337 vsrc += px.inc;
338 u = *usrc - 128;
339 usrc += px.inc;
340 rv = RVFAC*v;
341 guv = GUFAC*u + GVFAC*v;
342 bu = BUFAC*u;
344 while (1)
346 y = YFAC*(*ysrc);
347 ysrc += px.inc;
348 px.r = y + rv;
349 px.g = y + guv;
350 px.b = y + bu;
352 *dst_row = pixel_func();
353 dst_row += px.inc;
355 if (dst_row == row_end)
356 break;
358 xphase += px.inc;
359 if ((unsigned)xphase < (unsigned)csub_x)
360 continue;
362 /* fetch new chromas */
363 v = *vsrc - 128;
364 vsrc += px.inc;
365 u = *usrc - 128;
366 usrc += px.inc;
367 rv = RVFAC*v;
368 guv = GUFAC*u + GVFAC*v;
369 bu = BUFAC*u;
371 xphase -= xphase_reset;
374 else /* monochrome */
378 /* Set all components the same for dithering purposes */
379 px.g = px.r = px.b = YFAC*(*ysrc);
380 *dst_row = pixel_func();
381 ysrc += px.inc;
382 dst_row += px.inc;
384 while (dst_row != row_end);
387 src_y++;
388 dst += LCD_WIDTH;
390 while (dst < dst_end);