在linux系统中,使用framebuffer来提供用户态进程直接操作显示屏的功能.
在嵌入式系统开发中,需要对显示屏的内容进行截取,实现一个lcd截屏工具实现对显示屏内容的截取,存储为bmp格式.
一个bmp文件有四部分组成:
其中位图文件头内容如下:
WORD bfType;
DWORD bfSize;
WORD bfReserved1;
WORD bfReserved2;
DWORD bfOffBits;
bfType 说明文件的类型,该值必需是0x4D42,也就是字符'BM',否则表示根本不是BMP
bfSize 说明该位图文件的大小,用字节为单位
bfReserved1 保留,必须设置为0
bfReserved2 保留,必须设置为0
bfOffBits 说明从文件头开始到实际的图象数据之间的字节的偏移量。这个参数是非常有用的,因为位图信息头和调色板的长度会根据不同情况而变化,所以你可以用这个偏移值迅速的从文件中读取到位数据。
位图信息段内容如下:
DWORD biSize;
LONG biWidth;
LONG biHeight;
WORD biPlanes;
WORD biBitCount
DWORD biCompression;
DWORD biSizeImage;
LONG biXPelsPerMeter;
LONG biYPelsPerMeter;
DWORD biClrUsed;
DWORD biClrImportant;
biSize 说明BITMAPINFOHEADER结构所需要的字节数
biWidth 说明图象的宽度,以象素为单位
biHeight 说明图象的高度,以象素为单位。注:这个值除了用于描述图像的高度之外,它还有另一个用处,就是指明该图像是倒向的位图,还是正向的位图。如果该值是一个正数,说明图像是倒向的,即:数据的第一行其实是图像的最后一行,如果该值是一个负数,则说明图像是正向的。大多数的BMP文件都是倒向的位图,也就是时,高度值是一个正数。
biPlanes 表示bmp图片的平面属,显然显示器只有一个平面,所以恒等于1
biBitCount 说明比特数/象素,其值为1、4、8、16、24、或32。
biCompression 说明图象数据压缩的类型,其中:
BI_RGB:没有压缩
BI_RLE8:每个象素8比特的RLE压缩编码,压缩格式由2字节组成(重复象素计数和颜色索引);
BI_RLE4:每个象素4比特的RLE压缩编码,压缩格式由2字节组成
BI_BITFIELDS:每个象素的比特由指定的掩码决定。
BI_JPEG:JPEG格式
biSizeImage 说明图象的大小,以字节为单位。当用BI_RGB格式时,可设置为0。
biXPelsPerMeter 说明水平分辨率,用象素/米表示。
biYPelsPerMeter 说明垂直分辨率,用象素/米表示。
biClrUsed 说明位图实际使用的彩色表中的颜色索引数(设为0的话,则说明使用所有调色板项)。
biClrImportant 说明对图象显示有重要影响的颜色索引的数目,如果是0,表示都重要。
由于当前嵌入式设备使用的显示接口为RGB565格式,选择 biBitCount为16的格式来存储显示屏数据.显示屏大小为800x600.
实现代码如下:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/soundcard.h>
#include <stdio.h>
#include <unistd.h>
#include <math.h>
#include <string.h>
#include <stdlib.h>
static unsigned char sg_BHeader[] = {
0x42, 0x4D, 0x36, 0x58, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x28, 0x00,
0x00, 0x00, 0x40, 0x01, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x00, 0x01, 0x00, 0x10, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
#define RGB565TO1555(rgb) ((unsigned short)((unsigned short)(rgb & 0x001f) | ((unsigned short)(rgb & 0xffc0) >> 1)))
void SaveBMPFile(unsigned char *raw, char *filename)
{
unsigned short *p = (unsigned short *)raw;
typedef unsigned int UINT;
typedef unsigned char UCHAR;
UINT m_Width = 800, m_Height = 480;
UINT i, j;
int bmp = open(filename, O_WRONLY | O_CREAT);
if(bmp < 0)
return;
sg_BHeader[0x02] = (UCHAR)(m_Width * m_Height * 2 + 0x36) & 0xff;
sg_BHeader[0x03] = (UCHAR)((m_Width * m_Height * 2 + 0x36) >> 8) & 0xff;
sg_BHeader[0x04] = (UCHAR)((m_Width * m_Height * 2 + 0x36) >> 16) & 0xff;
sg_BHeader[0x05] = (UCHAR)((m_Width * m_Height * 2 + 0x36) >> 24) & 0xff;
sg_BHeader[0x12] = (UCHAR)m_Width & 0xff;
sg_BHeader[0x13] = (UCHAR)(m_Width >> 8) & 0xff;
sg_BHeader[0x14] = (UCHAR)(m_Width >> 16) & 0xff;
sg_BHeader[0x15] = (UCHAR)(m_Width >> 24) & 0xff;
sg_BHeader[0x16] = (UCHAR)m_Height & 0xff;
sg_BHeader[0x17] = (UCHAR)(m_Height >> 8) & 0xff;
sg_BHeader[0x18] = (UCHAR)(m_Height >> 16) & 0xff;
sg_BHeader[0x19] = (UCHAR)(m_Height >> 24) & 0xff;
write(bmp, sg_BHeader, sizeof(sg_BHeader));
for(i = 0; i < m_Height; i++)
{
unsigned short *c = p + (m_Height - 1 - i) * m_Width;
unsigned short cc;
for(j = 0; j < m_Width; j++)
{
cc = RGB565TO1555(*(c + j));
// cc = *(c + j);
write(bmp, &cc, 2);
}
}
close(bmp);
}
int main(int argc, char *argv[])
{
unsigned char buf[800*480*2];
char *filename;
int fb;
fb = open("/dev/fb0", O_RDONLY);
if(fb < 0)
exit(1);
if(argc == 2)
filename = argv[1];
else
exit(1);
printf("reading screen...\n");
read(fb, buf, 800*480*2);
close(fb);
printf("saving screen...\n");
SaveBMPFile(buf, filename);
printf("file %s created successfully\n", filename);
exit(0);
}
linux中将framebuffer保存为png、bmp图片
遇到一个需求,在读取/dev/fb0的原始数据并保存为bmp,png图片,并通过命令行格式进行保存.
写的不好,大家可以指点出来,一起讨论.
也将代码上传到github上了,地址:
https://github.com/Guazhen/Framebuffer_shot/blob/master/framework_shot.c
root@imx6qsabresd:~# ./imx6_shot -h
usage: ./imx6_shot [-hpb] [FILENAME]
imx6 [option]…
-p|–png Save the file as a png.
-b|–bmp Save the file as a bmp
-h|–help help information.
If FILENAME ends with .png it will be saved as a png.
If FILENAME ends with .bmp it will be saved as a bmp.
If FILENAME is not given, the default will be saved as a png.
实现代码如下:
#include <linux/fb.h>
#include <stdio.h>
#include <stdint.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <getopt.h>
#include <strings.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/vt.h>
#include <png.h>
#include <zlib.h>
static int Blue = 0;
static int Green = 1;
static int Red = 2;
static int Alpha = 3;
typedef unsigned short WORD;
typedef unsigned int DWORD;
typedef unsigned long LONG;
typedef struct tagBITMAPFILEHEADER {
WORD bfType;
DWORD bfSize;
WORD bfReserved1;
WORD bfReserved2;
DWORD bfOffBits;
} __attribute__((packed)) BITMAPFILEHEADER;
typedef struct tagBITMAPINFOHEADER
{
DWORD biSize; /*info header size in bytes*/
DWORD biWidth; /*widht of image*/
DWORD biHeight;/*height of image*/
WORD biPlanes;/*number of colour planes*/
WORD biBitCount;/*bits per pixel*/
DWORD biCompression;/*compression type*/
DWORD biSizeImage;/*image size meter*/
DWORD biXPelsPerMeter;/*pixels per meter*/
DWORD biYPelsPerMeter;/*pexels per meter*/
DWORD biClrUsed;/*number of colour*/
DWORD biClrImportant;/*important colour*/
} __attribute__((packed)) BITMAPINFOHEADER;
int png_file;
int bmp_file;
struct fb_fix_screeninfo finfo;
struct fb_var_screeninfo vinfo;
static const struct option long_options[]=
{
{"png",1,NULL,'p'},
{"bmp",1,NULL,'b'},
{"help",1,NULL,'h'},
{NULL,0,NULL,0}
};
static void usage(const char* pname)
{
fprintf(stderr,
"usage: %s [-hpb] [FILENAME]\n"
"imx6 [option]...\n"
" -p|--png Save the file as a png.\n"
" -b|--bmp Save the file as a bmp\n"
" -h|--help help information.\n"
"If FILENAME ends with .png it will be saved as a png.\n"
"If FILENAME ends with .bmp it will be saved as a bmp.\n"
"If FILENAME is not given, the default will be saved as a png.\n",
pname
);
};
static void image_bmp( const char *filename)
{
printf("starting bmp..\n");
FILE *fp;
BITMAPFILEHEADER bmfh;
BITMAPINFOHEADER bmih;
/*bmp图片的开头--BM开头*/
((unsigned char *)&bmfh.bfType)[0] = 'B';
((unsigned char *)&bmfh.bfType)[1] = 'M';
bmfh.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + vinfo.yres * vinfo.xres * 4;
bmfh.bfReserved1 = 0;
bmfh.bfReserved2 = 0;
bmfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
bmih.biSize = sizeof(BITMAPINFOHEADER);
bmih.biWidth = vinfo.xres;
bmih.biHeight = vinfo.yres;
bmih.biPlanes = 1;
bmih.biBitCount = 32;
bmih.biCompression = 0;
bmih.biSizeImage = 0; /*说明图像的大小,以字节为单位。当用BI_RGB格式时,总设置为0*/
bmih.biXPelsPerMeter = 0; /*缺省值*/
bmih.biYPelsPerMeter = 0;
bmih.biClrUsed = 0; /*说明位图实际使用的调色板索引数,0:使用所有的调色板索引*/
bmih.biClrImportant = 0; /*说明对图像显示有重要影响的颜色索引的数目,如果是0,表示都重要*/
printf("filename = %s\n",filename);
/*打开文件要存储的文件*/
FILE* image_file = fopen(filename,"a");
if( NULL == image_file)
{
printf("image fopen fail\n");
}
/*写图片文件的头部格式信息*/
fwrite(&bmfh, sizeof(BITMAPFILEHEADER),1,image_file);
fwrite(&bmih, sizeof(BITMAPINFOHEADER),1,image_file);
FILE *raw_file = fopen( "test.raw","rb");
if( NULL == raw_file)
{
printf("rawfile fopen fail..\n");
}
int ch = getc(raw_file);
int x, y;
for( y = vinfo.yres - 1; y >= 0; y--)
{
for(x = 0; x < vinfo.xres; x++)
{
/*字节数*/
long location = (x + vinfo.xoffset) * (vinfo.bits_per_pixel/8) + (y + vinfo.yoffset) * finfo.line_length;
fseek(raw_file, location, SEEK_SET);
ch = fgetc(raw_file);
fputc(ch,image_file);
ch = fgetc(raw_file);
fputc(ch,image_file);
ch = fgetc(raw_file);
fputc(ch,image_file);
ch = fgetc(raw_file);
fputc(ch,image_file);
}
}
fp = popen("rm ./test.raw","r");
pclose(fp);
fclose(raw_file);
fclose(image_file);
printf("ending bmp\n");
}
static void image_png( const char *filename)
{
struct fb_var_screeninfo fb_varinfo;
int fd;
int bitdepth, height, width;
size_t buf_size;
size_t buf_size1;
unsigned char *inbuffer;
unsigned char *outbuffer;
/*fb_fix_screeninfo信息的设置*/
memset(&fb_varinfo, 0, sizeof(struct fb_var_screeninfo));
/*打开fb0设备节点*/
fd = open("/dev/fb0",O_RDWR);
if( fd == -1)
{
printf("open dev fb0 error\n");
return -1;
}
ioctl(fd,FBIOGET_VSCREENINFO, &fb_varinfo);
printf("xres = %u yres = %u\n",fb_varinfo.xres,fb_varinfo.yres);
bitdepth = (int)fb_varinfo.bits_per_pixel;
width = (int)fb_varinfo.xres;
height = (int)fb_varinfo.yres;
/*存储raw文件*/
Blue = fb_varinfo.blue.offset >> 3;
Green = fb_varinfo.green.offset >> 3;
Red = fb_varinfo.red.offset >> 3;
Alpha = fb_varinfo.transp.offset >> 3;
/*计算缓存大小*/
buf_size = width * height * (bitdepth / 8);
/*分配空间大小*/
inbuffer = malloc(buf_size);
if(inbuffer == NULL)
{
printf("malloc error\n");
return -1;
}
outbuffer = malloc(buf_size);
if( outbuffer == NULL)
{
printf("malloc error\n");
return -1;
}
memset(inbuffer,0, buf_size);
/*将原始数据存储到buf中*/
if( read(fd, inbuffer, buf_size) != (ssize_t)buf_size)
{
printf("not enough memory or data\n");
return -1;
}
unsigned int i;
for( i = 0; i < (unsigned int) height*width; i++)
{
/* BLUE = 0 */
outbuffer[(i<<2)+Blue] = inbuffer[i*4+Blue];
/* GREEN = 1 */
outbuffer[(i<<2)+Green] = inbuffer[i*4+Green];
/* RED = 2 */
outbuffer[(i<<2)+Red] = inbuffer[i*4+Red];
/* ALPHA */
outbuffer[(i<<2)+Alpha] = inbuffer[i*4+Alpha];
}
FILE *outfile = NULL;
//png_bytep row_pointers[height];
png_bytep *row_pointers = malloc(sizeof(png_bytep)*height);
if( NULL == row_pointers)
{
printf("malloc row_pointers\n");
}
outfile = fopen(filename,"wb");
for( i = 0; i < height; i++)
row_pointers[i] = outbuffer + i*4*width;
png_structp png_ptr;
/**/
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
(png_voidp) NULL, (png_error_ptr) NULL, (png_error_ptr) NULL);
if( !png_ptr)
{
printf("png_create_write_struct error\n");
return -1;
}
png_infop info_ptr;
/*分配内存并初始化图像信息数据*/
info_ptr = png_create_info_struct(png_ptr);
if(!info_ptr)
{
printf("png_create_info_struct\n");
png_destroy_write_struct(&png_ptr,&info_ptr);
return -1;
}
if(setjmp(png_jmpbuf(png_ptr)))
{
fclose(fd);
png_destroy_write_struct(&png_ptr,&info_ptr);
return -1;
}
/*设置输出控制,如果使用的是c的标准I/O流*/
png_init_io(png_ptr,outfile);
/*读取图像宽度(width),高度(height),位深(bit_depth),颜色类型(color_type),压缩方法(compression_type)*/
/*滤波器方法(filter_type),隔行扫描方式(interlace_type)*/
png_set_IHDR(png_ptr,info_ptr,width,height,8,PNG_COLOR_TYPE_RGB_ALPHA,
PNG_INTERLACE_NONE,PNG_COMPRESSION_TYPE_DEFAULT,PNG_FILTER_TYPE_DEFAULT);
/*写入文件头信息(必需)*/
png_write_info(png_ptr,info_ptr);
/*写png文件格式内容*/
png_write_image(png_ptr,row_pointers);
/*写png的结束标记*/
png_write_end(png_ptr,info_ptr);
free(row_pointers);
/*释放&png_ptr,&info_ptr内存空间*/
png_destroy_write_struct(&png_ptr,&info_ptr);
if( outfile != NULL)
{
(void)fclose(outfile);
}
return 0;
}
int main(int argc, char **argv)
{
int opt = 0;
int options_index = 0;
char *tmp = NULL;
char filename[126] = {0};
char type[126] = {0};
const char *fn;
int len;
if(argc == 1)
{
usage(argv[0]);
return 2;
}
/* 解析命令行参数*/
while((opt=getopt_long(argc,argv,"pbh?",long_options,&options_index))!=EOF )
{
switch(opt)
{
case 'p':
png_file=1;
//sprintf(filename,"%s",optarg);
if(argv[optind] == NULL)
{
sprintf(filename, "%s.png", argv[0]);
printf("filename = %s\n", filename);
}
else
{
//sprintf(filename, "%s.png", argv[0]);
fn = argv[optind];
len = strlen(fn);
if (len >= 4 && 0 == strcmp(fn+len-4, ".png")) {
sprintf(filename, "%s", argv[optind]);
printf("filename = %s\n", filename);
}
else
{
sprintf(filename, "%s.png", argv[optind]);
printf("filename = %s\n", filename);
}
}
break;
case 'b':
bmp_file=1;
//sprintf(type,"%s",optarg);
if(argv[optind] == NULL)
{
sprintf(filename, "%s.bmp", argv[0]);
printf("filename = %s\n", filename);
}
else
{
fn = argv[optind];
len = strlen(fn);
if (len >= 4 && 0 == strcmp(fn+len-4, ".bmp")) {
sprintf(filename, "%s", argv[optind]);
printf("filename = %s\n", filename);
}
else
{
sprintf(filename, "%s.bmp", argv[optind]);
printf("filename = %s\n", filename);
}
}
break;
case 'h':
case '?':
usage(argv[0]);return 2;break;
}
}
int fb_fd = open("/dev/fb0",O_RDWR);
if(fb_fd == -1)
{
printf("open fail..\n");
return -1;
}
ioctl(fb_fd, FBIOGET_VSCREENINFO, &vinfo);
ioctl(fb_fd, FBIOGET_FSCREENINFO, &finfo);
close(fb_fd);
long screensize = vinfo.yres_virtual * finfo.line_length;
if( !bmp_file && !png_file)
{
png_file = 1;
sprintf(filename, "%s.png", argv[0]);
}
/*存储为bmp文件*/
if( bmp_file)
{
FILE *fp = popen("cat /dev/fb0 >> test.raw","r");
pclose(fp);
printf("bmp_file = %s\n", filename);
image_bmp(filename);
}
/*默认保存为png, 或是直接选择-p 保存为png图片*/
if( png_file)
{
printf("bmp_file = %s\n", filename);
image_png(filename);
}
return 0;
}
s3c2416板上实现framebuffer显示中文
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
/*
* 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));
}
}
main.c
#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码,这部分可以读者自己在网上查找实现方法。