这个电子书的功能很简单,通过在控制台输入"u"/"n"来控制显示上一页,下一页,并且使用轮询方法实现,很占CPU资源,后面我会慢慢改进。源码下载地址:https://download.csdn.net/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):