1、Framebuffer是用来一个视频输出设备从包含完整的帧数据的一个内存缓冲区中来驱动一个视频显示设备。
在内存缓冲区中标准上包含了屏幕上每个像素的色彩值组成。色彩值通常存储成1-bit(黑白色彩),4-bit调色版,8-bit调色版,16-bit高色彩,24-bit真色彩格式。一个额外的alpha通道有时用来保存像素透明度信息。
帧缓冲设备提供了显卡的抽象描述。他同时代表了显卡上的显存,应用程序通过定义好的接口可以访问显卡,而不需要知道底层的任何操作。该设备使用特殊的设备节点,通常位于/dev目录,如/dev/fb*
2、以16-bit高色彩格式为例,原理是使用freetype2库来获取汉字的点阵信息,将信息在framebuffer中显示出来。
代码如下:
/*
* fbutils.h
*
* Headers for utility routines for framebuffer interaction
*
* Copyright 2002 Russell King and Doug Lowder
*
* This file is placed under the GPL. Please see the
* file COPYING for details.
*
*/
#ifndef _FBUTILS_H_
#define _FBUTILS_H_
extern int xres, yres;
int OpenFrameBuffer(void);
void CloseFrameBuffer(void);
void ShowChineseString(int x, int y, const char* s, int color, int size);
void ClearScreen(void);
void ClearRect(int x, int y, int nWidth, int nHeight);
#endif
/*
* fbutils.c
*
* Utility routines for framebuffer interaction
*
* Copyright 2002 Russell King and Doug Lowder
*
* This file is placed under the GPL. Please see the
* file COPYING for details.
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include<unistd.h>
#include <sys/fcntl.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/time.h>
#include <linux/fb.h>
#include <linux/kd.h>
#include <linux/vt.h>
#include "gbk2ucs.h"
#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_GLYPH_H
#include FT_SYNTHESIS_H
static int fb_fd;
static struct fb_fix_screeninfo fix;
static struct fb_var_screeninfo var;
static struct fb_cmap cmap;
static char *fbuffer = NULL;
static int fb_fd = -1;
int xres, yres;
static char *defaultfbdevice = "/dev/fb0";
static char *fbdevice = NULL;
#ifndef HANDLE
#define HANDLE void*
#endif
#ifndef BYTE
#define BYTE unsigned char
#endif
#ifndef BOOL
#define BOOL int
#define TRUE (1)
#define FALSE (0)
#endif
#ifndef size_t
#define size_t unsigned long
#endif
#ifndef FT_PIXEL2PT
#define FT_PIXEL2PT(x) ((x)*72/133) //求解特定像素的字体pt大小,默认是133.33dpi
#endif
#ifndef DEF_FONT_FILE
#define DEF_FONT_FILE ( "/config/font/microhei.ttf" ) //默认的字体文件路径
#endif
#define COLOR_TO_MTK_COLOR_SIMUL(color) ((((color) >> 19) & 0x1F) << 11) \
|((((color) >> 10) & 0x3F) << 5) \
|(((color) >> 3) & 0x1F)
/*!
* \brief 定义点阵数据结构体
*/
typedef struct _GLYPHBITMAP
{
int top; //!<基线至点阵项点的距离。显示时,将基线垂直位置减去该值,得到字符左上角位置。
int left; //!<点阵左上角距离基点的水平距离.显示时,将基线水平位置减去该值,得到字符左上角位置。
int advancex; //!<x轴的步进宽度,每显示完一个字符后,显示基点应该水平移动advancex个像素
int advancey; //!<y轴的步进宽度,每显示完一个字符后,显示基点应该垂直移动advancey个像素
BYTE pixelbit; //!<每个像素的bit数,一般只有两种情况,要么是1表示位图,要么是8表示灰度图
BYTE bBold; //!<是否加粗,若加粗,则置为1,否则置为0
BYTE bReserved1;//!<预留
BYTE bReserved2;//!<预留
short underlinePosition; //!<下划线的垂直位置信息,单位是像素,是相对于原点来说的
short underlineThickness; //!<下划线的粗度,单位是像素
int rows; //!<点阵的行值
int width; //!<一行有多少个点
int pitch; //!<一行数据所占的字节数,包括后面的padding
BYTE* buffer; //!<点阵数据
}GLYPHBITMAP, *PGLYPHBITMAP;
//定义字体对象
typedef struct _FT2FONTOBJ
{
FT_Library hLib; //指向FT_LIBRARY
FT_Face hFace; //指定face
size_t nSize; //字体大小
}FT2FONTOBJ;
//加载字符库
HANDLE GnLoadFont( const char* pFontFile, const size_t nSize )
{
if ( NULL == pFontFile || nSize == 0 )
{
return NULL;
}
FT_Library library; //库类
if( 0 == FT_Init_FreeType( &library ))//初始化库
{
FT_Face face;
if( 0 == FT_New_Face( library, pFontFile, 0, &face ))//加载默认的字体库
{
if( 0 == FT_Set_Char_Size( face, 0, nSize * 64, 113, 113 ))//设定字体大小
{
FT2FONTOBJ* pObj = (FT2FONTOBJ*)malloc( sizeof( FT2FONTOBJ ));
if( pObj )
{
pObj->hLib = library;
pObj->hFace = face;
pObj->nSize = nSize;
return pObj;
}
}
}
FT_Done_FreeType( library ); //若失败就释放库
}
return NULL;
}
//释放字体对象
BOOL GnFreeFont( HANDLE hFontObj )
{
if ( NULL == hFontObj )
{
return FALSE;
}
FT2FONTOBJ* pFTObj = (FT2FONTOBJ*)hFontObj;
FT_Done_FreeType( (FT_Library)pFTObj->hLib );
free( pFTObj );
return TRUE;
}
//获取单个字符点阵信息
BOOL GnGetCharBitMap( HANDLE hFontObj, unsigned short charCode, PGLYPHBITMAP pGlyphBitmap )
{
if( NULL == hFontObj || NULL == pGlyphBitmap || charCode == 0x0000 )
{
return FALSE;
}
FT2FONTOBJ* pFTObj = (FT2FONTOBJ*)hFontObj;
FT_GlyphSlot slot = ((FT_Face)pFTObj->hFace)->glyph; //字形slot
FT_UInt nCharIndex = FT_Get_Char_Index( (FT_Face)pFTObj->hFace, charCode );//获取字符的字形索引位置
if( 0 != nCharIndex )
{
if( 0 == FT_Load_Glyph( pFTObj->hFace, nCharIndex, FT_LOAD_DEFAULT ))//加载字形,全屏花355ms
{
if( 0 == FT_Render_Glyph( slot, FT_RENDER_MODE_NORMAL ))//绘制字形,全屏大约花100ms
{
if( pGlyphBitmap->bBold )//加粗字体
{
FT_GlyphSlot_Embolden( slot );
}
pGlyphBitmap->top = slot->bitmap_top;
pGlyphBitmap->left = slot->bitmap_left;
pGlyphBitmap->advancex = slot->advance.x >> 6;//26.6像素格式即1/64像素
pGlyphBitmap->advancey = slot->advance.y >> 6;
pGlyphBitmap->pixelbit = 8; //固定灰度图
pGlyphBitmap->rows = slot->bitmap.rows;
pGlyphBitmap->width = slot->bitmap.width;
pGlyphBitmap->pitch = slot->bitmap.pitch;
pGlyphBitmap->buffer = slot->bitmap.buffer;
pGlyphBitmap->underlinePosition = pFTObj->hFace->underline_position>>6;
pGlyphBitmap->underlineThickness = (pFTObj->hFace->underline_thickness+32)>> 6;//+32是为了四舍五入
if( pGlyphBitmap->underlineThickness == 0 )//防止宽度为0
{
pGlyphBitmap->underlineThickness = 1;
}
return TRUE;
}
}
}
return FALSE;
}
int OpenFrameBuffer(void)
{
unsigned short col[2];
if ( (fbdevice = getenv("TSLIB_FBDEVICE")) == NULL )
{
fbdevice = defaultfbdevice;
}
fb_fd = open(fbdevice, O_RDWR);
if (fb_fd == -1)
{
perror("open fbdevice");
return -1;
}
if (ioctl(fb_fd, FBIOGET_FSCREENINFO, &fix) < 0)
{
perror("ioctl FBIOGET_FSCREENINFO");
close(fb_fd);
return -1;
}
if (ioctl(fb_fd, FBIOGET_VSCREENINFO, &var) < 0)
{
perror("ioctl FBIOGET_VSCREENINFO");
close(fb_fd);
return -1;
}
xres = var.xres;
yres = var.yres;
cmap.start = 0;
cmap.len = 2;
cmap.red = col;
cmap.green = col;
cmap.blue = col;
cmap.transp = NULL;
col[0] = 0;
col[1] = 0xffff;
if(var.bits_per_pixel==8)
{
if (ioctl(fb_fd, FBIOPUTCMAP, &cmap) < 0)
{
perror("ioctl FBIOPUTCMAP");
close(fb_fd);
return -1;
}
}
fbuffer = mmap(NULL, fix.smem_len, PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, fb_fd, 0);
if ( fbuffer == (char *)-1 )
{
perror("mmap framebuffer");
close(fb_fd);
return -1;
}
memset( fbuffer, 0x0, fix.smem_len );
return 0;
}
void CloseFrameBuffer(void)
{
if ( fbuffer != NULL )
{
munmap(fbuffer, fix.smem_len);
close(fb_fd);
}
}
void ShowUnicodeChar(HANDLE hFont, int x, int y, int color, int nSize, unsigned short *pText, int nContainerW, int *nWidth, int *nHeight)
{
int i,j,loc;
GLYPHBITMAP stBitmap;
stBitmap.bBold = 0;
GnGetCharBitMap( hFont, *pText, &stBitmap );//加载字形
size_t m = (y + nSize - stBitmap.top + 1 +var.yoffset) * fix.line_length + (x + stBitmap.left + var.xoffset)*(var.bits_per_pixel/8);
for(i = 0; i < stBitmap.rows; i++)
{
for(j = 0; j < stBitmap.width; j++)
{
loc = m + i * fix.line_length + j * (var.bits_per_pixel/8);
if(loc>=0 && loc<fix.smem_len )
{
switch(var.bits_per_pixel)
{
case 8:
default:
fbuffer[loc] = stBitmap.buffer[i * stBitmap.pitch + j];
break;
case 16:
if (stBitmap.buffer[i * stBitmap.pitch + j] != 0)
*((unsigned short *)(fbuffer + loc))= COLOR_TO_MTK_COLOR_SIMUL(color);
else
*((unsigned short *)(fbuffer + loc))= 0;
break;
case 24:
case 32:
if(color==0)
*((unsigned int *)(fbuffer + loc)) = 0;
else
*((unsigned int *)(fbuffer + loc)) = 0xffffffff;
break;
}
}
}
}
*nWidth = stBitmap.advancex;
*nHeight = stBitmap.advancey;
}
/*
*Description: Get the Width of last line of the unicode string
*Input - nContainerW - the width of container
others - like the name
*Output - nLineNUm - the number of full line. E.g. the width of string is less than the width of nContainer, the nLineNum should be zero
*Return - the width of last line
*
*/
int GetUnicodeStringW(HANDLE hFont, unsigned short *s, int nlen, int nContainerW, int *nLineNum)
{
int nWidth = 0;
int nNum = 0;
int i = 0;
GLYPHBITMAP stBitmap;
for (i = 0; i < nlen; i++)
{
GnGetCharBitMap( hFont, s[i], &stBitmap );//加载字形
if (nWidth + stBitmap.advancex < nContainerW)
{
nWidth += stBitmap.advancex;
}
else
{
nWidth = 0;
nNum++;
}
}
*nLineNum = nNum;
return nWidth;
}
void ShowUnicodeString(int x, int y, unsigned short *s, int nLen, int color, int size)
{
int i;
int nLineNum = 0;
HANDLE hFont;
hFont = GnLoadFont( DEF_FONT_FILE, FT_PIXEL2PT(size));
int nWidth = GetUnicodeStringW(hFont, s, nLen, 800, &nLineNum);
int nCharWidth = 0;
int nCharHeight = 0;
int nCurWidth = 0;
int nCurHeight = 0;
for (i = 0; i < nLen; i++)
{
ShowUnicodeChar(hFont, x - nWidth/2 + nCurWidth,y + nCurHeight, color, size, &s[i], 800, &nCharWidth, &nCharHeight );
nCurWidth = nCurWidth + nCharWidth;
}
GnFreeFont(hFont);
}
void ShowChineseString(int x, int y, char *s, int color, int size)
{
int nLen = GbkToUcs2( NULL, s, nLen ); //计算需要多少内存
unsigned short* szText = (unsigned short*)malloc( (nLen + 1)*sizeof(unsigned short));
if( szText )
{
memset( szText, 0x0, (nLen + 1)*sizeof(unsigned short) );
GbkToUcs2( szText, s, nLen );
ShowUnicodeString(x, y, szText, nLen, color, size);
}
free( szText );
}
void ClearScreen( void )
{
memset( fbuffer, 0x0, fix.smem_len );
}
void ClearRect(int x, int y, int nWidth, int nHeight)
{
int i = 0;
for (i = 0; i < nHeight; i++)
{
memset( fbuffer + fix.line_length*(y+var.yoffset+i) + (x + var.xoffset) * (var.bits_per_pixel/8) , 0x0, nWidth * (var.bits_per_pixel/8));
}
}
#include "fbutils.h"
int main( int argc, char* argv[] )
{
if ( OpenFrameBuffer() != 0 )
{
return -1;
}
ShowChineseString(xres/2, yres/2 - 45, "gn1108欢迎你的到来!", 0xFF0000, 45);
CloseFrameBuffer();
return 0;
}
本例要将汉字转成Unicode码,这部分可以读者自己在网上查找实现方法。