forked from len0rd/rockbox
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
This commit is contained in:
parent
a2c71fde1b
commit
781421afa2
14 changed files with 1460 additions and 404 deletions
|
|
@ -85,6 +85,7 @@ gui/viewport.c
|
||||||
|
|
||||||
#if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
|
#if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
|
||||||
gui/backdrop.c
|
gui/backdrop.c
|
||||||
|
recorder/resize.c
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_LCD_CHARCELLS
|
#ifdef HAVE_LCD_CHARCELLS
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,9 @@
|
||||||
#include "bmp.h"
|
#include "bmp.h"
|
||||||
#include "appevents.h"
|
#include "appevents.h"
|
||||||
#include "metadata.h"
|
#include "metadata.h"
|
||||||
|
#ifdef HAVE_ALBUMART
|
||||||
|
#include "albumart.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#if MEM > 1
|
#if MEM > 1
|
||||||
#define GUARD_BUFSIZE (32*1024)
|
#define GUARD_BUFSIZE (32*1024)
|
||||||
|
|
@ -852,8 +855,13 @@ static int load_bitmap(int fd)
|
||||||
bmp->maskdata = NULL;
|
bmp->maskdata = NULL;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int free = (int)MIN(buffer_len - BUF_USED, buffer_len - buf_widx);
|
int free = (int)MIN(buffer_len - BUF_USED, buffer_len - buf_widx)
|
||||||
rc = read_bmp_fd(fd, bmp, free, FORMAT_ANY|FORMAT_DITHER);
|
- sizeof(struct bitmap);
|
||||||
|
|
||||||
|
get_albumart_size(bmp);
|
||||||
|
|
||||||
|
rc = read_bmp_fd(fd, bmp, free, FORMAT_NATIVE|FORMAT_DITHER|
|
||||||
|
FORMAT_RESIZE|FORMAT_KEEP_ASPECT);
|
||||||
return rc + (rc > 0 ? sizeof(struct bitmap) : 0);
|
return rc + (rc > 0 ? sizeof(struct bitmap) : 0);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -813,6 +813,9 @@ void gui_sync_wps_init(void)
|
||||||
FOR_NB_SCREENS(i)
|
FOR_NB_SCREENS(i)
|
||||||
{
|
{
|
||||||
wps_data_init(&wps_datas[i]);
|
wps_data_init(&wps_datas[i]);
|
||||||
|
#ifdef HAVE_ALBUMART
|
||||||
|
wps_datas[i].wps_uses_albumart = 0;
|
||||||
|
#endif
|
||||||
#ifdef HAVE_REMOTE_LCD
|
#ifdef HAVE_REMOTE_LCD
|
||||||
wps_datas[i].remote_wps = (i != 0);
|
wps_datas[i].remote_wps = (i != 0);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -47,13 +47,11 @@
|
||||||
#define WPS_ALBUMART_CHECK 1 /* WPS contains AA conditional tag */
|
#define WPS_ALBUMART_CHECK 1 /* WPS contains AA conditional tag */
|
||||||
#define WPS_ALBUMART_LOAD 2 /* WPS contains AA 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_RIGHT 1 /* x align: right */
|
||||||
#define WPS_ALBUMART_ALIGN_CENTER WPS_ALIGN_CENTER /* x/y align: center */
|
#define WPS_ALBUMART_ALIGN_CENTER 2 /* x/y align: center */
|
||||||
#define WPS_ALBUMART_ALIGN_LEFT WPS_ALIGN_LEFT /* x align: left */
|
#define WPS_ALBUMART_ALIGN_LEFT 4 /* x align: left */
|
||||||
#define WPS_ALBUMART_ALIGN_TOP WPS_ALIGN_RIGHT /* y align: top */
|
#define WPS_ALBUMART_ALIGN_TOP 1 /* y align: top */
|
||||||
#define WPS_ALBUMART_ALIGN_BOTTOM WPS_ALIGN_LEFT /* y align: bottom */
|
#define WPS_ALBUMART_ALIGN_BOTTOM 4 /* y align: bottom */
|
||||||
#define WPS_ALBUMART_INCREASE 8 /* increase if smaller */
|
|
||||||
#define WPS_ALBUMART_DECREASE 16 /* decrease if larger */
|
|
||||||
|
|
||||||
#endif /* HAVE_ALBUMART */
|
#endif /* HAVE_ALBUMART */
|
||||||
|
|
||||||
|
|
@ -382,10 +380,8 @@ struct wps_data
|
||||||
unsigned char wps_uses_albumart; /* WPS_ALBUMART_NONE, _CHECK, _LOAD */
|
unsigned char wps_uses_albumart; /* WPS_ALBUMART_NONE, _CHECK, _LOAD */
|
||||||
short albumart_x;
|
short albumart_x;
|
||||||
short albumart_y;
|
short albumart_y;
|
||||||
unsigned short albumart_xalign; /* WPS_ALBUMART_ALIGN_LEFT, _CENTER, _RIGHT,
|
unsigned char albumart_xalign; /* WPS_ALBUMART_ALIGN_LEFT, _CENTER, _RIGHT */
|
||||||
+ .._INCREASE, + .._DECREASE */
|
unsigned char albumart_yalign; /* WPS_ALBUMART_ALIGN_TOP, _CENTER, _BOTTOM */
|
||||||
unsigned short albumart_yalign; /* WPS_ALBUMART_ALIGN_TOP, _CENTER, _BOTTOM,
|
|
||||||
+ .._INCREASE, + .._DECREASE */
|
|
||||||
short albumart_max_width;
|
short albumart_max_width;
|
||||||
short albumart_max_height;
|
short albumart_max_height;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -969,23 +969,15 @@ static int parse_albumart_load(const char *wps_bufptr,
|
||||||
{
|
{
|
||||||
const char *_pos, *newline;
|
const char *_pos, *newline;
|
||||||
bool parsing;
|
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 */
|
(void)token; /* silence warning */
|
||||||
|
|
||||||
/* reset albumart info in wps */
|
/* reset albumart info in wps */
|
||||||
wps_data->wps_uses_albumart = WPS_ALBUMART_NONE;
|
|
||||||
wps_data->albumart_max_width = -1;
|
wps_data->albumart_max_width = -1;
|
||||||
wps_data->albumart_max_height = -1;
|
wps_data->albumart_max_height = -1;
|
||||||
wps_data->albumart_xalign = WPS_ALBUMART_ALIGN_CENTER; /* default */
|
wps_data->albumart_xalign = WPS_ALBUMART_ALIGN_CENTER; /* default */
|
||||||
wps_data->albumart_yalign = 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');
|
newline = strchr(wps_bufptr, '\n');
|
||||||
|
|
||||||
|
|
@ -1020,35 +1012,24 @@ static int parse_albumart_load(const char *wps_bufptr,
|
||||||
case 'l':
|
case 'l':
|
||||||
case 'L':
|
case 'L':
|
||||||
case '+':
|
case '+':
|
||||||
wps_data->albumart_xalign =
|
wps_data->albumart_xalign = WPS_ALBUMART_ALIGN_LEFT;
|
||||||
(wps_data->albumart_xalign & xalign_mask) |
|
|
||||||
WPS_ALBUMART_ALIGN_LEFT;
|
|
||||||
break;
|
break;
|
||||||
case 'c':
|
case 'c':
|
||||||
case 'C':
|
case 'C':
|
||||||
wps_data->albumart_xalign =
|
wps_data->albumart_xalign = WPS_ALBUMART_ALIGN_CENTER;
|
||||||
(wps_data->albumart_xalign & xalign_mask) |
|
|
||||||
WPS_ALBUMART_ALIGN_CENTER;
|
|
||||||
break;
|
break;
|
||||||
case 'r':
|
case 'r':
|
||||||
case 'R':
|
case 'R':
|
||||||
case '-':
|
case '-':
|
||||||
wps_data->albumart_xalign =
|
wps_data->albumart_xalign = WPS_ALBUMART_ALIGN_RIGHT;
|
||||||
(wps_data->albumart_xalign & xalign_mask) |
|
|
||||||
WPS_ALBUMART_ALIGN_RIGHT;
|
|
||||||
break;
|
break;
|
||||||
case 'd':
|
case 'd':
|
||||||
case 'D':
|
case 'D':
|
||||||
wps_data->albumart_xalign |= WPS_ALBUMART_DECREASE;
|
|
||||||
break;
|
|
||||||
case 'i':
|
case 'i':
|
||||||
case 'I':
|
case 'I':
|
||||||
wps_data->albumart_xalign |= WPS_ALBUMART_INCREASE;
|
|
||||||
break;
|
|
||||||
case 's':
|
case 's':
|
||||||
case 'S':
|
case 'S':
|
||||||
wps_data->albumart_xalign |=
|
/* simply ignored */
|
||||||
(WPS_ALBUMART_DECREASE | WPS_ALBUMART_INCREASE);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
parsing = false;
|
parsing = false;
|
||||||
|
|
@ -1080,35 +1061,24 @@ static int parse_albumart_load(const char *wps_bufptr,
|
||||||
case 't':
|
case 't':
|
||||||
case 'T':
|
case 'T':
|
||||||
case '-':
|
case '-':
|
||||||
wps_data->albumart_yalign =
|
wps_data->albumart_yalign = WPS_ALBUMART_ALIGN_TOP;
|
||||||
(wps_data->albumart_yalign & yalign_mask) |
|
|
||||||
WPS_ALBUMART_ALIGN_TOP;
|
|
||||||
break;
|
break;
|
||||||
case 'c':
|
case 'c':
|
||||||
case 'C':
|
case 'C':
|
||||||
wps_data->albumart_yalign =
|
wps_data->albumart_yalign = WPS_ALBUMART_ALIGN_CENTER;
|
||||||
(wps_data->albumart_yalign & yalign_mask) |
|
|
||||||
WPS_ALBUMART_ALIGN_CENTER;
|
|
||||||
break;
|
break;
|
||||||
case 'b':
|
case 'b':
|
||||||
case 'B':
|
case 'B':
|
||||||
case '+':
|
case '+':
|
||||||
wps_data->albumart_yalign =
|
wps_data->albumart_yalign = WPS_ALBUMART_ALIGN_BOTTOM;
|
||||||
(wps_data->albumart_yalign & yalign_mask) |
|
|
||||||
WPS_ALBUMART_ALIGN_BOTTOM;
|
|
||||||
break;
|
break;
|
||||||
case 'd':
|
case 'd':
|
||||||
case 'D':
|
case 'D':
|
||||||
wps_data->albumart_yalign |= WPS_ALBUMART_DECREASE;
|
|
||||||
break;
|
|
||||||
case 'i':
|
case 'i':
|
||||||
case 'I':
|
case 'I':
|
||||||
wps_data->albumart_yalign |= WPS_ALBUMART_INCREASE;
|
|
||||||
break;
|
|
||||||
case 's':
|
case 's':
|
||||||
case 'S':
|
case 'S':
|
||||||
wps_data->albumart_yalign |=
|
/* simply ignored */
|
||||||
(WPS_ALBUMART_DECREASE | WPS_ALBUMART_INCREASE);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
parsing = false;
|
parsing = false;
|
||||||
|
|
@ -1524,9 +1494,6 @@ static void wps_reset(struct wps_data *data)
|
||||||
bool rwps = data->remote_wps; /* remember whether the data is for a RWPS */
|
bool rwps = data->remote_wps; /* remember whether the data is for a RWPS */
|
||||||
#endif
|
#endif
|
||||||
memset(data, 0, sizeof(*data));
|
memset(data, 0, sizeof(*data));
|
||||||
#ifdef HAVE_ALBUMART
|
|
||||||
data->wps_uses_albumart = WPS_ALBUMART_NONE;
|
|
||||||
#endif
|
|
||||||
wps_data_init(data);
|
wps_data_init(data);
|
||||||
#ifdef HAVE_REMOTE_LCD
|
#ifdef HAVE_REMOTE_LCD
|
||||||
data->remote_wps = rwps;
|
data->remote_wps = rwps;
|
||||||
|
|
@ -1617,6 +1584,14 @@ bool wps_data_load(struct wps_data *wps_data,
|
||||||
const char *buf,
|
const char *buf,
|
||||||
bool isfile)
|
bool isfile)
|
||||||
{
|
{
|
||||||
|
#ifdef HAVE_ALBUMART
|
||||||
|
struct mp3entry *curtrack;
|
||||||
|
long offset;
|
||||||
|
int status;
|
||||||
|
int wps_uses_albumart = wps_data->wps_uses_albumart;
|
||||||
|
int albumart_max_height = wps_data->albumart_max_height;
|
||||||
|
int albumart_max_width = wps_data->albumart_max_width;
|
||||||
|
#endif
|
||||||
if (!wps_data || !buf)
|
if (!wps_data || !buf)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|
@ -1731,6 +1706,21 @@ bool wps_data_load(struct wps_data *wps_data,
|
||||||
wps_reset(wps_data);
|
wps_reset(wps_data);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_ALBUMART
|
||||||
|
status = audio_status();
|
||||||
|
if (((!wps_uses_albumart && wps_data->wps_uses_albumart) ||
|
||||||
|
(wps_data->wps_uses_albumart &&
|
||||||
|
(albumart_max_height != wps_data->albumart_max_height ||
|
||||||
|
albumart_max_width != wps_data->albumart_max_width))) &&
|
||||||
|
status & AUDIO_STATUS_PLAY)
|
||||||
|
{
|
||||||
|
curtrack = audio_current_track();
|
||||||
|
offset = curtrack->offset;
|
||||||
|
audio_stop();
|
||||||
|
if (!(status & AUDIO_STATUS_PAUSE))
|
||||||
|
audio_play(offset);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -249,11 +249,12 @@ static int num_font = FONT_UI;
|
||||||
static int moves_font = FONT_UI;
|
static int moves_font = FONT_UI;
|
||||||
static int moves_y = 0;
|
static int moves_y = 0;
|
||||||
|
|
||||||
|
#ifdef HAVE_LCD_COLOR
|
||||||
|
static unsigned char *img_buf;
|
||||||
|
static size_t buf_len;
|
||||||
|
#else
|
||||||
static unsigned char img_buf[IMAGE_WIDTH*IMAGE_HEIGHT*sizeof(fb_data)]
|
static unsigned char img_buf[IMAGE_WIDTH*IMAGE_HEIGHT*sizeof(fb_data)]
|
||||||
__attribute__ ((aligned(16)));
|
__attribute__ ((aligned(16)));
|
||||||
#if LCD_DEPTH>1
|
|
||||||
static unsigned char temp_img_buf[LCD_WIDTH*LCD_HEIGHT*sizeof(fb_data)]
|
|
||||||
__attribute__ ((aligned(16)));
|
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_ALBUMART
|
#ifdef HAVE_ALBUMART
|
||||||
static char albumart_path[MAX_PATH+1];
|
static char albumart_path[MAX_PATH+1];
|
||||||
|
|
@ -330,37 +331,22 @@ static bool load_resize_bitmap(void)
|
||||||
rb->memset(&main_bitmap,0,sizeof(struct bitmap));
|
rb->memset(&main_bitmap,0,sizeof(struct bitmap));
|
||||||
main_bitmap.data = img_buf;
|
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.width = IMAGE_WIDTH;
|
||||||
main_bitmap.height = IMAGE_HEIGHT;
|
main_bitmap.height = IMAGE_HEIGHT;
|
||||||
|
|
||||||
rc = rb->read_bmp_file( filename, &temp_bitmap, sizeof(temp_img_buf),
|
#ifndef HAVE_LCD_COLOR
|
||||||
FORMAT_NATIVE );
|
size_t buf_len = sizeof(img_buf);
|
||||||
if( rc > 0 )
|
|
||||||
{
|
|
||||||
#ifdef HAVE_LCD_COLOR
|
|
||||||
smooth_resize_bitmap( &temp_bitmap, &main_bitmap );
|
|
||||||
#else
|
|
||||||
simple_resize_bitmap( &temp_bitmap, &main_bitmap );
|
|
||||||
#endif
|
#endif
|
||||||
puzzle_bmp_ptr = (const fb_data *)img_buf;
|
|
||||||
rb->strcpy( img_buf_path, filename );
|
rc = rb->read_bmp_file( filename, &main_bitmap,
|
||||||
return true;
|
buf_len,
|
||||||
}
|
FORMAT_NATIVE|FORMAT_RESIZE );
|
||||||
#else
|
|
||||||
rc = rb->read_bmp_file( filename, &main_bitmap, sizeof(img_buf),
|
|
||||||
FORMAT_NATIVE );
|
|
||||||
if( rc > 0 )
|
if( rc > 0 )
|
||||||
{
|
{
|
||||||
puzzle_bmp_ptr = (const fb_data *)img_buf;
|
puzzle_bmp_ptr = (const fb_data *)img_buf;
|
||||||
rb->strcpy( img_buf_path, filename );
|
rb->strcpy( img_buf_path, filename );
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* something must have failed. get_albumart_bmp_path could return
|
/* 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
|
||||||
initial_bmp_path=(const char *)parameter;
|
initial_bmp_path=(const char *)parameter;
|
||||||
picmode = PICMODE_INITIAL_PICTURE;
|
picmode = PICMODE_INITIAL_PICTURE;
|
||||||
img_buf_path[0] = '\0';
|
img_buf_path[0] = '\0';
|
||||||
|
#ifdef HAVE_LCD_COLOR
|
||||||
|
unsigned char *img_buf_end;
|
||||||
|
img_buf = (unsigned char *)(rb->plugin_get_buffer(&buf_len));
|
||||||
|
img_buf_end = img_buf + buf_len;
|
||||||
|
rb->align_buffer(PUN_PTR(void **,&img_buf), buf_len, 16);
|
||||||
|
buf_len = img_buf_end - img_buf;
|
||||||
|
#endif
|
||||||
|
|
||||||
/* If launched as a viewer, just go straight to the game without
|
/* If launched as a viewer, just go straight to the game without
|
||||||
bothering with the splash or instructions page */
|
bothering with the splash or instructions page */
|
||||||
|
|
|
||||||
|
|
@ -297,3 +297,12 @@ void draw_album_art(struct gui_wps *gwps, int handle_id, bool clear)
|
||||||
gwps->display->set_drawmode(DRMODE_SOLID);
|
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;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -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,
|
bool search_albumart_files(const struct mp3entry *id3, const char *size_string,
|
||||||
char *buf, int buflen);
|
char *buf, int buflen);
|
||||||
|
|
||||||
|
void get_albumart_size(struct bitmap *bmp);
|
||||||
|
|
||||||
#endif /* HAVE_ALBUMART */
|
#endif /* HAVE_ALBUMART */
|
||||||
|
|
||||||
#endif /* _ALBUMART_H_ */
|
#endif /* _ALBUMART_H_ */
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,13 @@
|
||||||
- better protection against malformed / non-standard BMPs
|
- better protection against malformed / non-standard BMPs
|
||||||
- code heavily optimised for both size and speed
|
- code heavily optimised for both size and speed
|
||||||
- dithering for 2 bit targets
|
- dithering for 2 bit targets
|
||||||
|
2008-11-02 Akio Idehara: refactor for scaler frontend
|
||||||
|
2008-12-08 Andrew Mahone: partial-line reading, scaler frontend
|
||||||
|
- read_part_line does the actual source BMP reading, return columns read
|
||||||
|
and updates fields in a struct bmp_args with the new data and current
|
||||||
|
reader state
|
||||||
|
- skip_lines_bmp and store_part_bmp implement the scaler callbacks to skip
|
||||||
|
ahead by whole lines, or read the next chunk of the current line
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
@ -41,10 +48,16 @@
|
||||||
#ifdef HAVE_REMOTE_LCD
|
#ifdef HAVE_REMOTE_LCD
|
||||||
#include "lcd-remote.h"
|
#include "lcd-remote.h"
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef ROCKBOX_DEBUG_BMP_LOADER
|
||||||
|
#define BDEBUGF DEBUGF
|
||||||
|
#else
|
||||||
|
#define BDEBUGF(...)
|
||||||
|
#endif
|
||||||
#ifndef __PCTOOL__
|
#ifndef __PCTOOL__
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "system.h"
|
#include "system.h"
|
||||||
#include "bmp.h"
|
#include "bmp.h"
|
||||||
|
#include "resize.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#else
|
#else
|
||||||
#undef DEBUGF
|
#undef DEBUGF
|
||||||
|
|
@ -88,16 +101,31 @@ union rgb_union {
|
||||||
uint32_t raw;
|
uint32_t raw;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* masks for supported BI_BITFIELDS encodings (16/32 bit), little endian */
|
/* masks for supported BI_BITFIELDS encodings (16/32 bit) */
|
||||||
static const unsigned char bitfields[3][12] = {
|
static const struct uint8_rgb bitfields[3][3] = {
|
||||||
{ 0x00,0x7c,0x00,0, 0xe0,0x03,0x00,0, 0x1f,0x00,0x00,0 }, /* 15 bit */
|
/* 15bit */
|
||||||
{ 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 */
|
{ .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)
|
#if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)
|
||||||
/* canonical ordered dither matrix */
|
/* canonical ordered dither matrix */
|
||||||
static const unsigned char dither_matrix[16][16] = {
|
const unsigned char dither_matrix[16][16] = {
|
||||||
{ 0,192, 48,240, 12,204, 60,252, 3,195, 51,243, 15,207, 63,255 },
|
{ 0,192, 48,240, 12,204, 60,252, 3,195, 51,243, 15,207, 63,255 },
|
||||||
{ 128, 64,176,112,140, 76,188,124,131, 67,179,115,143, 79,191,127 },
|
{ 128, 64,176,112,140, 76,188,124,131, 67,179,115,143, 79,191,127 },
|
||||||
{ 32,224, 16,208, 44,236, 28,220, 35,227, 19,211, 47,239, 31,223 },
|
{ 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] = {
|
||||||
#if ((LCD_DEPTH == 2) && (LCD_PIXELFORMAT == VERTICAL_INTERLEAVED)) \
|
#if ((LCD_DEPTH == 2) && (LCD_PIXELFORMAT == VERTICAL_INTERLEAVED)) \
|
||||||
|| (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH == 2) \
|
|| (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH == 2) \
|
||||||
&& (LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED))
|
&& (LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED))
|
||||||
static const unsigned short vi_pattern[4] = {
|
const unsigned short vi_pattern[4] = {
|
||||||
0x0101, 0x0100, 0x0001, 0x0000
|
0x0101, 0x0100, 0x0001, 0x0000
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* little endian functions */
|
|
||||||
static inline unsigned readshort(uint16_t *value)
|
|
||||||
{
|
|
||||||
unsigned char* bytes = (unsigned char*) value;
|
|
||||||
return (unsigned)bytes[0] | ((unsigned)bytes[1] << 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline uint32_t readlong(uint32_t *value)
|
|
||||||
{
|
|
||||||
unsigned char* bytes = (unsigned char*) value;
|
|
||||||
return (uint32_t)bytes[0] | ((uint32_t)bytes[1] << 8) |
|
|
||||||
((uint32_t)bytes[2] << 16) | ((uint32_t)bytes[3] << 24);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline unsigned brightness(union rgb_union color)
|
|
||||||
{
|
|
||||||
return (3 * (unsigned)color.red + 6 * (unsigned)color.green
|
|
||||||
+ (unsigned)color.blue) / 10;
|
|
||||||
}
|
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* read_bmp_file()
|
* read_bmp_file()
|
||||||
*
|
*
|
||||||
|
|
@ -165,11 +173,219 @@ int read_bmp_file(const char* filename,
|
||||||
return fd * 10 - 1;
|
return fd * 10 - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BDEBUGF("read_bmp_file: '%s' remote: %d resize: %d keep_aspect: %d\n",
|
||||||
|
filename, !!(format & FORMAT_REMOTE), !!(format & FORMAT_RESIZE),
|
||||||
|
!!(format & FORMAT_KEEP_ASPECT));
|
||||||
ret = read_bmp_fd(fd, bm, maxsize, format);
|
ret = read_bmp_fd(fd, bm, maxsize, format);
|
||||||
close(fd);
|
close(fd);
|
||||||
return ret;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct bmp_args {
|
||||||
|
int fd;
|
||||||
|
short padded_width;
|
||||||
|
short read_width;
|
||||||
|
short width;
|
||||||
|
short depth;
|
||||||
|
unsigned char buf[MAX_WIDTH * 4];
|
||||||
|
struct uint8_rgb *palette;
|
||||||
|
#if LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)
|
||||||
|
int cur_row;
|
||||||
|
int cur_col;
|
||||||
|
struct img_part part;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
static unsigned int read_part_line(struct bmp_args *ba)
|
||||||
|
{
|
||||||
|
const int padded_width = ba->padded_width;
|
||||||
|
const int read_width = ba->read_width;
|
||||||
|
const int width = ba->width;
|
||||||
|
const int depth = ba->depth;
|
||||||
|
#if LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)
|
||||||
|
int cur_row = ba->cur_row;
|
||||||
|
int cur_col = ba->cur_col;
|
||||||
|
#endif
|
||||||
|
const int fd = ba->fd;
|
||||||
|
uint8_t *ibuf;
|
||||||
|
struct uint8_rgb *buf = (struct uint8_rgb *)(ba->buf);
|
||||||
|
const struct uint8_rgb *palette = ba->palette;
|
||||||
|
uint32_t component, data = data;
|
||||||
|
int ret;
|
||||||
|
int i, cols, len;
|
||||||
|
|
||||||
|
#if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)
|
||||||
|
cols = MIN(width - cur_col,(int)MAX_WIDTH);
|
||||||
|
len = (cols * (depth == 15 ? 16 : depth) + 7) >> 3;
|
||||||
|
#else
|
||||||
|
cols = width;
|
||||||
|
len = read_width;
|
||||||
|
#endif
|
||||||
|
ibuf = ((unsigned char *)buf) + (MAX_WIDTH << 2) - len;
|
||||||
|
BDEBUGF("read_part_line: cols=%d len=%d\n",cols,len);
|
||||||
|
ret = read(fd, ibuf, len);
|
||||||
|
if (ret != len)
|
||||||
|
{
|
||||||
|
DEBUGF("read_part_line: error reading image, read returned %d "
|
||||||
|
"expected %d\n", ret, len);
|
||||||
|
BDEBUGF("cur_row: %d cur_col: %d cols: %d len: %d\n", cur_row, cur_col,
|
||||||
|
cols, len);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
for (i = 0; i < cols; i++)
|
||||||
|
{
|
||||||
|
switch (depth)
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
if ((i & 7) == 0)
|
||||||
|
data = *ibuf++;
|
||||||
|
*buf = palette[(data >> 7) & 1];
|
||||||
|
data <<= 1;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
*buf = palette[*ibuf >> 4];
|
||||||
|
if (i & 1)
|
||||||
|
ibuf++;
|
||||||
|
else
|
||||||
|
*ibuf <<= 4;
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
*buf = palette[*ibuf++];
|
||||||
|
break;
|
||||||
|
case 15:
|
||||||
|
case 16:
|
||||||
|
data = letoh16(*(uint16_t*)ibuf);
|
||||||
|
component = (data << 3) & 0xf8;
|
||||||
|
component |= component >> 5;
|
||||||
|
buf->blue = component;
|
||||||
|
if (depth == 15)
|
||||||
|
{
|
||||||
|
data >>= 2;
|
||||||
|
component = data & 0xf8;
|
||||||
|
component |= component >> 5;
|
||||||
|
} else {
|
||||||
|
data >>= 3;
|
||||||
|
component = data & 0xfc;
|
||||||
|
component |= component >> 6;
|
||||||
|
}
|
||||||
|
buf->green = component;
|
||||||
|
data >>= 5;
|
||||||
|
component = data & 0xf8;
|
||||||
|
component |= component >> 5;
|
||||||
|
buf->red = component;
|
||||||
|
ibuf += 2;
|
||||||
|
break;
|
||||||
|
case 32:
|
||||||
|
case 24:
|
||||||
|
buf->blue = *ibuf++;
|
||||||
|
buf->green = *ibuf++;
|
||||||
|
buf->red = *ibuf++;
|
||||||
|
if (depth == 32)
|
||||||
|
ibuf++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
buf++;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)
|
||||||
|
cur_col += cols;
|
||||||
|
if (cur_col == width)
|
||||||
|
{
|
||||||
|
#endif
|
||||||
|
int pad = padded_width - read_width;
|
||||||
|
if (pad > 0)
|
||||||
|
{
|
||||||
|
BDEBUGF("seeking %d bytes to next line\n",pad);
|
||||||
|
lseek(fd, pad, SEEK_CUR);
|
||||||
|
}
|
||||||
|
#if LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)
|
||||||
|
cur_col = 0;
|
||||||
|
BDEBUGF("read_part_line: completed row %d\n", cur_row);
|
||||||
|
cur_row += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ba->cur_row = cur_row;
|
||||||
|
ba->cur_col = cur_col;
|
||||||
|
#endif
|
||||||
|
return cols;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)
|
||||||
|
static struct img_part *store_part_bmp(void *args)
|
||||||
|
{
|
||||||
|
struct bmp_args *ba = (struct bmp_args *)args;
|
||||||
|
|
||||||
|
ba->part.len = read_part_line(ba);
|
||||||
|
ba->part.buf = (struct uint8_rgb *)ba->buf;
|
||||||
|
if (ba->part.len)
|
||||||
|
return &(ba->part);
|
||||||
|
else
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool skip_lines_bmp(void *args, unsigned int lines)
|
||||||
|
{
|
||||||
|
struct bmp_args * ba = (struct bmp_args *)args;
|
||||||
|
|
||||||
|
int pad = lines * ba->padded_width +
|
||||||
|
(ba->cur_col
|
||||||
|
? ((ba->cur_col * ba->depth + 7) >> 3) - ba->padded_width
|
||||||
|
: 0);
|
||||||
|
if (pad)
|
||||||
|
{
|
||||||
|
if(lseek(ba->fd, pad, SEEK_CUR) < 0)
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ba->cur_row += lines + (ba->cur_col ? 1 : 0);
|
||||||
|
ba->cur_col = 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)
|
||||||
|
static inline int recalc_dimension(struct dim *dst, struct dim *src)
|
||||||
|
{
|
||||||
|
int tmp;
|
||||||
|
if (dst->width <= 0)
|
||||||
|
dst->width = LCD_WIDTH;
|
||||||
|
if (dst->height <= 0)
|
||||||
|
dst->height = LCD_HEIGHT;
|
||||||
|
#ifndef HAVE_UPSCALER
|
||||||
|
if (dst->width > src->width || dst->height > src->height)
|
||||||
|
{
|
||||||
|
dst->width = src->width;
|
||||||
|
dst->height = src->height;
|
||||||
|
}
|
||||||
|
if (src->width == dst->width && src->height == dst->height)
|
||||||
|
return 1;
|
||||||
|
#endif
|
||||||
|
tmp = (src->width * dst->height + (src->height >> 1)) / src->height;
|
||||||
|
if (tmp > dst->width)
|
||||||
|
dst->height = (src->height * dst->width + (src->width >> 1))
|
||||||
|
/ src->width;
|
||||||
|
else
|
||||||
|
dst->width = tmp;
|
||||||
|
return src->width == dst->width && src->height == dst->height;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
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()
|
* read_bmp_fd()
|
||||||
*
|
*
|
||||||
|
|
@ -183,21 +399,22 @@ int read_bmp_fd(int fd,
|
||||||
int format)
|
int format)
|
||||||
{
|
{
|
||||||
struct bmp_header bmph;
|
struct bmp_header bmph;
|
||||||
int width, height, padded_width;
|
int padded_width;
|
||||||
int dst_height, dst_width;
|
int read_width;
|
||||||
int depth, numcolors, compression, totalsize;
|
int depth, numcolors, compression, totalsize;
|
||||||
int row, col, ret;
|
int ret;
|
||||||
int rowstart, rowstop, rowstep;
|
|
||||||
|
|
||||||
unsigned char *bitmap = bm->data;
|
unsigned char *bitmap = bm->data;
|
||||||
uint32_t bmpbuf[LCD_WIDTH]; /* Buffer for one line */
|
struct uint8_rgb palette[256];
|
||||||
uint32_t palette[256];
|
|
||||||
#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;
|
bool remote = false;
|
||||||
|
struct rowset rset;
|
||||||
|
struct dim src_dim;
|
||||||
|
#if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)
|
||||||
|
unsigned int resize = IMG_NORESIZE;
|
||||||
|
bool dither = false;
|
||||||
|
bool transparent = false;
|
||||||
|
|
||||||
|
#ifdef HAVE_REMOTE_LCD
|
||||||
if (format & FORMAT_REMOTE) {
|
if (format & FORMAT_REMOTE) {
|
||||||
remote = true;
|
remote = true;
|
||||||
#if LCD_REMOTE_DEPTH == 1
|
#if LCD_REMOTE_DEPTH == 1
|
||||||
|
|
@ -207,6 +424,12 @@ int read_bmp_fd(int fd,
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#endif /* HAVE_REMOTE_LCD */
|
#endif /* HAVE_REMOTE_LCD */
|
||||||
|
|
||||||
|
if (format & FORMAT_RESIZE) {
|
||||||
|
resize = IMG_RESIZE;
|
||||||
|
format &= ~FORMAT_RESIZE;
|
||||||
|
}
|
||||||
|
|
||||||
if (format & FORMAT_TRANSPARENT) {
|
if (format & FORMAT_TRANSPARENT) {
|
||||||
transparent = true;
|
transparent = true;
|
||||||
format &= ~FORMAT_TRANSPARENT;
|
format &= ~FORMAT_TRANSPARENT;
|
||||||
|
|
@ -218,7 +441,7 @@ int read_bmp_fd(int fd,
|
||||||
#else
|
#else
|
||||||
|
|
||||||
(void)format;
|
(void)format;
|
||||||
#endif /* (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) */
|
#endif /*(LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)*/
|
||||||
|
|
||||||
/* read fileheader */
|
/* read fileheader */
|
||||||
ret = read(fd, &bmph, sizeof(struct bmp_header));
|
ret = read(fd, &bmph, sizeof(struct bmp_header));
|
||||||
|
|
@ -231,77 +454,77 @@ int read_bmp_fd(int fd,
|
||||||
return -3;
|
return -3;
|
||||||
}
|
}
|
||||||
|
|
||||||
width = readlong(&bmph.width);
|
src_dim.width = letoh32(bmph.width);
|
||||||
if (width > LCD_WIDTH) {
|
src_dim.height = letoh32(bmph.height);
|
||||||
DEBUGF("read_bmp_fd: Bitmap too wide (%d pixels, max is %d)\n",
|
if (src_dim.height < 0) { /* Top-down BMP file */
|
||||||
width, LCD_WIDTH);
|
src_dim.height = -src_dim.height;
|
||||||
return -4;
|
rset.rowstep = 1;
|
||||||
}
|
|
||||||
|
|
||||||
height = readlong(&bmph.height);
|
|
||||||
if (height < 0) { /* Top-down BMP file */
|
|
||||||
height = -height;
|
|
||||||
rowstart = 0;
|
|
||||||
rowstop = height;
|
|
||||||
rowstep = 1;
|
|
||||||
} else { /* normal BMP */
|
} else { /* normal BMP */
|
||||||
rowstart = height - 1;
|
rset.rowstep = -1;
|
||||||
rowstop = -1;
|
|
||||||
rowstep = -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
depth = readshort(&bmph.bit_count);
|
depth = letoh16(bmph.bit_count);
|
||||||
padded_width = ((width * depth + 31) >> 3) & ~3; /* 4-byte boundary aligned */
|
/* 4-byte boundary aligned */
|
||||||
|
read_width = ((src_dim.width * (depth == 15 ? 16 : depth) + 7) >> 3);
|
||||||
|
padded_width = (read_width + 3) & ~3;
|
||||||
|
|
||||||
|
BDEBUGF("width: %d height: %d depth: %d padded_width: %d\n", src_dim.width,
|
||||||
|
src_dim.height, depth, padded_width);
|
||||||
|
|
||||||
#if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)
|
#if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)
|
||||||
if (format == FORMAT_ANY) {
|
if ((format & 3) == FORMAT_ANY) {
|
||||||
if (depth == 1)
|
if (depth == 1)
|
||||||
format = FORMAT_MONO;
|
format = (format & ~3);
|
||||||
else
|
else
|
||||||
format = FORMAT_NATIVE;
|
format = (format & ~3) | FORMAT_NATIVE;
|
||||||
}
|
}
|
||||||
bm->format = format;
|
bm->format = format & 3;
|
||||||
#endif /* (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) */
|
if ((format & 3) == FORMAT_MONO)
|
||||||
/* returning image size */
|
|
||||||
bm->width = width;
|
|
||||||
bm->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);
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
#endif /* (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) */
|
|
||||||
{
|
{
|
||||||
dst_width = width;
|
resize &= ~IMG_RESIZE;
|
||||||
dst_height = (height + 7) >> 3;
|
resize |= IMG_NORESIZE;
|
||||||
totalsize = dst_width * dst_height;
|
remote = 0;
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
if (src_dim.width > MAX_WIDTH)
|
||||||
|
return -6;
|
||||||
|
#endif /*(LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)*/
|
||||||
|
|
||||||
|
#if LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)
|
||||||
|
if (resize & IMG_RESIZE) {
|
||||||
|
if(format & FORMAT_KEEP_ASPECT) {
|
||||||
|
/* keep aspect ratio.. */
|
||||||
|
format &= ~FORMAT_KEEP_ASPECT;
|
||||||
|
struct dim resize_dim = {
|
||||||
|
.width = bm->width,
|
||||||
|
.height = bm->height,
|
||||||
|
};
|
||||||
|
if (recalc_dimension(&resize_dim, &src_dim))
|
||||||
|
resize = IMG_NORESIZE;
|
||||||
|
bm->width = resize_dim.width;
|
||||||
|
bm->height = resize_dim.height;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(resize & IMG_RESIZE)) {
|
||||||
|
#endif
|
||||||
|
/* returning image size */
|
||||||
|
bm->width = src_dim.width;
|
||||||
|
bm->height = src_dim.height;
|
||||||
|
|
||||||
|
#if LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (rset.rowstep > 0) { /* Top-down BMP file */
|
||||||
|
rset.rowstart = 0;
|
||||||
|
rset.rowstop = bm->height;
|
||||||
|
} else { /* normal BMP */
|
||||||
|
rset.rowstart = bm->height - 1;
|
||||||
|
rset.rowstop = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
totalsize = get_totalsize(bm, remote);
|
||||||
|
|
||||||
/* Check if this fits the buffer */
|
/* Check if this fits the buffer */
|
||||||
if (totalsize > maxsize) {
|
if (totalsize > maxsize) {
|
||||||
|
|
@ -310,20 +533,24 @@ int read_bmp_fd(int fd,
|
||||||
return -6;
|
return -6;
|
||||||
}
|
}
|
||||||
|
|
||||||
compression = readlong(&bmph.compression);
|
compression = letoh32(bmph.compression);
|
||||||
if (depth <= 8) {
|
if (depth <= 8) {
|
||||||
numcolors = readlong(&bmph.clr_used);
|
numcolors = letoh32(bmph.clr_used);
|
||||||
if (numcolors == 0)
|
if (numcolors == 0)
|
||||||
numcolors = 1 << depth;
|
numcolors = 1 << depth;
|
||||||
} else
|
} else
|
||||||
numcolors = (compression == 3) ? 3 : 0;
|
numcolors = (compression == 3) ? 3 : 0;
|
||||||
|
|
||||||
if (numcolors > 0 && numcolors <= 256) {
|
if (numcolors > 0 && numcolors <= 256) {
|
||||||
if (read(fd, palette, numcolors * sizeof(uint32_t))
|
int i;
|
||||||
!= numcolors * (int)sizeof(uint32_t))
|
union rgb_union pal;
|
||||||
{
|
for (i = 0; i < numcolors; i++) {
|
||||||
DEBUGF("read_bmp_fd: Can't read color palette\n");
|
if (read(fd, &pal, sizeof(pal)) != (int)sizeof(pal))
|
||||||
return -7;
|
{
|
||||||
|
DEBUGF("read_bmp_fd: Can't read color palette\n");
|
||||||
|
return -7;
|
||||||
|
}
|
||||||
|
set_rgb_union(&palette[i], pal);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -343,15 +570,27 @@ int read_bmp_fd(int fd,
|
||||||
|
|
||||||
case 32:
|
case 32:
|
||||||
if (compression == 3) { /* BI_BITFIELDS */
|
if (compression == 3) { /* BI_BITFIELDS */
|
||||||
if (!memcmp(palette, bitfields[0], 12)) { /* 15 bit */
|
bool found;
|
||||||
depth = 15;
|
int i, j;
|
||||||
break;
|
|
||||||
|
/* (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 */
|
if (found)
|
||||||
|| !memcmp(palette, bitfields[2], 12)) /* 32 bit */
|
|
||||||
{
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
} /* else fall through */
|
} /* else fall through */
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
@ -364,227 +603,104 @@ int read_bmp_fd(int fd,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Search to the beginning of the image data */
|
/* Search to the beginning of the image data */
|
||||||
lseek(fd, (off_t)readlong(&bmph.off_bits), SEEK_SET);
|
lseek(fd, (off_t)letoh32(bmph.off_bits), SEEK_SET);
|
||||||
|
|
||||||
memset(bitmap, 0, totalsize);
|
memset(bitmap, 0, totalsize);
|
||||||
|
|
||||||
/* loop to read rows and put them to buffer */
|
struct bmp_args ba = {
|
||||||
for (row = rowstart; row != rowstop; row += rowstep) {
|
.fd = fd, .padded_width = padded_width, .read_width = read_width,
|
||||||
unsigned data, mask;
|
.width = src_dim.width, .depth = depth, .palette = palette,
|
||||||
unsigned char *p;
|
#if LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)
|
||||||
uint16_t *p2;
|
.cur_row = 0, .cur_col = 0, .part = {0,0}
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 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;
|
|
||||||
|
|
||||||
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) {
|
|
||||||
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
|
#endif
|
||||||
}
|
};
|
||||||
break;
|
|
||||||
|
|
||||||
case 24:
|
#if LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)
|
||||||
p = (unsigned char*)bmpbuf + 3 * width;
|
#if LCD_DEPTH == 16
|
||||||
while (p > (unsigned char*)bmpbuf) {
|
#ifdef HAVE_REMOTE_LCD
|
||||||
data = *(--p);
|
if (resize & IMG_RESIZE || remote)
|
||||||
data = (data << 8) | *(--p);
|
#else
|
||||||
data = (data << 8) | *(--p);
|
if (resize & IMG_RESIZE)
|
||||||
*(--rp) = htole32(data);
|
#endif
|
||||||
}
|
#else
|
||||||
break;
|
if (format == FORMAT_NATIVE)
|
||||||
|
#endif
|
||||||
case 32: /* already in desired format */
|
return resize_on_load(bm, dither, &src_dim, &rset, remote,
|
||||||
break;
|
#ifdef HAVE_LCD_COLOR
|
||||||
}
|
bitmap + totalsize, maxsize - totalsize,
|
||||||
|
#endif
|
||||||
/* Convert to destination format */
|
store_part_bmp, skip_lines_bmp, &ba);
|
||||||
qp = (union rgb_union *)bmpbuf;
|
|
||||||
#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)
|
|
||||||
/* iAudio X5/M5 remote */
|
|
||||||
fb_remote_data *dest = (fb_remote_data *)bitmap
|
|
||||||
+ dst_width * (row >> 3);
|
|
||||||
int shift = row & 7;
|
|
||||||
int delta = 127;
|
|
||||||
unsigned bright;
|
|
||||||
|
|
||||||
for (col = 0; col < width; col++) {
|
|
||||||
if (dither)
|
|
||||||
delta = dither_matrix[row & 0xf][col & 0xf];
|
|
||||||
bright = brightness(*qp++);
|
|
||||||
bright = (3 * bright + (bright >> 6) + delta) >> 8;
|
|
||||||
*dest++ |= vi_pattern[bright] << shift;
|
|
||||||
}
|
|
||||||
#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
|
|
||||||
/* greyscale iPods */
|
|
||||||
fb_data *dest = (fb_data *)bitmap + dst_width * row;
|
|
||||||
int shift = 6;
|
|
||||||
int delta = 127;
|
|
||||||
unsigned bright;
|
|
||||||
unsigned data = 0;
|
|
||||||
|
|
||||||
for (col = 0; col < width; col++) {
|
|
||||||
if (dither)
|
|
||||||
delta = dither_matrix[row & 0xf][col & 0xf];
|
|
||||||
bright = brightness(*qp++);
|
|
||||||
bright = (3 * bright + (bright >> 6) + delta) >> 8;
|
|
||||||
data |= (~bright & 3) << shift;
|
|
||||||
shift -= 2;
|
|
||||||
if (shift < 0) {
|
|
||||||
*dest++ = data;
|
|
||||||
data = 0;
|
|
||||||
shift = 6;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (shift < 6)
|
|
||||||
*dest++ = data;
|
|
||||||
#elif LCD_PIXELFORMAT == VERTICAL_PACKING
|
|
||||||
/* iriver H1x0 */
|
|
||||||
fb_data *dest = (fb_data *)bitmap + dst_width * (row >> 2);
|
|
||||||
int shift = 2 * (row & 3);
|
|
||||||
int delta = 127;
|
|
||||||
unsigned bright;
|
|
||||||
|
|
||||||
for (col = 0; col < width; col++) {
|
|
||||||
if (dither)
|
|
||||||
delta = dither_matrix[row & 0xf][col & 0xf];
|
|
||||||
bright = brightness(*qp++);
|
|
||||||
bright = (3 * bright + (bright >> 6) + delta) >> 8;
|
|
||||||
*dest++ |= (~bright & 3) << shift;
|
|
||||||
}
|
|
||||||
#elif LCD_PIXELFORMAT == VERTICAL_INTERLEAVED
|
|
||||||
/* iAudio M3 */
|
|
||||||
fb_data *dest = (fb_data *)bitmap + dst_width * (row >> 3);
|
|
||||||
int shift = row & 7;
|
|
||||||
int delta = 127;
|
|
||||||
unsigned bright;
|
|
||||||
|
|
||||||
for (col = 0; col < width; col++) {
|
|
||||||
if (dither)
|
|
||||||
delta = dither_matrix[row & 0xf][col & 0xf];
|
|
||||||
bright = brightness(*qp++);
|
|
||||||
bright = (3 * bright + (bright >> 6) + delta) >> 8;
|
|
||||||
*dest++ |= vi_pattern[bright] << shift;
|
|
||||||
}
|
|
||||||
#endif /* LCD_PIXELFORMAT */
|
|
||||||
#elif LCD_DEPTH == 16
|
|
||||||
/* iriver h300, colour iPods, X5 */
|
|
||||||
fb_data *dest = (fb_data *)bitmap + dst_width * row;
|
|
||||||
int delta = 127;
|
|
||||||
unsigned r, g, b;
|
|
||||||
|
|
||||||
for (col = 0; col < width; col++) {
|
|
||||||
if (dither)
|
|
||||||
delta = dither_matrix[row & 0xf][col & 0xf];
|
|
||||||
q0 = *qp++;
|
|
||||||
r = (31 * q0.red + (q0.red >> 3) + delta) >> 8;
|
|
||||||
g = (63 * q0.green + (q0.green >> 2) + delta) >> 8;
|
|
||||||
b = (31 * q0.blue + (q0.blue >> 3) + delta) >> 8;
|
|
||||||
*dest++ = LCD_RGBPACK_LCD(r, g, b);
|
|
||||||
}
|
|
||||||
#endif /* LCD_DEPTH */
|
#endif /* LCD_DEPTH */
|
||||||
}
|
|
||||||
} else
|
|
||||||
#endif /* (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) */
|
|
||||||
{
|
|
||||||
p = bitmap + dst_width * (row >> 3);
|
|
||||||
mask = 1 << (row & 7);
|
|
||||||
|
|
||||||
for (col = 0; col < width; col++, p++)
|
int fb_width = get_fb_width(bm, remote);
|
||||||
|
int col, row;
|
||||||
|
|
||||||
|
/* loop to read rows and put them to buffer */
|
||||||
|
for (row = rset.rowstart; row != rset.rowstop; row += rset.rowstep) {
|
||||||
|
struct uint8_rgb *qp;
|
||||||
|
unsigned mask;
|
||||||
|
unsigned char *p;
|
||||||
|
#if LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)
|
||||||
|
unsigned int len;
|
||||||
|
|
||||||
|
if (!(len = read_part_line(&ba)))
|
||||||
|
return -9;
|
||||||
|
#else
|
||||||
|
if (!read_part_line(&ba))
|
||||||
|
return -9;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Convert to destination format */
|
||||||
|
qp = (struct uint8_rgb *) ba.buf;
|
||||||
|
#if LCD_DEPTH == 16
|
||||||
|
if (format == FORMAT_NATIVE)
|
||||||
|
{
|
||||||
|
/* iriver h300, colour iPods, X5 */
|
||||||
|
fb_data *dest = (fb_data *)bitmap + fb_width * row;
|
||||||
|
int delta = 127;
|
||||||
|
unsigned r, g, b;
|
||||||
|
struct uint8_rgb q0;
|
||||||
|
|
||||||
|
for (col = 0; col < src_dim.width; col++) {
|
||||||
|
if (dither)
|
||||||
|
delta = dither_mat(row & 0xf, col & 0xf);
|
||||||
|
if (!len)
|
||||||
|
{
|
||||||
|
if(!(len = read_part_line(&ba)))
|
||||||
|
return -9;
|
||||||
|
else
|
||||||
|
qp = (struct uint8_rgb *)ba.buf;
|
||||||
|
}
|
||||||
|
q0 = *qp++;
|
||||||
|
len--;
|
||||||
|
r = (31 * q0.red + (q0.red >> 3) + delta) >> 8;
|
||||||
|
g = (63 * q0.green + (q0.green >> 2) + delta) >> 8;
|
||||||
|
b = (31 * q0.blue + (q0.blue >> 3) + delta) >> 8;
|
||||||
|
*dest++ = LCD_RGBPACK_LCD(r, g, b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
p = bitmap + fb_width * (row >> 3);
|
||||||
|
mask = 1 << (row & 7);
|
||||||
|
for (col = 0; col < src_dim.width; col++)
|
||||||
|
{
|
||||||
|
#if LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)
|
||||||
|
if (!len)
|
||||||
|
{
|
||||||
|
if(!(len = read_part_line(&ba)))
|
||||||
|
return -9;
|
||||||
|
else
|
||||||
|
qp = (struct uint8_rgb *)ba.buf;
|
||||||
|
}
|
||||||
|
len--;
|
||||||
|
#endif
|
||||||
if (brightness(*qp++) < 128)
|
if (brightness(*qp++) < 128)
|
||||||
*p |= mask;
|
*p |= mask;
|
||||||
|
p++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return totalsize; /* return the used buffer size. */
|
return totalsize; /* return the used buffer size. */
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,163 @@
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "lcd.h"
|
#include "lcd.h"
|
||||||
|
#include "inttypes.h"
|
||||||
|
#ifdef HAVE_REMOTE_LCD
|
||||||
|
#include "lcd-remote.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define ARRAY_SIZE(array) (int)(sizeof(array)/(sizeof(array[0])))
|
||||||
|
|
||||||
|
#define IMG_NORESIZE 0
|
||||||
|
#define IMG_RESIZE 1
|
||||||
|
#if LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)
|
||||||
|
#define MAX_WIDTH 8
|
||||||
|
#else
|
||||||
|
#define MAX_WIDTH LCD_WIDTH
|
||||||
|
#endif
|
||||||
|
|
||||||
|
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)
|
||||||
|
extern const unsigned char dither_matrix[16][16];
|
||||||
|
static inline unsigned char dither_mat(unsigned int x, unsigned int y)
|
||||||
|
{
|
||||||
|
return dither_matrix[y][x];
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static inline unsigned brightness(struct uint8_rgb color)
|
||||||
|
{
|
||||||
|
return (3 * (unsigned)color.red + 6 * (unsigned)color.green
|
||||||
|
+ (unsigned)color.blue) / 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if ((LCD_DEPTH == 2) && (LCD_PIXELFORMAT == VERTICAL_INTERLEAVED)) \
|
||||||
|
|| (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH == 2) \
|
||||||
|
&& (LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED))
|
||||||
|
extern const unsigned short vi_pattern[4];
|
||||||
|
static inline unsigned short vi_pat(unsigned int bright)
|
||||||
|
{
|
||||||
|
return vi_pattern[bright];
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static inline int get_fb_height(struct bitmap *bm, bool remote)
|
||||||
|
{
|
||||||
|
const int height = bm->height;
|
||||||
|
#if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)
|
||||||
|
const int format = bm->format;
|
||||||
|
#endif
|
||||||
|
int 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 int width = bm->width;
|
||||||
|
#if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)
|
||||||
|
const int format = bm->format;
|
||||||
|
#endif
|
||||||
|
int 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()
|
* read_bmp_file()
|
||||||
|
|
|
||||||
718
apps/recorder/resize.c
Normal file
718
apps/recorder/resize.c
Normal file
|
|
@ -0,0 +1,718 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* __________ __ ___.
|
||||||
|
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||||
|
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||||
|
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||||
|
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||||
|
* \/ \/ \/ \/ \/
|
||||||
|
* $Id
|
||||||
|
*
|
||||||
|
* Copyright (C) 2008 by Akio Idehara, Andrew Mahone
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Implementation of area average and linear row and vertical scalers, and
|
||||||
|
* nearest-neighbor grey scaler (C) 2008 Andrew Mahone
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "inttypes.h"
|
||||||
|
#include "debug.h"
|
||||||
|
#include "lcd.h"
|
||||||
|
#include "file.h"
|
||||||
|
#ifdef HAVE_REMOTE_LCD
|
||||||
|
#include "lcd-remote.h"
|
||||||
|
#endif
|
||||||
|
#ifdef ROCKBOX_DEBUG_SCALERS
|
||||||
|
#define SDEBUGF DEBUGF
|
||||||
|
#else
|
||||||
|
#define SDEBUGF(...)
|
||||||
|
#endif
|
||||||
|
#ifndef __PCTOOL__
|
||||||
|
#include "config.h"
|
||||||
|
#include "system.h"
|
||||||
|
#include "bmp.h"
|
||||||
|
#include "resize.h"
|
||||||
|
#include "resize.h"
|
||||||
|
#include "debug.h"
|
||||||
|
#else
|
||||||
|
#undef DEBUGF
|
||||||
|
#define DEBUGF(...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_LCD_COLOR
|
||||||
|
#define PACKRED(r, delta) ((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)
|
||||||
|
|
||||||
|
#define FILL_BUF_INIT(img_part, store_part, args) { \
|
||||||
|
part = store_part(args); \
|
||||||
|
if (part == NULL) \
|
||||||
|
return false; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define FILL_BUF(img_part, store_part, args) { \
|
||||||
|
if (part->len == 0) \
|
||||||
|
part = store_part(args); \
|
||||||
|
if (part == NULL) \
|
||||||
|
return false; \
|
||||||
|
}
|
||||||
|
|
||||||
|
struct uint32_rgb {
|
||||||
|
uint32_t r;
|
||||||
|
uint32_t g;
|
||||||
|
uint32_t b;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct scaler_context {
|
||||||
|
uint32_t divmul;
|
||||||
|
uint32_t round;
|
||||||
|
struct img_part* (*store_part)(void *);
|
||||||
|
long last_tick;
|
||||||
|
unsigned char *buf;
|
||||||
|
int len;
|
||||||
|
void *args;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void scale_h_area_setup(struct bitmap *bm, struct dim *src,
|
||||||
|
struct scaler_context *ctx)
|
||||||
|
{
|
||||||
|
(void) bm;
|
||||||
|
ctx->divmul = ((src->width - 1 + 0x80000000U) / src->width) << 1;
|
||||||
|
ctx->round = (src->width + 1) >> 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* horizontal area average scaler */
|
||||||
|
static bool scale_h_area(struct bitmap *bm, struct dim *src,
|
||||||
|
struct uint32_rgb *out_line,
|
||||||
|
struct scaler_context *ctx, bool accum)
|
||||||
|
{
|
||||||
|
SDEBUGF("scale_h_area\n");
|
||||||
|
unsigned int ix, ox, oxe, mul;
|
||||||
|
struct uint32_rgb rgbval1, rgbval2;
|
||||||
|
struct img_part *part;
|
||||||
|
FILL_BUF_INIT(part,ctx->store_part,ctx->args);
|
||||||
|
ox = 0;
|
||||||
|
oxe = 0;
|
||||||
|
rgbval1.r = 0;
|
||||||
|
rgbval1.g = 0;
|
||||||
|
rgbval1.b = 0;
|
||||||
|
rgbval2.r = 0;
|
||||||
|
rgbval2.g = 0;
|
||||||
|
rgbval2.b = 0;
|
||||||
|
mul = 0;
|
||||||
|
for (ix = 0; ix < (unsigned int)src->width; ix++)
|
||||||
|
{
|
||||||
|
oxe += bm->width;
|
||||||
|
if (oxe >= (unsigned int)src->width)
|
||||||
|
{
|
||||||
|
if (ctx->last_tick != current_tick)
|
||||||
|
{
|
||||||
|
yield();
|
||||||
|
ctx->last_tick = current_tick;
|
||||||
|
}
|
||||||
|
oxe -= src->width;
|
||||||
|
rgbval1.r = rgbval1.r * bm->width + rgbval2.r * mul;
|
||||||
|
rgbval1.g = rgbval1.g * bm->width + rgbval2.g * mul;
|
||||||
|
rgbval1.b = rgbval1.b * bm->width + rgbval2.b * mul;
|
||||||
|
FILL_BUF(part,ctx->store_part,ctx->args);
|
||||||
|
rgbval2.r = part->buf->red;
|
||||||
|
rgbval2.g = part->buf->green;
|
||||||
|
rgbval2.b = part->buf->blue;
|
||||||
|
part->buf++;
|
||||||
|
part->len--;
|
||||||
|
mul = bm->width - oxe;
|
||||||
|
rgbval1.r += rgbval2.r * mul;
|
||||||
|
rgbval1.g += rgbval2.g * mul;
|
||||||
|
rgbval1.b += rgbval2.b * mul;
|
||||||
|
out_line[ox].r = (accum ? out_line[ox].r : 0) +
|
||||||
|
(((uint64_t)rgbval1.r + ctx->round) *
|
||||||
|
ctx->divmul >> 32);
|
||||||
|
out_line[ox].g = (accum ? out_line[ox].g : 0) +
|
||||||
|
(((uint64_t)rgbval1.g + ctx->round) *
|
||||||
|
ctx->divmul >> 32);
|
||||||
|
out_line[ox].b = (accum ? out_line[ox].b : 0) +
|
||||||
|
(((uint64_t)rgbval1.b + ctx->round) *
|
||||||
|
ctx->divmul >> 32);
|
||||||
|
rgbval1.r = 0;
|
||||||
|
rgbval1.g = 0;
|
||||||
|
rgbval1.b = 0;
|
||||||
|
mul = bm->width - mul;
|
||||||
|
ox += 1;
|
||||||
|
} else {
|
||||||
|
FILL_BUF(part,ctx->store_part,ctx->args);
|
||||||
|
rgbval1.r += part->buf->red;
|
||||||
|
rgbval1.g += part->buf->green;
|
||||||
|
rgbval1.b += part->buf->blue;
|
||||||
|
part->buf++;
|
||||||
|
part->len--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* vertical area average scaler */
|
||||||
|
static bool scale_v_area(struct bitmap *bm, bool dither, struct dim *src,
|
||||||
|
struct rowset *rset,
|
||||||
|
bool (*h_scaler)(struct bitmap*, struct dim*,
|
||||||
|
struct uint32_rgb*,
|
||||||
|
struct scaler_context*, bool),
|
||||||
|
struct scaler_context *ctx)
|
||||||
|
{
|
||||||
|
uint32_t mul, divmul, x, oy, iy, oye, round;
|
||||||
|
int delta = 127, r, g, b;
|
||||||
|
fb_data *row, *pix;
|
||||||
|
divmul = ((src->height - 1 + 0x80000000U) / src->height) << 1;
|
||||||
|
round = (src->height + 1) >> 1;
|
||||||
|
mul = 0;
|
||||||
|
oy = 0;
|
||||||
|
oye = 0;
|
||||||
|
struct uint32_rgb *crow1 = (struct uint32_rgb *)(ctx->buf),
|
||||||
|
*crow2 = crow1 + bm->width;
|
||||||
|
|
||||||
|
SDEBUGF("scale_v_area\n");
|
||||||
|
memset((void *)ctx->buf, 0, bm->width * 2 * sizeof(struct uint32_rgb));
|
||||||
|
row = (fb_data *)(bm->data) + bm->width *
|
||||||
|
(rset->rowstep == -1 ? bm->height - 1 : 0);
|
||||||
|
for (iy = 0; iy < (unsigned int)src->height; iy++)
|
||||||
|
{
|
||||||
|
oye += bm->height;
|
||||||
|
if (oye >= (unsigned int)src->height)
|
||||||
|
{
|
||||||
|
oye -= src->height;
|
||||||
|
for (x = 0; x < 3 *(unsigned int)bm->width; x++)
|
||||||
|
((uint32_t*)crow1)[x] = ((uint32_t*)crow1)[x] *
|
||||||
|
bm->height + mul *
|
||||||
|
((uint32_t*)crow2)[x];
|
||||||
|
if(!h_scaler(bm, src, crow2, ctx, false))
|
||||||
|
goto fail;
|
||||||
|
mul = bm->height - oye;
|
||||||
|
for (x = 0; x < 3 *(unsigned int)bm->width; x++)
|
||||||
|
{
|
||||||
|
((uint32_t*)crow1)[x] += mul * ((uint32_t*)crow2)[x];
|
||||||
|
((uint32_t*)crow1)[x] = (uint64_t)(round +
|
||||||
|
((uint32_t*)crow1)[x]) *
|
||||||
|
divmul >> 32;
|
||||||
|
}
|
||||||
|
pix = row;
|
||||||
|
for (x = 0; x < (unsigned int)bm->width; x++)
|
||||||
|
{
|
||||||
|
if (dither)
|
||||||
|
delta = dither_mat(x & 0xf, oy & 0xf);
|
||||||
|
r = PACKRED(crow1[x].r,delta);
|
||||||
|
g = PACKGREEN(crow1[x].g,delta);
|
||||||
|
b = PACKBLUE(crow1[x].b,delta);
|
||||||
|
*pix++ = LCD_RGBPACK_LCD(r, g, b);
|
||||||
|
}
|
||||||
|
memset((void *)crow1, 0, bm->width * sizeof(struct uint32_rgb));
|
||||||
|
mul = oye;
|
||||||
|
row += bm->width * rset->rowstep;
|
||||||
|
oy += 1;
|
||||||
|
} else {
|
||||||
|
if (!h_scaler(bm, src, crow1, ctx, true))
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
fail:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_UPSCALER
|
||||||
|
static void scale_h_linear_setup(struct bitmap *bm, struct dim *src,
|
||||||
|
struct scaler_context *ctx)
|
||||||
|
{
|
||||||
|
(void) src;
|
||||||
|
ctx->divmul = ((bm->width - 2 + 0x80000000U) / (bm->width - 1)) << 1;
|
||||||
|
ctx->round = bm->width >> 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* horizontal linear scaler */
|
||||||
|
static bool scale_h_linear(struct bitmap *bm, struct dim *src,
|
||||||
|
struct uint32_rgb *out_line,
|
||||||
|
struct scaler_context *ctx, bool accum)
|
||||||
|
{
|
||||||
|
unsigned int ix, ox, ixe;
|
||||||
|
struct uint32_rgb rgbval=rgbval, rgbinc=rgbinc;
|
||||||
|
struct img_part *part;
|
||||||
|
SDEBUGF("scale_h_linear\n");
|
||||||
|
FILL_BUF_INIT(part,ctx->store_part,ctx->args);
|
||||||
|
ix = 0;
|
||||||
|
ixe = bm->width - 1;
|
||||||
|
for (ox = 0; ox < (uint32_t)bm->width; ox++) {
|
||||||
|
if (ixe >= ((uint32_t)bm->width - 1))
|
||||||
|
{
|
||||||
|
if (ctx->last_tick != current_tick)
|
||||||
|
{
|
||||||
|
yield();
|
||||||
|
ctx->last_tick = current_tick;
|
||||||
|
}
|
||||||
|
ixe -= (bm->width - 1);
|
||||||
|
rgbinc.r = -(part->buf->red);
|
||||||
|
rgbinc.g = -(part->buf->green);
|
||||||
|
rgbinc.b = -(part->buf->blue);
|
||||||
|
rgbval.r = (part->buf->red) * (bm->width - 1);
|
||||||
|
rgbval.g = (part->buf->green) * (bm->width - 1);
|
||||||
|
rgbval.b = (part->buf->blue) * (bm->width - 1);
|
||||||
|
ix += 1;
|
||||||
|
if (ix < (uint32_t)src->width) {
|
||||||
|
part->buf++;
|
||||||
|
part->len--;
|
||||||
|
FILL_BUF(part,ctx->store_part,ctx->args);
|
||||||
|
rgbinc.r += part->buf->red;
|
||||||
|
rgbinc.g += part->buf->green;
|
||||||
|
rgbinc.b += part->buf->blue;
|
||||||
|
rgbval.r += rgbinc.r * ixe;
|
||||||
|
rgbval.g += rgbinc.g * ixe;
|
||||||
|
rgbval.b += rgbinc.b * ixe;
|
||||||
|
}
|
||||||
|
rgbinc.r *= src->width - 1;
|
||||||
|
rgbinc.g *= src->width - 1;
|
||||||
|
rgbinc.b *= src->width - 1;
|
||||||
|
}
|
||||||
|
out_line[ox].r = (accum ? out_line[ox].r : 0) +
|
||||||
|
(((uint64_t)rgbval.r + ctx->round) *
|
||||||
|
ctx->divmul >> 32);
|
||||||
|
out_line[ox].g = (accum ? out_line[ox].g : 0) +
|
||||||
|
(((uint64_t)rgbval.g + ctx->round) *
|
||||||
|
ctx->divmul >> 32);
|
||||||
|
out_line[ox].b = (accum ? out_line[ox].b : 0) +
|
||||||
|
(((uint64_t)rgbval.b + ctx->round) *
|
||||||
|
ctx->divmul >> 32);
|
||||||
|
rgbval.r += rgbinc.r;
|
||||||
|
rgbval.g += rgbinc.g;
|
||||||
|
rgbval.b += rgbinc.b;
|
||||||
|
ixe += src->width - 1;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* vertical linear scaler */
|
||||||
|
static bool scale_v_linear(struct bitmap *bm, bool dither, struct dim *src,
|
||||||
|
struct rowset *rset,
|
||||||
|
bool (*h_scaler)(struct bitmap*, struct dim*,
|
||||||
|
struct uint32_rgb*,
|
||||||
|
struct scaler_context*, bool),
|
||||||
|
struct scaler_context *ctx)
|
||||||
|
{
|
||||||
|
uint32_t mul, divmul, x, oy, iy, iye, round;
|
||||||
|
int delta = 127;
|
||||||
|
struct uint32_rgb p;
|
||||||
|
fb_data *row, *pix;
|
||||||
|
divmul = ((bm->height - 2 + 0x80000000U) / (bm->height - 1)) << 1;
|
||||||
|
round = bm->height >> 1;
|
||||||
|
mul = 0;
|
||||||
|
iy = 0;
|
||||||
|
iye = bm->height - 1;
|
||||||
|
struct uint32_rgb *crow1 = (struct uint32_rgb *)(ctx->buf),
|
||||||
|
*crow2 = crow1 + bm->width,
|
||||||
|
*t;
|
||||||
|
|
||||||
|
SDEBUGF("scale_v_linear\n");
|
||||||
|
row = (fb_data *)(bm->data) + bm->width *
|
||||||
|
(rset->rowstep == -1 ? bm->height - 1 : 0);
|
||||||
|
if(!h_scaler(bm, src, crow2, ctx, false))
|
||||||
|
goto fail;
|
||||||
|
for (oy = 0; oy < (uint32_t)bm->height; oy++)
|
||||||
|
{
|
||||||
|
if (iye >= (uint32_t)bm->height - 1)
|
||||||
|
{
|
||||||
|
t = crow2;
|
||||||
|
crow2 = crow1;
|
||||||
|
crow1 = t;
|
||||||
|
iye -= bm->height - 1;
|
||||||
|
iy += 1;
|
||||||
|
if (iy < (uint32_t)src->height)
|
||||||
|
{
|
||||||
|
if (!h_scaler(bm, src, crow2, ctx, false))
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pix = row;
|
||||||
|
for (x = 0; x < (uint32_t)bm->width; x++)
|
||||||
|
{
|
||||||
|
p.r = (uint64_t)(crow1[x].r * (bm->height - 1 - iye) +
|
||||||
|
crow2[x].r * iye + round) * divmul >> 32;
|
||||||
|
p.g = (uint64_t)(crow1[x].g * (bm->height - 1 - iye) +
|
||||||
|
crow2[x].g * iye + round) * divmul >> 32;
|
||||||
|
p.b = (uint64_t)(crow1[x].b * (bm->height - 1 - iye) +
|
||||||
|
crow2[x].b * iye + round) * divmul >> 32;
|
||||||
|
if (dither)
|
||||||
|
delta = dither_mat(x & 0xf, oy & 0xf);
|
||||||
|
p.r = PACKRED(p.r,delta);
|
||||||
|
p.g = PACKGREEN(p.g,delta);
|
||||||
|
p.b = PACKBLUE(p.b,delta);
|
||||||
|
*pix++ = LCD_RGBPACK_LCD(p.r, p.g, p.b);
|
||||||
|
}
|
||||||
|
row += bm->width * rset->rowstep;
|
||||||
|
iye += src->height - 1;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
fail:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif /* HAVE_UPSCALER */
|
||||||
|
#endif /* HAVE_LCD_COLOR */
|
||||||
|
|
||||||
|
#if LCD_DEPTH < 8 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH < 8)
|
||||||
|
/* nearest-neighbor up/down/non-scaler */
|
||||||
|
static inline bool scale_nearest(struct bitmap *bm,
|
||||||
|
struct dim *src,
|
||||||
|
struct rowset *rset,
|
||||||
|
bool remote, bool dither,
|
||||||
|
struct img_part* (*store_part)(void *args),
|
||||||
|
bool (*skip_lines)(void *args, unsigned int),
|
||||||
|
void *args)
|
||||||
|
{
|
||||||
|
const int sw = src->width;
|
||||||
|
const int sh = src->height;
|
||||||
|
const int dw = bm->width;
|
||||||
|
const int dh = bm->height;
|
||||||
|
unsigned char *bitmap = bm->data;
|
||||||
|
const int rowstep = rset->rowstep;
|
||||||
|
const int rowstart = rset->rowstart;
|
||||||
|
const int rowstop = rset->rowstop;
|
||||||
|
const int fb_width = get_fb_width(bm, false);
|
||||||
|
long last_tick = current_tick;
|
||||||
|
int ix, ox, lx, xe, iy, oy, ly, ye, yet, oyt;
|
||||||
|
int ixls, xels, iyls, yelsi, oyls, yelso, p;
|
||||||
|
struct img_part *cur_part;
|
||||||
|
#ifndef HAVE_LCD_COLOR
|
||||||
|
fb_data *dest, *dest_t;
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_REMOTE_LCD
|
||||||
|
fb_remote_data *rdest, *rdest_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
SDEBUGF("scale_nearest sw=%d sh=%d dw=%d dh=%d remote=%d\n", sw, sh, dw,
|
||||||
|
dh, remote);
|
||||||
|
ly = 0;
|
||||||
|
iy = 0;
|
||||||
|
ye = 0;
|
||||||
|
ixls = (sw > (dw - 1) && dw > 1) ? sw / (dw - 1) : 1;
|
||||||
|
xels = sw - ixls * (dw - 1) + (dw == 1 ? 1 : 0);
|
||||||
|
iyls = (sh > (dh - 1) && dh > 1) ? sh / (dh - 1) : 1;
|
||||||
|
oyls = dh > sh ? dh / sh : 1;
|
||||||
|
yelsi = iyls * (dh - 1) + (dh == 1 ? 1 : 0);
|
||||||
|
yelso = oyls * sh;
|
||||||
|
oyls *= rowstep;
|
||||||
|
int delta = 127;
|
||||||
|
#if LCD_PIXELFORMAT == HORIZONTAL_PACKING || \
|
||||||
|
(defined(HAVE_REMOTE_LCD) && LCD_REMOTE_PIXELFORMAT == HORIZONTAL_PACKING)
|
||||||
|
uint8_t buf[4];
|
||||||
|
int data, oxt;
|
||||||
|
#endif
|
||||||
|
#if LCD_PIXELFORMAT == VERTICAL_PACKING || \
|
||||||
|
LCD_PIXELFORMAT == VERTICAL_INTERLEAVED || \
|
||||||
|
(defined(HAVE_REMOTE_LCD) && \
|
||||||
|
(LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED || \
|
||||||
|
LCD_REMOTE_PIXELFORMAT == VERTICAL_PACKING))
|
||||||
|
int bright, shift;
|
||||||
|
#endif
|
||||||
|
for (oy = rowstart; oy != rowstop;) {
|
||||||
|
SDEBUGF("oy=%d iy=%d\n", oy, iy);
|
||||||
|
if (last_tick != current_tick)
|
||||||
|
{
|
||||||
|
yield();
|
||||||
|
last_tick = current_tick;
|
||||||
|
}
|
||||||
|
if (iy > ly && !skip_lines(args, iy - ly - 1))
|
||||||
|
return false;
|
||||||
|
ly = iy;
|
||||||
|
|
||||||
|
cur_part = store_part(args);
|
||||||
|
if (cur_part == NULL)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
lx = 0;
|
||||||
|
ix = 0;
|
||||||
|
xe = 0;
|
||||||
|
#if defined(HAVE_REMOTE_LCD) && !defined(HAVE_LCD_COLOR)
|
||||||
|
if(!remote)
|
||||||
|
#else
|
||||||
|
(void)remote;
|
||||||
|
#endif
|
||||||
|
#if LCD_PIXELFORMAT == HORIZONTAL_PACKING
|
||||||
|
dest = (fb_data *)bitmap + fb_width * oy;
|
||||||
|
#elif LCD_PIXELFORMAT == VERTICAL_PACKING
|
||||||
|
dest = (fb_data *)bitmap + fb_width * (oy >> 2);
|
||||||
|
#elif LCD_PIXELFORMAT == VERTICAL_INTERLEAVED
|
||||||
|
dest = (fb_data *)bitmap + fb_width * (oy >> 3);
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_REMOTE_LCD
|
||||||
|
#ifndef HAVE_LCD_COLOR
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
rdest = (fb_remote_data *)bitmap + fb_width * (oy >> 3);
|
||||||
|
#endif
|
||||||
|
for (ox = 0; ox < dw; ox++) {
|
||||||
|
while (cur_part->len <= ix - lx)
|
||||||
|
{
|
||||||
|
lx += cur_part->len;
|
||||||
|
cur_part = store_part(args);
|
||||||
|
if (cur_part == NULL)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
cur_part->len -= ix - lx;
|
||||||
|
cur_part->buf += ix - lx;
|
||||||
|
lx = ix;
|
||||||
|
#if defined(HAVE_REMOTE_LCD) && !defined(HAVE_LCD_COLOR)
|
||||||
|
if(!remote)
|
||||||
|
{
|
||||||
|
#endif
|
||||||
|
#if LCD_PIXELFORMAT == HORIZONTAL_PACKING
|
||||||
|
/* greyscale iPods */
|
||||||
|
buf[ox & 3] = brightness(*(cur_part->buf));
|
||||||
|
if ((ox & 3) == 3 || ox == dw - 1)
|
||||||
|
{
|
||||||
|
dest_t = dest++;
|
||||||
|
oyt = oy;
|
||||||
|
yet = ye;
|
||||||
|
int xo = ox & ~3;
|
||||||
|
while(yet < dh)
|
||||||
|
{
|
||||||
|
data = 0;
|
||||||
|
for (oxt = 0; oxt < (ox & 3) + 1; oxt++)
|
||||||
|
{
|
||||||
|
if (dither)
|
||||||
|
delta = dither_mat(oyt & 0xf, (xo + oxt) & 0xf);
|
||||||
|
p = (3 * buf[oxt] + (buf[oxt] >> 6) + delta) >> 8;
|
||||||
|
data |= (~p & 3) << ((3 - oxt) << 1);
|
||||||
|
}
|
||||||
|
*dest_t = data;
|
||||||
|
dest_t += rowstep * fb_width;
|
||||||
|
yet += sh;
|
||||||
|
oyt += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#elif LCD_PIXELFORMAT == VERTICAL_PACKING
|
||||||
|
/* iriver H1x0 */
|
||||||
|
bright = brightness(*(cur_part->buf));
|
||||||
|
dest_t = dest++;
|
||||||
|
oyt = oy;
|
||||||
|
yet = ye;
|
||||||
|
while(yet < dh)
|
||||||
|
{
|
||||||
|
shift = (oyt & 3) << 1;
|
||||||
|
if (dither)
|
||||||
|
delta = dither_mat(oyt & 0xf, ox & 0xf);
|
||||||
|
|
||||||
|
p = (3 * bright + (bright >> 6) + delta) >> 8;
|
||||||
|
*dest_t |= (~p & 3) << shift;
|
||||||
|
if ((rowstep > 0 && shift == 6) || shift == 0)
|
||||||
|
dest_t += rowstep * fb_width;
|
||||||
|
yet += sh;
|
||||||
|
oyt += 1;
|
||||||
|
}
|
||||||
|
#elif LCD_PIXELFORMAT == VERTICAL_INTERLEAVED
|
||||||
|
bright = brightness(*(cur_part->buf));
|
||||||
|
dest_t = dest++;
|
||||||
|
oyt = oy;
|
||||||
|
yet = ye;
|
||||||
|
while(yet < dh)
|
||||||
|
{
|
||||||
|
shift = oyt & 7;
|
||||||
|
if (dither)
|
||||||
|
delta = dither_mat(oyt & 0xf, ox & 0xf);
|
||||||
|
|
||||||
|
p = (3 * bright + (bright >> 6) + delta) >> 8;
|
||||||
|
*dest_t |= vi_pat(p) << shift;
|
||||||
|
if ((rowstep > 0 && shift == 7) || shift == 0)
|
||||||
|
dest_t += rowstep * fb_width;
|
||||||
|
yet += sh;
|
||||||
|
oyt += 1;
|
||||||
|
}
|
||||||
|
#endif /* LCD_PIXELFORMAT */
|
||||||
|
#ifdef HAVE_REMOTE_LCD
|
||||||
|
#ifndef HAVE_LCD_COLOR
|
||||||
|
} else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
#if LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED
|
||||||
|
bright = brightness(*(cur_part->buf));
|
||||||
|
rdest_t = rdest++;
|
||||||
|
oyt = oy;
|
||||||
|
yet = ye;
|
||||||
|
while(yet < dh)
|
||||||
|
{
|
||||||
|
shift = oyt & 7;
|
||||||
|
if (dither)
|
||||||
|
delta = dither_mat(oyt & 0xf, ox & 0xf);
|
||||||
|
|
||||||
|
p = (3 * bright + (bright >> 6) + delta) >> 8;
|
||||||
|
*rdest_t |= vi_pat(p) << shift;
|
||||||
|
if ((rowstep > 0 && shift == 7) || shift == 0)
|
||||||
|
rdest_t += rowstep * fb_width;
|
||||||
|
yet += sh;
|
||||||
|
oyt += 1;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
bright = brightness(*(cur_part->buf));
|
||||||
|
rdest_t = rdest++;
|
||||||
|
oyt = oy;
|
||||||
|
yet = ye;
|
||||||
|
while(yet < dh)
|
||||||
|
{
|
||||||
|
shift = oyt & 7;
|
||||||
|
if (dither)
|
||||||
|
delta = dither_mat(oyt & 0xf, ox & 0xf);
|
||||||
|
p = (bright + delta) >> 8;
|
||||||
|
*rdest_t |= (~p & 1) << shift;
|
||||||
|
if ((rowstep > 0 && shift == 7) || shift == 0)
|
||||||
|
rdest_t += rowstep * fb_width;
|
||||||
|
yet += sh;
|
||||||
|
oyt += 1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
xe += xels;
|
||||||
|
ix += ixls;
|
||||||
|
while (xe >= dw)
|
||||||
|
{
|
||||||
|
xe -= dw - 1;
|
||||||
|
ix += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
oy += oyls;
|
||||||
|
ye += yelso;
|
||||||
|
while (ye < dh)
|
||||||
|
{
|
||||||
|
ye += sh;
|
||||||
|
oy += rowstep;
|
||||||
|
}
|
||||||
|
iy += iyls;
|
||||||
|
ye -= yelsi;
|
||||||
|
while (ye >= dh)
|
||||||
|
{
|
||||||
|
ye -= dh - 1;
|
||||||
|
iy += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int resize_on_load(struct bitmap *bm, bool dither, struct dim *src,
|
||||||
|
struct rowset *rset, bool remote,
|
||||||
|
#ifdef HAVE_LCD_COLOR
|
||||||
|
unsigned char *buf, unsigned int len,
|
||||||
|
#endif
|
||||||
|
struct img_part* (*store_part)(void *args),
|
||||||
|
bool (*skip_lines)(void *args, unsigned int lines),
|
||||||
|
void *args)
|
||||||
|
{
|
||||||
|
|
||||||
|
#if defined(HAVE_LCD_COLOR) && !defined(HAVE_REMOTE_LCD)
|
||||||
|
(void)skip_lines;
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_LCD_COLOR
|
||||||
|
#ifdef HAVE_REMOTE_LCD
|
||||||
|
if (!remote)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
#ifdef HAVE_UPSCALER
|
||||||
|
const int sw = src->width;
|
||||||
|
const int sh = src->height;
|
||||||
|
const int dw = bm->width;
|
||||||
|
const int dh = bm->height;
|
||||||
|
#endif
|
||||||
|
int ret;
|
||||||
|
unsigned int needed = sizeof(struct uint32_rgb) * 2 * bm->width;
|
||||||
|
#if MAX_SC_STACK_ALLOC
|
||||||
|
uint8_t sc_buf[(needed <= len || needed > MAX_SC_STACK_ALLOC) ?
|
||||||
|
0 : needed];
|
||||||
|
#endif
|
||||||
|
if (needed > len)
|
||||||
|
{
|
||||||
|
#if MAX_SC_STACK_ALLOC
|
||||||
|
if (needed > MAX_SC_STACK_ALLOC)
|
||||||
|
{
|
||||||
|
DEBUGF("unable to allocate required buffer: %d needed, "
|
||||||
|
"%d available, %d permitted from stack\n",
|
||||||
|
needed, len, MAX_SC_STACK_ALLOC);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (sizeof(sc_buf) < needed)
|
||||||
|
{
|
||||||
|
DEBUGF("failed to allocate large enough buffer on stack: "
|
||||||
|
"%d needed, only got %d",
|
||||||
|
needed, MAX_SC_STACK_ALLOC);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
DEBUGF("unable to allocate required buffer: %d needed, "
|
||||||
|
"%d available\n", needed, len);
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool (*h_scaler)(struct bitmap*, struct dim*,
|
||||||
|
struct uint32_rgb*,
|
||||||
|
struct scaler_context*, bool);
|
||||||
|
struct scaler_context ctx;
|
||||||
|
ctx.last_tick = current_tick;
|
||||||
|
cpu_boost(true);
|
||||||
|
#ifdef HAVE_UPSCALER
|
||||||
|
if (sw > dw)
|
||||||
|
{
|
||||||
|
#endif
|
||||||
|
h_scaler = scale_h_area;
|
||||||
|
scale_h_area_setup(bm, src, &ctx);
|
||||||
|
#ifdef HAVE_UPSCALER
|
||||||
|
} else {
|
||||||
|
h_scaler = scale_h_linear;
|
||||||
|
scale_h_linear_setup(bm, src, &ctx);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
ctx.store_part = store_part;
|
||||||
|
ctx.args = args;
|
||||||
|
#if MAX_SC_STACK_ALLOC
|
||||||
|
ctx.buf = needed > len ? sc_buf : buf;
|
||||||
|
#else
|
||||||
|
ctx.buf = buf;
|
||||||
|
#endif
|
||||||
|
ctx.len = len;
|
||||||
|
#ifdef HAVE_UPSCALER
|
||||||
|
if (sh > dh)
|
||||||
|
#endif
|
||||||
|
ret = scale_v_area(bm, dither, src, rset, h_scaler, &ctx);
|
||||||
|
#ifdef HAVE_UPSCALER
|
||||||
|
else
|
||||||
|
ret = scale_v_linear(bm, dither, src, rset, h_scaler, &ctx);
|
||||||
|
#endif
|
||||||
|
cpu_boost(false);
|
||||||
|
if (!ret)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#ifdef HAVE_REMOTE_LCD
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
#endif /* HAVE_LCD_COLOR */
|
||||||
|
#if !defined(HAVE_LCD_COLOR) || defined(HAVE_REMOTE_LCD)
|
||||||
|
{
|
||||||
|
if (!scale_nearest(bm, src, rset, remote, dither, store_part,
|
||||||
|
skip_lines, args))
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif /* !HAVE_LCD_COLOR || HAVE_REMOTE_LCD*/
|
||||||
|
return get_totalsize(bm, remote);
|
||||||
|
}
|
||||||
60
apps/recorder/resize.h
Normal file
60
apps/recorder/resize.h
Normal file
|
|
@ -0,0 +1,60 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* __________ __ ___.
|
||||||
|
* 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 IMG_RESIZE_BILINER or IMG_RESIZE_NEAREST is NOT set
|
||||||
|
* - otherwise "Bilinear" or "Nearest Neighbour"
|
||||||
|
*
|
||||||
|
* If !(HAVE_LCD_COLOR) then use simple scaling algorithm "Nearest Neighbour"
|
||||||
|
*
|
||||||
|
* return -1 for error
|
||||||
|
****************************************************************/
|
||||||
|
|
||||||
|
/* nothing needs the on-stack buffer right now */
|
||||||
|
#define MAX_SC_STACK_ALLOC 0
|
||||||
|
#define HAVE_UPSCALER 1
|
||||||
|
|
||||||
|
struct img_part {
|
||||||
|
int len;
|
||||||
|
struct uint8_rgb* buf;
|
||||||
|
};
|
||||||
|
|
||||||
|
int resize_on_load(struct bitmap *bm, bool dither,
|
||||||
|
struct dim *src,
|
||||||
|
struct rowset *tmp_row, bool remote,
|
||||||
|
#ifdef HAVE_LCD_COLOR
|
||||||
|
unsigned char *buf, unsigned int len,
|
||||||
|
#endif
|
||||||
|
struct img_part* (*store_part)(void *args),
|
||||||
|
bool (*skip_lines)(void *args, unsigned int lines),
|
||||||
|
void *args);
|
||||||
|
#endif /* _RESIZE_H_ */
|
||||||
|
|
@ -434,6 +434,7 @@ Alex Bennee
|
||||||
Stéphane Quertinmont
|
Stéphane Quertinmont
|
||||||
Bartosz Fabianowski
|
Bartosz Fabianowski
|
||||||
Adam Hogan
|
Adam Hogan
|
||||||
|
Andrew Mahone
|
||||||
|
|
||||||
|
|
||||||
The libmad team
|
The libmad team
|
||||||
|
|
|
||||||
|
|
@ -368,6 +368,8 @@ enum
|
||||||
#define FORMAT_TRANSPARENT 0x40000000
|
#define FORMAT_TRANSPARENT 0x40000000
|
||||||
#define FORMAT_DITHER 0x20000000
|
#define FORMAT_DITHER 0x20000000
|
||||||
#define FORMAT_REMOTE 0x10000000
|
#define FORMAT_REMOTE 0x10000000
|
||||||
|
#define FORMAT_RESIZE 0x08000000
|
||||||
|
#define FORMAT_KEEP_ASPECT 0x04000000
|
||||||
|
|
||||||
#define TRANSPARENT_COLOR LCD_RGBPACK(255,0,255)
|
#define TRANSPARENT_COLOR LCD_RGBPACK(255,0,255)
|
||||||
#define REPLACEWITHFG_COLOR LCD_RGBPACK(0,255,255)
|
#define REPLACEWITHFG_COLOR LCD_RGBPACK(0,255,255)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue