summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Mahone <andrew.mahone@gmail.com>2008-12-09 23:07:59 +0000
committerAndrew Mahone <andrew.mahone@gmail.com>2008-12-09 23:07:59 +0000
commit781421afa2085b841b52f876d80f484f565c0755 (patch)
treee952fe4857a1ee3edb91642bfbb96c93947748b4
parenta2c71fde1bdb1a62cf66ae0e3b9a864824930dd0 (diff)
downloadrockbox-781421afa2085b841b52f876d80f484f565c0755.tar.gz
rockbox-781421afa2085b841b52f876d80f484f565c0755.zip
resize-on-load for bitmap files on 2bpp and color targets
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@19374 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--apps/SOURCES1
-rw-r--r--apps/buffering.c12
-rw-r--r--apps/gui/gwps.c3
-rw-r--r--apps/gui/gwps.h18
-rw-r--r--apps/gui/wps_parser.c74
-rw-r--r--apps/plugins/sliding_puzzle.c41
-rw-r--r--apps/recorder/albumart.c9
-rw-r--r--apps/recorder/albumart.h2
-rw-r--r--apps/recorder/bmp.c752
-rw-r--r--apps/recorder/bmp.h157
-rw-r--r--apps/recorder/resize.c718
-rw-r--r--apps/recorder/resize.h60
-rw-r--r--docs/CREDITS1
-rw-r--r--firmware/export/lcd.h2
14 files changed, 1453 insertions, 397 deletions
diff --git a/apps/SOURCES b/apps/SOURCES
index 2ea41c290a..c63bcb78e2 100644
--- a/apps/SOURCES
+++ b/apps/SOURCES
@@ -85,6 +85,7 @@ gui/viewport.c
85 85
86#if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)) 86#if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
87gui/backdrop.c 87gui/backdrop.c
88recorder/resize.c
88#endif 89#endif
89 90
90#ifdef HAVE_LCD_CHARCELLS 91#ifdef HAVE_LCD_CHARCELLS
diff --git a/apps/buffering.c b/apps/buffering.c
index ba613eb9db..dfc90065d6 100644
--- a/apps/buffering.c
+++ b/apps/buffering.c
@@ -52,6 +52,9 @@
52#include "bmp.h" 52#include "bmp.h"
53#include "appevents.h" 53#include "appevents.h"
54#include "metadata.h" 54#include "metadata.h"
55#ifdef HAVE_ALBUMART
56#include "albumart.h"
57#endif
55 58
56#if MEM > 1 59#if MEM > 1
57#define GUARD_BUFSIZE (32*1024) 60#define GUARD_BUFSIZE (32*1024)
@@ -852,8 +855,13 @@ static int load_bitmap(int fd)
852 bmp->maskdata = NULL; 855 bmp->maskdata = NULL;
853#endif 856#endif
854 857
855 int free = (int)MIN(buffer_len - BUF_USED, buffer_len - buf_widx); 858 int free = (int)MIN(buffer_len - BUF_USED, buffer_len - buf_widx)
856 rc = read_bmp_fd(fd, bmp, free, FORMAT_ANY|FORMAT_DITHER); 859 - sizeof(struct bitmap);
860
861 get_albumart_size(bmp);
862
863 rc = read_bmp_fd(fd, bmp, free, FORMAT_NATIVE|FORMAT_DITHER|
864 FORMAT_RESIZE|FORMAT_KEEP_ASPECT);
857 return rc + (rc > 0 ? sizeof(struct bitmap) : 0); 865 return rc + (rc > 0 ? sizeof(struct bitmap) : 0);
858} 866}
859#endif 867#endif
diff --git a/apps/gui/gwps.c b/apps/gui/gwps.c
index 9b6d6b5558..a9ad5788b7 100644
--- a/apps/gui/gwps.c
+++ b/apps/gui/gwps.c
@@ -813,6 +813,9 @@ void gui_sync_wps_init(void)
813 FOR_NB_SCREENS(i) 813 FOR_NB_SCREENS(i)
814 { 814 {
815 wps_data_init(&wps_datas[i]); 815 wps_data_init(&wps_datas[i]);
816#ifdef HAVE_ALBUMART
817 wps_datas[i].wps_uses_albumart = 0;
818#endif
816#ifdef HAVE_REMOTE_LCD 819#ifdef HAVE_REMOTE_LCD
817 wps_datas[i].remote_wps = (i != 0); 820 wps_datas[i].remote_wps = (i != 0);
818#endif 821#endif
diff --git a/apps/gui/gwps.h b/apps/gui/gwps.h
index 4cffb0de2c..6311bc058b 100644
--- a/apps/gui/gwps.h
+++ b/apps/gui/gwps.h
@@ -47,13 +47,11 @@
47#define WPS_ALBUMART_CHECK 1 /* WPS contains AA conditional tag */ 47#define WPS_ALBUMART_CHECK 1 /* WPS contains AA conditional tag */
48#define WPS_ALBUMART_LOAD 2 /* WPS contains AA tag */ 48#define WPS_ALBUMART_LOAD 2 /* WPS contains AA tag */
49 49
50#define WPS_ALBUMART_ALIGN_RIGHT WPS_ALIGN_RIGHT /* x align: right */ 50#define WPS_ALBUMART_ALIGN_RIGHT 1 /* x align: right */
51#define WPS_ALBUMART_ALIGN_CENTER WPS_ALIGN_CENTER /* x/y align: center */ 51#define WPS_ALBUMART_ALIGN_CENTER 2 /* x/y align: center */
52#define WPS_ALBUMART_ALIGN_LEFT WPS_ALIGN_LEFT /* x align: left */ 52#define WPS_ALBUMART_ALIGN_LEFT 4 /* x align: left */
53#define WPS_ALBUMART_ALIGN_TOP WPS_ALIGN_RIGHT /* y align: top */ 53#define WPS_ALBUMART_ALIGN_TOP 1 /* y align: top */
54#define WPS_ALBUMART_ALIGN_BOTTOM WPS_ALIGN_LEFT /* y align: bottom */ 54#define WPS_ALBUMART_ALIGN_BOTTOM 4 /* y align: bottom */
55#define WPS_ALBUMART_INCREASE 8 /* increase if smaller */
56#define WPS_ALBUMART_DECREASE 16 /* decrease if larger */
57 55
58#endif /* HAVE_ALBUMART */ 56#endif /* HAVE_ALBUMART */
59 57
@@ -382,10 +380,8 @@ struct wps_data
382 unsigned char wps_uses_albumart; /* WPS_ALBUMART_NONE, _CHECK, _LOAD */ 380 unsigned char wps_uses_albumart; /* WPS_ALBUMART_NONE, _CHECK, _LOAD */
383 short albumart_x; 381 short albumart_x;
384 short albumart_y; 382 short albumart_y;
385 unsigned short albumart_xalign; /* WPS_ALBUMART_ALIGN_LEFT, _CENTER, _RIGHT, 383 unsigned char albumart_xalign; /* WPS_ALBUMART_ALIGN_LEFT, _CENTER, _RIGHT */
386 + .._INCREASE, + .._DECREASE */ 384 unsigned char albumart_yalign; /* WPS_ALBUMART_ALIGN_TOP, _CENTER, _BOTTOM */
387 unsigned short albumart_yalign; /* WPS_ALBUMART_ALIGN_TOP, _CENTER, _BOTTOM,
388 + .._INCREASE, + .._DECREASE */
389 short albumart_max_width; 385 short albumart_max_width;
390 short albumart_max_height; 386 short albumart_max_height;
391 387
diff --git a/apps/gui/wps_parser.c b/apps/gui/wps_parser.c
index 42853e8fae..307d0bb784 100644
--- a/apps/gui/wps_parser.c
+++ b/apps/gui/wps_parser.c
@@ -969,23 +969,15 @@ static int parse_albumart_load(const char *wps_bufptr,
969{ 969{
970 const char *_pos, *newline; 970 const char *_pos, *newline;
971 bool parsing; 971 bool parsing;
972 const short xalign_mask = WPS_ALBUMART_ALIGN_LEFT |
973 WPS_ALBUMART_ALIGN_CENTER |
974 WPS_ALBUMART_ALIGN_RIGHT;
975 const short yalign_mask = WPS_ALBUMART_ALIGN_TOP |
976 WPS_ALBUMART_ALIGN_CENTER |
977 WPS_ALBUMART_ALIGN_BOTTOM;
978
979 (void)token; /* silence warning */ 972 (void)token; /* silence warning */
980 973
981 /* reset albumart info in wps */ 974 /* reset albumart info in wps */
982 wps_data->wps_uses_albumart = WPS_ALBUMART_NONE;
983 wps_data->albumart_max_width = -1; 975 wps_data->albumart_max_width = -1;
984 wps_data->albumart_max_height = -1; 976 wps_data->albumart_max_height = -1;
985 wps_data->albumart_xalign = WPS_ALBUMART_ALIGN_CENTER; /* default */ 977 wps_data->albumart_xalign = WPS_ALBUMART_ALIGN_CENTER; /* default */
986 wps_data->albumart_yalign = WPS_ALBUMART_ALIGN_CENTER; /* default */ 978 wps_data->albumart_yalign = WPS_ALBUMART_ALIGN_CENTER; /* default */
987 979
988 /* format: %Cl|x|y|[[l|c|r][d|i|s]mwidth]|[[t|c|b][d|i|s]mheight]| */ 980 /* format: %Cl|x|y|[[l|c|r]mwidth]|[[t|c|b]mheight]| */
989 981
990 newline = strchr(wps_bufptr, '\n'); 982 newline = strchr(wps_bufptr, '\n');
991 983
@@ -1020,35 +1012,24 @@ static int parse_albumart_load(const char *wps_bufptr,
1020 case 'l': 1012 case 'l':
1021 case 'L': 1013 case 'L':
1022 case '+': 1014 case '+':
1023 wps_data->albumart_xalign = 1015 wps_data->albumart_xalign = WPS_ALBUMART_ALIGN_LEFT;
1024 (wps_data->albumart_xalign & xalign_mask) |
1025 WPS_ALBUMART_ALIGN_LEFT;
1026 break; 1016 break;
1027 case 'c': 1017 case 'c':
1028 case 'C': 1018 case 'C':
1029 wps_data->albumart_xalign = 1019 wps_data->albumart_xalign = WPS_ALBUMART_ALIGN_CENTER;
1030 (wps_data->albumart_xalign & xalign_mask) |
1031 WPS_ALBUMART_ALIGN_CENTER;
1032 break; 1020 break;
1033 case 'r': 1021 case 'r':
1034 case 'R': 1022 case 'R':
1035 case '-': 1023 case '-':
1036 wps_data->albumart_xalign = 1024 wps_data->albumart_xalign = WPS_ALBUMART_ALIGN_RIGHT;
1037 (wps_data->albumart_xalign & xalign_mask) |
1038 WPS_ALBUMART_ALIGN_RIGHT;
1039 break; 1025 break;
1040 case 'd': 1026 case 'd':
1041 case 'D': 1027 case 'D':
1042 wps_data->albumart_xalign |= WPS_ALBUMART_DECREASE;
1043 break;
1044 case 'i': 1028 case 'i':
1045 case 'I': 1029 case 'I':
1046 wps_data->albumart_xalign |= WPS_ALBUMART_INCREASE;
1047 break;
1048 case 's': 1030 case 's':
1049 case 'S': 1031 case 'S':
1050 wps_data->albumart_xalign |= 1032 /* simply ignored */
1051 (WPS_ALBUMART_DECREASE | WPS_ALBUMART_INCREASE);
1052 break; 1033 break;
1053 default: 1034 default:
1054 parsing = false; 1035 parsing = false;
@@ -1080,35 +1061,24 @@ static int parse_albumart_load(const char *wps_bufptr,
1080 case 't': 1061 case 't':
1081 case 'T': 1062 case 'T':
1082 case '-': 1063 case '-':
1083 wps_data->albumart_yalign = 1064 wps_data->albumart_yalign = WPS_ALBUMART_ALIGN_TOP;
1084 (wps_data->albumart_yalign & yalign_mask) |
1085 WPS_ALBUMART_ALIGN_TOP;
1086 break; 1065 break;
1087 case 'c': 1066 case 'c':
1088 case 'C': 1067 case 'C':
1089 wps_data->albumart_yalign = 1068 wps_data->albumart_yalign = WPS_ALBUMART_ALIGN_CENTER;
1090 (wps_data->albumart_yalign & yalign_mask) |
1091 WPS_ALBUMART_ALIGN_CENTER;
1092 break; 1069 break;
1093 case 'b': 1070 case 'b':
1094 case 'B': 1071 case 'B':
1095 case '+': 1072 case '+':
1096 wps_data->albumart_yalign = 1073 wps_data->albumart_yalign = WPS_ALBUMART_ALIGN_BOTTOM;
1097 (wps_data->albumart_yalign & yalign_mask) |
1098 WPS_ALBUMART_ALIGN_BOTTOM;
1099 break; 1074 break;
1100 case 'd': 1075 case 'd':
1101 case 'D': 1076 case 'D':
1102 wps_data->albumart_yalign |= WPS_ALBUMART_DECREASE;
1103 break;
1104 case 'i': 1077 case 'i':
1105 case 'I': 1078 case 'I':
1106 wps_data->albumart_yalign |= WPS_ALBUMART_INCREASE;
1107 break;
1108 case 's': 1079 case 's':
1109 case 'S': 1080 case 'S':
1110 wps_data->albumart_yalign |= 1081 /* simply ignored */
1111 (WPS_ALBUMART_DECREASE | WPS_ALBUMART_INCREASE);
1112 break; 1082 break;
1113 default: 1083 default:
1114 parsing = false; 1084 parsing = false;
@@ -1524,9 +1494,6 @@ static void wps_reset(struct wps_data *data)
1524 bool rwps = data->remote_wps; /* remember whether the data is for a RWPS */ 1494 bool rwps = data->remote_wps; /* remember whether the data is for a RWPS */
1525#endif 1495#endif
1526 memset(data, 0, sizeof(*data)); 1496 memset(data, 0, sizeof(*data));
1527#ifdef HAVE_ALBUMART
1528 data->wps_uses_albumart = WPS_ALBUMART_NONE;
1529#endif
1530 wps_data_init(data); 1497 wps_data_init(data);
1531#ifdef HAVE_REMOTE_LCD 1498#ifdef HAVE_REMOTE_LCD
1532 data->remote_wps = rwps; 1499 data->remote_wps = rwps;
@@ -1617,6 +1584,14 @@ bool wps_data_load(struct wps_data *wps_data,
1617 const char *buf, 1584 const char *buf,
1618 bool isfile) 1585 bool isfile)
1619{ 1586{
1587#ifdef HAVE_ALBUMART
1588 struct mp3entry *curtrack;
1589 long offset;
1590 int status;
1591 int wps_uses_albumart = wps_data->wps_uses_albumart;
1592 int albumart_max_height = wps_data->albumart_max_height;
1593 int albumart_max_width = wps_data->albumart_max_width;
1594#endif
1620 if (!wps_data || !buf) 1595 if (!wps_data || !buf)
1621 return false; 1596 return false;
1622 1597
@@ -1732,6 +1707,21 @@ bool wps_data_load(struct wps_data *wps_data,
1732 return false; 1707 return false;
1733 } 1708 }
1734#endif 1709#endif
1710#ifdef HAVE_ALBUMART
1711 status = audio_status();
1712 if (((!wps_uses_albumart && wps_data->wps_uses_albumart) ||
1713 (wps_data->wps_uses_albumart &&
1714 (albumart_max_height != wps_data->albumart_max_height ||
1715 albumart_max_width != wps_data->albumart_max_width))) &&
1716 status & AUDIO_STATUS_PLAY)
1717 {
1718 curtrack = audio_current_track();
1719 offset = curtrack->offset;
1720 audio_stop();
1721 if (!(status & AUDIO_STATUS_PAUSE))
1722 audio_play(offset);
1723 }
1724#endif
1735 return true; 1725 return true;
1736 } 1726 }
1737} 1727}
diff --git a/apps/plugins/sliding_puzzle.c b/apps/plugins/sliding_puzzle.c
index 755129c9b9..fddb6bebc2 100644
--- a/apps/plugins/sliding_puzzle.c
+++ b/apps/plugins/sliding_puzzle.c
@@ -249,11 +249,12 @@ static int num_font = FONT_UI;
249static int moves_font = FONT_UI; 249static int moves_font = FONT_UI;
250static int moves_y = 0; 250static int moves_y = 0;
251 251
252#ifdef HAVE_LCD_COLOR
253static unsigned char *img_buf;
254static size_t buf_len;
255#else
252static unsigned char img_buf[IMAGE_WIDTH*IMAGE_HEIGHT*sizeof(fb_data)] 256static unsigned char img_buf[IMAGE_WIDTH*IMAGE_HEIGHT*sizeof(fb_data)]
253__attribute__ ((aligned(16))); 257__attribute__ ((aligned(16)));
254#if LCD_DEPTH>1
255static unsigned char temp_img_buf[LCD_WIDTH*LCD_HEIGHT*sizeof(fb_data)]
256__attribute__ ((aligned(16)));
257#endif 258#endif
258#ifdef HAVE_ALBUMART 259#ifdef HAVE_ALBUMART
259static char albumart_path[MAX_PATH+1]; 260static char albumart_path[MAX_PATH+1];
@@ -330,37 +331,22 @@ static bool load_resize_bitmap(void)
330 rb->memset(&main_bitmap,0,sizeof(struct bitmap)); 331 rb->memset(&main_bitmap,0,sizeof(struct bitmap));
331 main_bitmap.data = img_buf; 332 main_bitmap.data = img_buf;
332 333
333#if LCD_DEPTH>1
334 struct bitmap temp_bitmap;
335 rb->memset(&temp_bitmap,0,sizeof(struct bitmap));
336 temp_bitmap.data = temp_img_buf;
337
338 main_bitmap.width = IMAGE_WIDTH; 334 main_bitmap.width = IMAGE_WIDTH;
339 main_bitmap.height = IMAGE_HEIGHT; 335 main_bitmap.height = IMAGE_HEIGHT;
340 336
341 rc = rb->read_bmp_file( filename, &temp_bitmap, sizeof(temp_img_buf), 337#ifndef HAVE_LCD_COLOR
342 FORMAT_NATIVE ); 338 size_t buf_len = sizeof(img_buf);
343 if( rc > 0 )
344 {
345#ifdef HAVE_LCD_COLOR
346 smooth_resize_bitmap( &temp_bitmap, &main_bitmap );
347#else
348 simple_resize_bitmap( &temp_bitmap, &main_bitmap );
349#endif 339#endif
350 puzzle_bmp_ptr = (const fb_data *)img_buf; 340
351 rb->strcpy( img_buf_path, filename ); 341 rc = rb->read_bmp_file( filename, &main_bitmap,
352 return true; 342 buf_len,
353 } 343 FORMAT_NATIVE|FORMAT_RESIZE );
354#else
355 rc = rb->read_bmp_file( filename, &main_bitmap, sizeof(img_buf),
356 FORMAT_NATIVE );
357 if( rc > 0 ) 344 if( rc > 0 )
358 { 345 {
359 puzzle_bmp_ptr = (const fb_data *)img_buf; 346 puzzle_bmp_ptr = (const fb_data *)img_buf;
360 rb->strcpy( img_buf_path, filename ); 347 rb->strcpy( img_buf_path, filename );
361 return true; 348 return true;
362 } 349 }
363#endif
364 } 350 }
365 351
366 /* something must have failed. get_albumart_bmp_path could return 352 /* something must have failed. get_albumart_bmp_path could return
@@ -632,6 +618,13 @@ enum plugin_status plugin_start(const struct plugin_api* api, const void* parame
632 initial_bmp_path=(const char *)parameter; 618 initial_bmp_path=(const char *)parameter;
633 picmode = PICMODE_INITIAL_PICTURE; 619 picmode = PICMODE_INITIAL_PICTURE;
634 img_buf_path[0] = '\0'; 620 img_buf_path[0] = '\0';
621#ifdef HAVE_LCD_COLOR
622 unsigned char *img_buf_end;
623 img_buf = (unsigned char *)(rb->plugin_get_buffer(&buf_len));
624 img_buf_end = img_buf + buf_len;
625 rb->align_buffer(PUN_PTR(void **,&img_buf), buf_len, 16);
626 buf_len = img_buf_end - img_buf;
627#endif
635 628
636 /* If launched as a viewer, just go straight to the game without 629 /* If launched as a viewer, just go straight to the game without
637 bothering with the splash or instructions page */ 630 bothering with the splash or instructions page */
diff --git a/apps/recorder/albumart.c b/apps/recorder/albumart.c
index 30a4e0c49f..babf63ef1c 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)
297 gwps->display->set_drawmode(DRMODE_SOLID); 297 gwps->display->set_drawmode(DRMODE_SOLID);
298 } 298 }
299} 299}
300
301void get_albumart_size(struct bitmap *bmp)
302{
303 /* FIXME: What should we do with albumart on remote? */
304 struct wps_data *data = gui_wps[0].data;
305
306 bmp->width = data->albumart_max_width;
307 bmp->height = data->albumart_max_height;
308}
diff --git a/apps/recorder/albumart.h b/apps/recorder/albumart.h
index 52e7c74c02..ecfdb9c9ed 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);
40bool search_albumart_files(const struct mp3entry *id3, const char *size_string, 40bool search_albumart_files(const struct mp3entry *id3, const char *size_string,
41 char *buf, int buflen); 41 char *buf, int buflen);
42 42
43void get_albumart_size(struct bitmap *bmp);
44
43#endif /* HAVE_ALBUMART */ 45#endif /* HAVE_ALBUMART */
44 46
45#endif /* _ALBUMART_H_ */ 47#endif /* _ALBUMART_H_ */
diff --git a/apps/recorder/bmp.c b/apps/recorder/bmp.c
index 9327ac5ec4..cdff8ccb07 100644
--- a/apps/recorder/bmp.c
+++ b/apps/recorder/bmp.c
@@ -29,6 +29,13 @@
29 - better protection against malformed / non-standard BMPs 29 - better protection against malformed / non-standard BMPs
30 - code heavily optimised for both size and speed 30 - code heavily optimised for both size and speed
31 - dithering for 2 bit targets 31 - dithering for 2 bit targets
322008-11-02 Akio Idehara: refactor for scaler frontend
332008-12-08 Andrew Mahone: partial-line reading, scaler frontend
34 - read_part_line does the actual source BMP reading, return columns read
35 and updates fields in a struct bmp_args with the new data and current
36 reader state
37 - skip_lines_bmp and store_part_bmp implement the scaler callbacks to skip
38 ahead by whole lines, or read the next chunk of the current line
32*/ 39*/
33 40
34#include <stdio.h> 41#include <stdio.h>
@@ -41,10 +48,16 @@
41#ifdef HAVE_REMOTE_LCD 48#ifdef HAVE_REMOTE_LCD
42#include "lcd-remote.h" 49#include "lcd-remote.h"
43#endif 50#endif
51#ifdef ROCKBOX_DEBUG_BMP_LOADER
52#define BDEBUGF DEBUGF
53#else
54#define BDEBUGF(...)
55#endif
44#ifndef __PCTOOL__ 56#ifndef __PCTOOL__
45#include "config.h" 57#include "config.h"
46#include "system.h" 58#include "system.h"
47#include "bmp.h" 59#include "bmp.h"
60#include "resize.h"
48#include "debug.h" 61#include "debug.h"
49#else 62#else
50#undef DEBUGF 63#undef DEBUGF
@@ -88,16 +101,31 @@ union rgb_union {
88 uint32_t raw; 101 uint32_t raw;
89}; 102};
90 103
91/* masks for supported BI_BITFIELDS encodings (16/32 bit), little endian */ 104/* masks for supported BI_BITFIELDS encodings (16/32 bit) */
92static const unsigned char bitfields[3][12] = { 105static const struct uint8_rgb bitfields[3][3] = {
93 { 0x00,0x7c,0x00,0, 0xe0,0x03,0x00,0, 0x1f,0x00,0x00,0 }, /* 15 bit */ 106 /* 15bit */
94 { 0x00,0xf8,0x00,0, 0xe0,0x07,0x00,0, 0x1f,0x00,0x00,0 }, /* 16 bit */ 107 {
95 { 0x00,0x00,0xff,0, 0x00,0xff,0x00,0, 0xff,0x00,0x00,0 }, /* 32 bit */ 108 { .blue = 0x00, .green = 0x7c, .red = 0x00 },
109 { .blue = 0xe0, .green = 0x03, .red = 0x00 },
110 { .blue = 0x1f, .green = 0x00, .red = 0x00 },
111 },
112 /* 16bit */
113 {
114 { .blue = 0x00, .green = 0xf8, .red = 0x00 },
115 { .blue = 0xe0, .green = 0x07, .red = 0x00 },
116 { .blue = 0x1f, .green = 0x00, .red = 0x00 },
117 },
118 /* 32bit */
119 {
120 { .blue = 0x00, .green = 0x00, .red = 0xff },
121 { .blue = 0x00, .green = 0xff, .red = 0x00 },
122 { .blue = 0xff, .green = 0x00, .red = 0x00 },
123 },
96}; 124};
97 125
98#if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) 126#if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)
99/* canonical ordered dither matrix */ 127/* canonical ordered dither matrix */
100static const unsigned char dither_matrix[16][16] = { 128const unsigned char dither_matrix[16][16] = {
101 { 0,192, 48,240, 12,204, 60,252, 3,195, 51,243, 15,207, 63,255 }, 129 { 0,192, 48,240, 12,204, 60,252, 3,195, 51,243, 15,207, 63,255 },
102 { 128, 64,176,112,140, 76,188,124,131, 67,179,115,143, 79,191,127 }, 130 { 128, 64,176,112,140, 76,188,124,131, 67,179,115,143, 79,191,127 },
103 { 32,224, 16,208, 44,236, 28,220, 35,227, 19,211, 47,239, 31,223 }, 131 { 32,224, 16,208, 44,236, 28,220, 35,227, 19,211, 47,239, 31,223 },
@@ -120,31 +148,11 @@ static const unsigned char dither_matrix[16][16] = {
120#if ((LCD_DEPTH == 2) && (LCD_PIXELFORMAT == VERTICAL_INTERLEAVED)) \ 148#if ((LCD_DEPTH == 2) && (LCD_PIXELFORMAT == VERTICAL_INTERLEAVED)) \
121 || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH == 2) \ 149 || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH == 2) \
122 && (LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED)) 150 && (LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED))
123static const unsigned short vi_pattern[4] = { 151const unsigned short vi_pattern[4] = {
124 0x0101, 0x0100, 0x0001, 0x0000 152 0x0101, 0x0100, 0x0001, 0x0000
125}; 153};
126#endif 154#endif
127 155
128/* little endian functions */
129static inline unsigned readshort(uint16_t *value)
130{
131 unsigned char* bytes = (unsigned char*) value;
132 return (unsigned)bytes[0] | ((unsigned)bytes[1] << 8);
133}
134
135static inline uint32_t readlong(uint32_t *value)
136{
137 unsigned char* bytes = (unsigned char*) value;
138 return (uint32_t)bytes[0] | ((uint32_t)bytes[1] << 8) |
139 ((uint32_t)bytes[2] << 16) | ((uint32_t)bytes[3] << 24);
140}
141
142static inline unsigned brightness(union rgb_union color)
143{
144 return (3 * (unsigned)color.red + 6 * (unsigned)color.green
145 + (unsigned)color.blue) / 10;
146}
147
148/****************************************************************************** 156/******************************************************************************
149 * read_bmp_file() 157 * read_bmp_file()
150 * 158 *
@@ -165,11 +173,219 @@ int read_bmp_file(const char* filename,
165 return fd * 10 - 1; 173 return fd * 10 - 1;
166 } 174 }
167 175
176 BDEBUGF("read_bmp_file: '%s' remote: %d resize: %d keep_aspect: %d\n",
177 filename, !!(format & FORMAT_REMOTE), !!(format & FORMAT_RESIZE),
178 !!(format & FORMAT_KEEP_ASPECT));
168 ret = read_bmp_fd(fd, bm, maxsize, format); 179 ret = read_bmp_fd(fd, bm, maxsize, format);
169 close(fd); 180 close(fd);
170 return ret; 181 return ret;
171} 182}
172 183
184static inline void set_rgb_union(struct uint8_rgb *dst, union rgb_union src)
185{
186 dst->red = src.red;
187 dst->green = src.green;
188 dst->blue = src.blue;
189}
190
191struct bmp_args {
192 int fd;
193 short padded_width;
194 short read_width;
195 short width;
196 short depth;
197 unsigned char buf[MAX_WIDTH * 4];
198 struct uint8_rgb *palette;
199#if LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)
200 int cur_row;
201 int cur_col;
202 struct img_part part;
203#endif
204};
205
206static unsigned int read_part_line(struct bmp_args *ba)
207{
208 const int padded_width = ba->padded_width;
209 const int read_width = ba->read_width;
210 const int width = ba->width;
211 const int depth = ba->depth;
212#if LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)
213 int cur_row = ba->cur_row;
214 int cur_col = ba->cur_col;
215#endif
216 const int fd = ba->fd;
217 uint8_t *ibuf;
218 struct uint8_rgb *buf = (struct uint8_rgb *)(ba->buf);
219 const struct uint8_rgb *palette = ba->palette;
220 uint32_t component, data = data;
221 int ret;
222 int i, cols, len;
223
224#if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)
225 cols = MIN(width - cur_col,(int)MAX_WIDTH);
226 len = (cols * (depth == 15 ? 16 : depth) + 7) >> 3;
227#else
228 cols = width;
229 len = read_width;
230#endif
231 ibuf = ((unsigned char *)buf) + (MAX_WIDTH << 2) - len;
232 BDEBUGF("read_part_line: cols=%d len=%d\n",cols,len);
233 ret = read(fd, ibuf, len);
234 if (ret != len)
235 {
236 DEBUGF("read_part_line: error reading image, read returned %d "
237 "expected %d\n", ret, len);
238 BDEBUGF("cur_row: %d cur_col: %d cols: %d len: %d\n", cur_row, cur_col,
239 cols, len);
240 return 0;
241 }
242 for (i = 0; i < cols; i++)
243 {
244 switch (depth)
245 {
246 case 1:
247 if ((i & 7) == 0)
248 data = *ibuf++;
249 *buf = palette[(data >> 7) & 1];
250 data <<= 1;
251 break;
252 case 4:
253 *buf = palette[*ibuf >> 4];
254 if (i & 1)
255 ibuf++;
256 else
257 *ibuf <<= 4;
258 break;
259 case 8:
260 *buf = palette[*ibuf++];
261 break;
262 case 15:
263 case 16:
264 data = letoh16(*(uint16_t*)ibuf);
265 component = (data << 3) & 0xf8;
266 component |= component >> 5;
267 buf->blue = component;
268 if (depth == 15)
269 {
270 data >>= 2;
271 component = data & 0xf8;
272 component |= component >> 5;
273 } else {
274 data >>= 3;
275 component = data & 0xfc;
276 component |= component >> 6;
277 }
278 buf->green = component;
279 data >>= 5;
280 component = data & 0xf8;
281 component |= component >> 5;
282 buf->red = component;
283 ibuf += 2;
284 break;
285 case 32:
286 case 24:
287 buf->blue = *ibuf++;
288 buf->green = *ibuf++;
289 buf->red = *ibuf++;
290 if (depth == 32)
291 ibuf++;
292 break;
293 }
294 buf++;
295 }
296
297#if LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)
298 cur_col += cols;
299 if (cur_col == width)
300 {
301#endif
302 int pad = padded_width - read_width;
303 if (pad > 0)
304 {
305 BDEBUGF("seeking %d bytes to next line\n",pad);
306 lseek(fd, pad, SEEK_CUR);
307 }
308#if LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)
309 cur_col = 0;
310 BDEBUGF("read_part_line: completed row %d\n", cur_row);
311 cur_row += 1;
312 }
313
314 ba->cur_row = cur_row;
315 ba->cur_col = cur_col;
316#endif
317 return cols;
318}
319
320#if LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)
321static struct img_part *store_part_bmp(void *args)
322{
323 struct bmp_args *ba = (struct bmp_args *)args;
324
325 ba->part.len = read_part_line(ba);
326 ba->part.buf = (struct uint8_rgb *)ba->buf;
327 if (ba->part.len)
328 return &(ba->part);
329 else
330 return NULL;
331}
332
333static bool skip_lines_bmp(void *args, unsigned int lines)
334{
335 struct bmp_args * ba = (struct bmp_args *)args;
336
337 int pad = lines * ba->padded_width +
338 (ba->cur_col
339 ? ((ba->cur_col * ba->depth + 7) >> 3) - ba->padded_width
340 : 0);
341 if (pad)
342 {
343 if(lseek(ba->fd, pad, SEEK_CUR) < 0)
344
345 return false;
346 }
347 ba->cur_row += lines + (ba->cur_col ? 1 : 0);
348 ba->cur_col = 0;
349 return true;
350}
351#endif
352
353#if LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)
354static inline int recalc_dimension(struct dim *dst, struct dim *src)
355{
356 int tmp;
357 if (dst->width <= 0)
358 dst->width = LCD_WIDTH;
359 if (dst->height <= 0)
360 dst->height = LCD_HEIGHT;
361#ifndef HAVE_UPSCALER
362 if (dst->width > src->width || dst->height > src->height)
363 {
364 dst->width = src->width;
365 dst->height = src->height;
366 }
367 if (src->width == dst->width && src->height == dst->height)
368 return 1;
369#endif
370 tmp = (src->width * dst->height + (src->height >> 1)) / src->height;
371 if (tmp > dst->width)
372 dst->height = (src->height * dst->width + (src->width >> 1))
373 / src->width;
374 else
375 dst->width = tmp;
376 return src->width == dst->width && src->height == dst->height;
377}
378#endif
379
380static inline int rgbcmp(struct uint8_rgb rgb1, struct uint8_rgb rgb2)
381{
382 if ((rgb1.red == rgb2.red) && (rgb1.green == rgb2.green) &&
383 (rgb1.blue == rgb2.blue))
384 return 0;
385 else
386 return 1;
387}
388
173/****************************************************************************** 389/******************************************************************************
174 * read_bmp_fd() 390 * read_bmp_fd()
175 * 391 *
@@ -183,21 +399,22 @@ int read_bmp_fd(int fd,
183 int format) 399 int format)
184{ 400{
185 struct bmp_header bmph; 401 struct bmp_header bmph;
186 int width, height, padded_width; 402 int padded_width;
187 int dst_height, dst_width; 403 int read_width;
188 int depth, numcolors, compression, totalsize; 404 int depth, numcolors, compression, totalsize;
189 int row, col, ret; 405 int ret;
190 int rowstart, rowstop, rowstep;
191 406
192 unsigned char *bitmap = bm->data; 407 unsigned char *bitmap = bm->data;
193 uint32_t bmpbuf[LCD_WIDTH]; /* Buffer for one line */ 408 struct uint8_rgb palette[256];
194 uint32_t palette[256]; 409 bool remote = false;
410 struct rowset rset;
411 struct dim src_dim;
195#if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) 412#if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)
196 bool transparent = false; 413 unsigned int resize = IMG_NORESIZE;
197 bool dither = false; 414 bool dither = false;
198#ifdef HAVE_REMOTE_LCD 415 bool transparent = false;
199 bool remote = false;
200 416
417#ifdef HAVE_REMOTE_LCD
201 if (format & FORMAT_REMOTE) { 418 if (format & FORMAT_REMOTE) {
202 remote = true; 419 remote = true;
203#if LCD_REMOTE_DEPTH == 1 420#if LCD_REMOTE_DEPTH == 1
@@ -207,6 +424,12 @@ int read_bmp_fd(int fd,
207#endif 424#endif
208 } 425 }
209#endif /* HAVE_REMOTE_LCD */ 426#endif /* HAVE_REMOTE_LCD */
427
428 if (format & FORMAT_RESIZE) {
429 resize = IMG_RESIZE;
430 format &= ~FORMAT_RESIZE;
431 }
432
210 if (format & FORMAT_TRANSPARENT) { 433 if (format & FORMAT_TRANSPARENT) {
211 transparent = true; 434 transparent = true;
212 format &= ~FORMAT_TRANSPARENT; 435 format &= ~FORMAT_TRANSPARENT;
@@ -218,7 +441,7 @@ int read_bmp_fd(int fd,
218#else 441#else
219 442
220 (void)format; 443 (void)format;
221#endif /* (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) */ 444#endif /*(LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)*/
222 445
223 /* read fileheader */ 446 /* read fileheader */
224 ret = read(fd, &bmph, sizeof(struct bmp_header)); 447 ret = read(fd, &bmph, sizeof(struct bmp_header));
@@ -231,78 +454,78 @@ int read_bmp_fd(int fd,
231 return -3; 454 return -3;
232 } 455 }
233 456
234 width = readlong(&bmph.width); 457 src_dim.width = letoh32(bmph.width);
235 if (width > LCD_WIDTH) { 458 src_dim.height = letoh32(bmph.height);
236 DEBUGF("read_bmp_fd: Bitmap too wide (%d pixels, max is %d)\n", 459 if (src_dim.height < 0) { /* Top-down BMP file */
237 width, LCD_WIDTH); 460 src_dim.height = -src_dim.height;
238 return -4; 461 rset.rowstep = 1;
239 }
240
241 height = readlong(&bmph.height);
242 if (height < 0) { /* Top-down BMP file */
243 height = -height;
244 rowstart = 0;
245 rowstop = height;
246 rowstep = 1;
247 } else { /* normal BMP */ 462 } else { /* normal BMP */
248 rowstart = height - 1; 463 rset.rowstep = -1;
249 rowstop = -1;
250 rowstep = -1;
251 } 464 }
252 465
253 depth = readshort(&bmph.bit_count); 466 depth = letoh16(bmph.bit_count);
254 padded_width = ((width * depth + 31) >> 3) & ~3; /* 4-byte boundary aligned */ 467 /* 4-byte boundary aligned */
468 read_width = ((src_dim.width * (depth == 15 ? 16 : depth) + 7) >> 3);
469 padded_width = (read_width + 3) & ~3;
255 470
471 BDEBUGF("width: %d height: %d depth: %d padded_width: %d\n", src_dim.width,
472 src_dim.height, depth, padded_width);
473
256#if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) 474#if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)
257 if (format == FORMAT_ANY) { 475 if ((format & 3) == FORMAT_ANY) {
258 if (depth == 1) 476 if (depth == 1)
259 format = FORMAT_MONO; 477 format = (format & ~3);
260 else 478 else
261 format = FORMAT_NATIVE; 479 format = (format & ~3) | FORMAT_NATIVE;
262 } 480 }
263 bm->format = format; 481 bm->format = format & 3;
264#endif /* (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) */ 482 if ((format & 3) == FORMAT_MONO)
265 /* returning image size */
266 bm->width = width;
267 bm->height = height;
268
269#if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)
270 if (format == FORMAT_NATIVE) {
271#if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
272 if (remote) {
273#if (LCD_REMOTE_DEPTH == 2) && (LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED)
274 dst_width = width;
275 dst_height = (height + 7) >> 3;
276#endif /* LCD_REMOTE_DEPTH / LCD_REMOTE_PIXELFORMAT */
277 totalsize = dst_width * dst_height * sizeof(fb_remote_data);
278 } else
279#endif /* defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1 */
280 {
281#if LCD_DEPTH == 2
282#if LCD_PIXELFORMAT == HORIZONTAL_PACKING
283 dst_width = (width + 3) >> 2;
284 dst_height = height;
285#elif LCD_PIXELFORMAT == VERTICAL_PACKING
286 dst_width = width;
287 dst_height = (height + 3) >> 2;
288#elif LCD_PIXELFORMAT == VERTICAL_INTERLEAVED
289 dst_width = width;
290 dst_height = (height + 7) >> 3;
291#endif /* LCD_PIXELFORMAT */
292#elif LCD_DEPTH == 16
293 dst_width = width;
294 dst_height = height;
295#endif /* LCD_DEPTH */
296 totalsize = dst_width * dst_height * sizeof(fb_data);
297 }
298 } else
299#endif /* (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) */
300 { 483 {
301 dst_width = width; 484 resize &= ~IMG_RESIZE;
302 dst_height = (height + 7) >> 3; 485 resize |= IMG_NORESIZE;
303 totalsize = dst_width * dst_height; 486 remote = 0;
487 }
488#else
489 if (src_dim.width > MAX_WIDTH)
490 return -6;
491#endif /*(LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)*/
492
493#if LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)
494 if (resize & IMG_RESIZE) {
495 if(format & FORMAT_KEEP_ASPECT) {
496 /* keep aspect ratio.. */
497 format &= ~FORMAT_KEEP_ASPECT;
498 struct dim resize_dim = {
499 .width = bm->width,
500 .height = bm->height,
501 };
502 if (recalc_dimension(&resize_dim, &src_dim))
503 resize = IMG_NORESIZE;
504 bm->width = resize_dim.width;
505 bm->height = resize_dim.height;
506 }
304 } 507 }
305 508
509 if (!(resize & IMG_RESIZE)) {
510#endif
511 /* returning image size */
512 bm->width = src_dim.width;
513 bm->height = src_dim.height;
514
515#if LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)
516 }
517#endif
518
519 if (rset.rowstep > 0) { /* Top-down BMP file */
520 rset.rowstart = 0;
521 rset.rowstop = bm->height;
522 } else { /* normal BMP */
523 rset.rowstart = bm->height - 1;
524 rset.rowstop = -1;
525 }
526
527 totalsize = get_totalsize(bm, remote);
528
306 /* Check if this fits the buffer */ 529 /* Check if this fits the buffer */
307 if (totalsize > maxsize) { 530 if (totalsize > maxsize) {
308 DEBUGF("read_bmp_fd: Bitmap too large for buffer: " 531 DEBUGF("read_bmp_fd: Bitmap too large for buffer: "
@@ -310,20 +533,24 @@ int read_bmp_fd(int fd,
310 return -6; 533 return -6;
311 } 534 }
312 535
313 compression = readlong(&bmph.compression); 536 compression = letoh32(bmph.compression);
314 if (depth <= 8) { 537 if (depth <= 8) {
315 numcolors = readlong(&bmph.clr_used); 538 numcolors = letoh32(bmph.clr_used);
316 if (numcolors == 0) 539 if (numcolors == 0)
317 numcolors = 1 << depth; 540 numcolors = 1 << depth;
318 } else 541 } else
319 numcolors = (compression == 3) ? 3 : 0; 542 numcolors = (compression == 3) ? 3 : 0;
320 543
321 if (numcolors > 0 && numcolors <= 256) { 544 if (numcolors > 0 && numcolors <= 256) {
322 if (read(fd, palette, numcolors * sizeof(uint32_t)) 545 int i;
323 != numcolors * (int)sizeof(uint32_t)) 546 union rgb_union pal;
324 { 547 for (i = 0; i < numcolors; i++) {
325 DEBUGF("read_bmp_fd: Can't read color palette\n"); 548 if (read(fd, &pal, sizeof(pal)) != (int)sizeof(pal))
326 return -7; 549 {
550 DEBUGF("read_bmp_fd: Can't read color palette\n");
551 return -7;
552 }
553 set_rgb_union(&palette[i], pal);
327 } 554 }
328 } 555 }
329 556
@@ -343,15 +570,27 @@ int read_bmp_fd(int fd,
343 570
344 case 32: 571 case 32:
345 if (compression == 3) { /* BI_BITFIELDS */ 572 if (compression == 3) { /* BI_BITFIELDS */
346 if (!memcmp(palette, bitfields[0], 12)) { /* 15 bit */ 573 bool found;
347 depth = 15; 574 int i, j;
348 break; 575
576 /* (i == 0) is 15bit, (i == 1) is 16bit, (i == 2) is 32bit */
577 for (i = 0; i < ARRAY_SIZE(bitfields); i++) {
578 for (j = 0; j < ARRAY_SIZE(bitfields[0]); j++) {
579 if (!rgbcmp(palette[j], bitfields[i][j])) {
580 found = true;
581 } else {
582 found = false;
583 break;
584 }
585 }
586 if (found) {
587 if (i == 0) /* 15bit */
588 depth = 15;
589 break;
590 }
349 } 591 }
350 if (!memcmp(palette, bitfields[1], 12) /* 16 bit */ 592 if (found)
351 || !memcmp(palette, bitfields[2], 12)) /* 32 bit */
352 {
353 break; 593 break;
354 }
355 } /* else fall through */ 594 } /* else fall through */
356 595
357 default: 596 default:
@@ -364,227 +603,104 @@ int read_bmp_fd(int fd,
364 } 603 }
365 604
366 /* Search to the beginning of the image data */ 605 /* Search to the beginning of the image data */
367 lseek(fd, (off_t)readlong(&bmph.off_bits), SEEK_SET); 606 lseek(fd, (off_t)letoh32(bmph.off_bits), SEEK_SET);
368 607
369 memset(bitmap, 0, totalsize); 608 memset(bitmap, 0, totalsize);
370 609
371 /* loop to read rows and put them to buffer */ 610 struct bmp_args ba = {
372 for (row = rowstart; row != rowstop; row += rowstep) { 611 .fd = fd, .padded_width = padded_width, .read_width = read_width,
373 unsigned data, mask; 612 .width = src_dim.width, .depth = depth, .palette = palette,
374 unsigned char *p; 613#if LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)
375 uint16_t *p2; 614 .cur_row = 0, .cur_col = 0, .part = {0,0}
376 uint32_t *rp; 615#endif
377 union rgb_union *qp; 616 };
378 union rgb_union q0, q1;
379
380 /* read one row */
381 ret = read(fd, bmpbuf, padded_width);
382 if (ret != padded_width) {
383 DEBUGF("read_bmp_fd: error reading image, read returned: %d "
384 "expected: %d\n", ret, padded_width);
385 return -9;
386 }
387 617
388 /* convert whole line in-place to XRGB8888 (little endian) */ 618#if LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)
389 rp = bmpbuf + width; 619#if LCD_DEPTH == 16
390 switch (depth) { 620#ifdef HAVE_REMOTE_LCD
391 case 1: 621 if (resize & IMG_RESIZE || remote)
392 q0.raw = palette[0]; 622#else
393 q1.raw = palette[1]; 623 if (resize & IMG_RESIZE)
394 p = (unsigned char*)bmpbuf + ((width + 7) >> 3); 624#endif
395 mask = 0x80 >> ((width + 7) & 7); 625#else
396 while (p > (unsigned char*)bmpbuf) { 626 if (format == FORMAT_NATIVE)
397 data = *(--p); 627#endif
398 for (; mask <= 0x80; mask <<= 1) 628 return resize_on_load(bm, dither, &src_dim, &rset, remote,
399 *(--rp) = (data & mask) ? q1.raw : q0.raw; 629#ifdef HAVE_LCD_COLOR
400 mask = 0x01; 630 bitmap + totalsize, maxsize - totalsize,
401 } 631#endif
402 break; 632 store_part_bmp, skip_lines_bmp, &ba);
633#endif /* LCD_DEPTH */
403 634
404 case 4: 635 int fb_width = get_fb_width(bm, remote);
405 if (width & 1) 636 int col, row;
406 rp++;
407 p = (unsigned char*)bmpbuf + ((width + 1) >> 1);
408 while (p > (unsigned char*)bmpbuf) {
409 data = *(--p);
410 *(--rp) = palette[data & 0x0f];
411 *(--rp) = palette[data >> 4];
412 }
413 break;
414 637
415 case 8: 638 /* loop to read rows and put them to buffer */
416 p = (unsigned char*)bmpbuf + width; 639 for (row = rset.rowstart; row != rset.rowstop; row += rset.rowstep) {
417 while (p > (unsigned char*)bmpbuf) 640 struct uint8_rgb *qp;
418 *(--rp) = palette[*(--p)]; 641 unsigned mask;
419 break; 642 unsigned char *p;
420 643#if LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)
421 case 15: 644 unsigned int len;
422 case 16:
423 p2 = (uint16_t *)bmpbuf + width;
424 while (p2 > (uint16_t *)bmpbuf) {
425 unsigned component, rgb;
426
427 data = letoh16(*(--p2));
428 /* blue */
429 component = (data << 3) & 0xf8;
430#ifdef ROCKBOX_BIG_ENDIAN
431 rgb = (component | (component >> 5)) << 8;
432 /* green */
433 data >>= 2;
434 if (depth == 15) {
435 component = data & 0xf8;
436 rgb |= component | (component >> 5);
437 } else {
438 data >>= 1;
439 component = data & 0xfc;
440 rgb |= component | (component >> 6);
441 }
442 /* red */
443 data >>= 5;
444 component = data & 0xf8;
445 rgb = (rgb << 8) | component | (component >> 5);
446 *(--rp) = rgb << 8;
447#else /* little endian */
448 rgb = component | (component >> 5);
449 /* green */
450 data >>= 2;
451 if (depth == 15) {
452 component = data & 0xf8;
453 rgb |= (component | (component >> 5)) << 8;
454 } else {
455 data >>= 1;
456 component = data & 0xfc;
457 rgb |= (component | (component >> 6)) << 8;
458 }
459 /* red */
460 data >>= 5;
461 component = data & 0xf8;
462 rgb |= (component | (component >> 5)) << 16;
463 *(--rp) = rgb;
464#endif
465 }
466 break;
467 645
468 case 24: 646 if (!(len = read_part_line(&ba)))
469 p = (unsigned char*)bmpbuf + 3 * width; 647 return -9;
470 while (p > (unsigned char*)bmpbuf) { 648#else
471 data = *(--p); 649 if (!read_part_line(&ba))
472 data = (data << 8) | *(--p); 650 return -9;
473 data = (data << 8) | *(--p); 651#endif
474 *(--rp) = htole32(data);
475 }
476 break;
477 652
478 case 32: /* already in desired format */
479 break;
480 }
481
482 /* Convert to destination format */ 653 /* Convert to destination format */
483 qp = (union rgb_union *)bmpbuf; 654 qp = (struct uint8_rgb *) ba.buf;
484#if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) 655#if LCD_DEPTH == 16
485 if (format == FORMAT_NATIVE) { 656 if (format == FORMAT_NATIVE)
486#if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1 657 {
487 if (remote) { 658 /* iriver h300, colour iPods, X5 */
488#if (LCD_REMOTE_DEPTH == 2) && (LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED) 659 fb_data *dest = (fb_data *)bitmap + fb_width * row;
489 /* iAudio X5/M5 remote */ 660 int delta = 127;
490 fb_remote_data *dest = (fb_remote_data *)bitmap 661 unsigned r, g, b;
491 + dst_width * (row >> 3); 662 struct uint8_rgb q0;
492 int shift = row & 7; 663
493 int delta = 127; 664 for (col = 0; col < src_dim.width; col++) {
494 unsigned bright; 665 if (dither)
495 666 delta = dither_mat(row & 0xf, col & 0xf);
496 for (col = 0; col < width; col++) { 667 if (!len)
497 if (dither) 668 {
498 delta = dither_matrix[row & 0xf][col & 0xf]; 669 if(!(len = read_part_line(&ba)))
499 bright = brightness(*qp++); 670 return -9;
500 bright = (3 * bright + (bright >> 6) + delta) >> 8; 671 else
501 *dest++ |= vi_pattern[bright] << shift; 672 qp = (struct uint8_rgb *)ba.buf;
502 }
503#endif /* LCD_REMOTE_DEPTH / LCD_REMOTE_PIXELFORMAT */
504 } else
505#endif /* defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1 */
506 {
507#if LCD_DEPTH == 2
508#if LCD_PIXELFORMAT == HORIZONTAL_PACKING
509 /* greyscale iPods */
510 fb_data *dest = (fb_data *)bitmap + dst_width * row;
511 int shift = 6;
512 int delta = 127;
513 unsigned bright;
514 unsigned data = 0;
515
516 for (col = 0; col < width; col++) {
517 if (dither)
518 delta = dither_matrix[row & 0xf][col & 0xf];
519 bright = brightness(*qp++);
520 bright = (3 * bright + (bright >> 6) + delta) >> 8;
521 data |= (~bright & 3) << shift;
522 shift -= 2;
523 if (shift < 0) {
524 *dest++ = data;
525 data = 0;
526 shift = 6;
527 }
528 }
529 if (shift < 6)
530 *dest++ = data;
531#elif LCD_PIXELFORMAT == VERTICAL_PACKING
532 /* iriver H1x0 */
533 fb_data *dest = (fb_data *)bitmap + dst_width * (row >> 2);
534 int shift = 2 * (row & 3);
535 int delta = 127;
536 unsigned bright;
537
538 for (col = 0; col < width; col++) {
539 if (dither)
540 delta = dither_matrix[row & 0xf][col & 0xf];
541 bright = brightness(*qp++);
542 bright = (3 * bright + (bright >> 6) + delta) >> 8;
543 *dest++ |= (~bright & 3) << shift;
544 }
545#elif LCD_PIXELFORMAT == VERTICAL_INTERLEAVED
546 /* iAudio M3 */
547 fb_data *dest = (fb_data *)bitmap + dst_width * (row >> 3);
548 int shift = row & 7;
549 int delta = 127;
550 unsigned bright;
551
552 for (col = 0; col < width; col++) {
553 if (dither)
554 delta = dither_matrix[row & 0xf][col & 0xf];
555 bright = brightness(*qp++);
556 bright = (3 * bright + (bright >> 6) + delta) >> 8;
557 *dest++ |= vi_pattern[bright] << shift;
558 }
559#endif /* LCD_PIXELFORMAT */
560#elif LCD_DEPTH == 16
561 /* iriver h300, colour iPods, X5 */
562 fb_data *dest = (fb_data *)bitmap + dst_width * row;
563 int delta = 127;
564 unsigned r, g, b;
565
566 for (col = 0; col < width; col++) {
567 if (dither)
568 delta = dither_matrix[row & 0xf][col & 0xf];
569 q0 = *qp++;
570 r = (31 * q0.red + (q0.red >> 3) + delta) >> 8;
571 g = (63 * q0.green + (q0.green >> 2) + delta) >> 8;
572 b = (31 * q0.blue + (q0.blue >> 3) + delta) >> 8;
573 *dest++ = LCD_RGBPACK_LCD(r, g, b);
574 } 673 }
575#endif /* LCD_DEPTH */ 674 q0 = *qp++;
675 len--;
676 r = (31 * q0.red + (q0.red >> 3) + delta) >> 8;
677 g = (63 * q0.green + (q0.green >> 2) + delta) >> 8;
678 b = (31 * q0.blue + (q0.blue >> 3) + delta) >> 8;
679 *dest++ = LCD_RGBPACK_LCD(r, g, b);
576 } 680 }
577 } else 681 }
578#endif /* (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) */ 682 else
683#endif
579 { 684 {
580 p = bitmap + dst_width * (row >> 3); 685 p = bitmap + fb_width * (row >> 3);
581 mask = 1 << (row & 7); 686 mask = 1 << (row & 7);
582 687 for (col = 0; col < src_dim.width; col++)
583 for (col = 0; col < width; col++, p++) 688 {
689#if LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)
690 if (!len)
691 {
692 if(!(len = read_part_line(&ba)))
693 return -9;
694 else
695 qp = (struct uint8_rgb *)ba.buf;
696 }
697 len--;
698#endif
584 if (brightness(*qp++) < 128) 699 if (brightness(*qp++) < 128)
585 *p |= mask; 700 *p |= mask;
701 p++;
702 }
586 } 703 }
587 } 704 }
588
589 return totalsize; /* return the used buffer size. */ 705 return totalsize; /* return the used buffer size. */
590} 706}
diff --git a/apps/recorder/bmp.h b/apps/recorder/bmp.h
index 3ac73de03b..1f29103556 100644
--- a/apps/recorder/bmp.h
+++ b/apps/recorder/bmp.h
@@ -23,6 +23,163 @@
23 23
24#include "config.h" 24#include "config.h"
25#include "lcd.h" 25#include "lcd.h"
26#include "inttypes.h"
27#ifdef HAVE_REMOTE_LCD
28#include "lcd-remote.h"
29#endif
30
31#define ARRAY_SIZE(array) (int)(sizeof(array)/(sizeof(array[0])))
32
33#define IMG_NORESIZE 0
34#define IMG_RESIZE 1
35#if LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)
36#define MAX_WIDTH 8
37#else
38#define MAX_WIDTH LCD_WIDTH
39#endif
40
41struct uint8_rgb {
42 uint8_t blue;
43 uint8_t green;
44 uint8_t red;
45};
46
47struct dim {
48 short width;
49 short height;
50};
51
52struct rowset {
53 short rowstep;
54 short rowstart;
55 short rowstop;
56};
57
58#if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)
59extern const unsigned char dither_matrix[16][16];
60static inline unsigned char dither_mat(unsigned int x, unsigned int y)
61{
62 return dither_matrix[y][x];
63}
64#endif
65
66static inline unsigned brightness(struct uint8_rgb color)
67{
68 return (3 * (unsigned)color.red + 6 * (unsigned)color.green
69 + (unsigned)color.blue) / 10;
70}
71
72#if ((LCD_DEPTH == 2) && (LCD_PIXELFORMAT == VERTICAL_INTERLEAVED)) \
73 || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH == 2) \
74 && (LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED))
75extern const unsigned short vi_pattern[4];
76static inline unsigned short vi_pat(unsigned int bright)
77{
78 return vi_pattern[bright];
79}
80#endif
81
82static inline int get_fb_height(struct bitmap *bm, bool remote)
83{
84 const int height = bm->height;
85#if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)
86 const int format = bm->format;
87#endif
88 int dst_height;
89
90#if !defined(HAVE_REMOTE_LCD) || \
91 (defined(HAVE_REMOTE_LCD) &&(LCD_REMOTE_DEPTH == 1))
92 (void) remote;
93#endif
94
95#if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)
96 if (format == FORMAT_NATIVE) {
97#if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
98 if (remote) {
99#if (LCD_REMOTE_DEPTH == 2) && (LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED)
100 dst_height = (height + 7) >> 3;
101#endif /* LCD_REMOTE_DEPTH / LCD_REMOTE_PIXELFORMAT */
102 } else
103#endif /* defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1 */
104 {
105#if LCD_DEPTH == 2
106#if LCD_PIXELFORMAT == HORIZONTAL_PACKING
107 dst_height = height;
108#elif LCD_PIXELFORMAT == VERTICAL_PACKING
109 dst_height = (height + 3) >> 2;
110#elif LCD_PIXELFORMAT == VERTICAL_INTERLEAVED
111 dst_height = (height + 7) >> 3;
112#endif /* LCD_PIXELFORMAT */
113#elif LCD_DEPTH == 16
114 dst_height = height;
115#endif /* LCD_DEPTH */
116 }
117 } else
118#endif /* (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) */
119 {
120 dst_height = (height + 7) >> 3;
121 }
122
123 return dst_height;
124}
125
126static inline int get_fb_width(struct bitmap *bm, bool remote)
127{
128 const int width = bm->width;
129#if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)
130 const int format = bm->format;
131#endif
132 int dst_width;
133
134#if !defined(HAVE_REMOTE_LCD) || \
135 (defined(HAVE_REMOTE_LCD) &&(LCD_REMOTE_DEPTH == 1))
136 (void) remote;
137#endif
138
139#if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)
140 if (format == FORMAT_NATIVE) {
141#if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
142 if (remote) {
143#if (LCD_REMOTE_DEPTH == 2) && (LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED)
144 dst_width = width;
145#endif /* LCD_REMOTE_DEPTH / LCD_REMOTE_PIXELFORMAT */
146 } else
147#endif /* defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1 */
148 {
149#if LCD_DEPTH == 2
150#if LCD_PIXELFORMAT == HORIZONTAL_PACKING
151 dst_width = (width + 3) >> 2;
152#elif LCD_PIXELFORMAT == VERTICAL_PACKING
153 dst_width = width;
154#elif LCD_PIXELFORMAT == VERTICAL_INTERLEAVED
155 dst_width = width;
156#endif /* LCD_PIXELFORMAT */
157#elif LCD_DEPTH == 16
158 dst_width = width;
159#endif /* LCD_DEPTH */
160 }
161 } else
162#endif /* (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) */
163 {
164 dst_width = width;
165 }
166
167 return dst_width;
168}
169
170static inline int get_totalsize(struct bitmap *bm, bool remote)
171{
172 int sz;
173#if defined(HAVE_REMOTE_LCD) && \
174 (LCD_REMOTE_DEPTH == 2) && (LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED)
175 if (remote)
176 sz = sizeof(fb_remote_data);
177 else
178#endif /* LCD_REMOTE_DEPTH / LCD_REMOTE_PIXELFORMAT */
179 sz = sizeof(fb_data);
180
181 return get_fb_width(bm, remote) * get_fb_height(bm, remote) * sz;
182}
26 183
27/********************************************************************* 184/*********************************************************************
28 * read_bmp_file() 185 * read_bmp_file()
diff --git a/apps/recorder/resize.c b/apps/recorder/resize.c
new file mode 100644
index 0000000000..cce20cdd77
--- /dev/null
+++ b/apps/recorder/resize.c
@@ -0,0 +1,718 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id
9 *
10 * Copyright (C) 2008 by Akio Idehara, Andrew Mahone
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22/*
23 * Implementation of area average and linear row and vertical scalers, and
24 * nearest-neighbor grey scaler (C) 2008 Andrew Mahone
25 *
26 * All files in this archive are subject to the GNU General Public License.
27 * See the file COPYING in the source tree root for full license agreement.
28 *
29 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
30 * KIND, either express or implied.
31 *
32 ****************************************************************************/
33
34#include <stdio.h>
35#include <stdlib.h>
36#include <string.h>
37#include "inttypes.h"
38#include "debug.h"
39#include "lcd.h"
40#include "file.h"
41#ifdef HAVE_REMOTE_LCD
42#include "lcd-remote.h"
43#endif
44#ifdef ROCKBOX_DEBUG_SCALERS
45#define SDEBUGF DEBUGF
46#else
47#define SDEBUGF(...)
48#endif
49#ifndef __PCTOOL__
50#include "config.h"
51#include "system.h"
52#include "bmp.h"
53#include "resize.h"
54#include "resize.h"
55#include "debug.h"
56#else
57#undef DEBUGF
58#define DEBUGF(...)
59#endif
60
61#ifdef HAVE_LCD_COLOR
62#define PACKRED(r, delta) ((31 * r + (r >> 3) + delta) >> 8)
63#define PACKGREEN(g, delta) ((63 * g + (g >> 2) + delta) >> 8)
64#define PACKBLUE(b, delta) ((31 * b + (b >> 3) + delta) >> 8)
65
66#define FILL_BUF_INIT(img_part, store_part, args) { \
67 part = store_part(args); \
68 if (part == NULL) \
69 return false; \
70}
71
72#define FILL_BUF(img_part, store_part, args) { \
73 if (part->len == 0) \
74 part = store_part(args); \
75 if (part == NULL) \
76 return false; \
77}
78
79struct uint32_rgb {
80 uint32_t r;
81 uint32_t g;
82 uint32_t b;
83};
84
85struct scaler_context {
86 uint32_t divmul;
87 uint32_t round;
88 struct img_part* (*store_part)(void *);
89 long last_tick;
90 unsigned char *buf;
91 int len;
92 void *args;
93};
94
95static void scale_h_area_setup(struct bitmap *bm, struct dim *src,
96 struct scaler_context *ctx)
97{
98 (void) bm;
99 ctx->divmul = ((src->width - 1 + 0x80000000U) / src->width) << 1;
100 ctx->round = (src->width + 1) >> 1;
101}
102
103/* horizontal area average scaler */
104static bool scale_h_area(struct bitmap *bm, struct dim *src,
105 struct uint32_rgb *out_line,
106 struct scaler_context *ctx, bool accum)
107{
108 SDEBUGF("scale_h_area\n");
109 unsigned int ix, ox, oxe, mul;
110 struct uint32_rgb rgbval1, rgbval2;
111 struct img_part *part;
112 FILL_BUF_INIT(part,ctx->store_part,ctx->args);
113 ox = 0;
114 oxe = 0;
115 rgbval1.r = 0;
116 rgbval1.g = 0;
117 rgbval1.b = 0;
118 rgbval2.r = 0;
119 rgbval2.g = 0;
120 rgbval2.b = 0;
121 mul = 0;
122 for (ix = 0; ix < (unsigned int)src->width; ix++)
123 {
124 oxe += bm->width;
125 if (oxe >= (unsigned int)src->width)
126 {
127 if (ctx->last_tick != current_tick)
128 {
129 yield();
130 ctx->last_tick = current_tick;
131 }
132 oxe -= src->width;
133 rgbval1.r = rgbval1.r * bm->width + rgbval2.r * mul;
134 rgbval1.g = rgbval1.g * bm->width + rgbval2.g * mul;
135 rgbval1.b = rgbval1.b * bm->width + rgbval2.b * mul;
136 FILL_BUF(part,ctx->store_part,ctx->args);
137 rgbval2.r = part->buf->red;
138 rgbval2.g = part->buf->green;
139 rgbval2.b = part->buf->blue;
140 part->buf++;
141 part->len--;
142 mul = bm->width - oxe;
143 rgbval1.r += rgbval2.r * mul;
144 rgbval1.g += rgbval2.g * mul;
145 rgbval1.b += rgbval2.b * mul;
146 out_line[ox].r = (accum ? out_line[ox].r : 0) +
147 (((uint64_t)rgbval1.r + ctx->round) *
148 ctx->divmul >> 32);
149 out_line[ox].g = (accum ? out_line[ox].g : 0) +
150 (((uint64_t)rgbval1.g + ctx->round) *
151 ctx->divmul >> 32);
152 out_line[ox].b = (accum ? out_line[ox].b : 0) +
153 (((uint64_t)rgbval1.b + ctx->round) *
154 ctx->divmul >> 32);
155 rgbval1.r = 0;
156 rgbval1.g = 0;
157 rgbval1.b = 0;
158 mul = bm->width - mul;
159 ox += 1;
160 } else {
161 FILL_BUF(part,ctx->store_part,ctx->args);
162 rgbval1.r += part->buf->red;
163 rgbval1.g += part->buf->green;
164 rgbval1.b += part->buf->blue;
165 part->buf++;
166 part->len--;
167 }
168 }
169 return true;
170}
171
172/* vertical area average scaler */
173static bool scale_v_area(struct bitmap *bm, bool dither, struct dim *src,
174 struct rowset *rset,
175 bool (*h_scaler)(struct bitmap*, struct dim*,
176 struct uint32_rgb*,
177 struct scaler_context*, bool),
178 struct scaler_context *ctx)
179{
180 uint32_t mul, divmul, x, oy, iy, oye, round;
181 int delta = 127, r, g, b;
182 fb_data *row, *pix;
183 divmul = ((src->height - 1 + 0x80000000U) / src->height) << 1;
184 round = (src->height + 1) >> 1;
185 mul = 0;
186 oy = 0;
187 oye = 0;
188 struct uint32_rgb *crow1 = (struct uint32_rgb *)(ctx->buf),
189 *crow2 = crow1 + bm->width;
190
191 SDEBUGF("scale_v_area\n");
192 memset((void *)ctx->buf, 0, bm->width * 2 * sizeof(struct uint32_rgb));
193 row = (fb_data *)(bm->data) + bm->width *
194 (rset->rowstep == -1 ? bm->height - 1 : 0);
195 for (iy = 0; iy < (unsigned int)src->height; iy++)
196 {
197 oye += bm->height;
198 if (oye >= (unsigned int)src->height)
199 {
200 oye -= src->height;
201 for (x = 0; x < 3 *(unsigned int)bm->width; x++)
202 ((uint32_t*)crow1)[x] = ((uint32_t*)crow1)[x] *
203 bm->height + mul *
204 ((uint32_t*)crow2)[x];
205 if(!h_scaler(bm, src, crow2, ctx, false))
206 goto fail;
207 mul = bm->height - oye;
208 for (x = 0; x < 3 *(unsigned int)bm->width; x++)
209 {
210 ((uint32_t*)crow1)[x] += mul * ((uint32_t*)crow2)[x];
211 ((uint32_t*)crow1)[x] = (uint64_t)(round +
212 ((uint32_t*)crow1)[x]) *
213 divmul >> 32;
214 }
215 pix = row;
216 for (x = 0; x < (unsigned int)bm->width; x++)
217 {
218 if (dither)
219 delta = dither_mat(x & 0xf, oy & 0xf);
220 r = PACKRED(crow1[x].r,delta);
221 g = PACKGREEN(crow1[x].g,delta);
222 b = PACKBLUE(crow1[x].b,delta);
223 *pix++ = LCD_RGBPACK_LCD(r, g, b);
224 }
225 memset((void *)crow1, 0, bm->width * sizeof(struct uint32_rgb));
226 mul = oye;
227 row += bm->width * rset->rowstep;
228 oy += 1;
229 } else {
230 if (!h_scaler(bm, src, crow1, ctx, true))
231 goto fail;
232 }
233 }
234 return true;
235 fail:
236 return false;
237}
238
239#ifdef HAVE_UPSCALER
240static void scale_h_linear_setup(struct bitmap *bm, struct dim *src,
241 struct scaler_context *ctx)
242{
243 (void) src;
244 ctx->divmul = ((bm->width - 2 + 0x80000000U) / (bm->width - 1)) << 1;
245 ctx->round = bm->width >> 1;
246}
247
248/* horizontal linear scaler */
249static bool scale_h_linear(struct bitmap *bm, struct dim *src,
250 struct uint32_rgb *out_line,
251 struct scaler_context *ctx, bool accum)
252{
253 unsigned int ix, ox, ixe;
254 struct uint32_rgb rgbval=rgbval, rgbinc=rgbinc;
255 struct img_part *part;
256 SDEBUGF("scale_h_linear\n");
257 FILL_BUF_INIT(part,ctx->store_part,ctx->args);
258 ix = 0;
259 ixe = bm->width - 1;
260 for (ox = 0; ox < (uint32_t)bm->width; ox++) {
261 if (ixe >= ((uint32_t)bm->width - 1))
262 {
263 if (ctx->last_tick != current_tick)
264 {
265 yield();
266 ctx->last_tick = current_tick;
267 }
268 ixe -= (bm->width - 1);
269 rgbinc.r = -(part->buf->red);
270 rgbinc.g = -(part->buf->green);
271 rgbinc.b = -(part->buf->blue);
272 rgbval.r = (part->buf->red) * (bm->width - 1);
273 rgbval.g = (part->buf->green) * (bm->width - 1);
274 rgbval.b = (part->buf->blue) * (bm->width - 1);
275 ix += 1;
276 if (ix < (uint32_t)src->width) {
277 part->buf++;
278 part->len--;
279 FILL_BUF(part,ctx->store_part,ctx->args);
280 rgbinc.r += part->buf->red;
281 rgbinc.g += part->buf->green;
282 rgbinc.b += part->buf->blue;
283 rgbval.r += rgbinc.r * ixe;
284 rgbval.g += rgbinc.g * ixe;
285 rgbval.b += rgbinc.b * ixe;
286 }
287 rgbinc.r *= src->width - 1;
288 rgbinc.g *= src->width - 1;
289 rgbinc.b *= src->width - 1;
290 }
291 out_line[ox].r = (accum ? out_line[ox].r : 0) +
292 (((uint64_t)rgbval.r + ctx->round) *
293 ctx->divmul >> 32);
294 out_line[ox].g = (accum ? out_line[ox].g : 0) +
295 (((uint64_t)rgbval.g + ctx->round) *
296 ctx->divmul >> 32);
297 out_line[ox].b = (accum ? out_line[ox].b : 0) +
298 (((uint64_t)rgbval.b + ctx->round) *
299 ctx->divmul >> 32);
300 rgbval.r += rgbinc.r;
301 rgbval.g += rgbinc.g;
302 rgbval.b += rgbinc.b;
303 ixe += src->width - 1;
304 }
305 return true;
306}
307
308/* vertical linear scaler */
309static bool scale_v_linear(struct bitmap *bm, bool dither, struct dim *src,
310 struct rowset *rset,
311 bool (*h_scaler)(struct bitmap*, struct dim*,
312 struct uint32_rgb*,
313 struct scaler_context*, bool),
314 struct scaler_context *ctx)
315{
316 uint32_t mul, divmul, x, oy, iy, iye, round;
317 int delta = 127;
318 struct uint32_rgb p;
319 fb_data *row, *pix;
320 divmul = ((bm->height - 2 + 0x80000000U) / (bm->height - 1)) << 1;
321 round = bm->height >> 1;
322 mul = 0;
323 iy = 0;
324 iye = bm->height - 1;
325 struct uint32_rgb *crow1 = (struct uint32_rgb *)(ctx->buf),
326 *crow2 = crow1 + bm->width,
327 *t;
328
329 SDEBUGF("scale_v_linear\n");
330 row = (fb_data *)(bm->data) + bm->width *
331 (rset->rowstep == -1 ? bm->height - 1 : 0);
332 if(!h_scaler(bm, src, crow2, ctx, false))
333 goto fail;
334 for (oy = 0; oy < (uint32_t)bm->height; oy++)
335 {
336 if (iye >= (uint32_t)bm->height - 1)
337 {
338 t = crow2;
339 crow2 = crow1;
340 crow1 = t;
341 iye -= bm->height - 1;
342 iy += 1;
343 if (iy < (uint32_t)src->height)
344 {
345 if (!h_scaler(bm, src, crow2, ctx, false))
346 goto fail;
347 }
348 }
349 pix = row;
350 for (x = 0; x < (uint32_t)bm->width; x++)
351 {
352 p.r = (uint64_t)(crow1[x].r * (bm->height - 1 - iye) +
353 crow2[x].r * iye + round) * divmul >> 32;
354 p.g = (uint64_t)(crow1[x].g * (bm->height - 1 - iye) +
355 crow2[x].g * iye + round) * divmul >> 32;
356 p.b = (uint64_t)(crow1[x].b * (bm->height - 1 - iye) +
357 crow2[x].b * iye + round) * divmul >> 32;
358 if (dither)
359 delta = dither_mat(x & 0xf, oy & 0xf);
360 p.r = PACKRED(p.r,delta);
361 p.g = PACKGREEN(p.g,delta);
362 p.b = PACKBLUE(p.b,delta);
363 *pix++ = LCD_RGBPACK_LCD(p.r, p.g, p.b);
364 }
365 row += bm->width * rset->rowstep;
366 iye += src->height - 1;
367 }
368 return true;
369 fail:
370 return false;
371}
372#endif /* HAVE_UPSCALER */
373#endif /* HAVE_LCD_COLOR */
374
375#if LCD_DEPTH < 8 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH < 8)
376/* nearest-neighbor up/down/non-scaler */
377static inline bool scale_nearest(struct bitmap *bm,
378 struct dim *src,
379 struct rowset *rset,
380 bool remote, bool dither,
381 struct img_part* (*store_part)(void *args),
382 bool (*skip_lines)(void *args, unsigned int),
383 void *args)
384{
385 const int sw = src->width;
386 const int sh = src->height;
387 const int dw = bm->width;
388 const int dh = bm->height;
389 unsigned char *bitmap = bm->data;
390 const int rowstep = rset->rowstep;
391 const int rowstart = rset->rowstart;
392 const int rowstop = rset->rowstop;
393 const int fb_width = get_fb_width(bm, false);
394 long last_tick = current_tick;
395 int ix, ox, lx, xe, iy, oy, ly, ye, yet, oyt;
396 int ixls, xels, iyls, yelsi, oyls, yelso, p;
397 struct img_part *cur_part;
398#ifndef HAVE_LCD_COLOR
399 fb_data *dest, *dest_t;
400#endif
401#ifdef HAVE_REMOTE_LCD
402 fb_remote_data *rdest, *rdest_t;
403#endif
404
405 SDEBUGF("scale_nearest sw=%d sh=%d dw=%d dh=%d remote=%d\n", sw, sh, dw,
406 dh, remote);
407 ly = 0;
408 iy = 0;
409 ye = 0;
410 ixls = (sw > (dw - 1) && dw > 1) ? sw / (dw - 1) : 1;
411 xels = sw - ixls * (dw - 1) + (dw == 1 ? 1 : 0);
412 iyls = (sh > (dh - 1) && dh > 1) ? sh / (dh - 1) : 1;
413 oyls = dh > sh ? dh / sh : 1;
414 yelsi = iyls * (dh - 1) + (dh == 1 ? 1 : 0);
415 yelso = oyls * sh;
416 oyls *= rowstep;
417 int delta = 127;
418#if LCD_PIXELFORMAT == HORIZONTAL_PACKING || \
419 (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_PIXELFORMAT == HORIZONTAL_PACKING)
420 uint8_t buf[4];
421 int data, oxt;
422#endif
423#if LCD_PIXELFORMAT == VERTICAL_PACKING || \
424 LCD_PIXELFORMAT == VERTICAL_INTERLEAVED || \
425 (defined(HAVE_REMOTE_LCD) && \
426 (LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED || \
427 LCD_REMOTE_PIXELFORMAT == VERTICAL_PACKING))
428 int bright, shift;
429#endif
430 for (oy = rowstart; oy != rowstop;) {
431 SDEBUGF("oy=%d iy=%d\n", oy, iy);
432 if (last_tick != current_tick)
433 {
434 yield();
435 last_tick = current_tick;
436 }
437 if (iy > ly && !skip_lines(args, iy - ly - 1))
438 return false;
439 ly = iy;
440
441 cur_part = store_part(args);
442 if (cur_part == NULL)
443 return false;
444
445 lx = 0;
446 ix = 0;
447 xe = 0;
448#if defined(HAVE_REMOTE_LCD) && !defined(HAVE_LCD_COLOR)
449 if(!remote)
450#else
451 (void)remote;
452#endif
453#if LCD_PIXELFORMAT == HORIZONTAL_PACKING
454 dest = (fb_data *)bitmap + fb_width * oy;
455#elif LCD_PIXELFORMAT == VERTICAL_PACKING
456 dest = (fb_data *)bitmap + fb_width * (oy >> 2);
457#elif LCD_PIXELFORMAT == VERTICAL_INTERLEAVED
458 dest = (fb_data *)bitmap + fb_width * (oy >> 3);
459#endif
460#ifdef HAVE_REMOTE_LCD
461#ifndef HAVE_LCD_COLOR
462 else
463#endif
464 rdest = (fb_remote_data *)bitmap + fb_width * (oy >> 3);
465#endif
466 for (ox = 0; ox < dw; ox++) {
467 while (cur_part->len <= ix - lx)
468 {
469 lx += cur_part->len;
470 cur_part = store_part(args);
471 if (cur_part == NULL)
472 return false;
473 }
474 cur_part->len -= ix - lx;
475 cur_part->buf += ix - lx;
476 lx = ix;
477#if defined(HAVE_REMOTE_LCD) && !defined(HAVE_LCD_COLOR)
478 if(!remote)
479 {
480#endif
481#if LCD_PIXELFORMAT == HORIZONTAL_PACKING
482 /* greyscale iPods */
483 buf[ox & 3] = brightness(*(cur_part->buf));
484 if ((ox & 3) == 3 || ox == dw - 1)
485 {
486 dest_t = dest++;
487 oyt = oy;
488 yet = ye;
489 int xo = ox & ~3;
490 while(yet < dh)
491 {
492 data = 0;
493 for (oxt = 0; oxt < (ox & 3) + 1; oxt++)
494 {
495 if (dither)
496 delta = dither_mat(oyt & 0xf, (xo + oxt) & 0xf);
497 p = (3 * buf[oxt] + (buf[oxt] >> 6) + delta) >> 8;
498 data |= (~p & 3) << ((3 - oxt) << 1);
499 }
500 *dest_t = data;
501 dest_t += rowstep * fb_width;
502 yet += sh;
503 oyt += 1;
504 }
505 }
506#elif LCD_PIXELFORMAT == VERTICAL_PACKING
507 /* iriver H1x0 */
508 bright = brightness(*(cur_part->buf));
509 dest_t = dest++;
510 oyt = oy;
511 yet = ye;
512 while(yet < dh)
513 {
514 shift = (oyt & 3) << 1;
515 if (dither)
516 delta = dither_mat(oyt & 0xf, ox & 0xf);
517
518 p = (3 * bright + (bright >> 6) + delta) >> 8;
519 *dest_t |= (~p & 3) << shift;
520 if ((rowstep > 0 && shift == 6) || shift == 0)
521 dest_t += rowstep * fb_width;
522 yet += sh;
523 oyt += 1;
524 }
525#elif LCD_PIXELFORMAT == VERTICAL_INTERLEAVED
526 bright = brightness(*(cur_part->buf));
527 dest_t = dest++;
528 oyt = oy;
529 yet = ye;
530 while(yet < dh)
531 {
532 shift = oyt & 7;
533 if (dither)
534 delta = dither_mat(oyt & 0xf, ox & 0xf);
535
536 p = (3 * bright + (bright >> 6) + delta) >> 8;
537 *dest_t |= vi_pat(p) << shift;
538 if ((rowstep > 0 && shift == 7) || shift == 0)
539 dest_t += rowstep * fb_width;
540 yet += sh;
541 oyt += 1;
542 }
543#endif /* LCD_PIXELFORMAT */
544#ifdef HAVE_REMOTE_LCD
545#ifndef HAVE_LCD_COLOR
546 } else
547#endif
548 {
549#if LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED
550 bright = brightness(*(cur_part->buf));
551 rdest_t = rdest++;
552 oyt = oy;
553 yet = ye;
554 while(yet < dh)
555 {
556 shift = oyt & 7;
557 if (dither)
558 delta = dither_mat(oyt & 0xf, ox & 0xf);
559
560 p = (3 * bright + (bright >> 6) + delta) >> 8;
561 *rdest_t |= vi_pat(p) << shift;
562 if ((rowstep > 0 && shift == 7) || shift == 0)
563 rdest_t += rowstep * fb_width;
564 yet += sh;
565 oyt += 1;
566 }
567#else
568 bright = brightness(*(cur_part->buf));
569 rdest_t = rdest++;
570 oyt = oy;
571 yet = ye;
572 while(yet < dh)
573 {
574 shift = oyt & 7;
575 if (dither)
576 delta = dither_mat(oyt & 0xf, ox & 0xf);
577 p = (bright + delta) >> 8;
578 *rdest_t |= (~p & 1) << shift;
579 if ((rowstep > 0 && shift == 7) || shift == 0)
580 rdest_t += rowstep * fb_width;
581 yet += sh;
582 oyt += 1;
583 }
584#endif
585 }
586#endif
587 xe += xels;
588 ix += ixls;
589 while (xe >= dw)
590 {
591 xe -= dw - 1;
592 ix += 1;
593 }
594 }
595 oy += oyls;
596 ye += yelso;
597 while (ye < dh)
598 {
599 ye += sh;
600 oy += rowstep;
601 }
602 iy += iyls;
603 ye -= yelsi;
604 while (ye >= dh)
605 {
606 ye -= dh - 1;
607 iy += 1;
608 }
609 }
610 return true;
611}
612#endif
613
614int resize_on_load(struct bitmap *bm, bool dither, struct dim *src,
615 struct rowset *rset, bool remote,
616#ifdef HAVE_LCD_COLOR
617 unsigned char *buf, unsigned int len,
618#endif
619 struct img_part* (*store_part)(void *args),
620 bool (*skip_lines)(void *args, unsigned int lines),
621 void *args)
622{
623
624#if defined(HAVE_LCD_COLOR) && !defined(HAVE_REMOTE_LCD)
625 (void)skip_lines;
626#endif
627#ifdef HAVE_LCD_COLOR
628#ifdef HAVE_REMOTE_LCD
629 if (!remote)
630#endif
631 {
632#ifdef HAVE_UPSCALER
633 const int sw = src->width;
634 const int sh = src->height;
635 const int dw = bm->width;
636 const int dh = bm->height;
637#endif
638 int ret;
639 unsigned int needed = sizeof(struct uint32_rgb) * 2 * bm->width;
640#if MAX_SC_STACK_ALLOC
641 uint8_t sc_buf[(needed <= len || needed > MAX_SC_STACK_ALLOC) ?
642 0 : needed];
643#endif
644 if (needed > len)
645 {
646#if MAX_SC_STACK_ALLOC
647 if (needed > MAX_SC_STACK_ALLOC)
648 {
649 DEBUGF("unable to allocate required buffer: %d needed, "
650 "%d available, %d permitted from stack\n",
651 needed, len, MAX_SC_STACK_ALLOC);
652 return 0;
653 }
654 if (sizeof(sc_buf) < needed)
655 {
656 DEBUGF("failed to allocate large enough buffer on stack: "
657 "%d needed, only got %d",
658 needed, MAX_SC_STACK_ALLOC);
659 return 0;
660 }
661#else
662 DEBUGF("unable to allocate required buffer: %d needed, "
663 "%d available\n", needed, len);
664 return 0;
665#endif
666 }
667
668 bool (*h_scaler)(struct bitmap*, struct dim*,
669 struct uint32_rgb*,
670 struct scaler_context*, bool);
671 struct scaler_context ctx;
672 ctx.last_tick = current_tick;
673 cpu_boost(true);
674#ifdef HAVE_UPSCALER
675 if (sw > dw)
676 {
677#endif
678 h_scaler = scale_h_area;
679 scale_h_area_setup(bm, src, &ctx);
680#ifdef HAVE_UPSCALER
681 } else {
682 h_scaler = scale_h_linear;
683 scale_h_linear_setup(bm, src, &ctx);
684 }
685#endif
686 ctx.store_part = store_part;
687 ctx.args = args;
688#if MAX_SC_STACK_ALLOC
689 ctx.buf = needed > len ? sc_buf : buf;
690#else
691 ctx.buf = buf;
692#endif
693 ctx.len = len;
694#ifdef HAVE_UPSCALER
695 if (sh > dh)
696#endif
697 ret = scale_v_area(bm, dither, src, rset, h_scaler, &ctx);
698#ifdef HAVE_UPSCALER
699 else
700 ret = scale_v_linear(bm, dither, src, rset, h_scaler, &ctx);
701#endif
702 cpu_boost(false);
703 if (!ret)
704 return 0;
705 }
706#ifdef HAVE_REMOTE_LCD
707 else
708#endif
709#endif /* HAVE_LCD_COLOR */
710#if !defined(HAVE_LCD_COLOR) || defined(HAVE_REMOTE_LCD)
711 {
712 if (!scale_nearest(bm, src, rset, remote, dither, store_part,
713 skip_lines, args))
714 return 0;
715 }
716#endif /* !HAVE_LCD_COLOR || HAVE_REMOTE_LCD*/
717 return get_totalsize(bm, remote);
718}
diff --git a/apps/recorder/resize.h b/apps/recorder/resize.h
new file mode 100644
index 0000000000..133ac50fdd
--- /dev/null
+++ b/apps/recorder/resize.h
@@ -0,0 +1,60 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id
9 *
10 * Copyright (C) 2008 by Akio Idehara
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#ifndef _RESIZE_H_
22#define _RESIZE_H_
23
24#include "config.h"
25#include "lcd.h"
26
27/****************************************************************
28 * resize_on_load()
29 *
30 * resize bitmap on load with scaling
31 *
32 * If HAVE_LCD_COLOR then this func use smooth scaling algorithm
33 * - downscaling both way use "Area Sampling"
34 * if IMG_RESIZE_BILINER or IMG_RESIZE_NEAREST is NOT set
35 * - otherwise "Bilinear" or "Nearest Neighbour"
36 *
37 * If !(HAVE_LCD_COLOR) then use simple scaling algorithm "Nearest Neighbour"
38 *
39 * return -1 for error
40 ****************************************************************/
41
42/* nothing needs the on-stack buffer right now */
43#define MAX_SC_STACK_ALLOC 0
44#define HAVE_UPSCALER 1
45
46struct img_part {
47 int len;
48 struct uint8_rgb* buf;
49};
50
51int resize_on_load(struct bitmap *bm, bool dither,
52 struct dim *src,
53 struct rowset *tmp_row, bool remote,
54#ifdef HAVE_LCD_COLOR
55 unsigned char *buf, unsigned int len,
56#endif
57 struct img_part* (*store_part)(void *args),
58 bool (*skip_lines)(void *args, unsigned int lines),
59 void *args);
60#endif /* _RESIZE_H_ */
diff --git a/docs/CREDITS b/docs/CREDITS
index ba2bc54dbd..2b6128d14a 100644
--- a/docs/CREDITS
+++ b/docs/CREDITS
@@ -434,6 +434,7 @@ Alex Bennee
434Stéphane Quertinmont 434Stéphane Quertinmont
435Bartosz Fabianowski 435Bartosz Fabianowski
436Adam Hogan 436Adam Hogan
437Andrew Mahone
437 438
438 439
439The libmad team 440The libmad team
diff --git a/firmware/export/lcd.h b/firmware/export/lcd.h
index 60329147da..ea5851e736 100644
--- a/firmware/export/lcd.h
+++ b/firmware/export/lcd.h
@@ -368,6 +368,8 @@ enum
368#define FORMAT_TRANSPARENT 0x40000000 368#define FORMAT_TRANSPARENT 0x40000000
369#define FORMAT_DITHER 0x20000000 369#define FORMAT_DITHER 0x20000000
370#define FORMAT_REMOTE 0x10000000 370#define FORMAT_REMOTE 0x10000000
371#define FORMAT_RESIZE 0x08000000
372#define FORMAT_KEEP_ASPECT 0x04000000
371 373
372#define TRANSPARENT_COLOR LCD_RGBPACK(255,0,255) 374#define TRANSPARENT_COLOR LCD_RGBPACK(255,0,255)
373#define REPLACEWITHFG_COLOR LCD_RGBPACK(0,255,255) 375#define REPLACEWITHFG_COLOR LCD_RGBPACK(0,255,255)