嵌入式Linux下真彩Logo的实现
目前嵌入式产品越来越多了,一般都能带Logo显示启动的。让我们来看看Logo显示是怎么做的(我仅仅做Linux方面的,没有做过WinCE的)。
参考一些嵌入式平台的做法,基本是fb_prepare_logo(struct fb_info *info, int rotate)、fb_show_logo(struct fb_info *info, int rotate)两个函数实现的。但是该两个函数其实没有参考的价值。最简单的做法就是调用该两个函数。
1. 在 xxx__probe(struct platform_device *dev) 函数 return 0 之前调用
#if defined(CONFIG_LOGO)
// 原来代码先检查info->fbcon_par->rotate是否为FB_ROTATE_UR,这里直接设置FB_ROTATE_UR
if (fb_prepare_logo(info, FB_ROTATE_UR))
{
/* Start display and show logo on boot */
/* fb_set_cmap(info->cmap, info); */
/* Show the logo */
fb_show_logo(info, FB_ROTATE_UR);
}
#endif
注意:struct fb_info *info = framebuffer_alloc(...);
2. 在编译内核时选择 Boot logo, Logo_clut224
3. 制作ppm格式logo文件
首先使用 Photoshop 制作 png 文件(Windows下)
再将png图片转成pnm(下面步骤为linux下,我使用CentOS 4.7,使用root权限用户)
# pngtopnm uclinux_logo.png > uclinux_logo.pnm
然后将pnm图片的颜色数限制在224
# pnmquant 224 uclinux_logo.pnm > logo_linux_clut224.pnm
最后将pnm图片转换成我们需要的ppm
# pnmtoplainpnm logo_linux_clut224.pnm > logo_linux_clut224.ppm
将 logo_linux_clut224.ppm 替换 linux-2.6/drivers/video/logo 中对应的图像
我在这里制作的文件是与分辨率同样大小的文件,如果小于分辨率的话,应该显示在左上角。
说实话,上面步骤制作的Logo最多为224色图片效果。能不能显示真彩的Logo呢?实际上肯定是可以的。
我的实现方法:制作自己的fb_prepare_logo、fb_show_logo函数,将真彩的颜色值直接写到Frame Buffer的内存中。
1. 将分辨率和颜色位数定义放到头文件中 truecolor_logo.h
我的定义为
#define XRES 800 /* The pixel width of the LCD */
#define YRES 480 /* The pixel height of the LCD */
#define BPX 32 /* The bits depth of the LCD */
2. 增加一个 truecolor_logo.c 文件,将该文件加入到内核中,该文件实现
int fb_prepare_truecolor_logo(void)、void fb_show_truecolor_logo(struct fb_info *info) 两个函数
static struct TrueColor
{
int Width, Height;
int ColorBytes;
const char *BitData;
} _true_color_logo;
static unsigned char truecolor_logo_data[] = { ... }; 读取图片的颜色值赋值到这里
int fb_prepare_truecolor_logo(void)
{
_true_color_logo.ColorBytes = BPX/8;
_true_color_logo.Width = 351; /* 这里要与truecolor_logo_data的长度相对应 */
_true_color_logo.Height = 137;
_true_color_logo.BitData = truecolor_logo_data;
printk("fb_prepare_truecolor_logo ok \n");
return (_true_color_logo.ColorBytes > 1); /* 仅仅支持 16 位色或者更高位色 */
}
void fb_show_truecolor_logo(struct fb_info *info)
{
char *framebase = info->screen_base;
int m, n;
int startx, starty;
startx = (XRES- _true_color_logo.Width)/ 2;
if(startx < 0) startx = 0;
starty = (YRES- _true_color_logo.Height)/ 2;
if(starty < 0) starty = 0;
for(m=0; m<YRES; m++)
{
/* 设置图片之外(上、下部)是背景色为黑色 */
if((m < starty) || (m >= _true_color_logo.Height+starty))
{
memset(framebase+ (m* XRES* _true_color_logo.ColorBytes), 0, XRES* _true_color_logo.ColorBytes);
}
else
{
/* 设置图片之外(左边)是背景色为黑色 */
memset(framebase+ ((m* XRES)* _true_color_logo.ColorBytes), 0, _true_color_logo.ColorBytes* startx);
/* 将 Logo 显示在中间, 图片上下需要翻转 */
memcpy(framebase+ ((m* XRES+ startx)* _true_color_logo.ColorBytes),
// (_true_color_logo.BitData+ ((m-starty)* _true_color_logo.Width)* _true_color_logo.ColorBytes),
(_true_color_logo.BitData+ ((_true_color_logo.Height-(m-starty)-1)* _true_color_logo.Width)* _true_color_logo.ColorBytes),
_true_color_logo.ColorBytes* _true_color_logo.Width);
/* 设置图片之外(右边)是背景色为黑色 */
memset(framebase+ ((m* XRES+ startx+ _true_color_logo.Width)* _true_color_logo.ColorBytes), 0,
_true_color_logo.ColorBytes*(XRES- startx- _true_color_logo.Width));
}
}
}
3. 修改 xxx__probe(struct platform_device *dev) 函数
#if defined(SHOW_TRUECOLOR_LOGO)
if(fb_prepare_truecolor_logo())
fb_show_truecolor_logo(info);
#elif defined(CONFIG_LOGO)
if (fb_prepare_logo(info, FB_ROTATE_UR))
{
/* Start display and show logo on boot */
/* fb_set_cmap(info->cmap, info); */ /* Cancel the code */
/* Show the logo */
fb_show_logo(info, FB_ROTATE_UR);
}
#endif