UEFI编程入门-图形与文字显示

显示基础

UEFI进行图形开发步骤为:

  • 获取EFI_GRAPHICS_OUTPUT_PROTOCOL实例,存在多个显示设备则可获得多个实例。
  • 查询系统支持的显示模式,特别是模式的分辨率,确定可操作的画布大小。
  • 设置需要的显示模式。
  • 用图形显示接口函数Blt在屏幕上绘制。

EFI_GRAPHICS_OUTPUT_PROTOCOL结构为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
struct _EFI_GRAPHICS_OUTPUT_PROTOCOL {
EFI_GRAPHICS_OUTPUT_PROTOCOL_QUERY_MODE QueryMode; //查询系统显示模式
EFI_GRAPHICS_OUTPUT_PROTOCOL_SET_MODE SetMode; //设置显示模式
EFI_GRAPHICS_OUTPUT_PROTOCOL_BLT Blt; //图形显示接口函数
EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE *Mode; //当前显示模式
};
typedef struct {
UINT32 MaxMode; //显示设备支持的模式数
UINT32 Mode; //当前图形设备显示模式 0~MaxMode-1
EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info; //当前显示模式信息
UINTN SizeOfInfo; //Info大小
EFI_PHYSICAL_ADDRESS FrameBufferBase; //帧缓冲起始物理地址
UINTN FrameBufferSize; //帧缓冲大小
} EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE;

系统中存在的显示模式如分辨率和颜色深度等信息通过QueryMode获取:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
typedef EFI_STATUS(EFIAPI *EFI_GRAPHICS_OUTPUT_PROTOCOL_QUERY_MODE)(
IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This, //Protocol实例
IN UINT32 ModeNumber, //显示模式序号
OUT UINTN *SizeOfInfo, //指向显示模式信息结构体缓冲区Info大小的指针
OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION **Info //存储显示模式信息
);
typedef struct { //显示模式信息结构体
UINT32 Version; //版本号 向后兼容
UINT32 HorizontalResolution; //水平分辨率
UINT32 VerticalResolution; //垂直分辨率
EFI_GRAPHICS_PIXEL_FORMAT PixelFormat; //像素格式
EFI_PIXEL_BITMASK PixelInformation; //像素格式为PixelBitMask时有效
UINT32 PixelsPerScanLine; //每行扫描的像素数
} EFI_GRAPHICS_OUTPUT_MODE_INFORMATION;
typedef struct {
UINT32 RedMask; //红色分量
UINT32 GreenMask; //绿色分量
UINT32 BlueMask; //蓝色分量
UINT32 ReservedMask;
} EFI_PIXEL_BITMASK;
typedef enum {
PixelRedGreenBlueReserved8BitPerColor, //RGBA格式 每个分量8位
PixelBlueGreenRedReserved8BitPerColor, //BGRA格式 每个分量8位
PixelBitMask, //像素掩码
PixelBltOnly, //FrameBufferBase无效 只能通过Blt接口函数访问帧缓冲区 一般只用这个
PixelFormatMax //枚举变量最大值
} EFI_GRAPHICS_PIXEL_FORMAT;

SetMode设定显示模式,并将显示器屏幕清为黑色。

1
2
3
4
typedef EFI_STATUS(EFIAPI *EFI_GRAPHICS_OUTPUT_PROTOCOL_SET_MODE)(
IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This, //Protocol实例
IN UINT32 ModeNumber //指定的显示模式
);

Blt提供四种操作:将指定趋于填充为单一颜色、将某个区域数据复制到缓冲区、将缓冲区数据复制到屏幕指定区域、复制屏幕某区域到屏幕另一区域。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
typedef EFI_STATUS(EFIAPI *EFI_GRAPHICS_OUTPUT_PROTOCOL_BLT)(
IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This, //Protocol实例
IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer OPTIONAL, //图像缓冲区
IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation, //操作方式
IN UINTN SourceX, //源地址X坐标
IN UINTN SourceY, //源地址Y坐标
IN UINTN DestinationX, //目的地址X坐标
IN UINTN DestinationY, //目的地址Y坐标
IN UINTN Width, //操作区域宽
IN UINTN Height, //操作区域高
IN UINTN Delta OPTIONAL //BltBuffer每行字节数
);
typedef enum {
EfiBltVideoFill, //单一颜色填充屏幕
EfiBltVideoToBltBuffer, //屏幕到缓冲区
EfiBltBufferToVideo, //缓冲区到屏幕
EfiBltVideoToVideo, //屏幕到屏幕
EfiGraphicsOutputBltOperationMax
} EFI_GRAPHICS_OUTPUT_BLT_OPERATION;

例如各种操作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
extern EFI_GRAPHICS_OUTPUT_PROTOCOL* gGraphicsOutput;
//整个屏幕填充为蓝色 分辨率1024*768
EFI_STATUS Status;
EFI_GRAPHICS_OUTPUT_BLT_PIXEL ColorBuf[1000];
EFI_GRAPHICS_OUTPUT_BLT_PIXEL BackGroundColor={192,0,0,0}; //蓝色
Status=gGraphicsOutput->Blt(gGraphicsOutput,&BackGroundColor,EfiBltVideoFill,0,0,0,0,1024,768,0);
//将缓冲区内颜色数据复制到屏幕上
gBS->SetMem(ColorBuf,1000*sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL),0); //黑色
Status=gGraphicsOutput->Blt(gGraphicsOutput,ColorBuf,EfiBltBufferToVideo,0,0,20,20,100,10,100*sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL)); //(20,20)处显示
Status=gGraphicsOutput->Blt(gGraphicsOutput,ColorBuf,EfiBltBufferToVideo,0,5,20,60,100,5,100*sizeof(EFI_GRAPHICS_OUTPUT_PLT_PIXEL));
//复制屏幕区域到另一片屏幕区域
Status=gGraphicsOutput->Blt(gGraphicsOutput,0,EfiBltVideoToVideo,20,20,200,60,100,10,0); //(20,20)复制到(200,60) 复制大小为100x10
//屏幕区域复制到缓冲区
Status=gGraphicsOutput->Blt(gGraphicsOutput,ColorBuf,EfiBltVideoToBltBuffer,20,20,0,0,100,10,100*sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL)); //从(20,20)处获取

实战有:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
//读写像素点
VOID putpixel(UINTN x,UINTN y,EFI_GRAPHICS_OUTPUT_BLT_PIXEL *color) {
gGraphicsOutput->Blt (gGraphicsOutput,color,EfiBltVideoFill,0,0,x,y,1,1,0);
}
VOID getpixel(UINTN x,UINTN y, EFI_GRAPHICS_OUTPUT_BLT_PIXEL *color) {
gGraphicsOutput->Blt (gGraphicsOutput,color,EfiBltVideoToBltBuffer,x,y,0,0,1,1,0);
}
//Bresenham算法画线
VOID line(UINTN x1,UINTN y1,UINTN x2,UINTN y2,EFI_GRAPHICS_OUTPUT_BLT_PIXEL *color) {
INTN d,dx,dy,dx2,dy2,dxy;
INTN xinc,yinc;
dx=(INTN)((x2>x1)?(x2-x1):(x1-x2));
dx2=dx<<1;
dy=(INTN)((y2>y1)?(y2-y1):(y1-y2));
dy2=dy<<1;
xinc=(x2>x1)?1:((x2==x1)?0:(-1));
yinc=(y2>y1)?1:((y2==y1)?0:(-1));
putpixel(x1,y1,color);
if(dx>=dy){
d=dy2-dx;
dxy=dy2-dx2;
while(dx--){
if(d<=0)
d+=dy2;
else{
d+=dxy;
y1+=yinc;
}
// if(((x1+xinc)<=maxX)&&(y1<=maxY)) /* 对超出屏幕范围的点不予显示 */
putpixel(x1+=xinc,y1,color);
}
}
else{
d=dx2-dy;
dxy=dx2-dy2;
while(dy--){
if(d<=0)
d+=dx2;
else{
d+=dxy;
x1+=xinc;
}
// if((x1<=maxX)&&((y1+yinc)<=maxY)) /* 对超出屏幕范围的点不予显示 */
putpixel(x1,y1+=yinc,color);
}
}
}
//水平和垂直直线
VOID HLine(UINTN x1,UINTN x2,UINTN y,EFI_GRAPHICS_OUTPUT_BLT_PIXEL *color) {
UINTN minx,maxx;
minx=(x1<x2)?x1:x2;
maxx=(x1>x2)?x1:x2;
gGraphicsOutput->Blt (gGraphicsOutput,color,EfiBltVideoFill,0,0,minx,y,(maxx-minx+1),1,0);
}
VOID VLine(UINTN x,UINTN y1,UINTN y2,EFI_GRAPHICS_OUTPUT_BLT_PIXEL *color) {
UINTN miny,maxy;
miny=(y1<y2)?y1:y2;
maxy=(y1>y2)?y1:y2;
gGraphicsOutput->Blt (gGraphicsOutput,color,EfiBltVideoFill,0,0,x,miny,1,(maxy-miny+1),0);
}
//画圆
VOID circle(UINTN centerx,UINTN centery,UINTN radius,EFI_GRAPHICS_OUTPUT_BLT_PIXEL *color) {
INTN x,y,d;
if(!radius)
return;
y=(INTN)(radius);
d=3-((INTN)(radius)<<1);
putpixel(centerx,centery+y,color); /*0,-1*/
putpixel(centerx,centery-y,color); /*0,1*/
putpixel(centerx+y,centery,color);
putpixel(centerx-y,centery,color);
for(x=1;x<y;x++) {
putpixel(centerx+x,centery+y,color);
putpixel(centerx+x,centery-y,color);
putpixel(centerx-x,centery-y,color);
putpixel(centerx-x,centery+y,color);
putpixel(centerx+y,centery+x,color);
putpixel(centerx+y,centery-x,color);
putpixel(centerx-y,centery-x,color);
putpixel(centerx-y,centery+x,color);
if(d<0)
d+=((x<<2)+6);
else
d+=(((x-(y--))<<2)+10);
}
/* x=y */
putpixel(centerx+y,centery+y,color);
putpixel(centerx+y,centery-y,color);
putpixel(centerx-y,centery-y,color);
putpixel(centerx-y,centery+y,color);
}
//画矩形和矩形块
VOID rectangle(UINTN x1,UINTN y1,UINTN x2,UINTN y2,EFI_GRAPHICS_OUTPUT_BLT_PIXEL *color) {
UINTN minx,miny,maxx,maxy;
minx=(x1<x2)?x1:x2;
miny=(y1<y2)?y1:y2;
maxx=(x1>x2)?x1:x2;
maxy=(y1>y2)?y1:y2;
HLine(minx,maxx,miny,color);
VLine(minx,miny,maxy,color);
HLine(minx,maxx,maxy,color);
VLine(maxx,miny,maxy,color);
}
VOID rectblock(UINTN x1,UINTN y1,UINTN x2,UINTN y2,EFI_GRAPHICS_OUTPUT_BLT_PIXEL *color) {
UINTN minx,miny,maxx,maxy;
minx=(x1<x2)?x1:x2;
miny=(y1<y2)?y1:y2;
maxx=(x1>x2)?x1:x2;
maxy=(y1>y2)?y1:y2;
gGraphicsOutput->Blt (gGraphicsOutput,color,EfiBltVideoFill,0,0,minx,miny,(maxx-minx+1),(maxy-miny+1),0);
}

汉字显示

字模法

对于显示中文,有字模和HII两种方法。对于字模法,需要对汉字制作字模信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
typedef struct struct_lattice {
UINT32 utf8_code; //该汉字UTF-8编码
UINT8 width; //汉字宽度
UINT8 * pixel_gray_array; //字模信息
} LATTICE;
typedef struct struct_font_info {
UINT8 height; //汉字高度
UINT32 count; //提取的汉字总数
LATTICE* lattice_array; //字模信息数组
} FONT_INFO;
//UTF-8 数据 从左往右 从上往下 1个位表示1像素 1显示 0不显示
UINT8 _46_27[] = {
0, 96, 73, 1, 255, 1, 197, 1, 0, 2, 73, 1, 255, 1, 197, 1, 0, 31, };
UINT8 _49_27[] = {
0, 78, 153, 1, 255, 1, 0, 8, 197, 1, 255, 3, 0, 6, 153, 1, 255, 2, 153, 1, 255, 2, 0, 6, 153, 1, 197, 1, 0, 2, 255, 2, 0, 10, 255, 2, 0, 10, 255, 2, 0, 10, 255, 2, 0, 10, 255, 2, 0, 10, 255, 2, 0, 10, 255, 2, 0, 10, 255, 2, 0, 10, 255, 2, 0, 10, 255, 2, 0, 10, 255, 2, 0, 10, 255, 2, 0, 76, };
UINT8 _15041929_27[] = {
0, 109, 111, 1, 255, 1, 0, 11, 73, 1, 153, 1, 0, 5, 111, 1, 255, 1, 0, 5, 36, 1, 197, 1, 0, 4, 111, 1, 255, 1, 111, 1, 0, 4, 111, 1, 255, 1, 0, 5, 197, 1, 255, 1, 73, 1, 0, 4, 111, 1, 255, 1, 36, 1, 0, 3, 111, 1, 255, 1, 0, 4, 153, 1, 255, 1, 73, 1, 0, 6, 197, 1, 255, 1, 0, 3, 111, 1, 255, 1, 0, 3, 111, 1, 255, 1, 73, 1, 0, 7, 36, 1, 255, 1, 197, 1, 0, 2, 111, 1, 255, 1, 0, 2, 73, 1, 255, 1, 111, 1, 0, 9, 111, 2, 0, 2, 111, 1, 255, 1, 0, 2, 153, 1, 111, 1, 0, 14, 111, 1, 255, 1, 0, 9, 36, 1, 255, 18, 197, 1, 0, 6, 111, 1, 255, 1, 0, 3, 36, 1, 255, 1, 73, 1, 0, 12, 111, 1, 255, 1, 0, 3, 36, 1, 255, 1, 73, 1, 0, 12, 153, 1, 197, 1, 0, 3, 36, 1, 255, 1, 73, 1, 0, 12, 255, 1, 153, 1, 0, 3, 36, 1, 255, 1, 73, 1, 0, 4, 111, 1, 197, 1, 0, 5, 73, 1, 255, 1, 36, 1, 0, 3, 36, 1, 255, 1, 73, 1, 0, 4, 111, 1, 255, 1, 0, 5, 255, 1, 153, 1, 0, 4, 36, 1, 255, 1, 73, 1, 0, 4, 153, 1, 255, 1, 0, 4, 255, 1, 197, 1, 0, 6, 255, 1, 111, 1, 0, 4, 255, 1, 197, 1, 0, 2, 153, 1, 255, 1, 153, 1, 0, 7, 111, 1, 255, 6, 36, 1, 73, 1, 255, 1, 197, 1, 0, 97, };
UINT8 _15050173_27[] = {
0, 103, 153, 1, 197, 1, 0, 18, 197, 1, 153, 1, 0, 3, 73, 1, 255, 10, 73, 1, 0, 3, 255, 1, 111, 1, 0, 11, 111, 1, 255, 1, 197, 1, 0, 3, 36, 1, 255, 1, 73, 1, 0, 10, 153, 1, 255, 1, 197, 1, 0, 2, 111, 1, 255, 7, 0, 6, 197, 1, 255, 1, 153, 1, 0, 5, 111, 1, 197, 1, 0, 2, 111, 1, 255, 1, 0, 5, 111, 1, 255, 1, 111, 1, 0, 6, 197, 1, 153, 1, 0, 2, 153, 1, 197, 1, 0, 5, 111, 1, 255, 1, 0, 7, 255, 1, 111, 1, 0, 2, 153, 1, 197, 1, 0, 5, 111, 1, 255, 1, 0, 6, 36, 1, 255, 1, 36, 1, 0, 2, 197, 1, 153, 1, 255, 12, 0, 1, 111, 1, 255, 1, 0, 2, 36, 1, 255, 1, 73, 1, 0, 5, 111, 1, 255, 1, 0, 6, 197, 1, 153, 1, 0, 2, 111, 1, 255, 1, 36, 1, 0, 5, 111, 1, 255, 1, 0, 7, 153, 1, 255, 1, 0, 1, 197, 2, 0, 6, 111, 1, 255, 1, 0, 8, 111, 1, 255, 2, 73, 1, 0, 6, 111, 1, 255, 1, 0, 9, 255, 2, 153, 1, 0, 6, 111, 1, 255, 1, 0, 8, 153, 1, 255, 1, 36, 1, 255, 1, 197, 1, 0, 5, 111, 1, 255, 1, 0, 7, 111, 1, 255, 1, 36, 1, 0, 2, 255, 1, 153, 1, 0, 4, 111, 1, 255, 1, 0, 6, 153, 1, 255, 1, 36, 1, 0, 9, 153, 1, 197, 1, 0, 5, 73, 1, 255, 1, 0, 7, 36, 1, 255, 4, 73, 1, 0, 85, };
UINT8 _15111865_27[] = {
0, 89, 153, 1, 197, 1, 0, 18, 153, 1, 255, 1, 111, 1, 0, 18, 197, 1, 255, 1, 0, 9, 255, 18, 197, 1, 0, 6, 153, 1, 255, 1, 0, 18, 197, 2, 0, 18, 197, 2, 0, 18, 197, 2, 0, 18, 255, 11, 36, 1, 0, 8, 255, 1, 153, 1, 0, 7, 111, 1, 255, 1, 36, 1, 0, 7, 36, 1, 255, 1, 111, 1, 0, 7, 153, 1, 255, 1, 36, 1, 0, 7, 73, 1, 255, 1, 73, 1, 0, 7, 153, 1, 255, 1, 0, 8, 153, 1, 255, 1, 0, 8, 153, 1, 255, 1, 0, 8, 255, 1, 153, 1, 0, 8, 197, 2, 0, 7, 111, 1, 255, 1, 73, 1, 0, 8, 197, 2, 0, 7, 255, 1, 197, 1, 0, 9, 255, 1, 153, 1, 0, 6, 153, 1, 255, 1, 36, 1, 0, 8, 36, 1, 255, 1, 153, 1, 0, 5, 111, 1, 255, 1, 111, 1, 0, 9, 153, 1, 255, 1, 36, 1, 0, 4, 111, 1, 255, 1, 111, 1, 0, 5, 197, 1, 255, 5, 73, 1, 0, 4, 73, 1, 255, 1, 73, 1, 0, 77, };
UINT8 _15112628_27[] = {
0, 113, 255, 1, 153, 1, 0, 18, 255, 1, 153, 1, 0, 6, 73, 1, 255, 5, 0, 1, 255, 11, 197, 1, 0, 1, 73, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 0, 6, 255, 1, 153, 1, 0, 6, 73, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 0, 1, 153, 1, 255, 10, 111, 1, 0, 1, 73, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 0, 6, 255, 1, 153, 1, 0, 6, 73, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 73, 1, 255, 12, 0, 1, 73, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 0, 14, 73, 1, 255, 5, 0, 1, 73, 1, 255, 10, 0, 2, 73, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 0, 1, 73, 1, 255, 1, 36, 1, 0, 6, 111, 1, 255, 1, 0, 2, 73, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 0, 1, 73, 1, 255, 1, 36, 1, 0, 6, 111, 1, 255, 1, 0, 2, 73, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 0, 1, 73, 1, 255, 10, 0, 2, 73, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 0, 1, 73, 1, 255, 1, 36, 1, 0, 6, 111, 1, 255, 1, 0, 2, 73, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 0, 1, 73, 1, 255, 1, 36, 1, 0, 6, 111, 1, 255, 1, 0, 2, 73, 1, 255, 5, 0, 1, 73, 1, 255, 10, 0, 2, 73, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 0, 1, 73, 1, 255, 1, 36, 1, 0, 6, 111, 1, 255, 1, 0, 9, 73, 1, 255, 1, 36, 1, 0, 6, 153, 1, 197, 1, 0, 9, 73, 1, 255, 1, 36, 1, 0, 2, 111, 1, 255, 4, 73, 1, 0, 81, };
UINT8 _15118516_27[] = {
0, 89, 111, 1, 255, 1, 36, 1, 0, 17, 111, 1, 255, 1, 36, 1, 0, 17, 111, 1, 255, 1, 36, 1, 0, 17, 111, 1, 255, 1, 36, 1, 0, 5, 197, 1, 0, 11, 111, 1, 255, 1, 111, 1, 0, 4, 153, 1, 255, 1, 111, 1, 0, 2, 197, 1, 255, 5, 197, 1, 0, 1, 111, 1, 255, 2, 0, 3, 111, 1, 255, 1, 111, 1, 0, 8, 153, 1, 197, 1, 0, 1, 111, 1, 255, 2, 73, 1, 0, 1, 111, 1, 255, 1, 153, 1, 0, 9, 255, 1, 111, 1, 0, 1, 111, 1, 255, 2, 197, 1, 111, 1, 255, 1, 197, 1, 0, 9, 73, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 111, 1, 255, 2, 197, 1, 0, 10, 153, 1, 197, 1, 0, 2, 111, 1, 255, 1, 36, 1, 255, 1, 197, 1, 0, 10, 36, 1, 255, 1, 111, 1, 0, 2, 111, 1, 255, 1, 36, 1, 73, 1, 255, 1, 73, 1, 0, 9, 153, 1, 255, 1, 0, 3, 111, 1, 255, 1, 36, 1, 0, 1, 197, 1, 255, 1, 0, 8, 36, 1, 255, 1, 111, 1, 0, 3, 111, 1, 255, 1, 36, 1, 0, 1, 36, 1, 255, 1, 153, 1, 0, 7, 197, 1, 255, 1, 0, 4, 111, 1, 255, 1, 36, 1, 0, 2, 111, 1, 255, 1, 73, 1, 0, 5, 111, 1, 255, 1, 111, 1, 0, 4, 111, 1, 255, 1, 36, 1, 0, 3, 153, 1, 255, 1, 36, 1, 0, 3, 36, 1, 255, 1, 197, 1, 0, 5, 111, 1, 255, 1, 36, 1, 0, 4, 197, 1, 255, 1, 36, 1, 0, 2, 255, 2, 36, 1, 0, 5, 111, 1, 255, 1, 0, 6, 197, 1, 255, 1, 36, 2, 111, 1, 73, 1, 0, 6, 153, 1, 197, 1, 0, 7, 197, 1, 255, 1, 0, 5, 73, 1, 255, 4, 36, 1, 0, 89, };
UINT8 _15121311_27[] = {
0, 101, 73, 1, 255, 1, 0, 3, 36, 1, 255, 1, 73, 1, 0, 4, 255, 1, 197, 1, 0, 6, 36, 1, 153, 1, 255, 1, 36, 1, 0, 1, 36, 1, 255, 1, 73, 1, 0, 3, 111, 1, 255, 1, 36, 1, 0, 8, 153, 2, 0, 1, 36, 1, 255, 1, 73, 1, 0, 2, 36, 1, 255, 6, 153, 1, 0, 5, 36, 1, 255, 5, 111, 1, 197, 1, 153, 1, 0, 3, 111, 1, 255, 1, 36, 1, 0, 7, 36, 1, 255, 1, 73, 1, 0, 1, 153, 1, 197, 1, 0, 3, 153, 1, 255, 1, 0, 4, 255, 1, 36, 1, 0, 3, 36, 1, 255, 1, 73, 1, 0, 1, 255, 9, 36, 2, 111, 1, 255, 1, 111, 1, 0, 2, 36, 1, 255, 1, 73, 1, 0, 2, 255, 1, 153, 1, 0, 1, 153, 2, 0, 1, 73, 1, 255, 1, 36, 1, 0, 2, 73, 1, 255, 1, 36, 1, 255, 5, 73, 1, 255, 1, 153, 1, 0, 1, 153, 2, 0, 1, 73, 1, 255, 1, 36, 1, 0, 6, 36, 1, 255, 1, 73, 1, 0, 2, 255, 1, 153, 1, 0, 1, 153, 2, 0, 1, 73, 1, 255, 1, 36, 1, 0, 6, 36, 1, 255, 1, 73, 1, 0, 2, 255, 1, 153, 1, 0, 1, 153, 2, 0, 1, 73, 1, 255, 1, 36, 1, 0, 2, 73, 1, 255, 1, 0, 2, 36, 1, 255, 1, 73, 1, 0, 2, 255, 1, 153, 1, 0, 1, 153, 2, 0, 1, 73, 1, 255, 1, 36, 1, 0, 2, 111, 1, 255, 1, 153, 1, 255, 5, 153, 1, 255, 8, 36, 1, 0, 2, 153, 1, 197, 1, 0, 2, 36, 1, 255, 1, 73, 1, 0, 2, 255, 1, 153, 1, 0, 4, 73, 1, 255, 1, 36, 1, 0, 2, 255, 1, 111, 1, 0, 2, 36, 1, 255, 1, 73, 1, 0, 2, 255, 1, 153, 1, 0, 5, 73, 1, 255, 1, 0, 1, 36, 1, 255, 1, 73, 1, 0, 2, 36, 1, 255, 1, 73, 1, 0, 2, 255, 1, 153, 1, 0, 5, 111, 1, 255, 1, 0, 1, 111, 1, 255, 1, 0, 3, 36, 1, 255, 1, 73, 1, 0, 2, 255, 1, 153, 1, 0, 5, 111, 1, 255, 1, 0, 1, 197, 2, 0, 3, 36, 1, 255, 1, 73, 1, 0, 2, 197, 1, 153, 1, 0, 5, 197, 1, 153, 1, 0, 1, 255, 1, 111, 1, 0, 3, 36, 1, 255, 1, 73, 1, 0, 2, 73, 1, 255, 7, 0, 81, };
UINT8 _15121803_27[] = {
0, 101, 73, 1, 255, 1, 0, 5, 111, 1, 255, 1, 0, 4, 36, 1, 255, 1, 73, 1, 0, 4, 36, 1, 153, 1, 255, 1, 73, 1, 0, 2, 36, 1, 255, 2, 197, 1, 0, 3, 73, 1, 255, 1, 0, 7, 111, 1, 255, 1, 0, 2, 197, 1, 153, 1, 0, 1, 197, 2, 0, 2, 153, 2, 0, 10, 111, 1, 153, 1, 0, 3, 197, 2, 0, 1, 197, 1, 255, 5, 0, 5, 73, 1, 153, 1, 0, 5, 255, 1, 111, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 0, 1, 36, 1, 255, 1, 0, 2, 73, 1, 197, 1, 255, 6, 0, 1, 111, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 0, 1, 36, 1, 153, 1, 255, 1, 73, 1, 255, 1, 0, 8, 197, 1, 255, 1, 73, 1, 0, 1, 111, 1, 197, 1, 0, 3, 111, 1, 255, 1, 0, 3, 73, 1, 197, 1, 0, 3, 73, 1, 153, 1, 197, 1, 111, 1, 0, 1, 153, 2, 0, 5, 73, 1, 255, 1, 0, 1, 36, 1, 255, 1, 36, 1, 0, 1, 255, 2, 73, 1, 153, 2, 0, 1, 197, 1, 111, 1, 0, 6, 255, 1, 73, 1, 0, 1, 255, 1, 73, 1, 36, 1, 255, 1, 36, 1, 0, 1, 111, 1, 197, 1, 0, 1, 255, 1, 73, 1, 0, 6, 197, 1, 153, 1, 0, 1, 197, 1, 111, 2, 197, 1, 0, 2, 73, 1, 255, 1, 73, 1, 255, 1, 0, 4, 153, 2, 0, 1, 111, 1, 255, 1, 0, 1, 153, 2, 197, 1, 111, 1, 0, 3, 255, 2, 153, 1, 0, 4, 197, 2, 0, 1, 73, 1, 255, 1, 73, 1, 0, 1, 73, 1, 255, 1, 36, 1, 0, 3, 153, 1, 255, 1, 36, 1, 0, 3, 36, 1, 255, 1, 111, 1, 0, 5, 111, 1, 197, 1, 0, 4, 153, 1, 255, 1, 73, 1, 0, 3, 73, 1, 255, 1, 36, 1, 0, 3, 153, 1, 255, 5, 0, 1, 111, 1, 255, 1, 197, 1, 255, 1, 0, 3, 153, 1, 197, 1, 0, 1, 153, 1, 255, 2, 111, 1, 0, 5, 73, 1, 255, 1, 73, 1, 0, 1, 255, 1, 153, 1, 0, 2, 197, 1, 153, 1, 0, 9, 73, 1, 255, 1, 111, 1, 0, 2, 36, 1, 255, 1, 111, 1, 0, 1, 255, 1, 111, 1, 0, 9, 255, 1, 111, 1, 0, 4, 36, 1, 255, 1, 0, 80, };
LATTICE lattice_array[] = {
{46, 5, _46_27},
{49, 12, _49_27},
{15041929, 20, _15041929_27},
{15050173, 20, _15050173_27},
{15111865, 20, _15111865_27},
{15112628, 20, _15112628_27},
{15118516, 20, _15118516_27},
{15121311, 20, _15121311_27},
{15121803, 20, _15121803_27},
};
FONT_INFO MyFontArray ={
27,9,
lattice_array //1.水光潋滟晴方好
};

此外为了让编译器支持UTF-8而不是Unicode,在INF文件中添加:

1
2
[BuildOptions]
MSFT:*_*_*_CC_FLAGS = /utf-8

汉字显示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
//定位字模信息
LATTICE* get_lattice(FONT_INFO* font, UINT32 utf8_code) {
INTN first = 0;
INTN last = font->count - 1;
INTN middle = (first + last) / 2;
while (first <= last) {
if (font->lattice_array[middle].utf8_code < utf8_code)
first = middle + 1;
else if (font->lattice_array[middle].utf8_code == utf8_code)
return &font->lattice_array[middle];
else
last = middle - 1;
middle = (first + last) / 2;
}
return 0;
}
//绘制汉字
VOID draw_lattice(UINTN x, UINTN y, UINT8 width, UINT8 height, UINT8* p_data, EFI_GRAPHICS_OUTPUT_BLT_PIXEL *font_color) {
UINT8 blk_value = *p_data++;
UINT8 blk_cnt = *p_data++;
UINT8 x_, y_;
for (y_ = 0; y_ < height; y_++)
for (x_ = 0; x_ < width; x_++) {
if(blk_value)
putpixel((x + (UINTN)x_), (y + (UINTN)y_), font_color);
if (--blk_cnt == 0) {//reload new block
blk_value = *p_data++;
blk_cnt = *p_data++;
}
}
}

上面这俩是基础函数,还可扩展到ASCII字符的显示,但也得有字模才行:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
UINT8 draw_single_char(UINT32 utf8_code, UINTN x, UINTN y, FONT_INFO* font, EFI_GRAPHICS_OUTPUT_BLT_PIXEL *font_color) {
LATTICE *p_lattice;
if (font) {
p_lattice = get_lattice(font, utf8_code);
if (p_lattice){
draw_lattice(x, y, p_lattice->width, font->height, p_lattice->pixel_gray_array, font_color);
return p_lattice->width;
}
}
return 0;
}
VOID draw_string(UINT8 *str, UINTN x, UINTN y, FONT_INFO *font, EFI_GRAPHICS_OUTPUT_BLT_PIXEL *font_color) {
UINT8 temp;
UINT8 *ptr;
UINT32 char_utf8;
UINTN cur_x;
ptr = (UINT8 *)str;
cur_x = x;
while('\0' != *ptr) {
//1 get utf-8 code from str
temp = ptr[0];
if(temp > 128) { //汉字
char_utf8 = (((UINT32)ptr[0]) << 16) + (((UINT32)ptr[1]) << 8) + (UINT32)ptr[2];
ptr += 3;
}
else {
char_utf8 = (UINT32)ptr[0];
ptr += 1;
}
//2 display a char
cur_x += (UINTN)draw_single_char(char_utf8, cur_x, y, font, font_color);
}
}

然后可以这样用:

1
2
3
draw_string(s_text, 80, 60, &MyFontArray, &(gColorTable[8]));
draw_string(s_text, 80, 100, &MyFontArray, &(gColorTable[7]));
draw_string(s_text, 80, 140, &MyFontArray, &(gColorTable[6]));

HII法

对于HII法,字体处理的Protocol为EFI_HII_FONT_PROTOCOL,字符串处理的Protocol为EFI_HII_STRING_PROTOCOL。首先将字体或字符串资源组织在HII包中,用HiiAddPackage向UEFI系统HII数据库注册资源,再使用相应Protocol,在屏幕上显示文字,最后移除注册的HII包。

UEFI中有SimpleFont和Font两种字体格式。前者支持在字符模式下显示多国语言。后者能渲染复杂字符,性能高,但只提供了英文和法文的字体库。为实现汉字显示,要根据这俩字体格式要求提取相应字库。

SimpleFont有两种格式,窄字符为宽8高19像素,宽字符为宽16高19像素。Font格式比较灵活,信息都在结构中设置。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#define EFI_GLYPH_NON_SPACING  0x01
#define EFI_GLYPH_WIDE 0x02
#define EFI_GLYPH_HEIGHT 19
#define EFI_GLYPH_WIDTH 8
typedef struct { //窄字符 一般英文
CHAR16 UnicodeWeight; //字符编码 Unicode16
UINT8 Attributes; //字符属性
UINT8 GlyphCol1[EFI_GLYPH_HEIGHT]; //字模信息
} EFI_NARROW_GLYPH;
typedef struct { //宽字符 一般中文
CHAR16 UnicodeWeight; //字符编码 Unicode16
UINT8 Attributes; //字符属性
UINT8 GlyphCol1[EFI_GLYPH_HEIGHT]; //字模信息
UINT8 GlyphCol2[EFI_GLYPH_HEIGHT]; //字模信息
UINT8 Pad[3]; //填充0
} EFI_WIDE_GLYPH;

typedef struct _EFI_HII_GLYPH_INFO {
UINT16 Width; //字符宽 单位像素
UINT16 Height; //字符高 单位像素
INT16 OffsetX; //水平边距 左边框距离字体
INT16 OffsetY; //垂直边距 下边框距离字体
INT16 AdvanceX; //整个字符结构占据宽度
} EFI_HII_GLYPH_INFO;

例如SimpleFont格式字模信息:

1
2
3
4
5
EFI_NARROW_GLYPH  gMyNarrowGlyphData[] = {
{ 0x0020, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
{ 0x0021, 0x00, {0x00,0x00,0x00,0x18,0x3C,0x3C,0x3C,0x18,0x18,0x18,0x18,0x18,0x00,0x18,0x18,0x00,0x00,0x00,0x00}},
//略
};UINT32 nMyNarrowGlyphSize = sizeof (gMyNarrowGlyphData);

HiiAddPackages注册资源包:

1
2
3
4
5
EFI_HII_HANDLE EFIAPI HiiAddPackages (
IN CONST EFI_GUID *PackageListGuid, //包列表GUID 最后一个必须为NULL
IN EFI_HANDLE DeviceHandle OPTIONAL,
...
);

资源包和包列表结构如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
typedef struct {
UINT32 Length : 24; //资源包长度
UINT32 Type : 8; //资源包类型
} EFI_HII_PACKAGE_HEADER; //资源包头结构
#define EFI_HII_PACKAGE_TYPE_ALL 0x00 //匹配所有类型
#define EFI_HII_PACKAGE_TYPE_GUID 0x01 //厂商自定义
#define EFI_HII_PACKAGE_FORMS 0x02 //窗体
#define EFI_HII_PACKAGE_STRINGS 0x04 //字符串
#define EFI_HII_PACKAGE_FONTS 0x05 //字体
#define EFI_HII_PACKAGE_IMAGES 0x06 //图像
#define EFI_HII_PACKAGE_SIMPLE_FONTS 0x07 //字体
#define EFI_HII_PACKAGE_DEVICE_PATH 0x08 //设备路径
#define EFI_HII_PACKAGE_KEYBOARD_LAYOUT 0x09 //键盘布局
#define EFI_HII_PACKAGE_ANIMATIONS 0x0A //动画
#define EFI_HII_PACKAGE_END 0xDF //包列表结束标志
#define EFI_HII_PACKAGE_TYPE_SYSTEM_BEGIN 0xE0 //起始系统保留值
#define EFI_HII_PACKAGE_TYPE_SYSTEM_END 0xFF //结束系统保留值
typedef struct {
EFI_GUID PackageListGuid; //包列表GUID
UINT32 PackageLength; //包列表长度
} EFI_HII_PACKAGE_LIST_HEADER; //包列表头结构体

HiiAddPackages是只需关注资源包本身,内部会自动完成包列表处理。SimpleFont和Font格式对应包头结构体为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
typedef struct _EFI_HII_SIMPLE_FONT_PACKAGE_HDR {
EFI_HII_PACKAGE_HEADER Header; //资源包头部数据
UINT16 NumberOfNarrowGlyphs; //窄字符个数
UINT16 NumberOfWideGlyphs; //宽字符个数
} EFI_HII_SIMPLE_FONT_PACKAGE_HDR;
typedef struct _EFI_HII_FONT_PACKAGE_HDR {
EFI_HII_PACKAGE_HEADER Header; //资源包头部数据
UINT32 HdrSize; //本结构体大小
UINT32 GlyphBlockOffset; //包中点阵块偏移
EFI_HII_GLYPH_INFO Cell; //字体信息
EFI_HII_FONT_STYLE FontStyle; //字体类型
CHAR16 FontFamily[1]; //字体名称
} EFI_HII_FONT_PACKAGE_HDR;
typedef UINT32 EFI_HII_FONT_STYLE; //如Normal Bold Italic等

例如注册SimpleFont字体:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
EFI_STATUS CreateSimpleFontPkg(EFI_NARROW_GLYPH *NarrowGlyph, UINT32 nNarrow, EFI_WIDE_GLYPH *WideGlyph, UINT32 nWide) {
EFI_HII_SIMPLE_FONT_PACKAGE_HDR *simpleFont; //资源包
UINT8 *Package;
UINT8 *Location = NULL;
UINT32 packageLen = sizeof(EFI_HII_SIMPLE_FONT_PACKAGE_HDR) + nNarrow + nWide + 4;
Package = (UINT8 *)AllocateZeroPool(packageLen);
WriteUnaligned32((UINT32 *)Package, packageLen);
simpleFont = (EFI_HII_SIMPLE_FONT_PACKAGE_HDR *)(Package + 4);
simpleFont->Header.Length = (UINT32)(packageLen - 4);
simpleFont->Header.Type = EFI_HII_PACKAGE_SIMPLE_FONTS;
simpleFont->NumberOfNarrowGlyphs = (UINT16)(nNarrow / sizeof(EFI_NARROW_GLYPH));
simpleFont->NumberOfWideGlyphs = (UINT16)(nWide / sizeof(EFI_WIDE_GLYPH));
Location = (UINT8 *)(&simpleFont->NumberOfWideGlyphs + 1); //放到此处赋值,需要对齐
CopyMem(Location, NarrowGlyph, nNarrow); //复制窄字符点阵字库
Location += nNarrow;
CopyMem(Location, WideGlyph, nWide); //复制宽字符点阵字库
// Add this simplified font package to a package list then install it.
EFI_HII_HANDLE simpleFontHiiHandle = HiiAddPackages(&gSimpleFontPackageListGuid/*用户自定义包列表GUID*/,NULL,Package/*SimpleFont资源包*/,NULL);
if (simpleFontHiiHandle == NULL)
return EFI_NOT_FOUND; //查看了EfiError.h,选择这个返回值
FreePool(Package);
return EFI_SUCCESS;
}

Font格式点阵块结构为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
typedef struct _EFI_HII_GLYPH_BLOCK {
UINT8 BlockType; //点阵块类型
} EFI_HII_GLYPH_BLOCK;
//点阵块类型
#define EFI_HII_GIBT_END 0x00 //结束用
#define EFI_HII_GIBT_GLYPH 0x10 //单字符
#define EFI_HII_GIBT_GLYPHS 0x11 //多字符
#define EFI_HII_GIBT_GLYPH_DEFAULT 0x12 //默认字体的多字符
#define EFI_HII_GIBT_GLYPHS_DEFAULT 0x13 //默认字体的单字符
#define EFI_HII_GIBT_GLYPH_VARIABILITY 0x14 //可变字体
#define EFI_HII_GIBT_DUPLICATE 0x20 //复制现有字体到另一个新字符
#define EFI_HII_GIBT_SKIP2 0x21 //跳过指定字符 1~65535
#define EFI_HII_GIBT_SKIP1 0x22 //跳过指定字符 1~255
#define EFI_HII_GIBT_DEFAULTS 0x23 //默认字体信息
#define EFI_HII_GIBT_EXT1 0x30
#define EFI_HII_GIBT_EXT2 0x31
#define EFI_HII_GIBT_EXT4 0x32
typedef struct _EFI_GLYPH_GIBT_END_BLOCK { //结束用
EFI_HII_GLYPH_BLOCK Header;
} EFI_GLYPH_GIBT_END_BLOCK;
typedef struct _EFI_HII_GIBT_GLYPHS_BLOCK { //多字符
EFI_HII_GLYPH_BLOCK Header;
EFI_HII_GLYPH_INFO Cell;
UINT16 Count;
UINT8 BitmapData[1];
} EFI_HII_GIBT_GLYPHS_BLOCK;
typedef struct _EFI_HII_GIBT_GLYPH_DEFAULT_BLOCK { //默认字体多字符
EFI_HII_GLYPH_BLOCK Header;
UINT8 BitmapData[1];
} EFI_HII_GIBT_GLYPH_DEFAULT_BLOCK;
typedef struct _EFI_HII_GIBT_SKIP2_BLOCK { //跳过指定字符 1~65535
EFI_HII_GLYPH_BLOCK Header;
UINT16 SkipCount;
} EFI_HII_GIBT_SKIP2_BLOCK;

然后用EFI_HII_FONT_PROTOCOL字体Protocol将字符转为位图,显示到屏幕上:

这小节先鸽着。

图像

基础

图像显示也有两种方法,一种对图像格式解析,另一种用HII。BMP文件格式如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
typedef struct {
CHAR8 CharB; //'B'
CHAR8 CharM; //'M'
UINT32 Size; //位图文件大小
UINT16 Reserved[2]; //必须0
UINT32 ImageOffset; //位图数据距离文件头偏移 小端序
UINT32 HeaderSize; //此字段到结构尾长度 0x28
UINT32 PixelWidth; //位图宽
UINT32 PixelHeight; //位图高
UINT16 Planes; ///< Must be 1
UINT16 BitPerPixel; ///< 1, 4, 8, or 24
UINT32 CompressionType; //压缩方式 0、1或2 0不压缩
UINT32 ImageSize; ///< Compressed image size in bytes
UINT32 XPixelsPerMeter; //X方向分辨率 目标设备每米像素数
UINT32 YPixelsPerMeter; //Y方向分辨率 目标设备每米像素数
UINT32 NumberOfColors; //颜色数 0为2^BitPerPixel 一般编程不用
UINT32 ImportantColors; //重要影响的颜色索引数目 0为所有都重要
} BMP_IMAGE_HEADER;

对于BitPerPixel,1为单色,4为16色,8为256色,24为24位真彩色。对于CompressionType,1为8位游程编码BI_RLE8,2为4位游程编码BI_RLE4。对于NumberOfColors,若不为0且小于24,则位图形设备或驱动实际使用的颜色数,等于24则为优化调色板性能的参考色彩表大小。

位图文件头后为位图颜色表数据,有几种颜色就有几种这结构。

1
2
3
4
5
6
typedef struct {
UINT8 Blue; //蓝色分量
UINT8 Green; //绿色分量
UINT8 Red; //红色分量
UINT8 Reserved;
} BMP_COLOR_MAP;

接下来是位图点阵数据,单色、16色和256色图像由颜色索引值组成,24位真彩色由3字节颜色值组成,分别为蓝绿红色分量。

位图点阵数据是4字节对齐的,不够要补齐。

如某行像素值有$n$字节,分别为$b_0,b_1,\cdots,b_{n-1}$。当BitPerPixel为1时,每个字节记录8个像素的颜色索引值。当BitPerPixel为4时,$b_0$位7~4位第1个像素的颜色索引值,3~0位第2个像素的颜色索引值,以此类推。当BitPerPixel为8时,每个字节依次记录1个像素的颜色索引值。当BitPerPixel为24时,每3个字节记录1个像素的蓝绿红分量。

例如256色BMP图像显示如下,文件操作先不讲。但本节代码都没有考虑4字节对齐的问题,显示速度非常慢,可通过直接缓冲区写屏。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
EFI_STATUS ShowBMP256(CHAR16 *fileName,UINTN x,UINTN y) {
EFI_STATUS Status;
VOID *buffBMP = NULL; //存储图像的缓冲器
BMP_IMAGE_HEADER imageHeader; //位图头文件
EFI_FILE_PROTOCOL *file; //文件实例
UINTN bufLength = sizeof(BMP_IMAGE_HEADER); //BMP文件头长度
UINTN index,j,middleValue;
UINT8 *middleBuff,*bmpdata,*bmpplatte;
//1 open file
Status = OpenFile(&file, fileName, EFI_FILE_MODE_READ); //打开文件
if(EFI_ERROR(Status)){
Print(L"ShowBMP256: OpenFile %r\n",Status);
return Status;
}
//2 get datas to buffer
Status=ReadFile(file,&bufLength, &imageHeader); //读取BMP文件头
if(EFI_ERROR(Status)){
Print(L"ShowBMP256: ReadFile 1 %r\n",Status);
CloseFile(file);
return Status;
}
buffBMP = AllocateZeroPool(imageHeader.Size); //分配需要存储BMP文件的内存
if(buffBMP == NULL){
Print(L"ShowBMP256: Allocate memory fial!\n");
CloseFile(file);
return EFI_BUFFER_TOO_SMALL;
}
SetFilePosition(file, 0); //文件最开始处;
// SetFilePosition(file, imageHeader.ImageOffset); //点阵数据最开始处;
bufLength = (UINTN)(imageHeader.Size);
Status=ReadFile(file,&bufLength, buffBMP); //bmp 数据全部读入
if(EFI_ERROR(Status)){
Print(L"ShowBMP256: ReadFile 2 %r\n",Status);
CloseFile(file);
return Status;
}
middleValue = (imageHeader.PixelHeight / 2);
bmpdata=(UINT8 *)buffBMP + imageHeader.ImageOffset; //BMP图像点阵数据位置
bmpplatte=(UINT8 *)buffBMP + sizeof(BMP_IMAGE_HEADER); //BMP位图颜色表位置
middleBuff = AllocateZeroPool(imageHeader.PixelWidth);
for(j=0; j<middleValue; j++){
index = imageHeader.PixelHeight - 1 -j;
CopyMem(middleBuff,bmpdata+j*imageHeader.PixelWidth,imageHeader.PixelWidth);
CopyMem(bmpdata+j*imageHeader.PixelWidth,bmpdata+index*imageHeader.PixelWidth,imageHeader.PixelWidth);
CopyMem(bmpdata+index*imageHeader.PixelWidth,middleBuff,imageHeader.PixelWidth);
}
putBMP256(x,y,imageHeader.PixelWidth,imageHeader.PixelHeight,(EFI_GRAPHICS_OUTPUT_BLT_PIXEL *)bmpplatte ,bmpdata,0); //给定颜色表、点阵数据 进行256色图像显示
FreePool(middleBuff);
FreePool(buffBMP);
CloseFile(file);
return EFI_SUCCESS;
}
VOID putBMP256(UINTN x,UINTN y,UINTN Width,UINTN Height,EFI_GRAPHICS_OUTPUT_BLT_PIXEL *ColorTable,UINT8 *Picture,UINT8 MaskColor){ //显示位置和图像宽高、BMP图颜色表数据、BMP图像点阵数据、掩码颜色
UINTN i,j;
UINT32 index=0;
UINT8 color_number;
for(j=y;j<Height+y;j++)
for(i=x;i<Width+x;i++){
color_number=Picture[index];
if(color_number!=MaskColor)
putpixel(i,j,&(ColorTable[color_number]));
++index;
}
}

24位真彩色BMP图像显示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
EFI_STATUS ShowBMP24True(CHAR16 *fileName,UINTN x,UINTN y){
EFI_STATUS Status;
VOID *buffBMP = NULL; //存储图像的缓冲器
BMP_IMAGE_HEADER imageHeader; //位图文件头
EFI_FILE_PROTOCOL *file; //文件实例
UINTN bufLength = sizeof(BMP_IMAGE_HEADER); //BMP文件头长度
UINTN i, j, maxX, maxY, index;
EFI_GRAPHICS_OUTPUT_BLT_PIXEL color;
UINT8 *pic=NULL;
//1 open file
Status = OpenFile(&file, fileName, EFI_FILE_MODE_READ); //打开文件
if(EFI_ERROR(Status)){ //读取BMP文件头长
Print(L"ShowBMP24True: OpenFile %r\n",Status);
return Status;
}
//2 get datas to buffer
Status=ReadFile(file,&bufLength, &imageHeader);
if(EFI_ERROR(Status)){
Print(L"ShowBMP24True: ReadFile 1 %r\n",Status);
CloseFile(file);
return Status;
}
buffBMP = AllocateZeroPool(imageHeader.Size);
if(buffBMP == NULL){
Print(L"ShowBMP24True: Allocate memory fial!\n");
CloseFile(file);
return EFI_BUFFER_TOO_SMALL;
}
SetFilePosition(file, 0); //文件最开始处;
bufLength = (UINTN)(imageHeader.Size);
Status=ReadFile(file,&bufLength, buffBMP); //bmp 数据读入
if(EFI_ERROR(Status)){
Print(L"ShowBMP24True: ReadFile 2 %r\n",Status);
CloseFile(file);
return Status;
}
pic=(UINT8 *)buffBMP;
maxX = imageHeader.PixelWidth-1;
maxY = imageHeader.PixelHeight-1;
//从缓冲区中读入像素
index = imageHeader.ImageOffset;
for(i=0;i<=maxY;i++)
for(j=x;j<=maxX+x;j++){
color.Blue = pic[index];
color.Green = pic[index+1];
color.Red = pic[index+2];
color.Reserved = 0;
putpixel(j,maxY+y-i,&color);
index+=3;
}
FreePool(buffBMP);
CloseFile(file);
return EFI_SUCCESS;
}