Color BMP support
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@8472 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
9bd06032a3
commit
745adad22a
8 changed files with 261 additions and 60 deletions
|
@ -216,12 +216,12 @@ bool wps_data_preload_tags(struct wps_data *data, char *buf,
|
|||
}
|
||||
|
||||
/* load the image */
|
||||
ret = read_bmp_file(imgname, &data->img[n].w,
|
||||
&data->img[n].h, data->img_buf_ptr,
|
||||
data->img_buf_free);
|
||||
data->img[n].bm.data = data->img_buf_ptr;
|
||||
ret = read_bmp_file(imgname, &data->img[n].bm,
|
||||
data->img_buf_free,
|
||||
FORMAT_ANY);
|
||||
if (ret > 0)
|
||||
{
|
||||
data->img[n].ptr = data->img_buf_ptr;
|
||||
data->img_buf_ptr += ret;
|
||||
data->img_buf_free -= ret;
|
||||
data->img[n].loaded = true;
|
||||
|
@ -785,7 +785,7 @@ static void clear_image_pos(struct gui_wps *gwps, int n)
|
|||
struct wps_data *data = gwps->data;
|
||||
gwps->display->set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
|
||||
gwps->display->fillrect(data->img[n].x, data->img[n].y,
|
||||
data->img[n].w, data->img[n].h);
|
||||
data->img[n].bm.width, data->img[n].bm.height);
|
||||
gwps->display->set_drawmode(DRMODE_SOLID);
|
||||
}
|
||||
#endif
|
||||
|
@ -827,12 +827,13 @@ static const char* skip_conditional(struct gui_wps *gwps, const char* fmt,
|
|||
if(n >= 'A' && n <= 'Z')
|
||||
n = n - 'A' + 26;
|
||||
if(last_x != data->img[n].x || last_y != data->img[n].y
|
||||
|| last_w != data->img[n].w || last_h != data->img[n].h)
|
||||
|| last_w != data->img[n].bm.width
|
||||
|| last_h != data->img[n].bm.height)
|
||||
{
|
||||
last_x = data->img[n].x;
|
||||
last_y = data->img[n].y;
|
||||
last_w = data->img[n].w;
|
||||
last_h = data->img[n].h;
|
||||
last_w = data->img[n].bm.width;
|
||||
last_h = data->img[n].bm.height;
|
||||
clear_image_pos(gwps,n);
|
||||
}
|
||||
}
|
||||
|
@ -1243,9 +1244,19 @@ static void wps_draw_image(struct gui_wps *gwps, int n)
|
|||
else
|
||||
display->set_drawmode(DRMODE_SOLID);
|
||||
|
||||
display->mono_bitmap(data->img[n].ptr, data->img[n].x,
|
||||
data->img[n].y, data->img[n].w,
|
||||
data->img[n].h);
|
||||
#if LCD_DEPTH > 1
|
||||
if(data->img[n].bm.format == FORMAT_MONO) {
|
||||
#endif
|
||||
display->mono_bitmap(data->img[n].bm.data, data->img[n].x,
|
||||
data->img[n].y, data->img[n].bm.width,
|
||||
data->img[n].bm.height);
|
||||
#if LCD_DEPTH > 1
|
||||
} else {
|
||||
display->bitmap((fb_data *)data->img[n].bm.data, data->img[n].x,
|
||||
data->img[n].y, data->img[n].bm.width,
|
||||
data->img[n].bm.height);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
static void wps_display_images(struct gui_wps *gwps, bool always)
|
||||
{
|
||||
|
|
|
@ -255,11 +255,9 @@ extern bool keys_locked;
|
|||
|
||||
#ifdef HAVE_LCD_BITMAP
|
||||
struct gui_img{
|
||||
unsigned char* ptr; /* pointer */
|
||||
struct bitmap bm;
|
||||
int x; /* x-pos */
|
||||
int y; /* y-pos */
|
||||
int w; /* width */
|
||||
int h; /* height */
|
||||
bool loaded; /* load state */
|
||||
bool display; /* is to be displayed */
|
||||
bool always_display; /* not using the preload/display mechanism */
|
||||
|
@ -274,7 +272,7 @@ struct align_pos {
|
|||
|
||||
#ifdef HAVE_LCD_BITMAP
|
||||
#define MAX_IMAGES (26*2) /* a-z and A-Z */
|
||||
#define IMG_BUFSIZE (LCD_HEIGHT * LCD_WIDTH * MAX_IMAGES/10) / 8
|
||||
#define IMG_BUFSIZE (LCD_HEIGHT * LCD_WIDTH * MAX_IMAGES/10)
|
||||
#define WPS_MAX_LINES (LCD_HEIGHT/5+1)
|
||||
#define FORMAT_BUFFER_SIZE 3072
|
||||
#else
|
||||
|
|
|
@ -97,12 +97,12 @@
|
|||
#define PLUGIN_MAGIC 0x526F634B /* RocK */
|
||||
|
||||
/* increase this every time the api struct changes */
|
||||
#define PLUGIN_API_VERSION 3
|
||||
#define PLUGIN_API_VERSION 4
|
||||
|
||||
/* update this to latest version if a change to the api struct breaks
|
||||
backwards compatibility (and please take the opportunity to sort in any
|
||||
new function which are "waiting" at the end of the function table) */
|
||||
#define PLUGIN_MIN_API_VERSION 1
|
||||
#define PLUGIN_MIN_API_VERSION 2
|
||||
|
||||
/* plugin return codes */
|
||||
enum plugin_status {
|
||||
|
@ -420,8 +420,8 @@ struct plugin_api {
|
|||
bool (*peak_meter_get_use_dbfs)(void);
|
||||
#endif
|
||||
#ifdef HAVE_LCD_BITMAP
|
||||
int (*read_bmp_file)(char* filename, int *get_width, int *get_height,
|
||||
char *bitmap, int maxsize);
|
||||
int (*read_bmp_file)(char* filename, struct bitmap *bm, int maxsize,
|
||||
int format);
|
||||
void (*screen_dump_set_hook)(void (*hook)(int fh));
|
||||
#endif
|
||||
int (*show_logo)(void);
|
||||
|
|
|
@ -26,11 +26,13 @@
|
|||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <string.h>
|
||||
#include "debug.h"
|
||||
#include "lcd.h"
|
||||
#include "file.h"
|
||||
#include "autoconf.h"
|
||||
#include "config.h"
|
||||
#include "bmp.h"
|
||||
#include "lcd.h"
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define STRUCT_PACKED __attribute__((packed))
|
||||
|
@ -59,6 +61,12 @@ struct Fileheader {
|
|||
unsigned long ClrImportant; /* important color count */
|
||||
} STRUCT_PACKED;
|
||||
|
||||
struct rgb_quad { /* Little endian */
|
||||
unsigned char blue;
|
||||
unsigned char green;
|
||||
unsigned char red;
|
||||
unsigned char reserved;
|
||||
} STRUCT_PACKED;
|
||||
|
||||
#ifdef ROCKBOX_LITTLE_ENDIAN
|
||||
#define readshort(x) *(x)
|
||||
|
@ -79,6 +87,19 @@ static long readlong(long *value) {
|
|||
|
||||
#endif
|
||||
|
||||
unsigned char brightness(struct rgb_quad color)
|
||||
{
|
||||
return (3 * (unsigned int)color.red + 6 * (unsigned int)color.green
|
||||
+ (unsigned int)color.blue) / 10;
|
||||
}
|
||||
|
||||
/* Function to get a pixel from a line. (Tomas: maybe a better way?) */
|
||||
inline int getpix(int px, unsigned char *bmpbuf) {
|
||||
int a = (px / 8);
|
||||
int b = (7 - (px % 8));
|
||||
|
||||
return (bmpbuf[a] & (1 << b)) != 0;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
|
@ -88,16 +109,26 @@ static long readlong(long *value) {
|
|||
*
|
||||
*****************************************************************************/
|
||||
int read_bmp_file(char* filename,
|
||||
int *get_width, /* in pixels */
|
||||
int *get_height, /* in pixels */
|
||||
char *bitmap,
|
||||
int maxsize) /* Maximum amount of bytes to write to bitmap */
|
||||
struct bitmap *bm,
|
||||
int maxsize,
|
||||
int format)
|
||||
{
|
||||
struct Fileheader fh;
|
||||
int bitmap_width, bitmap_height, PaddedWidth, PaddedHeight;
|
||||
int width, height, PaddedWidth, PaddedHeight;
|
||||
int fd, row, col, ret;
|
||||
char bmpbuf[(LCD_WIDTH / 8 + 3) & ~3]; /* Buffer for one line */
|
||||
struct rgb_quad palette[256];
|
||||
int invert_pixel = 0;
|
||||
int numcolors;
|
||||
int depth;
|
||||
int totalsize;
|
||||
char *bitmap = bm->data;
|
||||
|
||||
unsigned char bmpbuf[LCD_WIDTH*sizeof(struct rgb_quad)]; /* Buffer for one line */
|
||||
|
||||
#if LCD_DEPTH == 1
|
||||
(void)format;
|
||||
#endif
|
||||
|
||||
fd = open(filename, O_RDONLY);
|
||||
|
||||
/* Exit if file opening failed */
|
||||
|
@ -119,14 +150,6 @@ int read_bmp_file(char* filename,
|
|||
return -3;
|
||||
}
|
||||
|
||||
/* Exit if not monochrome */
|
||||
if (readshort(&fh.BitCount) != 1) {
|
||||
DEBUGF("error - Bitmap must be in 1 bit per pixel format. "
|
||||
"This one is: %d\n", readshort(&fh.BitCount));
|
||||
close(fd);
|
||||
return -4;
|
||||
}
|
||||
|
||||
/* Exit if too wide */
|
||||
if (readlong(&fh.Width) > LCD_WIDTH) {
|
||||
DEBUGF("error - Bitmap is too wide (%d pixels, max is %d)\n",
|
||||
|
@ -144,28 +167,80 @@ int read_bmp_file(char* filename,
|
|||
}
|
||||
|
||||
/* Calculate image size */
|
||||
bitmap_height = readlong(&fh.Height);
|
||||
bitmap_width = readlong(&fh.Width);
|
||||
/* Paddedwidth is for BMP files. */
|
||||
PaddedWidth = ((bitmap_width + 31) & (~0x1f)) / 8;
|
||||
height = readlong(&fh.Height);
|
||||
width = readlong(&fh.Width);
|
||||
depth = readshort(&fh.BitCount);
|
||||
|
||||
/* 4-byte boundary aligned */
|
||||
PaddedWidth = (width * depth / 8 + 3) & ~3;
|
||||
|
||||
#if LCD_DEPTH > 1
|
||||
if(format == FORMAT_ANY) {
|
||||
if(depth == 1)
|
||||
format = FORMAT_MONO;
|
||||
else
|
||||
format = FORMAT_NATIVE;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* PaddedHeight is for rockbox format. */
|
||||
PaddedHeight = (bitmap_height + 7) / 8;
|
||||
if(format == FORMAT_MONO) {
|
||||
PaddedHeight = (height + 7) / 8;
|
||||
totalsize = PaddedHeight * width;
|
||||
} else {
|
||||
#if LCD_DEPTH == 2
|
||||
PaddedHeight = height/4;
|
||||
#else
|
||||
PaddedHeight = height;
|
||||
#endif
|
||||
totalsize = PaddedHeight * width * sizeof(fb_data);
|
||||
}
|
||||
|
||||
/* Check if this fits the buffer */
|
||||
if ((PaddedHeight * bitmap_width) > maxsize) {
|
||||
|
||||
if (totalsize > maxsize) {
|
||||
DEBUGF("error - Bitmap is too large to fit the supplied buffer: "
|
||||
"%d bytes.\n", (PaddedHeight * bitmap_width));
|
||||
"%d bytes.\n", (PaddedHeight * width));
|
||||
close(fd);
|
||||
return -7;
|
||||
}
|
||||
|
||||
if (depth <= 8)
|
||||
{
|
||||
numcolors = readlong(&fh.ClrUsed);
|
||||
if (numcolors == 0)
|
||||
numcolors = 1 << depth;
|
||||
|
||||
if(read(fd, palette, numcolors * sizeof(struct rgb_quad))
|
||||
!= numcolors * (int)sizeof(struct rgb_quad))
|
||||
{
|
||||
DEBUGF("error - Can't read bitmap's color palette\n");
|
||||
close(fd);
|
||||
return -8;
|
||||
}
|
||||
}
|
||||
|
||||
/* Use the darker palette color as foreground on mono bitmaps */
|
||||
if(readshort(&fh.BitCount) == 1) {
|
||||
if(brightness(palette[0]) > brightness(palette[1]))
|
||||
invert_pixel = 1;
|
||||
}
|
||||
|
||||
/* Search to the beginning of the image data */
|
||||
lseek(fd, (off_t)readlong(&fh.OffBits), SEEK_SET);
|
||||
|
||||
#if LCD_DEPTH == 2
|
||||
if(format == FORMAT_NATIVE)
|
||||
memset(bitmap, 0, width * height / 4);
|
||||
#endif
|
||||
|
||||
#if LCD_DEPTH > 1
|
||||
fb_data *dest = (fb_data *)bitmap;
|
||||
#endif
|
||||
|
||||
/* loop to read rows and put them to buffer */
|
||||
for (row = 0; row < bitmap_height; row++) {
|
||||
int bitsel = 1 << ((bitmap_height - row - 1) % 8);
|
||||
int bytesel = bitmap_width * ((bitmap_height - row - 1) / 8);
|
||||
for (row = 0; row < height; row++) {
|
||||
unsigned char *p;
|
||||
|
||||
/* read one row */
|
||||
ret = read(fd, bmpbuf, PaddedWidth);
|
||||
|
@ -173,24 +248,115 @@ int read_bmp_file(char* filename,
|
|||
DEBUGF("error reading image, read returned: %d expected was: "
|
||||
"%d\n", ret, PaddedWidth);
|
||||
close(fd);
|
||||
return -8;
|
||||
return -9;
|
||||
}
|
||||
|
||||
/* loop though the pixels in this line. */
|
||||
for (col = 0; col < bitmap_width; col++) {
|
||||
ret = (bmpbuf[col/8] & (1 << (7 - (col % 8)))) != 0;
|
||||
if (ret == 1)
|
||||
bitmap[bytesel + col] &= ~bitsel;
|
||||
else
|
||||
bitmap[bytesel + col] |= bitsel;
|
||||
switch(depth) {
|
||||
case 1:
|
||||
#if LCD_DEPTH > 1
|
||||
if(format == FORMAT_MONO) {
|
||||
#endif
|
||||
/* Mono -> Mono */
|
||||
for (col = 0; col < width; col++) {
|
||||
ret = getpix(col, bmpbuf) ^ invert_pixel;
|
||||
if (ret == 1) {
|
||||
bitmap[width * ((height - row - 1) / 8) + col]
|
||||
&= ~ 1 << ((height - row - 1) % 8);
|
||||
} else {
|
||||
bitmap[width * ((height - row - 1) / 8) + col]
|
||||
|= 1 << ((height - row - 1) % 8);
|
||||
}
|
||||
}
|
||||
#if LCD_DEPTH == 2
|
||||
} else {
|
||||
/* Mono -> 2gray (iriver H1xx) */
|
||||
for (col = 0; col < width; col++) {
|
||||
ret = brightness(palette[getpix(col, bmpbuf)]);
|
||||
|
||||
if (ret > 96) {
|
||||
bitmap[width * ((height - row - 1) / 8) + col]
|
||||
&= ~ 1 << ((height - row - 1) % 8);
|
||||
} else {
|
||||
bitmap[width * ((height - row - 1) / 8) + col]
|
||||
|= 1 << ((height - row - 1) % 8);
|
||||
}
|
||||
}
|
||||
}
|
||||
#elif LCD_DEPTH == 16
|
||||
} else {
|
||||
/* Mono -> RGB16 */
|
||||
for (col = 0; col < width; col++) {
|
||||
ret = getpix(col, bmpbuf);
|
||||
unsigned short rgb = (((palette[ret].red >> 3) << 11) |
|
||||
((palette[ret].green >> 2) << 5) |
|
||||
((palette[ret].blue >> 3)));
|
||||
dest[width * (height - row - 1) + col] = rgb;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
|
||||
case 24:
|
||||
p = bmpbuf;
|
||||
#if LCD_DEPTH > 1
|
||||
if(format == FORMAT_MONO) {
|
||||
#endif
|
||||
/* RGB24 -> mono */
|
||||
for (col = 0; col < width; col++) {
|
||||
struct rgb_quad rgb;
|
||||
rgb.red = p[2];
|
||||
rgb.green = p[1];
|
||||
rgb.blue = p[0];
|
||||
ret = brightness(rgb);
|
||||
if (ret > 96) {
|
||||
bitmap[width * ((height - row - 1) / 8) + col]
|
||||
&= ~ 1 << ((height - row - 1) % 8);
|
||||
} else {
|
||||
bitmap[width * ((height - row - 1) / 8) + col]
|
||||
|= 1 << ((height - row - 1) % 8);
|
||||
}
|
||||
p += 3;
|
||||
}
|
||||
#if LCD_DEPTH == 2
|
||||
} else {
|
||||
/* RGB24 -> 2gray (iriver H1xx) */
|
||||
for (col = 0; col < width; col++) {
|
||||
struct rgb_quad rgb;
|
||||
rgb.red = p[2];
|
||||
rgb.green = p[1];
|
||||
rgb.blue = p[0];
|
||||
ret = brightness(rgb);
|
||||
|
||||
dest[((height - row - 1)/4) * width + col] |=
|
||||
(~ret & 0xC0) >> (2 * (~(height - row - 1) & 3));
|
||||
p += 3;
|
||||
}
|
||||
}
|
||||
#elif LCD_DEPTH == 16
|
||||
} else {
|
||||
/* RGB24 -> RGB16 */
|
||||
for (col = 0; col < width; col++) {
|
||||
unsigned short rgb = (((p[2] >> 3) << 11) |
|
||||
((p[1] >> 2) << 5) |
|
||||
((p[0] >> 3)));
|
||||
dest[width * (height - row - 1) + col] = rgb;
|
||||
p += 3;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
close(fd);
|
||||
|
||||
/* returning image size: */
|
||||
*get_width = bitmap_width;
|
||||
*get_height = bitmap_height;
|
||||
bm->width = width;
|
||||
bm->height = height;
|
||||
#if LCD_DEPTH > 1
|
||||
bm->format = format;
|
||||
#endif
|
||||
|
||||
return (PaddedHeight * bitmap_width); /* return the used buffer size. */
|
||||
DEBUGF("totalsize: %d\n", totalsize);
|
||||
return totalsize; /* return the used buffer size. */
|
||||
}
|
||||
|
|
|
@ -16,6 +16,12 @@
|
|||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
#ifndef _BMP_H_
|
||||
#define _BMP_H_
|
||||
|
||||
#include "config.h"
|
||||
#include "lcd.h"
|
||||
|
||||
/*********************************************************************
|
||||
* read_bmp_file()
|
||||
*
|
||||
|
@ -24,7 +30,7 @@
|
|||
*
|
||||
**********************************************/
|
||||
int read_bmp_file(char* filename,
|
||||
int *get_width, /* in pixels */
|
||||
int *get_height, /* in pixels */
|
||||
char *bitmap,
|
||||
int maxsize);/* Maximum amount of bytes to write to bitmap */
|
||||
struct bitmap *bm,
|
||||
int maxsize,
|
||||
int format);
|
||||
#endif
|
||||
|
|
|
@ -120,6 +120,7 @@ void screen_init(struct screen * screen, enum screen_type screen_type)
|
|||
screen->mono_bitmap=&lcd_mono_bitmap;
|
||||
screen->set_drawmode=&lcd_set_drawmode;
|
||||
#if LCD_DEPTH > 1
|
||||
screen->bitmap=&lcd_bitmap;
|
||||
screen->set_background=&lcd_set_background;
|
||||
#endif
|
||||
screen->update_rect=&lcd_update_rect;
|
||||
|
|
|
@ -82,6 +82,8 @@ struct screen
|
|||
int style, int offset);
|
||||
void (*mono_bitmap)(const unsigned char *src,
|
||||
int x, int y, int width, int height);
|
||||
void (*bitmap)(const fb_data *src,
|
||||
int x, int y, int width, int height);
|
||||
void (*set_drawmode)(int mode);
|
||||
#if (LCD_DEPTH > 1) || (LCD_REMOTE_DEPTH > 1)
|
||||
void (*set_background)(unsigned background);
|
||||
|
|
|
@ -193,6 +193,23 @@ extern fb_data lcd_framebuffer[LCD_HEIGHT][LCD_WIDTH];
|
|||
extern void lcd_enable(bool on);
|
||||
#endif
|
||||
|
||||
/* Bitmap formats */
|
||||
enum
|
||||
{
|
||||
FORMAT_MONO,
|
||||
FORMAT_NATIVE,
|
||||
FORMAT_ANY /* For passing to read_bmp_file() */
|
||||
};
|
||||
|
||||
struct bitmap {
|
||||
int width;
|
||||
int height;
|
||||
#if LCD_DEPTH > 1
|
||||
int format;
|
||||
#endif
|
||||
unsigned char *data;
|
||||
};
|
||||
|
||||
extern void lcd_set_invert_display(bool yesno);
|
||||
extern void lcd_set_flip(bool yesno);
|
||||
extern void lcd_roll(int pixels);
|
||||
|
|
Loading…
Reference in a new issue