这个电子书的功能很简单,通过在控制台输入"u"/"n"来控制显示上一页,下一页,并且使用轮询方法实现,很占CPU资源,后面我会慢慢改进。源码下载地址:https://download.youkuaiyun.com/download/qq_22863733/10399962
总共3个文件:main.c、function.c、function.h
function.h:
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <linux/fb.h>
#include <fcntl.h>
#include <wchar.h>
#include <ft2build.h>
#include FT_FREETYPE_H
#define WIDTH 80
#define HEIGHT 80
#define FONTSIZE 30
#define iHeadLen 3
#define DBG_PRINTF(...)
typedef struct PageInfo{
unsigned char * pucPagePos;
struct PageInfo *pt_PrePageInfo;
struct PageInfo *pt_NextPageInfo;
}T_PageInfo,*PT_PageInfo;
int lcd_init(void);
void lcd_put_pixel(int x, int y, unsigned int color);
void freetype_init(void);
void draw_bitmap( FT_Bitmap* bitmap, FT_Int x, FT_Int y);
void close_freetype(void);
int OpenTextFile(char *pcFileName);
unsigned int GetCodeFrmUTF8Buf(unsigned char * pucUTF8Buf);
int show_one_font(unsigned int);
unsigned char * show_line(unsigned char *pucLineFirsPostAtFile);
unsigned char* show_one_page(PT_PageInfo ptCurPageInfo);
static void RecordPage(PT_PageInfo ptPageNew);
unsigned char* Renew_pucLcdFirstPosAtFile(unsigned int code,unsigned char * pucCurPosAtFile);
int fd_fb;
struct fb_var_screeninfo var; /* Current var */
struct fb_fix_screeninfo fix; /* Current fix */
int screen_size;
unsigned char *fbmem;
unsigned int line_width;
unsigned int pixel_width;
FT_Library library;
FT_Face face;
FT_GlyphSlot slot;
FT_Matrix matrix; /* transformation matrix */
FT_Vector pen; /* untransformed origin */
FT_Error error;
double angle;
int target_height;
int n, num_chars;
int g_iFdTextFile;
unsigned char *g_pucTextFileMem;
unsigned char *g_pucLcdFirstPosAtFile;
unsigned char *g_pucTextFileMemEnd;
char *TextFileName;
char *FontFile;
T_PageInfo g_tPageInfoHeader;
PT_PageInfo g_ptPageInfoCur;
PT_PageInfo g_ptPages;
function.c:
#include"function.h"
int lcd_init(void)
{
fd_fb = open("/dev/fb0", O_RDWR);
if (fd_fb < 0)
{
printf("can't open /dev/fb0\n");
return -1;
}
if (ioctl(fd_fb, FBIOGET_VSCREENINFO, &var))
{
printf("can't get var\n");
return -1;
}
if (ioctl(fd_fb, FBIOGET_FSCREENINFO, &fix))
{
printf("can't get fix\n");
return -1;
}
line_width = var.xres * var.bits_per_pixel / 8;
pixel_width = var.bits_per_pixel / 8;
screen_size = var.xres * var.yres * var.bits_per_pixel / 8;
fbmem = (unsigned char *)mmap(NULL , screen_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd_fb, 0);
if (fbmem == (unsigned char *)-1)
{
printf("can't mmap\n");
return -1;
}
fprintf ( stderr, "lcd init done!\n");
}
/* color : 0x00RRGGBB */
void lcd_put_pixel(int x, int y, unsigned int color)
{
unsigned char *pen_8 = fbmem+y*line_width+x*pixel_width;
unsigned short *pen_16;
unsigned int *pen_32;
unsigned int red, green, blue;
pen_16 = (unsigned short *)pen_8;
pen_32 = (unsigned int *)pen_8;
switch (var.bits_per_pixel)//不同的像素位数,颜色值格式不同。根据位数设置颜色值格式,并写值。
{//像素的各位就代表着颜色分量值。
case 8:
{
*pen_8 = color;//8位像素的话,颜色值直接赋给这个内存中即可。
break;
}
case 16:
{
/* color : 0x00RRGGBB ,unsigned int 32位color的格式*/
/* 565 */
red = (color >> 16) & 0xff;//右移16位后剩下高16位,再&0xff,又剩下低8位。即取出32位color的16-23位
green = (color >> 8) & 0xff;//取出32color的8-15位
blue = (color >> 0) & 0xff;//取出32color的0-7位
color = ((red >> 3) << 11) | ((green >> 2) << 5) | (blue >> 3);//取出对应的组成565
*pen_16 = color;
break;
}
case 32:
{
*pen_32 = color;//32位像素也直接写即可。
break;
}
default:
{
printf("can't surport %dbpp\n", var.bits_per_pixel);
break;
}
}
}
void freetype_init(void)
{
angle = ( 0.0 / 360 ) * 3.14159 * 2; /* use 25 degrees */
target_height = var.yres;
error = FT_Init_FreeType( &library ); /* initialize library */
error = FT_New_Face( library, FontFile, 0, &face ); /* create face object */
#if 0
/* use 50pt at 100dpi */
error = FT_Set_Char_Size( face, 50 * 64, 0,
100, 0 ); /* set character size */
/* pixels = 50 /72 * 100 = 69 */
#else
FT_Set_Pixel_Sizes(face, FONTSIZE, 0);
#endif
slot = face->glyph; //先使slot指向face->glyph,下面也是通过glyph来设置slot。
/* set up matrix */
matrix.xx = (FT_Fixed)( cos( angle ) * 0x10000L );
matrix.xy = (FT_Fixed)(-sin( angle ) * 0x10000L );
matrix.yx = (FT_Fixed)( sin( angle ) * 0x10000L );
matrix.yy = (FT_Fixed)( cos( angle ) * 0x10000L );
/* the pen position in 26.6 cartesian space coordinates; */
/* start at (0,40) relative to the upper left corner */
pen.x = 0 * 64;
pen.y = ( target_height - FONTSIZE ) * 64;
fprintf(stderr,"freetype init done!\n");
}
void draw_bitmap(FT_Bitmap* bitmap, FT_Int x, FT_Int y)
{
FT_Int i, j, p, q;
FT_Int x_max = x + bitmap->width;
FT_Int y_max = y + bitmap->rows;
for ( i = x, p = 0; i < x_max; i++, p++ )
{
for ( j = y, q = 0; j < y_max; j++, q++ )
{
if ( i < 0 || j < 0 ||
i >= var.xres || j >= var.yres )
continue;
lcd_put_pixel(i,j,bitmap->buffer[q * bitmap->width + p]);
}
}
}
void close_freetype(void)
{
FT_Done_Face( face );
FT_Done_FreeType( library );
}
int OpenTextFile(char *pcFileName)
{
struct stat tStat;
g_iFdTextFile = open(pcFileName, O_RDONLY);
if (0 > g_iFdTextFile)
{
DBG_PRINTF("can't open text file %s\n", pcFileName);
return -1;
}
if(fstat(g_iFdTextFile, &tStat))
{
DBG_PRINTF("can't get fstat\n");
return -1;
}
g_pucTextFileMem = (unsigned char *)mmap(NULL , tStat.st_size, PROT_READ, MAP_SHARED, g_iFdTextFile, 0);
if (g_pucTextFileMem == (unsigned char *)-1)
{
DBG_PRINTF("can't mmap for text file\n");
return -1;
}
g_pucTextFileMemEnd = g_pucTextFileMem + tStat.st_size;
g_tPageInfoHeader.pucPagePos = g_pucTextFileMem + iHeadLen;
return 0;
}
unsigned int GetCodeFrmUTF8Buf(unsigned char * pucUTF8Buf)
{
unsigned int cFirst;
unsigned int cSecond;
unsigned int cThird;
unsigned int cForth;
unsigned int code=0;
if((cFirst=(pucUTF8Buf[0]>>7) == 0))//ASCII
{
code = (unsigned int)pucUTF8Buf[0];
return code;
}
if((cFirst=(pucUTF8Buf[0]>>5) == 6))//110xxxxx 10xxxxxx
{
cFirst=pucUTF8Buf[0]&0x1f;
cSecond=pucUTF8Buf[1]&0x3f;
code = (cFirst<<6)|cSecond;
return code;
}
if((cFirst=(pucUTF8Buf[0]>>4) == 14))//1110xxxx 10xxxxxx 10xxxxxx
{
cFirst=pucUTF8Buf[0]&0xf;
cSecond=pucUTF8Buf[1]&0x3f;
cThird=pucUTF8Buf[2]&0x3f;
code = (cFirst<<12)|(cSecond<<6)|cThird;
return code;
}
if((cFirst=(pucUTF8Buf[0]>>3) == 30))//11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
{
cFirst=pucUTF8Buf[0]&0x7;
cSecond=pucUTF8Buf[1]&0x3f;
cThird=pucUTF8Buf[2]&0x3f;
cForth=pucUTF8Buf[3] &0x3f;
code = (cFirst<<18)|(cSecond<<12)|(cThird<<6)|cForth;
return code;
}
else
{
return -1;
}
}
// Show a font for a Unicode.And will renew pen.x after draw_bitmap()
int show_one_font(unsigned int code)
{
FT_Set_Transform( face, &matrix, &pen );
/* load glyph image into the slot (erase previous one) */
FT_Load_Char( face, code, FT_LOAD_RENDER );//就会设置face->glyph,或slot,转换的位图又保存在哪里?
//位图点阵应该是保存在face->glyph.bitmap或slot->bitmap中。
/* now, draw to our target surface (convert position) */
draw_bitmap( &slot->bitmap,slot->bitmap_left,target_height - slot->bitmap_top );
/* increment pen position */
pen.x += slot->advance.x;
return 0;
}
//will renew pen.x and pen.y after show one line.
unsigned char * show_line(unsigned char *pucLineFirsPostAtFile)
{
unsigned int code = GetCodeFrmUTF8Buf(pucLineFirsPostAtFile);
while(((pen.x/64 +FONTSIZE) <= var.xres) &&(code != '\0'))
{
if (code == '\n')
{
pen.y = pen.y -FONTSIZE*64;
pen.x = FONTSIZE*2*64;
pucLineFirsPostAtFile=Renew_pucLcdFirstPosAtFile(code,pucLineFirsPostAtFile);
code = GetCodeFrmUTF8Buf(pucLineFirsPostAtFile);
return pucLineFirsPostAtFile;
}
else if (code == '\r')
{
pucLineFirsPostAtFile=Renew_pucLcdFirstPosAtFile(code,pucLineFirsPostAtFile);
code = GetCodeFrmUTF8Buf(pucLineFirsPostAtFile);
return pucLineFirsPostAtFile;
}
else if (code == '\t')
{
/* TAB键用一个空格代替 */
code = ' ';
}
show_one_font(code);
pucLineFirsPostAtFile=Renew_pucLcdFirstPosAtFile(code,pucLineFirsPostAtFile);
code = GetCodeFrmUTF8Buf(pucLineFirsPostAtFile);
}
if((pen.x/64 + FONTSIZE) > var.xres || (code == '\0'))
{
pen.x=0;
pen.y = pen.y - FONTSIZE*64;
}
return pucLineFirsPostAtFile;
}
unsigned char* show_one_page(PT_PageInfo ptCurPageInfo)
{
PT_PageInfo ptPageToRecord = malloc(sizeof(T_PageInfo));
unsigned char * puctmp=ptCurPageInfo->pucPagePos;
while(pen.y-64*FONTSIZE >=0)
{
puctmp = show_line(puctmp);
}
if(ptCurPageInfo->pt_NextPageInfo == NULL)
{
ptPageToRecord->pucPagePos=puctmp;
RecordPage(ptPageToRecord);
}
pen.y = ( target_height - FONTSIZE ) * 64;
return puctmp;
}
static void RecordPage(PT_PageInfo ptPageNew)
{
PT_PageInfo ptPage;
if (!g_ptPages)
{
g_ptPages = ptPageNew;
}
else
{
ptPage = g_ptPages;
while (ptPage->pt_NextPageInfo)
{
ptPage = ptPage->pt_NextPageInfo;
}
ptPage->pt_NextPageInfo = ptPageNew;
ptPageNew->pt_PrePageInfo = ptPage;
ptPageNew->pt_NextPageInfo = NULL;
}
}
unsigned char* Renew_pucLcdFirstPosAtFile(unsigned int code,unsigned char *pucCurPosAtFile)
{
int pitch;
if( 0<=code &&code<=127 )
{
pitch = 1;
}
else if( 128<=code &&code<=2047 )
{
pitch = 2;
}
else if( 2048<=code &&code<=65535 )
{
pitch = 3;
}
else if( 65536<=code &&code<=1114111 )
{
pitch = 4;
}
else
{
fprintf(stderr,"renew err\n");
return pucCurPosAtFile;
}
pucCurPosAtFile=&pucCurPosAtFile[pitch];
return pucCurPosAtFile;
}
main.c:
#include "function.h"
int main(int argc,char** argv)
{
char cOpr;
if ( argc != 3 )
{
fprintf ( stderr, "usage: %s FontFile TextFileName\n", argv[0] );
exit( 1 );
}
lcd_init();
memset(fbmem, 0, screen_size);
FontFile = argv[1];
freetype_init();
TextFileName = argv[2];
OpenTextFile(TextFileName);
g_ptPageInfoCur = &g_tPageInfoHeader;
g_ptPages = &g_tPageInfoHeader;
show_one_page(g_ptPageInfoCur);
while (1)
{
printf("Enter 'n' to show next page, 'u' to show previous page, 'q' to exit: ");
do {
cOpr = getchar();
} while ((cOpr != 'n') && (cOpr != 'u') && (cOpr != 'q'));
if (cOpr == 'n')
{
if(g_ptPageInfoCur->pt_NextPageInfo->pucPagePos==g_pucTextFileMemEnd)
{
printf("is the end!\n");
continue;
}
memset(fbmem, 0, screen_size);
show_one_page(g_ptPageInfoCur->pt_NextPageInfo);
g_ptPageInfoCur=g_ptPageInfoCur->pt_NextPageInfo;
}
else if (cOpr == 'u')
{
if(g_ptPageInfoCur->pt_PrePageInfo == NULL)
{
printf("this is first page!\n");
}
else
{
memset(fbmem, 0, screen_size);
show_one_page((g_ptPageInfoCur->pt_PrePageInfo));
g_ptPageInfoCur=g_ptPageInfoCur->pt_PrePageInfo;
}
}
else
{
break;
}
}
close_freetype();
close(fd_fb);
return 0;
}
电子书效果(为方便观察,我把字体调大了点,可在function.h文件中修改字体大小:#define FONTSIZE 30):