Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1809252
  • 博文数量: 134
  • 博客积分: 2488
  • 博客等级: 大尉
  • 技术积分: 7554
  • 用 户 组: 普通用户
  • 注册时间: 2011-02-26 21:19
个人简介

1.每日自省; 2.享受人生; 3.尽力而为; 4.坚持不懈; 5.切莫急躁; 6.慎言敏行; 7.动心忍性; 8.上善若水。

文章分类

全部博文(134)

文章存档

2014年(38)

2013年(42)

2012年(15)

2011年(39)

分类: LINUX

2014-06-24 14:05:22

        本文使用的uboot版本是2010.12版本。首先讲述下显示的基本原理。

一、位图、调色板和bmp文件格式
1.1、位图和调色板

        
显示器屏幕是由许许多多
点构成的,我们称之为象素。显示时采用扫描的方法:电子枪每次从左到右扫描一行,为每个象素着色,然后从上到下这样扫描若干行,就扫过了一屏。为了防止闪烁,每秒要重复上述过程几十次。例如我们常说的屏幕分辨率为800×480,刷新频率为70Hz意思是说每行要扫描800个象素,一共有480行,每秒重复扫描屏幕70次。
我们称这种显示器为位映象设备。所谓位映象,就是指一个二维的象素矩阵,而位图就是采用位映象方法显示和存储的图象。

       自然界中的所有颜色都可以由红、绿、蓝(RGB)组合而成。有的颜色含有红色成分多一些,如深红;有的含有红色成分少一些,如浅红。针对含有红色成分的多少,可以分成0255256个等级,0级表示不含红色成分255级表示含有100%的红色成分。同样绿色和蓝色也被分成256级。这种分级概念称为量化这样根据红、绿、蓝各种不同的组合就能表示出256×256×256,约1600万种颜色。

1.1     常见颜色的RGB组合值

颜色

R

G

B

255

0

0

0

255

0

绿

0

0

255

255

255

0

255

0

255

0

255

255

255

255

255

0

0

0

128

128

128

        当一幅图中每个象素赋予不同的RGB值时,能呈现出五彩缤纷的颜色,这样就形成了彩色图。

        有一个长宽各为200个象素,颜色数为16色的彩色图,每一个象素都用RGB三个分量表示。因为每个分量有256个级别,要用8(bit),即一个字节(byte)来表示,所以每个象素需要用3个字节。整个图象要用200×200×3,约120k字节,如果用下面的方法就能省的多。因为是一个16色图,也就是说这幅图中最多只有16种颜色,我们可以用一个表:表中的每一行记录一种颜色的RGB值。这样当我们表示一个象素的颜色时,只需要指出该颜色是在第几行,即该颜色在表中的索引值。举个例子,如果表的第0行为25500(红色),那么当某个象素为红色时,只需要标明0即可。

        16种状态可以用4(bit)表示,所以一个象素要用半个字节。整个图象要用200×200×0.5,约20k字节,再加上表占用的字节为3×16=48字节整个占用的字节数约为前面的1/6。这张RGB的表,就是我们常说的调色板(Palette),另一种叫法是颜色查找表LUT(Look Up Table)
        本文中使用的是RGB565
彩色模式, 一个像素占两个字节,其中:低字节的前5位用来表示B(BLUE),低的后三位+高字节的前三位用来表示G(Green)高字节的后5位用来表示R(RED)。

        有一种图,它的颜色数高达256×256×256种,也就是说包含我们上述提到的RGB颜色表示方法中所有的颜色,这种图叫做真彩色图(true color)。真彩色图并不是说一幅图包含了所有的颜色,而是说它具有显示所有颜色的能力,即最多可以包含所有的颜色。表示真彩色图时,每个象素直接用RGB三个分量字节表示,而不采用调色板技术。原因很明显:如果用调色板,表示一个象素也要用24位,这是因为每种颜色的索引要用24(因为总共有224种颜色,即调色板有224),和直接用RGB三个分量表示用的字节数一样,还要加上一个256×256×256×3个字节的大调色板。所以真彩色图直接用RGB三个分量表示,它又叫做24位色图。
1.2、bmp文件格式

        bmp文件大体上分成四个部分,如下图所示。

位图文件头BITMAPFILEHEADER

位图信息头BITMAPINFOHEADER

调色板Palette

实际的位图数据ImageDate

Windows位图文件结构示意图

        第一部分为位图文件头BITMAPFILEHEADER,是一个结构,其定义如下:

        typedef struct tagBITMAPFILEHEADER {

            WORD           bfType;

            DWORD bfSize;

            WORD           bfReserved1;

            WORD           bfReserved2;

            DWORD bfOffBits;

        } BITMAPFILEHEADER;
        这个结构的长度是固定的,为
14个字节(WORD为无符号16位整数,DWORD为无符号32位整数),各个域的说明如下:
      bfType
指定文件类型,必须是0x424D,即字符串“BM”,也就是说所有.bmp文件的头两个字节都是“BM。在4.3中打开文件后即判别是否为此字符,如果不是,错误退出。

      bfSize:指定文件大小,包括这14个字节。

      bfReserved1bfReserved2:为保留字,不用考虑

      bfOffBits:为从文件头到实际的位图数据的偏移字节数,即上图中前三个部分的长度之和。

        第二部分为位图信息头BITMAPINFOHEADER,也是一个结构,其定义如下:

        typedef struct tagBITMAPINFOHEADER{

            DWORD  biSize;

            LONG            biWidth;

            LONG            biHeight;

            WORD           biPlanes;

            WORD           biBitCount

            DWORD  biCompression;

            DWORD  biSizeImage;

            LONG            biXPelsPerMeter;

            LONG            biYPelsPerMeter;

            DWORD  biClrUsed;

            DWORD  biClrImportant;

        } BITMAPINFOHEADER;

        这个结构的长度是固定的,为40个字节(LONG32位整数),各个域的说明如下:

      biSize:指定这个结构体的长度,为40

      biWidth:指定图象的宽度,单位是象素。

      biHeight:指定图象的高度,单位是象素。

      biPlanes:必须是1,不用考虑。

      biBitCount:指定表示颜色时要用到的位数,常用的值为1(黑白二色图), 4(16色图), 8(256), 24(真彩色图)

      biCompression:指定位图是否压缩,有效的值为BI_RGBBI_RLE8BI_RLE4BI_BITFIELDS

      biSizeImage:指定实际的位图数据占用的字节数,其实也可以从以下的公式中计算出来:

        biSizeImage=biWidth’ × biHeight

        要注意的是:上述公式中的biWidth’必须是4的整倍数(所以不是biWidth,而是biWidth’,表示大于或等于biWidth的,最接近4的整倍数。举个例子,如果biWidth=240,则biWidth’=240;如果biWidth=241biWidth’=244)

        如果biCompressionBI_RGB,则该项可能为零

      biXPelsPerMeter:指定目标设备的水平分辨率,单位是每米的象素个数,关于分辨率的概念,我们将在第4章详细介绍。

      biYPelsPerMeter:指定目标设备的垂直分辨率,单位同上。

      biClrUsed:指定本图象实际用到的颜色数,如果该值为零,则用到的颜色数为2biBitCount

      biClrImportant:指定本图象中重要的颜色数,如果该值为零,则认为所有的颜色都是重要的。

        第三部分为调色板Palette,当然这里是对那些需要调色板的位图文件而言的。有些位图,如真彩色图是不需要调色板的,BITMAPINFOHEADER后直接是位图数据。

        调色板实际上是一个数组,共有biClrUsed个元素(如果该值为零,则有2biBitCount个元素)。数组中每个元素的类型是一个RGBQUAD结构,占4个字节,其定义如下:

        typedef struct tagRGBQUAD {

            BYTE    rgbBlue; //该颜色的蓝色分量

            BYTE    rgbGreen; //该颜色的绿色分量

            BYTE    rgbRed; //该颜色的红色分量

            BYTE    rgbReserved; //保留值

        } RGBQUAD;

        第四部分就是实际的图象数据了。对于用到调色板的位图,图象数据就是该象素颜在调色板中的索引值。对于真彩色图,图象数据就是实际的RGB值。下面针对2色、16色、256色位图和真彩色位图分别介绍。

        对于2色位图,用1位就可以表示该象素的颜色(一般0表示黑,1表示白),所以一个字节可以表示8个象素。

        对于16色位图,用4位可以表示一个象素的颜色,所以一个字节可以表示2个象素。

        对于256色位图,一个字节刚好可以表示1个象素。

        对于真彩色图,三个字节才能表示1个象素。

        要注意两点:

        (1) 每一行的字节数必须是4的整倍数,如果不是,则需要补齐。这在前面介绍biSizeImage时已经提到了。

        (2) 一般来说,.bMP文件的数据从下到上,从左到右的。也就是说,从文件中最先读到的是图象最下面一行的左边第一个象素,然后是左边第二个象素……接下来是倒数第二行左边第一个象素,左边第二个象素……依次类推 ,最后得到的是最上面一行的最右一个象素。

二、logo显示调用流程

        在uboot移植(二)中讲述了uboot执行的第二个步骤是进入board_init_r()函数(/arch/mips/lib/board.c文件中),现在来讲述下logo显示的调用流程:

        board_init_r()->stdio_init()(common/stdio.c文件中)->drv_video_init()(drivers/video/cfb_console.c文件中)->video_init()(drivers/video/cfb_console.c文件中)。

        在video_init()函数中,首先调用了video_hw_init()函数,该函数初始化GSC3280芯片的LCD控制器和GraphicDevice结构体。video_init()函数调用video_logo()函数显示logo图片。

        接下来主要讲述video_hw_init()和video_logo()函数。

三、GSC3280 LCD初始化

       芯片初始化包括初始化芯片内部控制寄存器和设置像素信息等。

       在uboot源码的根目录下,drivers/video/目录下建立gsc3280_lcdfb.c文件,video_hw_init()程序如下:

点击(此处)折叠或打开

  1. GraphicDevice fb;

  2. static void gsc3280_lcd_init(void)
  3. {
  4.     printf("init lcd sysctl\n");
  5.     lcdc_disable();
  6.     lcd_sysctl();
  7.     gsc3280_ctr_init();
  8.     lcdc_dma_init((void *)DEFAULT_VIDEO_HW_ADDR);
  9.     lcdc_monitor_para(0);
  10.     lcd_enable();
  11. }
  12. void *video_hw_init(void)
  13. {
  14.     memset(&fb, 0, sizeof(GraphicDevice));
  15.     fb.winSizeX = MAX_VIDEO_WIDTH_LEN;
  16.     fb.winSizeY = MAX_VIDEO_HIGH_LEN;
  17.     //over 16M from the head of kseg1, unmapped and uncacheable ddr2 address
  18.     fb.frameAdrs = DEFAULT_VIDEO_BASE_ADDR;
  19.     fb.plnSizeX = fb.winSizeX;
  20.     fb.plnSizeY = fb.winSizeY;
  21.     fb.gdfBytesPP = COLOR_PIXEL_SIZE / 8;
  22.     fb.gdfIndex = GDF_16BIT_565RGB;
  23.     fb.isaBase = 0;
  24.     fb.pciBase = 0;
  25.     fb.memSize = fb.winSizeX * fb.winSizeY * fb.gdfBytesPP;
  26.     /* Cursor Start Address */
  27.     fb.dprBase = 0;
  28.     fb.vprBase = 0;
  29.     fb.cprBase = 0;
  30.     gsc3280_lcd_init();
  31.     return &fb;
  32. }

        说明:
        1) 第16和17行分别定义了X和Y方向的分辨率,为800*480。
        2) 接下来初始化了GraphicDevice结构体成员。
        3) gsc3280_lcd_init()函数完成GSC3280的LCD模块、DMA等初始化。
四、uboot显示logo
        video_logo()函数完成显示logo,该函数位于/drivers/video/cfb_console.c文件中

4.1、宏定义

          在显示图片时,需要定义一些宏,这些宏在显示流程中会被使用,它们定义在“include/config/blx.h”文件中,包括:

点击(此处)折叠或打开

  1. #define CONFIG_VIDEO
  2. #define CONFIG_CMD_BMP
  3. #define CONFIG_VIDEO_LOGO
  4. #define CONFIG_CFB_CONSOLE
  5. #define CONFIG_VIDEO_BMP_LOGO
  6. #define VIDEO_FB_16BPP_WORD_SWAP

  7. #define CONFIG_GSC3280_LCD
  8. #define CONFIG_GSC3280_CMD_LCD

4.2、制作logo图片

        logo图片必须是bmp格式的,这个bmp文件位深度必须为8位,大小也有限制,自己做个格式为".jpg"的logo图片即可,使用linux下的图片工具转成8位的bmp文件,命令如下:

点击(此处)折叠或打开

  1. jpegtopnm logo.jpg | ppmquant 31 | ppmtobmp -bpp 8 > denx.bmp
        将生成的”denx.bmp“文件覆盖”tools/logo/“下的原文件即可。
4.3、制作图片显示数据
        ”tools/bmp_logo.c“文件实现将图片转换为数组数据,该文件中有main()函数,这说明此文件是单独执行的,具体的执行程序地点就在:”tools/Makefile“文件中有如下语句:

点击(此处)折叠或打开

  1. LOGO_H = $(OBJTREE)/include/bmp_logo.h

  2. ifeq ($(LOGO_BMP),)
  3. LOGO_BMP= logos/denx.bmp
  4. endif

  5. $(LOGO_H):    $(obj)bmp_logo $(LOGO_BMP)
  6.     $(obj)./bmp_logo $(LOGO_BMP) >$@
        说明:
        1) 第7行实现了logo显示数组的生成,调用"bmp_logo"可执行文件,有一个参数即是我们在4.2中拷贝的图片,最后生成的数据保存在”include/bmp_logo.h“文件中。
        ”tools/bmp_logo.c“文件中的main函数如下:

点击(此处)折叠或打开

  1. int main (int argc, char *argv[])
  2. {
  3.     int    i, x;
  4.     FILE    *fp;
  5.     bitmap_t bmp;
  6.     bitmap_t *b = &bmp;
  7.     uint16_t data_offset, n_colors;

  8.     if (argc < 2) {
  9.         fprintf (stderr, "Usage: %s file\n", argv[0]);
  10.         exit (EXIT_FAILURE);
  11.     }

  12.     if ((fp = fopen (argv[1], "rb")) == NULL) {
  13.         perror (argv[1]);
  14.         exit (EXIT_FAILURE);
  15.     }

  16.     if (fgetc (fp) != 'B' || fgetc (fp) != 'M')
  17.         error ("Input file is not a bitmap", fp);

  18.     /*
  19.      * read width and height of the image, and the number of colors used;
  20.      * ignore the rest
  21.      */
  22.     skip_bytes (fp, 8);
  23.     if (fread (&data_offset, sizeof (uint16_t), 1, fp) != 1)
  24.         error ("Couldn't read bitmap data offset", fp);
  25.     skip_bytes (fp, 6);
  26.     if (fread (&b->width, sizeof (uint16_t), 1, fp) != 1)
  27.         error ("Couldn't read bitmap width", fp);
  28.     skip_bytes (fp, 2);
  29.     if (fread (&b->height, sizeof (uint16_t), 1, fp) != 1)
  30.         error ("Couldn't read bitmap height", fp);
  31.     skip_bytes (fp, 22);
  32.     if (fread (&n_colors, sizeof (uint16_t), 1, fp) != 1)
  33.         error ("Couldn't read bitmap colors", fp);
  34.     skip_bytes (fp, 6);

  35.     /*
  36.      * Repair endianess.
  37.      */
  38.     data_offset = le_short(data_offset);
  39.     b->width = le_short(b->width);
  40.     b->height = le_short(b->height);
  41.     n_colors = le_short(n_colors);

  42.     /* assume we are working with an 8-bit file */
  43.     if ((n_colors == 0) || (n_colors > 256 - DEFAULT_CMAP_SIZE)) {
  44.         /* reserve DEFAULT_CMAP_SIZE color map entries for default map */
  45.         n_colors = 256 - DEFAULT_CMAP_SIZE;
  46.     }

  47.     printf ("/*\n"
  48.         " * Automatically generated by \"tools/bmp_logo\"\n"
  49.         " *\n"
  50.         " * DO NOT EDIT\n"
  51.         " *\n"
  52.         " */\n\n\n"
  53.         "#ifndef __BMP_LOGO_H__\n"
  54.         "#define __BMP_LOGO_H__\n\n"
  55.         "#define BMP_LOGO_WIDTH\t\t%d\n"
  56.         "#define BMP_LOGO_HEIGHT\t\t%d\n"
  57.         "#define BMP_LOGO_COLORS\t\t%d\n"
  58.         "#define BMP_LOGO_OFFSET\t\t%d\n"
  59.         "\n",
  60.         b->width, b->height, n_colors,
  61.         DEFAULT_CMAP_SIZE);

  62.     /* allocate memory */
  63.     if ((b->data = (uint8_t *)malloc(b->width * b->height)) == NULL)
  64.         error ("Error allocating memory for file", fp);

  65.     /* read and print the palette information */
  66.     printf ("unsigned short bmp_logo_palette[] = {\n");

  67.     for (i=0; i<n_colors; ++i) {
  68.         b->palette[(int)(i*3+2)] = fgetc(fp);
  69.         b->palette[(int)(i*3+1)] = fgetc(fp);
  70.         b->palette[(int)(i*3+0)] = fgetc(fp);
  71.         x=fgetc(fp);

  72.         printf ("%s0x0%X%X%X,%s",
  73.             ((i%8) == 0) ? "\t" : " ",
  74.             (b->palette[(int)(i*3+0)] >> 4) & 0x0F,
  75.             (b->palette[(int)(i*3+1)] >> 4) & 0x0F,
  76.             (b->palette[(int)(i*3+2)] >> 4) & 0x0F,
  77.             ((i%8) == 7) ? "\n" : ""
  78.         );
  79.     }

  80.     /* seek to offset indicated by file header */
  81.     fseek(fp, (long)data_offset, SEEK_SET);

  82.     /* read the bitmap; leave room for default color map */
  83.     printf ("\n");
  84.     printf ("};\n");
  85.     printf ("\n");
  86.     printf ("unsigned char bmp_logo_bitmap[] = {\n");
  87.     for (i=(b->height-1)*b->width; i>=0; i-=b->width) {
  88.         for (x = 0; x < b->width; x++) {
  89.             b->data[(uint32_t) i + x] = (uint8_t) fgetc (fp) \
  90.                         + DEFAULT_CMAP_SIZE;
  91.         }
  92.     }
  93.     fclose (fp);

  94.     for (i=0; i<(b->height*b->width); ++i) {
  95.         if ((i%8) == 0)
  96.             putchar ('\t');
  97.         printf ("0x%02X,%c",
  98.             b->data[i],
  99.             ((i%8) == 7) ? '\n' : ' '
  100.         );
  101.     }
  102.     printf ("\n"
  103.         "};\n\n"
  104.         "#endif /* __BMP_LOGO_H__ */\n"
  105.     );

  106.     return (0);
  107. }
        说明:
        1) 第9-12行检查参数是否正确,如果错误直接返回。
        2) 第14行以二进制读的方式打开图片文件,如果打开错误直接返回,如果打开正确,返回文件描述符fd。
        3) 第19行判断此图片是否为bmp格式,如果不是,打印错误
        4) 第26-38行从图片中读取图片的像素和颜色值。
        5) 第71行根据从图片取得的像素值分配数据存储空间。
        6) 第77-90行从图片中取得调色板数组的值。
        7) 第100-105行从图片取得调色板中的索引值
        8) 上面取数据的顺序按照1.2的bmp图片存储格式来获取的。

        9) bmp_logo.c文件中,有一个地方程序需要更改,如果不改,只能显示半屏数据,修改的是bmp_logo.c文件中main()函数语句,内容如下:

点击(此处)折叠或打开

  1. for (i=(b->height-1)*b->width; i>=0; i-=b->width) {
  2.         for (x = 0; x < b->width; x++) {
  3.             b->data[(uint32_t) i + x] = (uint8_t) fgetc (fp) \
  4.                         + DEFAULT_CMAP_SIZE;
  5.         }
  6.     }

        红色部分即为修改内容,原来为uint16_t。

4.4、显示logo函数
        video_logo()函数调用“void logo_plot (void *screen, int width, int x, int y)”函数完成最终的显示,该函数有四个形参,为:
        *screen:显示区域内存首地址。
        width:显示屏幕的宽度,对于此处即为800。
        x,y:屏幕显示的起始位置,我们可以让logo从屏幕头开始显示,那么此处x和y的值就是(0,0),当然我们也可以让它从屏幕上其它点开始显示,只要输入相应的起点坐标即可。比如我们现在需要显示的图片的像素为300*77,经过计算,如果想要这个图片显示在800*480屏幕的中间,那么起始坐标为(250,202),即调用logo_plot()函数为:

点击(此处)折叠或打开

  1. logo_plot (video_fb_address, VIDEO_COLS, 250, 202);
        logo_plot()程序如下:

点击(此处)折叠或打开

  1. #ifdef CONFIG_VIDEO_LOGO
  2. void logo_plot (void *screen, int width, int x, int y)
  3. {

  4.     int xcount, i;
  5.     int skip = (width - VIDEO_LOGO_WIDTH) * VIDEO_PIXEL_SIZE;
  6.     volatile int ycount = video_logo_height;
  7.     unsigned char r, g, b, *logo_red, *logo_blue, *logo_green;
  8.     unsigned char *source;
  9.     unsigned char *dest = (unsigned char *)screen +
  10.              ((y * width * VIDEO_PIXEL_SIZE) +
  11.              x * VIDEO_PIXEL_SIZE);

  12. #ifdef CONFIG_VIDEO_BMP_LOGO
  13.     source = bmp_logo_bitmap;

  14.     /* Allocate temporary space for computing colormap */
  15.     logo_red = malloc (BMP_LOGO_COLORS);
  16.     logo_green = malloc (BMP_LOGO_COLORS);
  17.     logo_blue = malloc (BMP_LOGO_COLORS);
  18.     /* Compute color map */
  19.     for (i = 0; i < VIDEO_LOGO_COLORS; i++) {
  20.         logo_red[i] = (bmp_logo_palette[i] & 0x0f00) >> 4;
  21.         logo_green[i] = (bmp_logo_palette[i] & 0x00f0);
  22.         logo_blue[i] = (bmp_logo_palette[i] & 0x000f) << 4;
  23.     }
  24. #else
  25.     source = linux_logo;
  26.     logo_red = linux_logo_red;
  27.     logo_green = linux_logo_green;
  28.     logo_blue = linux_logo_blue;
  29. #endif

  30.     if (VIDEO_DATA_FORMAT == GDF__8BIT_INDEX) {
  31.         for (i = 0; i < VIDEO_LOGO_COLORS; i++) {
  32.             video_set_lut (i + VIDEO_LOGO_LUT_OFFSET,
  33.                  logo_red[i], logo_green[i], logo_blue[i]);
  34.         }
  35.     }
  36.     
  37.     //plot the blackground 800 * 480
  38. #if 1
  39.     ycount = 480;
  40.     while (ycount--) {
  41.         xcount = 800;
  42.         while (xcount--) {
  43.             r = 0;
  44.             g = 0;
  45.             b = 0;
  46.             *(unsigned short *) dest =
  47.                 SWAP16 ((unsigned short) (((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3)));
  48.             //source++;
  49.             dest += VIDEO_PIXEL_SIZE;
  50.         }
  51.         //dest += skip;
  52.     }
  53. #endif

  54. #if 1
  55.     ycount = video_logo_height;
  56.     source = bmp_logo_bitmap;
  57.     dest = (unsigned char *)screen +
  58.              ((y * width * VIDEO_PIXEL_SIZE) +
  59.              x * VIDEO_PIXEL_SIZE);

  60.     while (ycount--) {
  61. #if defined(VIDEO_FB_16BPP_PIXEL_SWAP)
  62.         int xpos = x;
  63. #endif
  64.         xcount = VIDEO_LOGO_WIDTH;
  65.         while (xcount--) {
  66.             r = logo_red[*source - VIDEO_LOGO_LUT_OFFSET];
  67.             g = logo_green[*source - VIDEO_LOGO_LUT_OFFSET];
  68.             b = logo_blue[*source - VIDEO_LOGO_LUT_OFFSET];

  69.             switch (VIDEO_DATA_FORMAT) {
  70.             case GDF__8BIT_INDEX:
  71.                 *dest = *source;
  72.                 break;
  73.             case GDF__8BIT_332RGB:
  74.                 *dest = ((r >> 5) << 5) | ((g >> 5) << 2) | (b >> 6);
  75.                 break;
  76.             case GDF_15BIT_555RGB:
  77. #if defined(VIDEO_FB_16BPP_PIXEL_SWAP)
  78.                 fill_555rgb_pswap (dest, xpos++, r, g, b);
  79. #else
  80.                 *(unsigned short *) dest =
  81.                     SWAP16 ((unsigned short) (((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3)));
  82. #endif
  83.                 break;
  84.             case GDF_16BIT_565RGB:
  85.                 *(unsigned short *) dest =
  86.                     SWAP16 ((unsigned short) (((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3)));
  87.                 break;
  88.             case GDF_32BIT_X888RGB:
  89.                 *(unsigned long *) dest =
  90.                     SWAP32 ((unsigned long) ((r << 16) | (g << 8) | b));
  91.                 break;
  92.             case GDF_24BIT_888RGB:
  93. #ifdef VIDEO_FB_LITTLE_ENDIAN
  94.                 dest[0] = b;
  95.                 dest[1] = g;
  96.                 dest[2] = r;
  97. #else
  98.                 dest[0] = r;
  99.                 dest[1] = g;
  100.                 dest[2] = b;
  101. #endif
  102.                 break;
  103.             }
  104.             source++;
  105.             dest += VIDEO_PIXEL_SIZE;
  106.         }
  107.         dest += skip;
  108.     }
  109. #endif

  110.     //plot the bottom
  111. #if 1
  112.     ycount = 204;
  113.     x = 0;
  114.     y = 0;
  115.     dest = (unsigned char *)screen +
  116.              ((y * width * VIDEO_PIXEL_SIZE) +
  117.              x * VIDEO_PIXEL_SIZE);
  118.     while (ycount--) {
  119.         xcount = 800;
  120.         while (xcount--) {
  121.             r = 0;
  122.             g = 0;
  123.             b = 0;
  124.             *(unsigned short *) dest =
  125.                 SWAP16 ((unsigned short) (((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3)));
  126.             dest += VIDEO_PIXEL_SIZE;
  127.         }
  128.         //dest += skip;
  129.     }
  130. #endif
  131.     
  132. #ifdef CONFIG_VIDEO_BMP_LOGO
  133.     free (logo_red);
  134.     free (logo_green);
  135.     free (logo_blue);
  136. #endif
  137. }
        说明:
        1) 函数的开头以”#ifdef CONFIG_VIDEO_LOGO“宏定义开始,所以想要显示图片首先需要定义宏”CONFIG_VIDEO_LOGO“。即为4.1所示。
        2) 第6行指定了行扫描时跳过的字节数,”width - VIDEO_LOGO_WIDTH“中,width是屏幕的实际宽度,本文为800,VIDEO_LOGO_WIDTH”tools/logo/denx.bmp“图片的实际宽度,最大为800。VIDEO_PIXEL_SIZE为2,表示一个像素占用两个字节。
        3) 第10行定义了显示内存的实际地址,如果我们从(0,0)开始显示,那么此处即为"screen"。
        4) 第15行取得实际位图数据数组的起始地址。
        5) 第18-26行首先申请内存,然后从调色板中取得RGB相应的值。
        6) 第43-56行首先将屏幕刷黑,RGB数据全为0,此时也不需要skip,因为是刷全屏。
        7) 第60-115行实现将图片显示在屏幕上,ycount即为实际图片高度,xcount为实际图片的宽度,72-74行取得RGB数据,然后将其赋值在显示内存上。switch分支中走的case为"GDF_16BIT_565RGB”。
        8) 第120-137行将图片的上半部再一次刷黑。

        注意,在调试中发现,需要将int ycount = video_logo_height;定义为volatile类型,否则会造成外层循环退不出来,即改为:volatile int ycount = video_logo_height;

阅读(5309) | 评论(1) | 转发(0) |
0

上一篇:第3章-变量

下一篇:shell 特殊变量

给主人留下些什么吧!~~

CU博客助理2014-07-11 15:56:34

专家点评:博主很好地梳理了位图、调色板和bmp格式的基本知识,在参阅相关文献的基础上按照移植过程进行了实现,对重要参数也做了详细说明,同时也给出了若干需要注意之处。
想必做过嵌入式的人都有同样的经历,定制一个漂亮的开机Logo几乎是每个人都会完成的必修任务,此博文可供具有同样愿景的小白们参考,省却了在黑暗中摸索的宝贵时间。(感谢参加原创评选活动,获奖结果即将公布)