diff --git a/apps/SOURCES b/apps/SOURCES index d68ca1b..33cb030 100644 --- a/apps/SOURCES +++ b/apps/SOURCES @@ -93,6 +93,12 @@ recorder/bmp.c recorder/icons.c recorder/keyboard.c recorder/peakmeter.c +recorder/resize-common.c +#ifdef HAVE_LCD_COLOR +recorder/resize-color.c +#else +recorder/resize-gray.c +#endif #ifdef HAVE_ALBUMART recorder/albumart.c #endif diff --git a/apps/buffering.c b/apps/buffering.c index 4c6a2ba..36c00e0 100644 --- a/apps/buffering.c +++ b/apps/buffering.c @@ -52,6 +52,9 @@ #include "bmp.h" #include "appevents.h" #include "metadata.h" +#ifdef HAVE_ALBUMART +#include "albumart.h" +#endif #if MEM > 1 #define GUARD_BUFSIZE (32*1024) @@ -852,8 +855,12 @@ static int load_bitmap(int fd) bmp->maskdata = NULL; #endif - int free = (int)MIN(buffer_len - BUF_USED, buffer_len - buf_widx); - rc = read_bmp_fd(fd, bmp, free, FORMAT_ANY|FORMAT_DITHER); + int free = (int)MIN(buffer_len - BUF_USED, buffer_len - buf_widx) + - sizeof(struct bitmap); + + get_albumart_size(bmp); + + rc = read_bmp_fd(fd, bmp, free, FORMAT_NATIVE|FORMAT_DITHER); return rc + (rc > 0 ? sizeof(struct bitmap) : 0); } #endif diff --git a/apps/gui/backdrop.c b/apps/gui/backdrop.c index ba7ff6b..03f37b5 100644 --- a/apps/gui/backdrop.c +++ b/apps/gui/backdrop.c @@ -51,7 +51,7 @@ static bool load_backdrop(const char* filename, fb_data* backdrop_buffer) /* load the image */ bm.data=(char*)backdrop_buffer; - ret = read_bmp_file(filename, &bm, sizeof(main_backdrop), + ret = read_bmp_file(filename, noresize(&bm), sizeof(main_backdrop), FORMAT_NATIVE | FORMAT_DITHER); if ((ret > 0) && (bm.width == LCD_WIDTH) && (bm.height == LCD_HEIGHT)) @@ -113,7 +113,7 @@ static bool load_remote_backdrop(const char* filename, fb_remote_data* backdrop_ /* load the image */ bm.data=(char*)backdrop_buffer; - ret = read_bmp_file(filename, &bm, sizeof(main_backdrop), + ret = read_bmp_file(filename, noresize(&bm), sizeof(main_backdrop), FORMAT_NATIVE | FORMAT_DITHER | FORMAT_REMOTE); if ((ret > 0) && (bm.width == LCD_REMOTE_WIDTH) && (bm.height == LCD_REMOTE_HEIGHT)) diff --git a/apps/gui/gwps.h b/apps/gui/gwps.h index fdb3904..d0523b9 100644 --- a/apps/gui/gwps.h +++ b/apps/gui/gwps.h @@ -47,13 +47,11 @@ #define WPS_ALBUMART_CHECK 1 /* WPS contains AA conditional tag */ #define WPS_ALBUMART_LOAD 2 /* WPS contains AA tag */ -#define WPS_ALBUMART_ALIGN_RIGHT WPS_ALIGN_RIGHT /* x align: right */ -#define WPS_ALBUMART_ALIGN_CENTER WPS_ALIGN_CENTER /* x/y align: center */ -#define WPS_ALBUMART_ALIGN_LEFT WPS_ALIGN_LEFT /* x align: left */ -#define WPS_ALBUMART_ALIGN_TOP WPS_ALIGN_RIGHT /* y align: top */ -#define WPS_ALBUMART_ALIGN_BOTTOM WPS_ALIGN_LEFT /* y align: bottom */ -#define WPS_ALBUMART_INCREASE 8 /* increase if smaller */ -#define WPS_ALBUMART_DECREASE 16 /* decrease if larger */ +#define WPS_ALBUMART_ALIGN_RIGHT 1 /* x align: right */ +#define WPS_ALBUMART_ALIGN_CENTER 2 /* x/y align: center */ +#define WPS_ALBUMART_ALIGN_LEFT 4 /* x align: left */ +#define WPS_ALBUMART_ALIGN_TOP 1 /* y align: top */ +#define WPS_ALBUMART_ALIGN_BOTTOM 4 /* y align: bottom */ #endif /* HAVE_ALBUMART */ @@ -382,10 +380,8 @@ struct wps_data unsigned char wps_uses_albumart; /* WPS_ALBUMART_NONE, _CHECK, _LOAD */ short albumart_x; short albumart_y; - unsigned short albumart_xalign; /* WPS_ALBUMART_ALIGN_LEFT, _CENTER, _RIGHT, - + .._INCREASE, + .._DECREASE */ - unsigned short albumart_yalign; /* WPS_ALBUMART_ALIGN_TOP, _CENTER, _BOTTOM, - + .._INCREASE, + .._DECREASE */ + unsigned char albumart_xalign; /* WPS_ALBUMART_ALIGN_LEFT, _CENTER, _RIGHT */ + unsigned char albumart_yalign; /* WPS_ALBUMART_ALIGN_TOP, _CENTER, _BOTTOM */ short albumart_max_width; short albumart_max_height; diff --git a/apps/gui/icon.c b/apps/gui/icon.c index bfadb72..bd6b234 100644 --- a/apps/gui/icon.c +++ b/apps/gui/icon.c @@ -222,7 +222,7 @@ static void load_icons(const char* filename, enum Iconset iconset, char path[MAX_PATH]; snprintf(path, sizeof(path), "%s/%s.bmp", ICON_DIR, filename); - size_read = read_bmp_file(path, bmp, IMG_BUFSIZE, bmpformat); + size_read = read_bmp_file(path, noresize(bmp), IMG_BUFSIZE, bmpformat); if (size_read > 0) { *loaded_ok = true; diff --git a/apps/gui/wps_parser.c b/apps/gui/wps_parser.c index 33e773f..bfeed19 100644 --- a/apps/gui/wps_parser.c +++ b/apps/gui/wps_parser.c @@ -409,7 +409,7 @@ static bool load_bitmap(struct wps_data *wps_data, #endif format = FORMAT_ANY|FORMAT_TRANSPARENT; - int ret = read_bmp_file(filename, bm, + int ret = read_bmp_file(filename, noresize(bm), wps_data->img_buf_free, format); @@ -930,13 +930,6 @@ static int parse_albumart_load(const char *wps_bufptr, { const char *_pos, *newline; bool parsing; - const short xalign_mask = WPS_ALBUMART_ALIGN_LEFT | - WPS_ALBUMART_ALIGN_CENTER | - WPS_ALBUMART_ALIGN_RIGHT; - const short yalign_mask = WPS_ALBUMART_ALIGN_TOP | - WPS_ALBUMART_ALIGN_CENTER | - WPS_ALBUMART_ALIGN_BOTTOM; - (void)token; /* silence warning */ /* reset albumart info in wps */ @@ -946,7 +939,7 @@ static int parse_albumart_load(const char *wps_bufptr, wps_data->albumart_xalign = WPS_ALBUMART_ALIGN_CENTER; /* default */ wps_data->albumart_yalign = WPS_ALBUMART_ALIGN_CENTER; /* default */ - /* format: %Cl|x|y|[[l|c|r][d|i|s]mwidth]|[[t|c|b][d|i|s]mheight]| */ + /* format: %Cl|x|y|[[l|c|r]mwidth]|[[t|c|b]mheight]| */ newline = strchr(wps_bufptr, '\n'); @@ -981,35 +974,24 @@ static int parse_albumart_load(const char *wps_bufptr, case 'l': case 'L': case '+': - wps_data->albumart_xalign = - (wps_data->albumart_xalign & xalign_mask) | - WPS_ALBUMART_ALIGN_LEFT; + wps_data->albumart_xalign = WPS_ALBUMART_ALIGN_LEFT; break; case 'c': case 'C': - wps_data->albumart_xalign = - (wps_data->albumart_xalign & xalign_mask) | - WPS_ALBUMART_ALIGN_CENTER; + wps_data->albumart_xalign = WPS_ALBUMART_ALIGN_CENTER; break; case 'r': case 'R': case '-': - wps_data->albumart_xalign = - (wps_data->albumart_xalign & xalign_mask) | - WPS_ALBUMART_ALIGN_RIGHT; + wps_data->albumart_xalign = WPS_ALBUMART_ALIGN_RIGHT; break; case 'd': case 'D': - wps_data->albumart_xalign |= WPS_ALBUMART_DECREASE; - break; case 'i': case 'I': - wps_data->albumart_xalign |= WPS_ALBUMART_INCREASE; - break; case 's': case 'S': - wps_data->albumart_xalign |= - (WPS_ALBUMART_DECREASE | WPS_ALBUMART_INCREASE); + /* simply ignored */ break; default: parsing = false; @@ -1041,35 +1023,24 @@ static int parse_albumart_load(const char *wps_bufptr, case 't': case 'T': case '-': - wps_data->albumart_yalign = - (wps_data->albumart_yalign & yalign_mask) | - WPS_ALBUMART_ALIGN_TOP; + wps_data->albumart_yalign = WPS_ALBUMART_ALIGN_TOP; break; case 'c': case 'C': - wps_data->albumart_yalign = - (wps_data->albumart_yalign & yalign_mask) | - WPS_ALBUMART_ALIGN_CENTER; + wps_data->albumart_yalign = WPS_ALBUMART_ALIGN_CENTER; break; case 'b': case 'B': case '+': - wps_data->albumart_yalign = - (wps_data->albumart_yalign & yalign_mask) | - WPS_ALBUMART_ALIGN_BOTTOM; + wps_data->albumart_yalign = WPS_ALBUMART_ALIGN_BOTTOM; break; case 'd': case 'D': - wps_data->albumart_yalign |= WPS_ALBUMART_DECREASE; - break; case 'i': case 'I': - wps_data->albumart_yalign |= WPS_ALBUMART_INCREASE; - break; case 's': case 'S': - wps_data->albumart_yalign |= - (WPS_ALBUMART_DECREASE | WPS_ALBUMART_INCREASE); + /* simply ignored */ break; default: parsing = false; diff --git a/apps/plugin.h b/apps/plugin.h index 083de90..f353832 100644 --- a/apps/plugin.h +++ b/apps/plugin.h @@ -703,7 +703,7 @@ struct plugin_api { #endif #ifdef HAVE_LCD_BITMAP int (*read_bmp_file)(const char* filename, struct bitmap *bm, int maxsize, - int format); + unsigned int format); void (*screen_dump_set_hook)(void (*hook)(int fh)); #endif int (*show_logo)(void); diff --git a/apps/plugins/pictureflow.c b/apps/plugins/pictureflow.c index 7a7f25d..7c6eda1 100644 --- a/apps/plugins/pictureflow.c +++ b/apps/plugins/pictureflow.c @@ -634,7 +634,7 @@ bool create_albumart_cache(bool force) continue; input_bmp.data = (char *)input_bmp_buffer; - ret = rb->read_bmp_file(tmp_path_name, &input_bmp, + ret = rb->read_bmp_file(tmp_path_name, noresize(&input_bmp), sizeof(fb_data)*MAX_IMG_WIDTH*MAX_IMG_HEIGHT, FORMAT_NATIVE); if (ret <= 0) { diff --git a/apps/plugins/rockpaint.c b/apps/plugins/rockpaint.c index 391523a..ed6ca7b 100644 --- a/apps/plugins/rockpaint.c +++ b/apps/plugins/rockpaint.c @@ -2956,7 +2956,7 @@ static int load_bitmap( const char *file ) int l; bm.data = (char*)save_buffer; - ret = rb->read_bmp_file( file, &bm, ROWS*COLS*sizeof( fb_data ), + ret = rb->read_bmp_file( file, noresize(&bm), ROWS*COLS*sizeof( fb_data ), FORMAT_NATIVE ); if((bm.width > COLS ) || ( bm.height > ROWS )) diff --git a/apps/plugins/sliding_puzzle.c b/apps/plugins/sliding_puzzle.c index 51b88cb..297b08c 100644 --- a/apps/plugins/sliding_puzzle.c +++ b/apps/plugins/sliding_puzzle.c @@ -233,10 +233,6 @@ static int moves_y = 0; static unsigned char img_buf[IMAGE_WIDTH*IMAGE_HEIGHT*sizeof(fb_data)] __attribute__ ((aligned(16))); -#if LCD_DEPTH>1 -static unsigned char temp_img_buf[LCD_WIDTH*LCD_HEIGHT*sizeof(fb_data)] -__attribute__ ((aligned(16))); -#endif #ifdef HAVE_ALBUMART static char albumart_path[MAX_PATH+1]; #endif @@ -312,28 +308,9 @@ static bool load_resize_bitmap(void) rb->memset(&main_bitmap,0,sizeof(struct bitmap)); main_bitmap.data = img_buf; -#if LCD_DEPTH>1 - struct bitmap temp_bitmap; - rb->memset(&temp_bitmap,0,sizeof(struct bitmap)); - temp_bitmap.data = temp_img_buf; - main_bitmap.width = IMAGE_WIDTH; main_bitmap.height = IMAGE_HEIGHT; - rc = rb->read_bmp_file( filename, &temp_bitmap, sizeof(temp_img_buf), - FORMAT_NATIVE ); - if( rc > 0 ) - { -#ifdef HAVE_LCD_COLOR - smooth_resize_bitmap( &temp_bitmap, &main_bitmap ); -#else - simple_resize_bitmap( &temp_bitmap, &main_bitmap ); -#endif - puzzle_bmp_ptr = (const fb_data *)img_buf; - rb->strcpy( img_buf_path, filename ); - return true; - } -#else rc = rb->read_bmp_file( filename, &main_bitmap, sizeof(img_buf), FORMAT_NATIVE ); if( rc > 0 ) @@ -342,7 +319,6 @@ static bool load_resize_bitmap(void) rb->strcpy( img_buf_path, filename ); return true; } -#endif } /* something must have failed. get_albumart_bmp_path could return diff --git a/apps/plugins/test_resize.c b/apps/plugins/test_resize.c index 23e7ca2..ba60b7d 100644 --- a/apps/plugins/test_resize.c +++ b/apps/plugins/test_resize.c @@ -77,8 +77,8 @@ enum plugin_status plugin_start(const struct plugin_api* api, const void* parame input_bmp.data = (char*)input_bmp_data; output_bmp.data = (char*)output_bmp_data; - int ret = rb->read_bmp_file("/test.bmp", &input_bmp, sizeof(input_bmp_data), - FORMAT_NATIVE); + int ret = rb->read_bmp_file("/test.bmp", noresize(&input_bmp), + sizeof(input_bmp_data), FORMAT_NATIVE); if (ret < 0) { rb->splash(HZ, "Could not load /test.bmp"); diff --git a/apps/recorder/albumart.c b/apps/recorder/albumart.c index 7e5e1df..26e0a8d 100644 --- a/apps/recorder/albumart.c +++ b/apps/recorder/albumart.c @@ -297,3 +297,12 @@ void draw_album_art(struct gui_wps *gwps, int handle_id, bool clear) gwps->display->set_drawmode(DRMODE_SOLID); } } + +void get_albumart_size(struct bitmap *bmp) +{ + /* FIXME: What should we do with albumart on remote? */ + struct wps_data *data = gui_wps[0].data; + + bmp->width = data->albumart_max_width; + bmp->height = data->albumart_max_height; +} diff --git a/apps/recorder/albumart.h b/apps/recorder/albumart.h index cb4fa4f..e09c13a 100644 --- a/apps/recorder/albumart.h +++ b/apps/recorder/albumart.h @@ -40,6 +40,8 @@ void draw_album_art(struct gui_wps *gwps, int handle_id, bool clear); bool search_albumart_files(const struct mp3entry *id3, const char *size_string, char *buf, int buflen); +void get_albumart_size(struct bitmap *bmp); + #endif /* HAVE_ALBUMART */ #endif /* _ALBUMART_H_ */ diff --git a/apps/recorder/bmp.c b/apps/recorder/bmp.c index e965d56..65c5f2b 100644 --- a/apps/recorder/bmp.c +++ b/apps/recorder/bmp.c @@ -45,6 +45,7 @@ #include "config.h" #include "system.h" #include "bmp.h" +#include "resize.h" #include "debug.h" #else #undef DEBUGF @@ -88,11 +89,26 @@ union rgb_union { uint32_t raw; }; -/* masks for supported BI_BITFIELDS encodings (16/32 bit), little endian */ -static const unsigned char bitfields[3][12] = { - { 0x00,0x7c,0x00,0, 0xe0,0x03,0x00,0, 0x1f,0x00,0x00,0 }, /* 15 bit */ - { 0x00,0xf8,0x00,0, 0xe0,0x07,0x00,0, 0x1f,0x00,0x00,0 }, /* 16 bit */ - { 0x00,0x00,0xff,0, 0x00,0xff,0x00,0, 0xff,0x00,0x00,0 }, /* 32 bit */ +/* masks for supported BI_BITFIELDS encodings (16/32 bit) */ +static const struct uint8_rgb bitfields[3][3] = { + /* 15bit */ + { + { .blue = 0x00, .green = 0x7c, .red = 0x00 }, + { .blue = 0xe0, .green = 0x03, .red = 0x00 }, + { .blue = 0x1f, .green = 0x00, .red = 0x00 }, + }, + /* 16bit */ + { + { .blue = 0x00, .green = 0xf8, .red = 0x00 }, + { .blue = 0xe0, .green = 0x07, .red = 0x00 }, + { .blue = 0x1f, .green = 0x00, .red = 0x00 }, + }, + /* 32bit */ + { + { .blue = 0x00, .green = 0x00, .red = 0xff }, + { .blue = 0x00, .green = 0xff, .red = 0x00 }, + { .blue = 0xff, .green = 0x00, .red = 0x00 }, + }, }; #if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) @@ -115,6 +131,11 @@ static const unsigned char dither_matrix[16][16] = { { 42,234, 26,218, 38,230, 22,214, 41,233, 25,217, 37,229, 21,213 }, { 170,106,154, 90,166,102,150, 86,169,105,153, 89,165,101,149, 85 } }; + +unsigned char dither_mat(unsigned char y, unsigned char x) +{ + return dither_matrix[y][x]; +} #endif #if ((LCD_DEPTH == 2) && (LCD_PIXELFORMAT == VERTICAL_INTERLEAVED)) \ @@ -123,6 +144,11 @@ static const unsigned char dither_matrix[16][16] = { static const unsigned short vi_pattern[4] = { 0x0101, 0x0100, 0x0001, 0x0000 }; + +unsigned short vi_pat(unsigned char bright) +{ + return vi_pattern[bright]; +} #endif /* little endian functions */ @@ -139,7 +165,7 @@ static inline uint32_t readlong(uint32_t *value) ((uint32_t)bytes[2] << 16) | ((uint32_t)bytes[3] << 24); } -static inline unsigned brightness(union rgb_union color) +unsigned brightness(struct uint8_rgb color) { return (3 * (unsigned)color.red + 6 * (unsigned)color.green + (unsigned)color.blue) / 10; @@ -154,7 +180,7 @@ static inline unsigned brightness(union rgb_union color) int read_bmp_file(const char* filename, struct bitmap *bm, int maxsize, - int format) + unsigned int format) { int fd, ret; fd = open(filename, O_RDONLY); @@ -170,6 +196,278 @@ int read_bmp_file(const char* filename, return ret; } +static inline void set_rgb_union(struct uint8_rgb *dst, union rgb_union src) +{ + dst->red = src.red; + dst->green = src.green; + dst->blue = src.blue; +} + +#if (LCD_DEPTH > 1) +#define LIMIT_WIDTH (500) +#else +#define LIMIT_WIDTH LCD_WIDTH +#endif + +#if (LCD_WIDTH < LIMIT_WIDTH) +#define MAX_WIDTH LIMIT_WIDTH +#else +#define MAX_WIDTH LCD_WIDTH +#endif + +static uint32_t bmpbuf[MAX_WIDTH]; /* Buffer for one line */ + +static int read_one_line(int fd, struct uint8_rgb *bmpb, short padded_width, + short width, short depth, struct uint8_rgb *palette) +{ + uint32_t data, mask; + unsigned char *p; + uint16_t *p2; + uint32_t *p3; + struct uint8_rgb *rp; + int ret; + struct uint8_rgb q0, q1; + + ret = read(fd, bmpbuf, padded_width); + if (ret != padded_width) { + DEBUGF("read_one_line: error reading image, read returned: %d " + "expected: %d\n", ret, padded_width); + return -9; + } + + /* convert whole line to struct uint8_rgb */ + rp = bmpb + width; + switch (depth) { + case 1: + q0 = palette[0]; + q1 = palette[1]; + p = (unsigned char*)bmpbuf + ((width + 7) >> 3); + mask = 0x80 >> ((width + 7) & 7); + while (p > (unsigned char*)bmpbuf) { + data = *(--p); + for (; mask <= 0x80; mask <<= 1) + *(--rp) = (data & mask) ? q1 : q0; + mask = 0x01; + } + break; + + case 4: + if (width & 1) + rp++; + p = (unsigned char*)bmpbuf + ((width + 1) >> 1); + while (p > (unsigned char*)bmpbuf) { + data = *(--p); + *(--rp) = palette[data & 0x0f]; + *(--rp) = palette[data >> 4]; + } + break; + + case 8: + p = (unsigned char*)bmpbuf + width; + while (p > (unsigned char*)bmpbuf) + *(--rp) = palette[*(--p)]; + break; + + case 15: + case 16: + p2 = (uint16_t *)bmpbuf + width; + while (p2 > (uint16_t *)bmpbuf) { + uint32_t component, rgb; + + data = letoh16(*(--p2)); + /* blue */ + component = (data << 3) & 0xf8; +#ifdef ROCKBOX_BIG_ENDIAN + rgb = (component | (component >> 5)) << 8; + /* green */ + data >>= 2; + if (depth == 15) { + component = data & 0xf8; + rgb |= component | (component >> 5); + } else { + data >>= 1; + component = data & 0xfc; + rgb |= component | (component >> 6); + } + /* red */ + data >>= 5; + component = data & 0xf8; + rgb = (rgb << 8) | component | (component >> 5); + set_rgb_union(--rp, (union rgb_union)(rgb << 8)); +#else /* little endian */ + rgb = component | (component >> 5); + /* green */ + data >>= 2; + if (depth == 15) { + component = data & 0xf8; + rgb |= (component | (component >> 5)) << 8; + } else { + data >>= 1; + component = data & 0xfc; + rgb |= (component | (component >> 6)) << 8; + } + /* red */ + data >>= 5; + component = data & 0xf8; + rgb |= (component | (component >> 5)) << 16; + set_rgb_union(--rp, (union rgb_union)rgb); +#endif + } + break; + + case 24: + p = (unsigned char*)bmpbuf + 3 * width; + while (p > (unsigned char*)bmpbuf) { + data = *(--p); + data = (data << 8) | *(--p); + data = (data << 8) | *(--p); + set_rgb_union(--rp, (union rgb_union)(htole32(data))); + } + break; + + case 32: + p3 = bmpbuf + width; + while (p3 > bmpbuf) + set_rgb_union(--rp, (union rgb_union)(*(--p3))); + break; + } + return 0; +} + +struct cache_line { + struct uint8_rgb bmpbuf[MAX_WIDTH]; + short y; +}; + +#ifdef HAVE_LCD_COLOR +/* needs more than 2 lines for bilinear */ +#define CACHE_SZ 5 +#else +/* only 1 line for nearest neighbour */ +#define CACHE_SZ 1 +#endif + +#define ARRAY_SIZE(array) (int)(sizeof(array)/(sizeof(array[0]))) + +static struct cache_line cache[CACHE_SZ]; +static short cache_index = 0; +static short cache_srcy = -1; + +struct bmp_args { + int fd; + short padded_width; + short width; + short depth; + struct uint8_rgb *palette; +}; + +static struct uint8_rgb *store_line_bmp(short y, void *args) +{ + struct bmp_args *ba = (struct bmp_args *)args; + struct uint8_rgb *qp = NULL; + int i; + + for (i = 0; i < ARRAY_SIZE(cache); i++) { + if (y == cache[i].y) { + qp = cache[i].bmpbuf; + + cache_index = i + 1; + if (cache_index == ARRAY_SIZE(cache)) + cache_index = 0; + + return qp; /* cache found */ + } + } + + /* cache missed, so read some lines from disk.. */ + + /* skip some needless lines */ + int skip = y - cache_srcy - 1; + if (skip > 0) { + if(-1 == lseek(ba->fd, ba->padded_width * skip, SEEK_CUR)) + return NULL; + } + + /* read one line form disk, and store to cache */ + qp = cache[cache_index].bmpbuf; + if (0 != read_one_line(ba->fd, qp, ba->padded_width, ba->width, + ba->depth, ba->palette)) + return NULL; + + cache[cache_index].y = y; + cache_srcy = y; + + cache_index++; + if (cache_index == ARRAY_SIZE(cache)) + cache_index = 0; + + return qp; +} + +static void init_cache(void) +{ + int i; + cache_index = 0; + cache_srcy = -1; + for (i = 0; i < ARRAY_SIZE(cache); i++) + cache[i].y = -1; +} + +#define SCALE 10 + +static inline bool recalc_dimension(struct dim *dst, struct dim *src) +{ + short dst_width = dst->width; + short dst_height = dst->height; + const short src_width = src->width; + const short src_height = src->height; + bool ret = false; + + if (dst_width < 0 || dst_height < 0 || src_width <= 0 || src_height <= 0) { + dst->width = src_width; + dst->height = src_height; + ret = false; + goto out; + } + + if (dst_width == 0) + dst_width = src_width; + if (dst_height == 0) + dst_height = src_height; + + if ((dst_width == src_width) && (dst_height == src_height)) { + dst->width = src_width; + dst->height = src_height; + ret = false; + } else { + /* recalc bmpsize to keep aspect ratio */ + const unsigned short fact_w = (dst_width << SCALE) / src_width; + const unsigned short fact_h = (dst_height << SCALE) / src_height; + const unsigned short fact = MIN(fact_w, fact_h); + + /* "1 << (SCALE -1)" is "round off" */ + dst->width = (src_width * fact + (1 << (SCALE - 1))) >> SCALE; + dst->height = (src_height * fact + (1 << (SCALE -1))) >> SCALE; + + if ((dst->width == src_width) && (dst->height == src_height)) + ret = false; + else + ret = true; + } + +out: + return ret; +} + +static inline int rgbcmp(struct uint8_rgb rgb1, struct uint8_rgb rgb2) +{ + if ((rgb1.red == rgb2.red) && (rgb1.green == rgb2.green) && + (rgb1.blue == rgb2.blue)) + return 0; + else + return 1; +} + /****************************************************************************** * read_bmp_fd() * @@ -180,23 +478,23 @@ int read_bmp_file(const char* filename, int read_bmp_fd(int fd, struct bitmap *bm, int maxsize, - int format) + unsigned int format) { struct bmp_header bmph; - int width, height, padded_width; - int dst_height, dst_width; - int depth, numcolors, compression, totalsize; - int row, col, ret; - int rowstart, rowstop, rowstep; + short width, height, padded_width; + short depth; + int numcolors, compression, totalsize; + short row, col, ret; + short rowstart, rowstop, rowstep; unsigned char *bitmap = bm->data; - uint32_t bmpbuf[LCD_WIDTH]; /* Buffer for one line */ - uint32_t palette[256]; + unsigned char resize = BMP_NORESIZE; + struct uint8_rgb palette[256]; + bool remote = false; #if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) bool transparent = false; bool dither = false; #ifdef HAVE_REMOTE_LCD - bool remote = false; if (format & FORMAT_REMOTE) { remote = true; @@ -207,6 +505,10 @@ int read_bmp_fd(int fd, #endif } #endif /* HAVE_REMOTE_LCD */ + + if ((bm->height > 0) || (bm->width > 0)) + resize = BMP_RESIZE; + if (format & FORMAT_TRANSPARENT) { transparent = true; format &= ~FORMAT_TRANSPARENT; @@ -216,7 +518,7 @@ int read_bmp_fd(int fd, format &= ~FORMAT_DITHER; } #else - + bool dither = false; (void)format; #endif /* (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) */ @@ -232,21 +534,17 @@ int read_bmp_fd(int fd, } width = readlong(&bmph.width); - if (width > LCD_WIDTH) { + if (width > MAX_WIDTH) { DEBUGF("read_bmp_fd: Bitmap too wide (%d pixels, max is %d)\n", - width, LCD_WIDTH); + width, MAX_WIDTH); return -4; } height = readlong(&bmph.height); if (height < 0) { /* Top-down BMP file */ height = -height; - rowstart = 0; - rowstop = height; rowstep = 1; } else { /* normal BMP */ - rowstart = height - 1; - rowstop = -1; rowstep = -1; } @@ -262,46 +560,47 @@ int read_bmp_fd(int fd, } bm->format = format; #endif /* (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) */ - /* returning image size */ - bm->width = width; - bm->height = height; + struct dim src_dim = { + .width = width, + .height = height, + }; -#if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) - if (format == FORMAT_NATIVE) { -#if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1 - if (remote) { -#if (LCD_REMOTE_DEPTH == 2) && (LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED) - dst_width = width; - dst_height = (height + 7) >> 3; -#endif /* LCD_REMOTE_DEPTH / LCD_REMOTE_PIXELFORMAT */ - totalsize = dst_width * dst_height * sizeof(fb_remote_data); - } else -#endif /* defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1 */ - { -#if LCD_DEPTH == 2 -#if LCD_PIXELFORMAT == HORIZONTAL_PACKING - dst_width = (width + 3) >> 2; - dst_height = height; -#elif LCD_PIXELFORMAT == VERTICAL_PACKING - dst_width = width; - dst_height = (height + 3) >> 2; -#elif LCD_PIXELFORMAT == VERTICAL_INTERLEAVED - dst_width = width; - dst_height = (height + 7) >> 3; -#endif /* LCD_PIXELFORMAT */ -#elif LCD_DEPTH == 16 - dst_width = width; - dst_height = height; -#endif /* LCD_DEPTH */ - totalsize = dst_width * dst_height * sizeof(fb_data); + if (resize & BMP_RESIZE) { + struct dim resize_dim = { + .width = bm->width, + .height = bm->height, + }; + /* We always keep aspect ratio.. */ + if (!recalc_dimension(&resize_dim, &src_dim)) + resize = BMP_NORESIZE; + width = resize_dim.width; + height = resize_dim.height; + bm->width = width; + bm->height = height; + } else { + /* returning image size */ + bm->width = src_dim.width; + bm->height = src_dim.height; + } + +#ifdef HAVE_LCD_COLOR + if (resize & BMP_RESIZE) { + if (bm->height * CACHE_SZ < src_dim.height) { + DEBUGF("Warning: This bitmap is too large to downscale!\n"); + resize = BMP_RESIZE_BILINEAR; } - } else -#endif /* (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) */ - { - dst_width = width; - dst_height = (height + 7) >> 3; - totalsize = dst_width * dst_height; } +#endif + + if (rowstep > 0) { /* Top-down BMP file */ + rowstart = 0; + rowstop = height; + } else { /* normal BMP */ + rowstart = height - 1; + rowstop = -1; + } + + totalsize = get_totalsize(bm, remote); /* Check if this fits the buffer */ if (totalsize > maxsize) { @@ -319,11 +618,15 @@ int read_bmp_fd(int fd, numcolors = (compression == 3) ? 3 : 0; if (numcolors > 0 && numcolors <= 256) { - if (read(fd, palette, numcolors * sizeof(uint32_t)) - != numcolors * (int)sizeof(uint32_t)) - { - DEBUGF("read_bmp_fd: Can't read color palette\n"); - return -7; + int i; + union rgb_union pal; + for (i = 0; i < numcolors; i++) { + if (read(fd, &pal, sizeof(pal)) != (int)sizeof(pal)) + { + DEBUGF("read_bmp_fd: Can't read color palette\n"); + return -7; + } + set_rgb_union(&palette[i], pal); } } @@ -343,15 +646,27 @@ int read_bmp_fd(int fd, case 32: if (compression == 3) { /* BI_BITFIELDS */ - if (!memcmp(palette, bitfields[0], 12)) { /* 15 bit */ - depth = 15; - break; + bool found; + int i, j; + + /* (i == 0) is 15bit, (i == 1) is 16bit, (i == 2) is 32bit */ + for (i = 0; i < ARRAY_SIZE(bitfields); i++) { + for (j = 0; j < ARRAY_SIZE(bitfields[0]); j++) { + if (!rgbcmp(palette[j], bitfields[i][j])) { + found = true; + } else { + found = false; + break; + } + } + if (found) { + if (i == 0) /* 15bit */ + depth = 15; + break; + } } - if (!memcmp(palette, bitfields[1], 12) /* 16 bit */ - || !memcmp(palette, bitfields[2], 12)) /* 32 bit */ - { + if (found) break; - } } /* else fall through */ default: @@ -368,119 +683,35 @@ int read_bmp_fd(int fd, memset(bitmap, 0, totalsize); - /* loop to read rows and put them to buffer */ - for (row = rowstart; row != rowstop; row += rowstep) { - unsigned data, mask; - unsigned char *p; - uint16_t *p2; - uint32_t *rp; - union rgb_union *qp; - union rgb_union q0, q1; - - /* read one row */ - ret = read(fd, bmpbuf, padded_width); - if (ret != padded_width) { - DEBUGF("read_bmp_fd: error reading image, read returned: %d " - "expected: %d\n", ret, padded_width); - return -9; - } + if (resize & BMP_RESIZE) { + struct rowset rset = { + .rowstep = rowstep, .rowstart = rowstart, .rowstop = rowstop, + }; + struct bmp_args ba = { + .fd = fd, .padded_width = padded_width, + .width = src_dim.width, .depth = depth, .palette = palette, + }; - /* convert whole line in-place to XRGB8888 (little endian) */ - rp = bmpbuf + width; - switch (depth) { - case 1: - q0.raw = palette[0]; - q1.raw = palette[1]; - p = (unsigned char*)bmpbuf + ((width + 7) >> 3); - mask = 0x80 >> ((width + 7) & 7); - while (p > (unsigned char*)bmpbuf) { - data = *(--p); - for (; mask <= 0x80; mask <<= 1) - *(--rp) = (data & mask) ? q1.raw : q0.raw; - mask = 0x01; - } - break; + init_cache(); - case 4: - if (width & 1) - rp++; - p = (unsigned char*)bmpbuf + ((width + 1) >> 1); - while (p > (unsigned char*)bmpbuf) { - data = *(--p); - *(--rp) = palette[data & 0x0f]; - *(--rp) = palette[data >> 4]; - } - break; + return resize_on_load(bm, dither, &src_dim, &rset, remote, + resize, store_line_bmp, &ba); + } - case 8: - p = (unsigned char*)bmpbuf + width; - while (p > (unsigned char*)bmpbuf) - *(--rp) = palette[*(--p)]; - break; - - case 15: - case 16: - p2 = (uint16_t *)bmpbuf + width; - while (p2 > (uint16_t *)bmpbuf) { - unsigned component, rgb; - - data = letoh16(*(--p2)); - /* blue */ - component = (data << 3) & 0xf8; -#ifdef ROCKBOX_BIG_ENDIAN - rgb = (component | (component >> 5)) << 8; - /* green */ - data >>= 2; - if (depth == 15) { - component = data & 0xf8; - rgb |= component | (component >> 5); - } else { - data >>= 1; - component = data & 0xfc; - rgb |= component | (component >> 6); - } - /* red */ - data >>= 5; - component = data & 0xf8; - rgb = (rgb << 8) | component | (component >> 5); - *(--rp) = rgb << 8; -#else /* little endian */ - rgb = component | (component >> 5); - /* green */ - data >>= 2; - if (depth == 15) { - component = data & 0xf8; - rgb |= (component | (component >> 5)) << 8; - } else { - data >>= 1; - component = data & 0xfc; - rgb |= (component | (component >> 6)) << 8; - } - /* red */ - data >>= 5; - component = data & 0xf8; - rgb |= (component | (component >> 5)) << 16; - *(--rp) = rgb; -#endif - } - break; + struct uint8_rgb *bmpb = cache[0].bmpbuf; + short fb_width = get_fb_width(bm, remote); - case 24: - p = (unsigned char*)bmpbuf + 3 * width; - while (p > (unsigned char*)bmpbuf) { - data = *(--p); - data = (data << 8) | *(--p); - data = (data << 8) | *(--p); - *(--rp) = htole32(data); - } - break; + /* loop to read rows and put them to buffer */ + for (row = rowstart; row != rowstop; row += rowstep) { + unsigned mask; + unsigned char *p; + struct uint8_rgb *qp; - case 32: /* already in desired format */ - break; - } + if (0 != read_one_line(fd, bmpb, padded_width, width, depth, palette)) + return -9; /* Convert to destination format */ - qp = (union rgb_union *)bmpbuf; + qp = bmpb; #if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) if (format == FORMAT_NATIVE) { #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1 @@ -488,7 +719,7 @@ int read_bmp_fd(int fd, #if (LCD_REMOTE_DEPTH == 2) && (LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED) /* iAudio X5/M5 remote */ fb_remote_data *dest = (fb_remote_data *)bitmap - + dst_width * (row >> 3); + + fb_width * (row >> 3); int shift = row & 7; int delta = 127; unsigned bright; @@ -507,7 +738,7 @@ int read_bmp_fd(int fd, #if LCD_DEPTH == 2 #if LCD_PIXELFORMAT == HORIZONTAL_PACKING /* greyscale iPods */ - fb_data *dest = (fb_data *)bitmap + dst_width * row; + fb_data *dest = (fb_data *)bitmap + fb_width * row; int shift = 6; int delta = 127; unsigned bright; @@ -530,7 +761,7 @@ int read_bmp_fd(int fd, *dest++ = data; #elif LCD_PIXELFORMAT == VERTICAL_PACKING /* iriver H1x0 */ - fb_data *dest = (fb_data *)bitmap + dst_width * (row >> 2); + fb_data *dest = (fb_data *)bitmap + fb_width * (row >> 2); int shift = 2 * (row & 3); int delta = 127; unsigned bright; @@ -544,7 +775,7 @@ int read_bmp_fd(int fd, } #elif LCD_PIXELFORMAT == VERTICAL_INTERLEAVED /* iAudio M3 */ - fb_data *dest = (fb_data *)bitmap + dst_width * (row >> 3); + fb_data *dest = (fb_data *)bitmap + fb_width * (row >> 3); int shift = row & 7; int delta = 127; unsigned bright; @@ -559,9 +790,10 @@ int read_bmp_fd(int fd, #endif /* LCD_PIXELFORMAT */ #elif LCD_DEPTH == 16 /* iriver h300, colour iPods, X5 */ - fb_data *dest = (fb_data *)bitmap + dst_width * row; + fb_data *dest = (fb_data *)bitmap + fb_width * row; int delta = 127; unsigned r, g, b; + struct uint8_rgb q0; for (col = 0; col < width; col++) { if (dither) @@ -577,7 +809,7 @@ int read_bmp_fd(int fd, } else #endif /* (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) */ { - p = bitmap + dst_width * (row >> 3); + p = bitmap + fb_width * (row >> 3); mask = 1 << (row & 7); for (col = 0; col < width; col++, p++) diff --git a/apps/recorder/bmp.h b/apps/recorder/bmp.h index 4e9f336..ffc0511 100644 --- a/apps/recorder/bmp.h +++ b/apps/recorder/bmp.h @@ -23,6 +23,146 @@ #include "config.h" #include "lcd.h" +#include "inttypes.h" +#ifdef HAVE_REMOTE_LCD +#include "lcd-remote.h" +#endif + +#define BMP_NORESIZE 0 +#define BMP_RESIZE 1 +#define BMP_BILINEAR 2 +#define BMP_RESIZE_BILINEAR (BMP_RESIZE | BMP_BILINEAR) + +struct uint8_rgb { + uint8_t blue; + uint8_t green; + uint8_t red; +}; + +struct dim { + short width; + short height; +}; + +struct rowset { + short rowstep; + short rowstart; + short rowstop; +}; + +#if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) +unsigned char dither_mat(unsigned char x, unsigned char y); +#endif + +unsigned brightness(struct uint8_rgb color); + +#if ((LCD_DEPTH == 2) && (LCD_PIXELFORMAT == VERTICAL_INTERLEAVED)) \ + || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH == 2) \ + && (LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED)) +unsigned short vi_pat(unsigned char bright); +#endif + +static inline int get_fb_height(struct bitmap *bm, bool remote) +{ + const short height = bm->height; +#if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) + const unsigned int format = bm->format; +#endif + short dst_height; + +#if !defined(HAVE_REMOTE_LCD) || \ + (defined(HAVE_REMOTE_LCD) &&(LCD_REMOTE_DEPTH == 1)) + (void) remote; +#endif + +#if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) + if (format == FORMAT_NATIVE) { +#if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1 + if (remote) { +#if (LCD_REMOTE_DEPTH == 2) && (LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED) + dst_height = (height + 7) >> 3; +#endif /* LCD_REMOTE_DEPTH / LCD_REMOTE_PIXELFORMAT */ + } else +#endif /* defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1 */ + { +#if LCD_DEPTH == 2 +#if LCD_PIXELFORMAT == HORIZONTAL_PACKING + dst_height = height; +#elif LCD_PIXELFORMAT == VERTICAL_PACKING + dst_height = (height + 3) >> 2; +#elif LCD_PIXELFORMAT == VERTICAL_INTERLEAVED + dst_height = (height + 7) >> 3; +#endif /* LCD_PIXELFORMAT */ +#elif LCD_DEPTH == 16 + dst_height = height; +#endif /* LCD_DEPTH */ + } + } else +#endif /* (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) */ + { + dst_height = (height + 7) >> 3; + } + + return dst_height; +} + +static inline int get_fb_width(struct bitmap *bm, bool remote) +{ + const short width = bm->width; +#if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) + const unsigned int format = bm->format; +#endif + short dst_width; + +#if !defined(HAVE_REMOTE_LCD) || \ + (defined(HAVE_REMOTE_LCD) &&(LCD_REMOTE_DEPTH == 1)) + (void) remote; +#endif + +#if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) + if (format == FORMAT_NATIVE) { +#if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1 + if (remote) { +#if (LCD_REMOTE_DEPTH == 2) && (LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED) + dst_width = width; +#endif /* LCD_REMOTE_DEPTH / LCD_REMOTE_PIXELFORMAT */ + } else +#endif /* defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1 */ + { +#if LCD_DEPTH == 2 +#if LCD_PIXELFORMAT == HORIZONTAL_PACKING + dst_width = (width + 3) >> 2; +#elif LCD_PIXELFORMAT == VERTICAL_PACKING + dst_width = width; +#elif LCD_PIXELFORMAT == VERTICAL_INTERLEAVED + dst_width = width; +#endif /* LCD_PIXELFORMAT */ +#elif LCD_DEPTH == 16 + dst_width = width; +#endif /* LCD_DEPTH */ + } + } else +#endif /* (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) */ + { + dst_width = width; + } + + return dst_width; +} + +static inline int get_totalsize(struct bitmap *bm, bool remote) +{ + int sz; +#if defined(HAVE_REMOTE_LCD) && \ + (LCD_REMOTE_DEPTH == 2) && (LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED) + if (remote) + sz = sizeof(fb_remote_data); + else +#endif /* LCD_REMOTE_DEPTH / LCD_REMOTE_PIXELFORMAT */ + sz = sizeof(fb_data); + + return get_fb_width(bm, remote) * get_fb_height(bm, remote) * sz; +} /********************************************************************* * read_bmp_file() @@ -35,10 +175,10 @@ int read_bmp_file(const char* filename, struct bitmap *bm, int maxsize, - int format); + unsigned int format); int read_bmp_fd(int fd, struct bitmap *bm, int maxsize, - int format); + unsigned int format); #endif diff --git a/apps/recorder/resize-color.c b/apps/recorder/resize-color.c new file mode 100644 index 0000000..e9bc31f --- /dev/null +++ b/apps/recorder/resize-color.c @@ -0,0 +1,453 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id + * + * Copyright (C) 2008 by Akio Idehara + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +/* + * Code for the scaling algorithm: + * Imlib2 is (C) Carsten Haitzler and various contributors. The MMX code + * is by Willem Monsuwe . Additional modifications are by + * (C) Daniel M. Duley. + * + * Port to Rockbox + * Copyright (C) 2007 Jonas Hurrelmann (j@outpo.st) + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +/* + * Copyright (C) 2004, 2005 Daniel M. Duley + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +/* OTHER CREDITS: + * + * This is the normal smoothscale method, based on Imlib2's smoothscale. + * + * Originally I took the algorithm used in NetPBM and Qt and added MMX/3dnow + * optimizations. It ran in about 1/2 the time as Qt. Then I ported Imlib's + * C algorithm and it ran at about the same speed as my MMX optimized one... + * Finally I ported Imlib's MMX version and it ran in less than half the + * time as my MMX algorithm, (taking only a quarter of the time Qt does). + * After further optimization it seems to run at around 1/6th. + * + * Changes include formatting, namespaces and other C++'ings, removal of old + * #ifdef'ed code, and removal of unneeded border calculation code. + * + * Imlib2 is (C) Carsten Haitzler and various contributors. The MMX code + * is by Willem Monsuwe . All other modifications are + * (C) Daniel M. Duley. + */ + +#include +#include +#include +#include "inttypes.h" +#include "debug.h" +#include "lcd.h" +#include "file.h" +#ifdef HAVE_REMOTE_LCD +#include "lcd-remote.h" +#endif +#ifndef __PCTOOL__ +#include "config.h" +#include "system.h" +#include "bmp.h" +#include "resize.h" +#include "resize-common.h" +#include "debug.h" +#else +#undef DEBUGF +#define DEBUGF(...) +#endif + +#define PACKRED(r, delata) (31 * r + (r >> 3) + delta) >> 8; +#define PACKGREEN(g, delta) (63 * g + (g >> 2) + delta) >> 8; +#define PACKBLUE(b, delta) (31 * b + (b >> 3) + delta) >> 8; + +struct int32_rgb { + int32_t r; + int32_t g; + int32_t b; +}; + +/* + * "BILINEAR" algorithm is taken from app/plugins/lib/bmp_smooth_scale.c + * smooth_resize_bitmap() (xup_yup == 3). + * And that is take from Imlib2 + */ +static inline bool bilinear(struct bitmap *bm, bool dither, struct dim *src, + struct rowset *rset, + struct uint8_rgb* (*store_line)(short y, void *args), + void *args) +{ + const short sw = src->width; + const short sh = src->height; + const short dw = bm->width; + const short dh = bm->height; + const int inc_x = (sw << 16) / dw; + const int inc_y = (sh << 16) / dh; + unsigned char *bitmap = bm->data; + int XAP, YAP, INV_YAP, INV_XAP; + int val_y = 0, val_x; + short x, y, xpoint, ypoint; + const short rowstep = rset->rowstep; + const short rowstart = rset->rowstart; + const short rowstop = rset->rowstop; + + for (y = rowstart; y != rowstop; y += rowstep) { + struct uint8_rgb *qp, *qp2; + int delta = 127; + + ypoint = (val_y >> 16); + fb_data *dest = (fb_data *)bitmap + y * dw; + + if ((qp = (*store_line)(ypoint, args)) == NULL) + goto out; + + YAP = ((val_y >> 16) >= (sh - 1)) ? 0 : + (val_y >> 8) - ((val_y >> 8) & 0xffffff00); + INV_YAP = 256 - YAP; + val_y += inc_y; + val_x = 0; + if (YAP > 0) { + for (x = 0; x < dw; x++) { + int r = 0, g = 0, b = 0; + int rr = 0, gg = 0, bb = 0; + struct uint8_rgb *pix; + if (dither) + delta = dither_mat(y & 0xf, x & 0xf); + xpoint = (val_x >> 16); + XAP = ((val_x >> 16) >= (sw - 1)) ? 0 : + (val_x >> 8) - ((val_x >> 8) & 0xffffff00); + INV_XAP = 256 - XAP; + val_x += inc_x; + + if (XAP > 0) { + pix = qp + xpoint; + r = pix->red * INV_XAP; + g = pix->green * INV_XAP; + b = pix->blue * INV_XAP; + pix++; + r += pix->red * XAP; + g += pix->green * XAP; + b += pix->blue * XAP; + + if ((qp2 = (*store_line)(ypoint + 1, args)) == NULL) + goto out; + + + pix = qp2 + xpoint; + rr = pix->red * INV_XAP; + gg = pix->green * INV_XAP; + bb = pix->blue * INV_XAP; + pix++; + rr += pix->red * XAP; + gg += pix->green * XAP; + bb += pix->blue * XAP; + r = ((rr * YAP) + (r * INV_YAP)) >> 16; + g = ((gg * YAP) + (g * INV_YAP)) >> 16; + b = ((bb * YAP) + (b * INV_YAP)) >> 16; + r = PACKRED(r, delta); + g = PACKGREEN(g, delta); + b = PACKBLUE(b, delta); + *dest++ = LCD_RGBPACK_LCD(r, g, b); + } else { + pix = qp + xpoint; + r = pix->red * INV_YAP; + g = pix->green * INV_YAP; + b = pix->blue * INV_YAP; + + if ((qp2 = (*store_line)(ypoint + 1, args)) == NULL) + goto out; + + pix = qp2 + xpoint; + r += pix->red * YAP; + g += pix->green * YAP; + b += pix->blue * YAP; + r >>= 8; + g >>= 8; + b >>= 8; + r = PACKRED(r, delta); + g = PACKGREEN(g, delta); + b = PACKBLUE(b, delta); + *dest++ = LCD_RGBPACK_LCD(r, g, b); + } + } + } else { + for (x = 0; x < dw; x++) { + int r = 0, g = 0, b = 0; + struct uint8_rgb *pix; + if (dither) + delta = dither_mat(y & 0xf, x & 0xf); + xpoint = (val_x >> 16); + XAP = ((val_x >> 16) >= (sw - 1)) ? 0 : + (val_x >> 8) - ((val_x >> 8) & 0xffffff00); + INV_XAP = 256 - XAP; + val_x += inc_x; + + if (XAP > 0) { + pix = qp + xpoint; + r = pix->red * INV_XAP; + g = pix->green * INV_XAP; + b = pix->blue * INV_XAP; + pix++; + r += pix->red * XAP; + g += pix->green * XAP; + b += pix->blue * XAP; + r >>= 8; + g >>= 8; + b >>= 8; + r = PACKRED(r, delta); + g = PACKGREEN(g, delta); + b = PACKBLUE(b, delta); + *dest++ = LCD_RGBPACK_LCD(r, g, b); + } else { + pix = qp + xpoint; + r = pix->red; + g = pix->green; + b = pix->blue; + r = PACKRED(r, delta); + g = PACKGREEN(g, delta); + b = PACKBLUE(b, delta); + *dest++ = LCD_RGBPACK_LCD(r, g, b); + } + } + } + } + return true; + +out: + return false; +} + +/* + * "AREA SAMPLING" algorithm is taken from app/plugins/lib/bmp_smooth_scale.c + * smooth_resize_bitmap() (xup_yup == 0). + * And that is take from Imlib2 + */ +static void area_sample_part(struct uint8_rgb *pix, int xap, + int Cx, int Cy, struct int32_rgb *rgb) +{ + int i; + int rx = (pix->red * xap) >> 9; + int gx = (pix->green * xap) >> 9; + int bx = (pix->blue * xap) >> 9; + pix++; + for (i = (1 << 14) - xap; i > Cx; i -= Cx) { + rx += (pix->red * Cx) >> 9; + gx += (pix->green * Cx) >> 9; + bx += (pix->blue * Cx) >> 9; + pix++; + } + if (i > 0) { + rx += (pix->red * i) >> 9; + gx += (pix->green * i) >> 9; + bx += (pix->blue * i) >> 9; + } + + rgb->r = (rx * Cy) >> 14; + rgb->g = (gx * Cy) >> 14; + rgb->b = (bx * Cy) >> 14; +} + +static inline bool area_sample(struct bitmap *bm, bool dither, struct dim *src, + struct rowset *rset, + struct uint8_rgb* (*store_line)(short y, void *args), + void *args) +{ + const short sw = src->width; + const short sh = src->height; + const short dw = bm->width; + const short dh = bm->height; + const int inc_x = (sw << 16) / dw; + const int inc_y = (sh << 16) / dh; + const int Cp_x = ((dw << 14) / sw) + 1; + const int Cp_y = ((dh << 14) / sh) + 1; + unsigned char *bitmap = bm->data; + int XAP, YAP, INV_YAP, INV_XAP; + int val_y = 0, val_x; + short x, y, xpoint, ypoint; + const short rowstep = rset->rowstep; + const short rowstart = rset->rowstart; + const short rowstop = rset->rowstop; + + for (y = rowstart; y != rowstop; y += rowstep) { + int delta = 127; + struct uint8_rgb *qp; + int Cx, Cy, j; + struct uint8_rgb *pix; + int r, g, b; + int xap, yap; + fb_data *dest = (fb_data *)bitmap + y * dw; + + if ((qp = (*store_line)(val_y >> 16, args)) == NULL) + goto out; + + YAP = (((0x100 - ((val_y >> 8) & 0xff)) * Cp_y) >> 8) | + (Cp_y << 16); + INV_YAP = 256 - YAP; + val_y += inc_y; + val_x = 0; + + Cy = YAP >> 16; + yap = YAP & 0xffff; + + for (x = 0; x < dw; x++) { + struct int32_rgb rgbset; + ypoint = ((val_y - inc_y) >> 16); + if (dither) + delta = dither_mat(y & 0xf, x & 0xf); + xpoint = (val_x >> 16); + XAP = (((0x100 - ((val_x >> 8) & 0xff)) * Cp_x) >> 8) | + (Cp_x << 16); + INV_XAP = 256 - XAP; + val_x += inc_x; + + Cx = XAP >> 16; + xap = XAP & 0xffff; + + pix = qp + xpoint; + ypoint++; + + area_sample_part(pix, xap, Cx, yap, &rgbset); + r = rgbset.r; + g = rgbset.g; + b = rgbset.b; + + for (j = (1 << 14) - yap; j > Cy; j -= Cy) { + if ((qp = (*store_line)(ypoint, args)) == NULL) + goto out; + + pix = qp + xpoint; + ypoint++; + + area_sample_part(pix, xap, Cx, Cy, &rgbset); + r += rgbset.r; + g += rgbset.g; + b += rgbset.b; + } + if (j > 0) { + + if ((qp = (*store_line)(ypoint, args)) == NULL) + goto out; + + pix = qp + xpoint; + ypoint++; + + area_sample_part(pix, xap, Cx, j, &rgbset); + r += rgbset.r; + g += rgbset.g; + b += rgbset.b; + } + + r = PACKRED(r, delta); + g = PACKGREEN(g, delta); + b = PACKBLUE(b, delta); + *dest = LCD_RGBPACK_LCD(r >> 5, g >> 5, b >> 5); + dest++; + } + } + return true; + +out: + return false; + +} + +int resize_on_load(struct bitmap *bm, bool dither, struct dim *src, + struct rowset *rset, bool remote, unsigned char resize, + struct uint8_rgb* (*store_line)(short y, void *args), + void *args) +{ + const short sw = src->width; + const short sh = src->height; + const short dw = bm->width; + const short dh = bm->height; + unsigned char xup_yup; + int format = bm->format; + + if (resize & BMP_BILINEAR) + xup_yup = 3; /* always use bilinear */ + else + xup_yup = (dw >= sw) + ((dh >= sh) << 1); + + + if (format == FORMAT_NATIVE) { +#if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1 + if (remote) { +#if (LCD_REMOTE_DEPTH == 2) && (LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED) + /* resize with "Nearest Neighbour" */ + if (!nearest_remote(bm, dither, src, rset, store_line, args)) + goto out; +#endif /* LCD_REMOTE_DEPTH / LCD_REMOTE_PIXELFORMAT */ + } else +#endif /* defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1 */ + { + if (xup_yup == 0) { + /* downscaling both way use "Area Sampling" */ + if (!area_sample(bm, dither, src, rset, store_line, args)) + goto out; + } else { + /* + * xup_yup == 3 then upscaling both way + * xup_yup == 2 then downscaling horizontal + * xup_yup == 1 then downscaling vertically + * use "Biliner" + */ + if (!bilinear(bm, dither, src, rset, store_line, args)) + goto out; + } + } + } else { + /* resize with "Nearest Neighbour" */ + if (!nearest_mono(bm, src, rset, store_line, args)) + goto out; + } + return get_totalsize(bm, remote); + +out: + return -1; +} diff --git a/apps/recorder/resize-common.c b/apps/recorder/resize-common.c new file mode 100644 index 0000000..84eb462 --- /dev/null +++ b/apps/recorder/resize-common.c @@ -0,0 +1,134 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id + * + * Copyright (C) 2008 by Akio Idehara + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#include +#include +#include +#include "inttypes.h" +#include "debug.h" +#include "lcd.h" +#include "file.h" +#ifdef HAVE_REMOTE_LCD +#include "lcd-remote.h" +#endif +#ifndef __PCTOOL__ +#include "config.h" +#include "system.h" +#include "bmp.h" +#include "resize.h" +#include "debug.h" +#else +#undef DEBUGF +#define DEBUGF(...) +#endif + +/* resize with "Nearest Neighbour" */ +bool nearest_mono(struct bitmap *bm, struct dim *src, struct rowset *rset, + struct uint8_rgb* (*store_line)(short y, void *args), + void *args) +{ + const short sw = src->width; + const short sh = src->height; + const short dw = bm->width; + const short dh = bm->height; + const int inc_x = (sw << 16) / dw; + const int inc_y = (sh << 16) / dh; + unsigned char *bitmap = bm->data; + int val_y = 0, val_x; + short x, y, xpoint, ypoint; + const short rowstep = rset->rowstep; + const short rowstart = rset->rowstart; + const short rowstop = rset->rowstop; + + for (y = rowstart; y != rowstop; y += rowstep) { + unsigned char *p = bitmap + get_fb_width(bm, false) * (y >> 3); + unsigned mask = 1 << (y & 7); + struct uint8_rgb *qp; + + ypoint = (val_y >> 8); + if ((qp = (*store_line)(ypoint, args)) == NULL) + return false; + + for (val_x = 0, x = 0; x < dw; x++, p++) { + struct uint8_rgb *pix; + xpoint = (val_x >> 8); + pix = qp + xpoint; + if (brightness(*pix) < 128) + *p |= mask; + val_x += inc_x; + } + val_y += inc_y; + } + + return true; +} + +#if defined(HAVE_REMOTE_LCD) && \ + (LCD_REMOTE_DEPTH == 2) && (LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED) +/* resize with "Nearest Neighbour" */ +bool nearest_remote(struct bitmap *bm, bool dither, struct dim *src, + struct rowset *rset, + struct uint8_rgb* (*store_line)(short y, void *args), + void *args) +{ + const short sw = src->width; + const short sh = src->height; + const short dw = bm->width; + const short dh = bm->height; + const int inc_x = (sw << 16) / dw; + const int inc_y = (sh << 16) / dh; + unsigned char *bitmap = bm->data; + int val_y = 0, val_x; + short x, y, xpoint, ypoint; + const short rowstep = rset->rowstep; + const short rowstart = rset->rowstart; + const short rowstop = rset->rowstop; + + for (y = rowstart; y != rowstop; y += rowstep) { + /* iAudio X5/M5 remote */ + fb_remote_data *dest = (fb_remote_data *)bitmap + + get_fb_width(bm, true) * (y >> 3); + int shift = y & 7; + int delta = 127; + unsigned bright; + struct uint8_rgb *qp; + + ypoint = (val_y >> 8); + if ((qp = (*store_line)(ypoint, args)) == NULL) + return false; + + for (val_x = 0, x = 0; x < dw; x++) { + struct uint8_rgb *pix; + if (dither) + delta = dither_mat(y & 0xf, x & 0xf); + xpoint = (val_x >> 8); + pix = qp + xpoint; + bright = brightness(*pix); + bright = (3 * bright + (bright >> 6) + delta) >> 8; + *dest++ |= vi_pat(bright) << shift; + val_x += inc_x; + } + val_y += inc_y; + } + + return true; +} +#endif /* LCD_REMOTE_DEPTH / LCD_REMOTE_PIXELFORMAT */ diff --git a/apps/recorder/resize-common.h b/apps/recorder/resize-common.h new file mode 100644 index 0000000..e698147 --- /dev/null +++ b/apps/recorder/resize-common.h @@ -0,0 +1,38 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id + * + * Copyright (C) 2008 by Akio Idehara + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#ifndef _RESIZE_COMMON_H_ +#define _RESIZE_COMMON_H_ + +#include "config.h" +#include "lcd.h" + +bool nearest_mono(struct bitmap *bm, struct dim *src, struct rowset *rset, + struct uint8_rgb* (*store_line)(short y, void *args), + void *args); +#if defined(HAVE_REMOTE_LCD) && \ + (LCD_REMOTE_DEPTH == 2) && (LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED) +bool nearest_remote(struct bitmap *bm, bool dither, struct dim *src, + struct rowset *rset, + struct uint8_rgb* (*store_line)(short y, void *args), + void *args); +#endif + +#endif /* _RESIZE_COMMON_H_ */ diff --git a/apps/recorder/resize-gray.c b/apps/recorder/resize-gray.c new file mode 100644 index 0000000..896c261 --- /dev/null +++ b/apps/recorder/resize-gray.c @@ -0,0 +1,202 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id + * + * Copyright (C) 2008 by Akio Idehara + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#include +#include +#include +#include "inttypes.h" +#include "debug.h" +#include "lcd.h" +#include "file.h" +#ifdef HAVE_REMOTE_LCD +#include "lcd-remote.h" +#endif +#ifndef __PCTOOL__ +#include "config.h" +#include "system.h" +#include "bmp.h" +#include "resize.h" +#include "resize-common.h" +#include "debug.h" +#else +#undef DEBUGF +#define DEBUGF(...) +#endif + +#if (LCD_DEPTH == 2) +/* + * This algorithm is taken from apps/plugins/lib/bmp.c simple_resize_bitmap(). + * And that algorithm is "Nearest Neighbour". + */ +static inline bool nearest_2bpp(struct bitmap *bm, bool dither, + struct dim *src, + struct rowset *rset, + struct uint8_rgb* (*store_line)(short y, void *args), + void *args) +{ + const short sw = src->width; + const short sh = src->height; + const short dw = bm->width; + const short dh = bm->height; + int val_y = 0, val_x; + const int inc_x = ((sw - 1) << 8) / (dw - 1); + const int inc_y = ((sh - 1) << 8) / (dh - 1); + unsigned char *bitmap = bm->data; + short x, y, xpoint, ypoint; + const short rowstep = rset->rowstep; + const short rowstart = rset->rowstart; + const short rowstop = rset->rowstop; + const short fb_width = get_fb_width(bm, false); + + for (y = rowstart; y != rowstop; y += rowstep) { +#if LCD_PIXELFORMAT == HORIZONTAL_PACKING + /* greyscale iPods */ + fb_data *dest = (fb_data *)bitmap + fb_width * y; + int shift = 6; + int delta = 127; + unsigned bright; + unsigned data = 0; + struct uint8_rgb *qp; + + ypoint = (val_y >> 8); + if ((qp = (*store_line)(ypoint, args)) == NULL) + return NULL; + + for (val_x = 0, x = 0; x < dw; x++) { + struct uint8_rgb *pix; + if (dither) + delta = dither_mat(y & 0xf, x & 0xf); + xpoint = (val_x >> 8); + pix = qp + xpoint; + bright = brightness(*pix); + bright = (3 * bright + (bright >> 6) + delta) >> 8; + data |= (~bright & 3) << shift; + shift -= 2; + if (shift < 0) { + *dest++ = data; + data = 0; + shift = 6; + } + val_x += inc_x; + } + val_y += inc_y; + if (shift < 6) + *dest++ = data; +#elif LCD_PIXELFORMAT == VERTICAL_PACKING + /* iriver H1x0 */ + fb_data *dest = (fb_data *)bitmap + fb_width * (y >> 2); + int shift = 2 * (y & 3); + int delta = 127; + unsigned bright; + struct uint8_rgb *qp; + + ypoint = (val_y >> 8); + if ((qp = (*store_line)(ypoint, args)) == NULL) + return NULL; + + for (val_x = 0, x = 0; x < dw; x++) { + struct uint8_rgb *pix; + if (dither) + delta = dither_mat(y & 0xf, x & 0xf); + xpoint = (val_x >> 8); + pix = qp + xpoint; + bright = brightness(*pix); + bright = (3 * bright + (bright >> 6) + delta) >> 8; + *dest++ |= (~bright & 3) << shift; + val_x += inc_x; + } + val_y += inc_y; +#elif LCD_PIXELFORMAT == VERTICAL_INTERLEAVED + /* iAudio M3 */ + fb_data *dest = (fb_data *)bitmap + fb_width * (y >> 3); + int shift = y & 7; + int delta = 127; + unsigned bright; + struct uint8_rgb *qp; + + ypoint = (val_y >> 8); + if ((qp = (*store_line)(ypoint, args)) == NULL) + return NULL; + + for (val_x = 0, x = 0; x < dw; x++) { + struct uint8_rgb *pix; + if (dither) + delta = dither_mat(y & 0xf, x & 0xf); + xpoint = (val_x >> 8); + pix = qp + xpoint; + bright = brightness(*pix); + bright = (3 * bright + (bright >> 6) + delta) >> 8; + *dest++ |= vi_pat(bright) << shift; + val_x += inc_x; + } + val_y += inc_y; +#endif /* LCD_PIXELFORMAT */ + } + + return true; +} +#endif + +int resize_on_load(struct bitmap *bm, bool dither, + struct dim *src, + struct rowset *rset, bool remote, unsigned char resize, + struct uint8_rgb* (*store_line)(short y, void *args), + void *args) +{ +#if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) + int format = bm->format; +#endif /* (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) */ + (void) resize; + +#if (LCD_DEPTH == 1) + (void) dither; +#endif + +#if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) + if (format == FORMAT_NATIVE) { +#if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1 + if (remote) { +#if (LCD_REMOTE_DEPTH == 2) && (LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED) + /* resize with "Nearest Neighbour" */ + if (!nearest_remote(bm, dither, src, rset, store_line, args)) + goto out; +#endif /* LCD_REMOTE_DEPTH / LCD_REMOTE_PIXELFORMAT */ + } else +#endif /* defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1 */ + { +#if LCD_DEPTH == 2 + /* resize with "Nearest Neighbour" */ + if (!nearest_2bpp(bm, dither, src, rset, store_line, args)) + goto out; +#endif /* LCD_DEPTH == 2 */ + } + } else +#endif /* (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) */ + { + /* resize with "Nearest Neighbour" */ + if (!nearest_mono(bm, src, rset, store_line, args)) + goto out; + } + return get_totalsize(bm, remote); + +out: + return -1; +} diff --git a/apps/recorder/resize.h b/apps/recorder/resize.h new file mode 100644 index 0000000..5768a26 --- /dev/null +++ b/apps/recorder/resize.h @@ -0,0 +1,46 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id + * + * Copyright (C) 2008 by Akio Idehara + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#ifndef _RESIZE_H_ +#define _RESIZE_H_ + +#include "config.h" +#include "lcd.h" + +/**************************************************************** + * resize_on_load() + * + * resize bitmap on load with scaling + * + * If HAVE_LCD_COLOR then this func use smooth scaling algorithm + * - downscaling both way use "Area Sampling" if BMP_RESIZE_BILINER is NOT set + * - otherwise "Bilinear" + * + * If !(HAVE_LCD_COLOR) then use simple scaling algorithm "Nearest Neighbour" + * + * return -1 for error + ****************************************************************/ + +int resize_on_load(struct bitmap *bm, bool dither, + struct dim *src, + struct rowset *tmp_row, bool remote, unsigned char resize, + struct uint8_rgb* (*store_line)(short y, void *args), + void *args); +#endif /* _RESIZE_H_ */ diff --git a/firmware/export/lcd.h b/firmware/export/lcd.h index b210154..5121799 100644 --- a/firmware/export/lcd.h +++ b/firmware/export/lcd.h @@ -372,12 +372,21 @@ struct bitmap { int width; int height; #if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) - int format; + unsigned int format; unsigned char *maskdata; #endif unsigned char *data; }; +static inline struct bitmap* noresize(struct bitmap *bm) +{ + /* no resize */ + bm->width = 0; + bm->height = 0; + + return bm; +} + extern void lcd_set_invert_display(bool yesno); #ifdef HAVE_BACKLIGHT_INVERSION extern void lcd_set_backlight_inversion(bool yesno);