diff options
Diffstat (limited to 'apps/plugins')
-rw-r--r-- | apps/plugins/jpeg.c | 625 |
1 files changed, 507 insertions, 118 deletions
diff --git a/apps/plugins/jpeg.c b/apps/plugins/jpeg.c index dbe7270d18..a330748404 100644 --- a/apps/plugins/jpeg.c +++ b/apps/plugins/jpeg.c | |||
@@ -31,6 +31,10 @@ | |||
31 | #include "gray.h" | 31 | #include "gray.h" |
32 | #include "xlcd.h" | 32 | #include "xlcd.h" |
33 | 33 | ||
34 | #ifdef HAVE_LCD_COLOR | ||
35 | #include "lib/configfile.h" | ||
36 | #endif | ||
37 | |||
34 | PLUGIN_HEADER | 38 | PLUGIN_HEADER |
35 | 39 | ||
36 | /* variable button definitions */ | 40 | /* variable button definitions */ |
@@ -192,7 +196,49 @@ static int running_slideshow = false; /* loading image because of slideshw */ | |||
192 | #ifndef SIMULATOR | 196 | #ifndef SIMULATOR |
193 | static int immediate_ata_off = false; /* power down disk after loading */ | 197 | static int immediate_ata_off = false; /* power down disk after loading */ |
194 | #endif | 198 | #endif |
195 | static int button_timeout = HZ*5; | 199 | static int button_timeout = HZ*5; |
200 | |||
201 | #ifdef HAVE_LCD_COLOR | ||
202 | |||
203 | /* Persistent configuration - only needed for color displays atm */ | ||
204 | #define JPEG_CONFIGFILE "jpeg.cfg" | ||
205 | #define JPEG_SETTINGS_MINVERSION 1 | ||
206 | #define JPEG_SETTINGS_VERSION 1 | ||
207 | |||
208 | enum color_modes | ||
209 | { | ||
210 | COLOURMODE_COLOUR = 0, | ||
211 | COLOURMODE_GRAY, | ||
212 | COLOUR_NUM_MODES | ||
213 | }; | ||
214 | |||
215 | enum dither_modes | ||
216 | { | ||
217 | DITHER_NONE = 0, /* No dithering */ | ||
218 | DITHER_ORDERED, /* Bayer ordered */ | ||
219 | DITHER_DIFFUSION, /* Floyd/Steinberg error diffusion */ | ||
220 | DITHER_NUM_MODES | ||
221 | }; | ||
222 | |||
223 | struct jpeg_settings | ||
224 | { | ||
225 | int colour_mode; | ||
226 | int dither_mode; | ||
227 | }; | ||
228 | |||
229 | static struct jpeg_settings jpeg_settings = | ||
230 | { COLOURMODE_COLOUR, DITHER_NONE }; | ||
231 | static struct jpeg_settings old_settings; | ||
232 | |||
233 | static struct configdata jpeg_config[] = | ||
234 | { | ||
235 | { TYPE_ENUM, 0, COLOUR_NUM_MODES, &jpeg_settings.colour_mode, | ||
236 | "Colour Mode", (char *[]){ "Colour", "Grayscale" }, NULL }, | ||
237 | { TYPE_ENUM, 0, DITHER_NUM_MODES, &jpeg_settings.dither_mode, | ||
238 | "Dither Mode", (char *[]){ "None", "Ordered", "Diffusion" }, NULL }, | ||
239 | }; | ||
240 | |||
241 | #endif /* HAVE_LCD_COLOR */ | ||
196 | #if LCD_DEPTH > 1 | 242 | #if LCD_DEPTH > 1 |
197 | fb_data* old_backdrop; | 243 | fb_data* old_backdrop; |
198 | #endif | 244 | #endif |
@@ -1852,143 +1898,369 @@ bool plug_buf = false; | |||
1852 | /************************* Implementation ***************************/ | 1898 | /************************* Implementation ***************************/ |
1853 | 1899 | ||
1854 | #ifdef HAVE_LCD_COLOR | 1900 | #ifdef HAVE_LCD_COLOR |
1901 | /* | ||
1902 | * Conversion of full 0-255 range YCrCb to RGB: | ||
1903 | * |R| |1.000000 -0.000001 1.402000| |Y'| | ||
1904 | * |G| = |1.000000 -0.334136 -0.714136| |Pb| | ||
1905 | * |B| |1.000000 1.772000 0.000000| |Pr| | ||
1906 | * Scaled (yields s15-bit output): | ||
1907 | * |R| |128 0 179| |Y | | ||
1908 | * |G| = |128 -43 -91| |Cb - 128| | ||
1909 | * |B| |128 227 0| |Cr - 128| | ||
1910 | */ | ||
1911 | #define YFAC 128 | ||
1912 | #define RVFAC 179 | ||
1913 | #define GUFAC (-43) | ||
1914 | #define GVFAC (-91) | ||
1915 | #define BUFAC 227 | ||
1916 | #define YUV_WHITE (255*YFAC) | ||
1917 | #define NODITHER_DELTA (127*YFAC) | ||
1918 | #define COMPONENT_SHIFT 15 | ||
1919 | #define MATRIX_SHIFT 7 | ||
1920 | |||
1921 | static inline int clamp_component(int x) | ||
1922 | { | ||
1923 | if ((unsigned)x > YUV_WHITE) | ||
1924 | x = x < 0 ? 0 : YUV_WHITE; | ||
1925 | return x; | ||
1926 | } | ||
1855 | 1927 | ||
1856 | #if (LCD_DEPTH == 16) && \ | 1928 | static inline int clamp_component_bits(int x, int bits) |
1857 | ((LCD_PIXELFORMAT == RGB565) || (LCD_PIXELFORMAT == RGB565SWAPPED)) | 1929 | { |
1858 | #define RYFAC (31*257) | 1930 | if ((unsigned)x > (1u << bits) - 1) |
1859 | #define GYFAC (63*257) | 1931 | x = x < 0 ? 0 : (1 << bits) - 1; |
1860 | #define BYFAC (31*257) | 1932 | return x; |
1861 | #define RVFAC 11170 /* 31 * 257 * 1.402 */ | 1933 | } |
1862 | #define GVFAC (-11563) /* 63 * 257 * -0.714136 */ | 1934 | |
1863 | #define GUFAC (-5572) /* 63 * 257 * -0.344136 */ | 1935 | static inline int component_to_lcd(int x, int bits, int delta) |
1864 | #define BUFAC 14118 /* 31 * 257 * 1.772 */ | 1936 | { |
1865 | #endif | 1937 | /* Formula used in core bitmap loader. */ |
1938 | return (((1 << bits) - 1)*x + (x >> (8 - bits)) + delta) >> COMPONENT_SHIFT; | ||
1939 | } | ||
1940 | |||
1941 | static inline int lcd_to_component(int x, int bits, int delta) | ||
1942 | { | ||
1943 | /* Reasonable, approximate reversal to get a full range back from the | ||
1944 | quantized value. */ | ||
1945 | return YUV_WHITE*x / ((1 << bits) - 1); | ||
1946 | (void)delta; | ||
1947 | } | ||
1948 | |||
1949 | #define RED 0 | ||
1950 | #define GRN 1 | ||
1951 | #define BLU 2 | ||
1952 | |||
1953 | struct rgb_err | ||
1954 | { | ||
1955 | int16_t errbuf[LCD_WIDTH+2]; /* Error record for line below */ | ||
1956 | } rgb_err_buffers[3]; | ||
1957 | |||
1958 | fb_data rgb_linebuf[LCD_WIDTH]; /* Line buffer for scrolling when | ||
1959 | DITHER_DIFFUSION is set */ | ||
1960 | |||
1961 | struct rgb_pixel | ||
1962 | { | ||
1963 | int r, g, b; /* Current pixel components in s16.0 */ | ||
1964 | int inc; /* Current line increment (-1 or 1) */ | ||
1965 | int row; /* Current row in source image */ | ||
1966 | int col; /* Current column in source image */ | ||
1967 | int ce[3]; /* Errors to apply to current pixel */ | ||
1968 | struct rgb_err *e; /* RED, GRN, BLU */ | ||
1969 | int epos; /* Current position in error record */ | ||
1970 | }; | ||
1971 | |||
1972 | struct rgb_pixel *pixel; | ||
1973 | |||
1974 | /** round and truncate to lcd depth **/ | ||
1975 | static fb_data pixel_to_lcd_colour(void) | ||
1976 | { | ||
1977 | struct rgb_pixel *p = pixel; | ||
1978 | int r, g, b; | ||
1979 | |||
1980 | r = component_to_lcd(p->r, LCD_RED_BITS, NODITHER_DELTA); | ||
1981 | r = clamp_component_bits(r, LCD_RED_BITS); | ||
1866 | 1982 | ||
1867 | #define ROUNDOFFS (127*257) | 1983 | g = component_to_lcd(p->g, LCD_GREEN_BITS, NODITHER_DELTA); |
1984 | g = clamp_component_bits(g, LCD_GREEN_BITS); | ||
1868 | 1985 | ||
1869 | /* Draw a partial YUV colour bitmap */ | 1986 | b = component_to_lcd(p->b, LCD_BLUE_BITS, NODITHER_DELTA); |
1987 | b = clamp_component_bits(b, LCD_BLUE_BITS); | ||
1988 | |||
1989 | return LCD_RGBPACK_LCD(r, g, b); | ||
1990 | } | ||
1991 | |||
1992 | /** write a monochrome pixel to the colour LCD **/ | ||
1993 | static fb_data pixel_to_lcd_gray(void) | ||
1994 | { | ||
1995 | int r, g, b; | ||
1996 | |||
1997 | g = clamp_component(pixel->g); | ||
1998 | r = component_to_lcd(g, LCD_RED_BITS, NODITHER_DELTA); | ||
1999 | b = component_to_lcd(g, LCD_BLUE_BITS, NODITHER_DELTA); | ||
2000 | g = component_to_lcd(g, LCD_GREEN_BITS, NODITHER_DELTA); | ||
2001 | |||
2002 | return LCD_RGBPACK_LCD(r, g, b); | ||
2003 | } | ||
2004 | |||
2005 | /** | ||
2006 | * Bayer ordered dithering - swiped from the core bitmap loader. | ||
2007 | */ | ||
2008 | static fb_data pixel_odither_to_lcd(void) | ||
2009 | { | ||
2010 | /* canonical ordered dither matrix */ | ||
2011 | static const unsigned char dither_matrix[16][16] = { | ||
2012 | { 0,192, 48,240, 12,204, 60,252, 3,195, 51,243, 15,207, 63,255 }, | ||
2013 | { 128, 64,176,112,140, 76,188,124,131, 67,179,115,143, 79,191,127 }, | ||
2014 | { 32,224, 16,208, 44,236, 28,220, 35,227, 19,211, 47,239, 31,223 }, | ||
2015 | { 160, 96,144, 80,172,108,156, 92,163, 99,147, 83,175,111,159, 95 }, | ||
2016 | { 8,200, 56,248, 4,196, 52,244, 11,203, 59,251, 7,199, 55,247 }, | ||
2017 | { 136, 72,184,120,132, 68,180,116,139, 75,187,123,135, 71,183,119 }, | ||
2018 | { 40,232, 24,216, 36,228, 20,212, 43,235, 27,219, 39,231, 23,215 }, | ||
2019 | { 168,104,152, 88,164,100,148, 84,171,107,155, 91,167,103,151, 87 }, | ||
2020 | { 2,194, 50,242, 14,206, 62,254, 1,193, 49,241, 13,205, 61,253 }, | ||
2021 | { 130, 66,178,114,142, 78,190,126,129, 65,177,113,141, 77,189,125 }, | ||
2022 | { 34,226, 18,210, 46,238, 30,222, 33,225, 17,209, 45,237, 29,221 }, | ||
2023 | { 162, 98,146, 82,174,110,158, 94,161, 97,145, 81,173,109,157, 93 }, | ||
2024 | { 10,202, 58,250, 6,198, 54,246, 9,201, 57,249, 5,197, 53,245 }, | ||
2025 | { 138, 74,186,122,134, 70,182,118,137, 73,185,121,133, 69,181,117 }, | ||
2026 | { 42,234, 26,218, 38,230, 22,214, 41,233, 25,217, 37,229, 21,213 }, | ||
2027 | { 170,106,154, 90,166,102,150, 86,169,105,153, 89,165,101,149, 85 } | ||
2028 | }; | ||
2029 | |||
2030 | struct rgb_pixel *p = pixel; | ||
2031 | int r, g, b, delta; | ||
2032 | |||
2033 | delta = dither_matrix[p->col & 15][p->row & 15] << MATRIX_SHIFT; | ||
2034 | |||
2035 | r = component_to_lcd(p->r, LCD_RED_BITS, delta); | ||
2036 | r = clamp_component_bits(r, LCD_RED_BITS); | ||
2037 | |||
2038 | g = component_to_lcd(p->g, LCD_GREEN_BITS, delta); | ||
2039 | g = clamp_component_bits(g, LCD_GREEN_BITS); | ||
2040 | |||
2041 | b = component_to_lcd(p->b, LCD_BLUE_BITS, delta); | ||
2042 | b = clamp_component_bits(b, LCD_BLUE_BITS); | ||
2043 | |||
2044 | p->col += p->inc; | ||
2045 | |||
2046 | return LCD_RGBPACK_LCD(r, g, b); | ||
2047 | } | ||
2048 | |||
2049 | /** | ||
2050 | * Floyd/Steinberg dither to lcd depth. | ||
2051 | * | ||
2052 | * Apply filter to each component in serpentine pattern. Kernel shown for | ||
2053 | * L->R scan. Kernel is reversed for R->L. | ||
2054 | * * 7 | ||
2055 | * 3 5 1 (1/16) | ||
2056 | */ | ||
2057 | static inline void distribute_error(int *ce, struct rgb_err *e, | ||
2058 | int err, int epos, int inc) | ||
2059 | { | ||
2060 | *ce = (7*err >> 4) + e->errbuf[epos+inc]; | ||
2061 | e->errbuf[epos+inc] = err >> 4; | ||
2062 | e->errbuf[epos] += 5*err >> 4; | ||
2063 | e->errbuf[epos-inc] += 3*err >> 4; | ||
2064 | } | ||
2065 | |||
2066 | static fb_data pixel_fsdither_to_lcd(void) | ||
2067 | { | ||
2068 | struct rgb_pixel *p = pixel; | ||
2069 | int rc, gc, bc, r, g, b; | ||
2070 | int inc, epos; | ||
2071 | |||
2072 | /* Full components with error terms */ | ||
2073 | rc = p->r + p->ce[RED]; | ||
2074 | r = component_to_lcd(rc, LCD_RED_BITS, 0); | ||
2075 | r = clamp_component_bits(r, LCD_RED_BITS); | ||
2076 | |||
2077 | gc = p->g + p->ce[GRN]; | ||
2078 | g = component_to_lcd(gc, LCD_GREEN_BITS, 0); | ||
2079 | g = clamp_component_bits(g, LCD_GREEN_BITS); | ||
2080 | |||
2081 | bc = p->b + p->ce[BLU]; | ||
2082 | b = component_to_lcd(bc, LCD_BLUE_BITS, 0); | ||
2083 | b = clamp_component_bits(b, LCD_BLUE_BITS); | ||
2084 | |||
2085 | /* Get pixel errors */ | ||
2086 | rc -= lcd_to_component(r, LCD_RED_BITS, 0); | ||
2087 | gc -= lcd_to_component(g, LCD_GREEN_BITS, 0); | ||
2088 | bc -= lcd_to_component(b, LCD_BLUE_BITS, 0); | ||
2089 | |||
2090 | /* Spead error to surrounding pixels. */ | ||
2091 | inc = p->inc; | ||
2092 | epos = p->epos; | ||
2093 | p->epos += inc; | ||
2094 | |||
2095 | distribute_error(&p->ce[RED], &p->e[RED], rc, epos, inc); | ||
2096 | distribute_error(&p->ce[GRN], &p->e[GRN], gc, epos, inc); | ||
2097 | distribute_error(&p->ce[BLU], &p->e[BLU], bc, epos, inc); | ||
2098 | |||
2099 | /* Pack and return pixel */ | ||
2100 | return LCD_RGBPACK_LCD(r, g, b); | ||
2101 | } | ||
2102 | |||
2103 | /* Functions for each output mode, colour then grayscale. */ | ||
2104 | static fb_data (* const pixel_funcs[COLOUR_NUM_MODES][DITHER_NUM_MODES])(void) = | ||
2105 | { | ||
2106 | [COLOURMODE_COLOUR] = | ||
2107 | { | ||
2108 | [DITHER_NONE] = pixel_to_lcd_colour, | ||
2109 | [DITHER_ORDERED] = pixel_odither_to_lcd, | ||
2110 | [DITHER_DIFFUSION] = pixel_fsdither_to_lcd, | ||
2111 | }, | ||
2112 | [COLOURMODE_GRAY] = | ||
2113 | { | ||
2114 | [DITHER_NONE] = pixel_to_lcd_gray, | ||
2115 | [DITHER_ORDERED] = pixel_odither_to_lcd, | ||
2116 | [DITHER_DIFFUSION] = pixel_fsdither_to_lcd, | ||
2117 | }, | ||
2118 | }; | ||
2119 | |||
2120 | /** | ||
2121 | * Draw a partial YUV colour bitmap | ||
2122 | * | ||
2123 | * Runs serpentine pattern when dithering is DITHER_DIFFUSION, else scan is | ||
2124 | * always L->R. | ||
2125 | */ | ||
1870 | void yuv_bitmap_part(unsigned char *src[3], int csub_x, int csub_y, | 2126 | void yuv_bitmap_part(unsigned char *src[3], int csub_x, int csub_y, |
1871 | int src_x, int src_y, int stride, | 2127 | int src_x, int src_y, int stride, |
1872 | int x, int y, int width, int height) | 2128 | int x, int y, int width, int height) |
1873 | { | 2129 | { |
1874 | fb_data *dst, *dst_end; | 2130 | fb_data *dst, *dst_end; |
2131 | fb_data (*pixel_func)(void); | ||
2132 | struct rgb_pixel px; | ||
1875 | 2133 | ||
1876 | /* nothing to draw? */ | ||
1877 | if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_HEIGHT) | ||
1878 | || (x + width <= 0) || (y + height <= 0)) | ||
1879 | return; | ||
1880 | |||
1881 | /* clipping */ | ||
1882 | if (x < 0) | ||
1883 | { | ||
1884 | width += x; | ||
1885 | src_x -= x; | ||
1886 | x = 0; | ||
1887 | } | ||
1888 | if (y < 0) | ||
1889 | { | ||
1890 | height += y; | ||
1891 | src_y -= y; | ||
1892 | y = 0; | ||
1893 | } | ||
1894 | if (x + width > LCD_WIDTH) | 2134 | if (x + width > LCD_WIDTH) |
1895 | width = LCD_WIDTH - x; | 2135 | width = LCD_WIDTH - x; /* Clip right */ |
2136 | if (x < 0) | ||
2137 | width += x, x = 0; /* Clip left */ | ||
2138 | if (width <= 0) | ||
2139 | return; /* nothing left to do */ | ||
2140 | |||
1896 | if (y + height > LCD_HEIGHT) | 2141 | if (y + height > LCD_HEIGHT) |
1897 | height = LCD_HEIGHT - y; | 2142 | height = LCD_HEIGHT - y; /* Clip bottom */ |
2143 | if (y < 0) | ||
2144 | height += y, y = 0; /* Clip top */ | ||
2145 | if (height <= 0) | ||
2146 | return; /* nothing left to do */ | ||
2147 | |||
2148 | pixel = &px; | ||
1898 | 2149 | ||
1899 | dst = rb->lcd_framebuffer + LCD_WIDTH * y + x; | 2150 | dst = rb->lcd_framebuffer + LCD_WIDTH * y + x; |
1900 | dst_end = dst + LCD_WIDTH * height; | 2151 | dst_end = dst + LCD_WIDTH * height; |
1901 | 2152 | ||
2153 | if (jpeg_settings.colour_mode == COLOURMODE_GRAY) | ||
2154 | csub_y = 0; /* Ignore Cb, Cr */ | ||
2155 | |||
2156 | pixel_func = pixel_funcs[jpeg_settings.colour_mode] | ||
2157 | [jpeg_settings.dither_mode]; | ||
2158 | |||
2159 | if (jpeg_settings.dither_mode == DITHER_DIFFUSION) | ||
2160 | { | ||
2161 | /* Reset error terms. */ | ||
2162 | px.e = rgb_err_buffers; | ||
2163 | px.ce[RED] = px.ce[GRN] = px.ce[BLU] = 0; | ||
2164 | rb->memset(px.e, 0, 3*sizeof (struct rgb_err)); | ||
2165 | } | ||
2166 | |||
1902 | do | 2167 | do |
1903 | { | 2168 | { |
1904 | fb_data *dst_row = dst; | 2169 | fb_data *dst_row, *row_end; |
1905 | fb_data *row_end = dst_row + width; | 2170 | const unsigned char *ysrc; |
1906 | const unsigned char *ysrc = src[0] + stride * src_y + src_x; | 2171 | px.inc = 1; |
1907 | int y, u, v; | 2172 | |
1908 | int red, green, blue; | 2173 | if (jpeg_settings.dither_mode == DITHER_DIFFUSION) |
1909 | unsigned rbits, gbits, bbits; | 2174 | { |
2175 | /* Use R->L scan on odd lines */ | ||
2176 | px.inc -= (src_y & 1) << 1; | ||
2177 | px.epos = x + 1; | ||
2178 | |||
2179 | if (px.inc < 0) | ||
2180 | px.epos += width - 1; | ||
2181 | } | ||
2182 | |||
2183 | if (px.inc == 1) | ||
2184 | { | ||
2185 | /* Scan is L->R */ | ||
2186 | dst_row = dst; | ||
2187 | row_end = dst_row + width; | ||
2188 | px.col = src_x; | ||
2189 | } | ||
2190 | else | ||
2191 | { | ||
2192 | /* Scan is R->L */ | ||
2193 | row_end = dst - 1; | ||
2194 | dst_row = row_end + width; | ||
2195 | px.col = src_x + width - 1; | ||
2196 | } | ||
1910 | 2197 | ||
2198 | ysrc = src[0] + stride * src_y + px.col; | ||
2199 | px.row = src_y; | ||
2200 | |||
2201 | /* Do one row of pixels */ | ||
1911 | if (csub_y) /* colour */ | 2202 | if (csub_y) /* colour */ |
1912 | { | 2203 | { |
1913 | /* upsampling, YUV->RGB conversion and reduction to RGB565 in one go */ | 2204 | /* upsampling, YUV->RGB conversion and reduction to RGB565 in one go */ |
1914 | const unsigned char *usrc = src[1] + (stride/csub_x) * (src_y/csub_y) | 2205 | const unsigned char *usrc, *vsrc; |
1915 | + (src_x/csub_x); | 2206 | |
1916 | const unsigned char *vsrc = src[2] + (stride/csub_x) * (src_y/csub_y) | 2207 | usrc = src[1] + (stride/csub_x) * (src_y/csub_y) |
1917 | + (src_x/csub_x); | 2208 | + (px.col/csub_x); |
1918 | int xphase = src_x % csub_x; | 2209 | vsrc = src[2] + (stride/csub_x) * (src_y/csub_y) |
1919 | int rc, gc, bc; | 2210 | + (px.col/csub_x); |
1920 | 2211 | int xphase = px.col % csub_x; | |
1921 | u = *usrc++ - 128; | 2212 | int xphase_reset = px.inc * csub_x; |
1922 | v = *vsrc++ - 128; | 2213 | int y, v, u, rv, guv, bu; |
1923 | rc = RVFAC * v + ROUNDOFFS; | 2214 | |
1924 | gc = GVFAC * v + GUFAC * u + ROUNDOFFS; | 2215 | v = *vsrc - 128; |
1925 | bc = BUFAC * u + ROUNDOFFS; | 2216 | vsrc += px.inc; |
2217 | u = *usrc - 128; | ||
2218 | usrc += px.inc; | ||
2219 | rv = RVFAC*v; | ||
2220 | guv = GUFAC*u + GVFAC*v; | ||
2221 | bu = BUFAC*u; | ||
1926 | 2222 | ||
1927 | do | 2223 | while (1) |
1928 | { | 2224 | { |
1929 | y = *ysrc++; | 2225 | y = YFAC*(*ysrc); |
1930 | red = RYFAC * y + rc; | 2226 | ysrc += px.inc; |
1931 | green = GYFAC * y + gc; | 2227 | px.r = y + rv; |
1932 | blue = BYFAC * y + bc; | 2228 | px.g = y + guv; |
2229 | px.b = y + bu; | ||
1933 | 2230 | ||
1934 | if ((unsigned)red > (RYFAC*255+ROUNDOFFS)) | 2231 | *dst_row = pixel_func(); |
1935 | { | 2232 | dst_row += px.inc; |
1936 | if (red < 0) | ||
1937 | red = 0; | ||
1938 | else | ||
1939 | red = (RYFAC*255+ROUNDOFFS); | ||
1940 | } | ||
1941 | if ((unsigned)green > (GYFAC*255+ROUNDOFFS)) | ||
1942 | { | ||
1943 | if (green < 0) | ||
1944 | green = 0; | ||
1945 | else | ||
1946 | green = (GYFAC*255+ROUNDOFFS); | ||
1947 | } | ||
1948 | if ((unsigned)blue > (BYFAC*255+ROUNDOFFS)) | ||
1949 | { | ||
1950 | if (blue < 0) | ||
1951 | blue = 0; | ||
1952 | else | ||
1953 | blue = (BYFAC*255+ROUNDOFFS); | ||
1954 | } | ||
1955 | rbits = ((unsigned)red) >> 16 ; | ||
1956 | gbits = ((unsigned)green) >> 16 ; | ||
1957 | bbits = ((unsigned)blue) >> 16 ; | ||
1958 | #if LCD_PIXELFORMAT == RGB565 | ||
1959 | *dst_row++ = (rbits << 11) | (gbits << 5) | bbits; | ||
1960 | #elif LCD_PIXELFORMAT == RGB565SWAPPED | ||
1961 | *dst_row++ = swap16((rbits << 11) | (gbits << 5) | bbits); | ||
1962 | #endif | ||
1963 | 2233 | ||
1964 | if (++xphase >= csub_x) | 2234 | if (dst_row == row_end) |
1965 | { | 2235 | break; |
1966 | u = *usrc++ - 128; | 2236 | |
1967 | v = *vsrc++ - 128; | 2237 | xphase += px.inc; |
1968 | rc = RVFAC * v + ROUNDOFFS; | 2238 | if ((unsigned)xphase < (unsigned)csub_x) |
1969 | gc = GVFAC * v + GUFAC * u + ROUNDOFFS; | 2239 | continue; |
1970 | bc = BUFAC * u + ROUNDOFFS; | 2240 | |
1971 | xphase = 0; | 2241 | /* fetch new chromas */ |
1972 | } | 2242 | v = *vsrc - 128; |
2243 | vsrc += px.inc; | ||
2244 | u = *usrc - 128; | ||
2245 | usrc += px.inc; | ||
2246 | rv = RVFAC*v; | ||
2247 | guv = GUFAC*u + GVFAC*v; | ||
2248 | bu = BUFAC*u; | ||
2249 | |||
2250 | xphase -= xphase_reset; | ||
1973 | } | 2251 | } |
1974 | while (dst_row < row_end); | ||
1975 | } | 2252 | } |
1976 | else /* monochrome */ | 2253 | else /* monochrome */ |
1977 | { | 2254 | { |
1978 | do | 2255 | do |
1979 | { | 2256 | { |
1980 | y = *ysrc++; | 2257 | /* Set all components the same for dithering purposes */ |
1981 | red = RYFAC * y + ROUNDOFFS; /* blue == red */ | 2258 | px.g = px.r = px.b = YFAC*(*ysrc); |
1982 | green = GYFAC * y + ROUNDOFFS; | 2259 | *dst_row = pixel_func(); |
1983 | rbits = ((unsigned)red) >> 16; | 2260 | ysrc += px.inc; |
1984 | gbits = ((unsigned)green) >> 16; | 2261 | dst_row += px.inc; |
1985 | #if LCD_PIXELFORMAT == RGB565 | ||
1986 | *dst_row++ = (rbits << 11) | (gbits << 5) | rbits; | ||
1987 | #elif LCD_PIXELFORMAT == RGB565SWAPPED | ||
1988 | *dst_row++ = swap16((rbits << 11) | (gbits << 5) | rbits); | ||
1989 | #endif | ||
1990 | } | 2262 | } |
1991 | while (dst_row < row_end); | 2263 | while (dst_row != row_end); |
1992 | } | 2264 | } |
1993 | 2265 | ||
1994 | src_y++; | 2266 | src_y++; |
@@ -1996,7 +2268,8 @@ void yuv_bitmap_part(unsigned char *src[3], int csub_x, int csub_y, | |||
1996 | } | 2268 | } |
1997 | while (dst < dst_end); | 2269 | while (dst < dst_end); |
1998 | } | 2270 | } |
1999 | #endif | 2271 | |
2272 | #endif /* HAVE_LCD_COLOR */ | ||
2000 | 2273 | ||
2001 | 2274 | ||
2002 | /* support function for qsort() */ | 2275 | /* support function for qsort() */ |
@@ -2114,6 +2387,42 @@ void cleanup(void *parameter) | |||
2114 | #define ZOOM_IN 100 /* return codes for below function */ | 2387 | #define ZOOM_IN 100 /* return codes for below function */ |
2115 | #define ZOOM_OUT 101 | 2388 | #define ZOOM_OUT 101 |
2116 | 2389 | ||
2390 | #ifdef HAVE_LCD_COLOR | ||
2391 | bool set_option_grayscale(void) | ||
2392 | { | ||
2393 | bool gray = jpeg_settings.colour_mode == COLOURMODE_GRAY; | ||
2394 | rb->set_bool("Grayscale", &gray); | ||
2395 | jpeg_settings.colour_mode = gray ? COLOURMODE_GRAY : COLOURMODE_COLOUR; | ||
2396 | return false; | ||
2397 | } | ||
2398 | |||
2399 | bool set_option_dithering(void) | ||
2400 | { | ||
2401 | static const struct opt_items dithering[DITHER_NUM_MODES] = { | ||
2402 | [DITHER_NONE] = { "Off", -1 }, | ||
2403 | [DITHER_ORDERED] = { "Ordered", -1 }, | ||
2404 | [DITHER_DIFFUSION] = { "Diffusion", -1 }, | ||
2405 | }; | ||
2406 | |||
2407 | rb->set_option("Dithering", &jpeg_settings.dither_mode, INT, | ||
2408 | dithering, DITHER_NUM_MODES, NULL); | ||
2409 | return false; | ||
2410 | } | ||
2411 | |||
2412 | static void display_options(void) | ||
2413 | { | ||
2414 | static const struct menu_item items[] = { | ||
2415 | { "Grayscale", set_option_grayscale }, | ||
2416 | { "Dithering", set_option_dithering }, | ||
2417 | }; | ||
2418 | |||
2419 | int m = rb->menu_init(items, ARRAYLEN(items), | ||
2420 | NULL, NULL, NULL, NULL); | ||
2421 | rb->menu_run(m); | ||
2422 | rb->menu_exit(m); | ||
2423 | } | ||
2424 | #endif /* HAVE_LCD_COLOR */ | ||
2425 | |||
2117 | int show_menu(void) /* return 1 to quit */ | 2426 | int show_menu(void) /* return 1 to quit */ |
2118 | { | 2427 | { |
2119 | #if LCD_DEPTH > 1 | 2428 | #if LCD_DEPTH > 1 |
@@ -2128,19 +2437,45 @@ int show_menu(void) /* return 1 to quit */ | |||
2128 | #endif | 2437 | #endif |
2129 | int m; | 2438 | int m; |
2130 | int result; | 2439 | int result; |
2440 | |||
2441 | enum menu_id | ||
2442 | { | ||
2443 | MIID_QUIT = 0, | ||
2444 | MIID_TOGGLE_SS_MODE, | ||
2445 | MIID_CHANGE_SS_MODE, | ||
2446 | #if PLUGIN_BUFFER_SIZE >= MIN_MEM | ||
2447 | MIID_SHOW_PLAYBACK_MENU, | ||
2448 | #endif | ||
2449 | #ifdef HAVE_LCD_COLOR | ||
2450 | MIID_DISPLAY_OPTIONS, | ||
2451 | #endif | ||
2452 | MIID_RETURN, | ||
2453 | }; | ||
2454 | |||
2131 | static const struct menu_item items[] = { | 2455 | static const struct menu_item items[] = { |
2132 | { "Quit", NULL }, | 2456 | [MIID_QUIT] = |
2133 | { "Toggle Slideshow Mode", NULL }, | 2457 | { "Quit", NULL }, |
2134 | { "Change Slideshow Time", NULL }, | 2458 | [MIID_TOGGLE_SS_MODE] = |
2459 | { "Toggle Slideshow Mode", NULL }, | ||
2460 | [MIID_CHANGE_SS_MODE] = | ||
2461 | { "Change Slideshow Time", NULL }, | ||
2135 | #if PLUGIN_BUFFER_SIZE >= MIN_MEM | 2462 | #if PLUGIN_BUFFER_SIZE >= MIN_MEM |
2136 | { "Show Playback Menu", NULL }, | 2463 | [MIID_SHOW_PLAYBACK_MENU] = |
2464 | { "Show Playback Menu", NULL }, | ||
2137 | #endif | 2465 | #endif |
2138 | { "Return", NULL }, | 2466 | #ifdef HAVE_LCD_COLOR |
2467 | [MIID_DISPLAY_OPTIONS] = | ||
2468 | { "Display Options", NULL }, | ||
2469 | #endif | ||
2470 | [MIID_RETURN] = | ||
2471 | { "Return", NULL }, | ||
2139 | }; | 2472 | }; |
2473 | |||
2140 | static const struct opt_items slideshow[2] = { | 2474 | static const struct opt_items slideshow[2] = { |
2141 | { "Disable", -1 }, | 2475 | { "Disable", -1 }, |
2142 | { "Enable", -1 }, | 2476 | { "Enable", -1 }, |
2143 | }; | 2477 | }; |
2478 | |||
2144 | static const struct opt_items timeout[12] = { | 2479 | static const struct opt_items timeout[12] = { |
2145 | { "1 second", -1 }, | 2480 | { "1 second", -1 }, |
2146 | { "2 seconds", -1 }, | 2481 | { "2 seconds", -1 }, |
@@ -2155,20 +2490,22 @@ int show_menu(void) /* return 1 to quit */ | |||
2155 | { "15 seconds", -1 }, | 2490 | { "15 seconds", -1 }, |
2156 | { "20 seconds", -1 }, | 2491 | { "20 seconds", -1 }, |
2157 | }; | 2492 | }; |
2493 | |||
2158 | m = rb->menu_init(items, sizeof(items) / sizeof(*items), | 2494 | m = rb->menu_init(items, sizeof(items) / sizeof(*items), |
2159 | NULL, NULL, NULL, NULL); | 2495 | NULL, NULL, NULL, NULL); |
2160 | result=rb->menu_show(m); | 2496 | result=rb->menu_show(m); |
2497 | |||
2161 | switch (result) | 2498 | switch (result) |
2162 | { | 2499 | { |
2163 | case 0: | 2500 | case MIID_QUIT: |
2164 | rb->menu_exit(m); | 2501 | rb->menu_exit(m); |
2165 | return 1; | 2502 | return 1; |
2166 | break; | 2503 | break; |
2167 | case 1: //toggle slideshow | 2504 | case MIID_TOGGLE_SS_MODE: |
2168 | rb->set_option("Toggle Slideshow", &slideshow_enabled, INT, | 2505 | rb->set_option("Toggle Slideshow", &slideshow_enabled, INT, |
2169 | slideshow , 2, NULL); | 2506 | slideshow , 2, NULL); |
2170 | break; | 2507 | break; |
2171 | case 2: | 2508 | case MIID_CHANGE_SS_MODE: |
2172 | switch (button_timeout/HZ) | 2509 | switch (button_timeout/HZ) |
2173 | { | 2510 | { |
2174 | case 10: result = 9; break; | 2511 | case 10: result = 9; break; |
@@ -2186,12 +2523,17 @@ int show_menu(void) /* return 1 to quit */ | |||
2186 | default: button_timeout = (result+1)*HZ; break; | 2523 | default: button_timeout = (result+1)*HZ; break; |
2187 | } | 2524 | } |
2188 | break; | 2525 | break; |
2189 | case 3: | ||
2190 | #if PLUGIN_BUFFER_SIZE >= MIN_MEM | 2526 | #if PLUGIN_BUFFER_SIZE >= MIN_MEM |
2527 | case MIID_SHOW_PLAYBACK_MENU: | ||
2191 | playback_control(rb); | 2528 | playback_control(rb); |
2192 | break; | 2529 | break; |
2193 | case 4: | ||
2194 | #endif | 2530 | #endif |
2531 | #ifdef HAVE_LCD_COLOR | ||
2532 | case MIID_DISPLAY_OPTIONS: | ||
2533 | display_options(); | ||
2534 | break; | ||
2535 | #endif | ||
2536 | case MIID_RETURN: | ||
2195 | break; | 2537 | break; |
2196 | } | 2538 | } |
2197 | 2539 | ||
@@ -2300,6 +2642,13 @@ int scroll_bmp(struct t_disp* pdisp) | |||
2300 | MYXLCD(scroll_down)(move); /* scroll down */ | 2642 | MYXLCD(scroll_down)(move); /* scroll down */ |
2301 | pdisp->y -= move; | 2643 | pdisp->y -= move; |
2302 | #ifdef HAVE_LCD_COLOR | 2644 | #ifdef HAVE_LCD_COLOR |
2645 | if (jpeg_settings.dither_mode == DITHER_DIFFUSION) | ||
2646 | { | ||
2647 | /* Draw over the band at the top of the last update | ||
2648 | caused by lack of error history on line zero. */ | ||
2649 | move = MIN(move + 1, pdisp->y + pdisp->height); | ||
2650 | } | ||
2651 | |||
2303 | yuv_bitmap_part( | 2652 | yuv_bitmap_part( |
2304 | pdisp->bitmap, pdisp->csub_x, pdisp->csub_y, | 2653 | pdisp->bitmap, pdisp->csub_x, pdisp->csub_y, |
2305 | pdisp->x, pdisp->y, pdisp->stride, | 2654 | pdisp->x, pdisp->y, pdisp->stride, |
@@ -2323,11 +2672,32 @@ int scroll_bmp(struct t_disp* pdisp) | |||
2323 | MYXLCD(scroll_up)(move); /* scroll up */ | 2672 | MYXLCD(scroll_up)(move); /* scroll up */ |
2324 | pdisp->y += move; | 2673 | pdisp->y += move; |
2325 | #ifdef HAVE_LCD_COLOR | 2674 | #ifdef HAVE_LCD_COLOR |
2326 | yuv_bitmap_part( | 2675 | if (jpeg_settings.dither_mode == DITHER_DIFFUSION) |
2676 | { | ||
2677 | /* Save the line that was on the last line of the display | ||
2678 | and draw one extra line above then recover the line with | ||
2679 | image data that had an error history when it was drawn. | ||
2680 | */ | ||
2681 | move++, pdisp->y--; | ||
2682 | MEMCPY(rgb_linebuf, | ||
2683 | rb->lcd_framebuffer + (LCD_HEIGHT - move)*LCD_WIDTH, | ||
2684 | LCD_WIDTH*sizeof (fb_data)); | ||
2685 | } | ||
2686 | |||
2687 | yuv_bitmap_part( | ||
2327 | pdisp->bitmap, pdisp->csub_x, pdisp->csub_y, pdisp->x, | 2688 | pdisp->bitmap, pdisp->csub_x, pdisp->csub_y, pdisp->x, |
2328 | pdisp->y + LCD_HEIGHT - move, pdisp->stride, | 2689 | pdisp->y + LCD_HEIGHT - move, pdisp->stride, |
2329 | MAX(0, (LCD_WIDTH-pdisp->width)/2), LCD_HEIGHT - move, /* x, y */ | 2690 | MAX(0, (LCD_WIDTH-pdisp->width)/2), LCD_HEIGHT - move, /* x, y */ |
2330 | MIN(LCD_WIDTH, pdisp->width), move); /* w, h */ | 2691 | MIN(LCD_WIDTH, pdisp->width), move); /* w, h */ |
2692 | |||
2693 | if (jpeg_settings.dither_mode == DITHER_DIFFUSION) | ||
2694 | { | ||
2695 | /* Cover the first row drawn with previous image data. */ | ||
2696 | MEMCPY(rb->lcd_framebuffer + (LCD_HEIGHT - move)*LCD_WIDTH, | ||
2697 | rgb_linebuf, | ||
2698 | LCD_WIDTH*sizeof (fb_data)); | ||
2699 | pdisp->y++; | ||
2700 | } | ||
2331 | #else | 2701 | #else |
2332 | MYXLCD(gray_bitmap_part)( | 2702 | MYXLCD(gray_bitmap_part)( |
2333 | pdisp->bitmap[0], pdisp->x, | 2703 | pdisp->bitmap[0], pdisp->x, |
@@ -2909,6 +3279,15 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parameter) | |||
2909 | xlcd_init(rb); | 3279 | xlcd_init(rb); |
2910 | #endif | 3280 | #endif |
2911 | 3281 | ||
3282 | #ifdef HAVE_LCD_COLOR | ||
3283 | /* should be ok to just load settings since a parameter is present | ||
3284 | here and the drive should be spinning */ | ||
3285 | configfile_init(rb); | ||
3286 | configfile_load(JPEG_CONFIGFILE, jpeg_config, | ||
3287 | ARRAYLEN(jpeg_config), JPEG_SETTINGS_MINVERSION); | ||
3288 | old_settings = jpeg_settings; | ||
3289 | #endif | ||
3290 | |||
2912 | buf_images = buf; buf_images_size = buf_size; | 3291 | buf_images = buf; buf_images_size = buf_size; |
2913 | 3292 | ||
2914 | /* make sure the backlight is always on when viewing pictures | 3293 | /* make sure the backlight is always on when viewing pictures |
@@ -2926,6 +3305,16 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parameter) | |||
2926 | }while (condition != PLUGIN_OK && condition != PLUGIN_USB_CONNECTED | 3305 | }while (condition != PLUGIN_OK && condition != PLUGIN_USB_CONNECTED |
2927 | && condition != PLUGIN_ERROR); | 3306 | && condition != PLUGIN_ERROR); |
2928 | 3307 | ||
3308 | #ifdef HAVE_LCD_COLOR | ||
3309 | if (rb->memcmp(&jpeg_settings, &old_settings, sizeof (jpeg_settings))) | ||
3310 | { | ||
3311 | /* Just in case drive has to spin, keep it from looking locked */ | ||
3312 | rb->splash(0, "Saving Settings"); | ||
3313 | configfile_save(JPEG_CONFIGFILE, jpeg_config, | ||
3314 | ARRAYLEN(jpeg_config), JPEG_SETTINGS_VERSION); | ||
3315 | } | ||
3316 | #endif | ||
3317 | |||
2929 | #ifndef SIMULATOR | 3318 | #ifndef SIMULATOR |
2930 | /* set back ata spindown time in case we changed it */ | 3319 | /* set back ata spindown time in case we changed it */ |
2931 | rb->ata_spindown(rb->global_settings->disk_spindown); | 3320 | rb->ata_spindown(rb->global_settings->disk_spindown); |