电子书——main.c + draw.c(核心)

一、main.c 与 draw.c 介绍
1)main.c与draw.c 的在电子书项目中的位置如下
	|---draw
	|-----draw.c
	|---main.c
2)draw.c 和 main.c 在电子书中的地位、作用
	2.1) main.c  顾名思义是电子书项目的入口,主要进行一些初始化工作后显示一页,
	      然后进入while(1)等待用户的输入操作(下一页/前一页/退出)
	2.2) draw.c  是电子书项目的核心层,换句话说,起到“承上启下”的作用。
	      向下与底层三个子模块的管理者打交道,向上给main.c提供接口。
	      这些接口包括:打开文本文件、设置文本文件、显示一页,显示下一页,显示前一页等关键接口。
3) 两个文件的流程图,如下

电子书的main.c流程图
电子书的draw.c页切换

二、main.c 与 draw.c源码实现
main.c
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <config.h>
#include <draw.h>
#include <encoding_manager.h>
#include <fonts_manager.h>
#include <disp_manager.h>
#include <string.h>

/* ./show_file [-s Size] [-f freetype_font_file] [-h HZK] <text_file> */
int main(int argc, char ** argv)
{
    int iError;
    unsigned int dwFontSize = 16;
    char acHzkFile[128];
    char acFreetypeFile[128];
    char acTextFile[128];
    char acDisplay[128];
    char cOpr;
    int  bList = 0;
    acHzkFile[0] = '\0';
    acFreetypeFile[0] = '\0';
    acTextFile[0] = '\0';
    
    strcpy(acDisplay, "fb");
    while ((iError = getopt(argc, argv, "ls:f:h:d:")) != -1)
    {
        switch (iError)
        {
            case 'l':
            {
                bList = 1;
                break;
            }
            case 's':
            {
                dwFontSize = strtoul(optarg, NULL, 0);
                break;
            }
            case 'f':
            {
                strncpy(acFreetypeFile, optarg, 128);
                acFreetypeFile[127] = '\0';
            }
            case 'h':
   	   {
     		strncpy(acHzkFile, optarg, 128);
     		acHzkFile[127] = '\0';
     		break;
   	   }
   	   case 'd':
   	   {
   		strncpy(acDisplay, optarg, 128);
    		acDisplay[127] = '\0';
    		break;
   	   }
   	   default:
   	   {
     		printf("Usage: %s [-s Size] [-d display] [-f font_file] [-h HZK] <text_file>\n", argv[0]);
     		printf("Usage: %s -l\n", argv[0]);
     		return -1;
     		break;
   	   }
       }
    }
    if (!bList && (optind >= argc))
    {
  	printf("Usage: %s [-s Size] [-d display] [-f font_file] [-h HZK] <text_file>\n", argv[0]);
  	printf("Usage: %s -l\n", argv[0]);
  	return -1;
    } 
    iError = DisplayInit();
    if (iError)
    {
  	printf("DisplayInit error!\n");
  	return -1;
    }
    iError = FontsInit();
    if (iError)
    {
  	printf("FontsInit error!\n");
  	return -1;
    }
    iError = EncodingInit();
    if (iError)
    {
  	printf("EncodingInit error!\n");
  	return -1;
    }
    if (bList)
    {
  	printf("supported display:\n");
  	ShowDispOpr();
  	printf("supported font:\n");
  	ShowFontOpr();
  	printf("supported encoding:\n");
  	ShowEncodingOpr();
  	return 0;
    }
    strncpy(acTextFile, argv[optind], 128);
    acTextFile[127] = '\0';
    iError = OpenTextFile(acTextFile);
    if (iError)
    {
  	printf("OpenTextFile error!\n");
  	return -1;
    }
    iError = SetTextDetail(acHzkFile, acFreetypeFile, dwFontSize);
    if (iError)
    {
  	printf("SetTextDetail error!\n");
  	return -1;
    }
    DBG_PRINTF("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
    iError = SelectAndInitDisplay(acDisplay);
    if (iError)
    {
  	printf("SelectAndInitDisplay error!\n");
  	return -1;
    }
    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')
    	{
   		ShowNextPage();
    	}
    	else if (cOpr == 'u')
    	{
   		ShowPrePage();   
    	}
    	else 
    	{
   		return 0;
    	}   
   }
   return 0;
}
draw.c
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <config.h>
#include <draw.h>
#include <encoding_manager.h>
#include <fonts_manager.h>
#include <disp_manager.h>
#include <string.h>

typedef struct PageDesc {
 int iPage;
 unsigned char *pucLcdFirstPosAtFile;
 unsigned char *pucLcdNextPageFirstPosAtFile;
 struct PageDesc *ptPrePage;
 struct PageDesc *ptNextPage;
} T_PageDesc, *PT_PageDesc;

static int g_iFdTextFile;
static unsigned char *g_pucTextFileMem;
static unsigned char *g_pucTextFileMemEnd;
static PT_EncodingOpr g_ptEncodingOprForFile;

static PT_DispOpr g_ptDispOpr
static int g_dwFontSize;;

static unsigned char *g_pucLcdFirstPosAtFile;
static unsigned char *g_pucLcdNextPosAtFile;

static PT_PageDesc g_ptPages   = NULL;
static PT_PageDesc g_ptCurPage = NULL;

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_ptEncodingOprForFile = SelectEncodingOprForFile(g_pucTextFileMem);
 	if (g_ptEncodingOprForFile)
 	{
  		g_pucLcdFirstPosAtFile = g_pucTextFileMem + g_ptEncodingOprForFile->iHeadLen;
  		return 0;
 	}
 	else
 	{
  		return -1;
 	}
}

int SetTextDetail(char *pcHZKFile, char *pcFileFreetype, unsigned int dwFontSize)
{
 	int iError = 0;
 	PT_FontOpr ptFontOpr;
 	PT_FontOpr ptTmp;
 	int iRet = -1;
	g_dwFontSize = dwFontSize;
 	ptFontOpr = g_ptEncodingOprForFile->ptFontOprSupportedHead;
 	
 	while (ptFontOpr)
 	{
  		if (strcmp(ptFontOpr->name, "ascii") == 0)
  		{
   			iError = ptFontOpr->FontInit(NULL, dwFontSize);
  		}
  		else if (strcmp(ptFontOpr->name, "gbk") == 0)
  		{
   			iError = ptFontOpr->FontInit(pcHZKFile, dwFontSize);
  		}
  		else
  		{
   			iError = ptFontOpr->FontInit(pcFileFreetype, dwFontSize);
  		}
  		DBG_PRINTF("%s, %d\n", ptFontOpr->name, iError);
  		ptTmp = ptFontOpr->ptNext;
  		if (iError == 0)
  		{
   			/* 比如对于ascii编码的文件, 可能用ascii字体也可能用gbk字体, 
    			* 所以只要有一个FontInit成功, SetTextDetail最终就返回成功
    			*/
   			iRet = 0;
  		}
  		else
  		{
   			DelFontOprFrmEncoding(g_ptEncodingOprForFile, ptFontOpr);
  		}
  		ptFontOpr = ptTmp;
 	}
 	return iRet;
}

int SelectAndInitDisplay(char *pcName)
{
 	int iError;
 	
 	g_ptDispOpr = GetDispOpr(pcName);
 	if (!g_ptDispOpr)
 	{
  		return -1;
 	}
 	iError = g_ptDispOpr->DeviceInit();
 	return iError;
}
int IncLcdX(int iX)
{
 	if (iX + 1 < g_ptDispOpr->iXres)
  		return (iX + 1);
 	else
  		return 0;
}
int IncLcdY(int iY)
{
 	if (iY + g_dwFontSize < g_ptDispOpr->iYres)
  		return (iY + g_dwFontSize);
 	else
  		return 0;
}
int RelocateFontPos(PT_FontBitMap ptFontBitMap)
{
 	int iLcdY;
 	int iDeltaX;
 	int iDeltaY;
 	
 	if (ptFontBitMap->iYMax > g_ptDispOpr->iYres)
 	{
  		/* 满页了 */
  		return -1;
 	}
 	/* 超过LCD最右边 */
 	if (ptFontBitMap->iXMax > g_ptDispOpr->iXres)
 	{
  		/* 换行 */  
  		iLcdY = IncLcdY(ptFontBitMap->iCurOriginY);
  		if (0 == iLcdY)
  		{
  			/* 满页了 */
   			return -1;
  		}
  		else
  		{
   			/* 没满页 */
   			iDeltaX = 0 - ptFontBitMap->iCurOriginX;
   			iDeltaY = iLcdY - ptFontBitMap->iCurOriginY;
   			ptFontBitMap->iCurOriginX  += iDeltaX;
   			ptFontBitMap->iCurOriginY  += iDeltaY;
   			ptFontBitMap->iNextOriginX += iDeltaX;
   			ptFontBitMap->iNextOriginY += iDeltaY;
  			ptFontBitMap->iXLeft += iDeltaX;
   			ptFontBitMap->iXMax  += iDeltaX;
   			ptFontBitMap->iYTop  += iDeltaY;
   			ptFontBitMap->iYMax  += iDeltaY;;
   			return 0; 
  		}
 	}
 	return 0;
}

int ShowOneFont(PT_FontBitMap ptFontBitMap)
{
	int x;
 	int y;
 	unsigned char ucByte = 0;
 	int i = 0;
 	int bit;
 	
 	if (ptFontBitMap->iBpp == 1)
 	{
  		for (y = ptFontBitMap->iYTop; y < ptFontBitMap->iYMax; y++)
  		{
   			i = (y - ptFontBitMap->iYTop) * ptFontBitMap->iPitch;
   			for (x = ptFontBitMap->iXLeft, bit = 7; x < ptFontBitMap->iXMax; x++)
   			{
    				if (bit == 7)
    				{
     					ucByte = ptFontBitMap->pucBuffer[i++];
    				}
    				if (ucByte & (1<<bit))
    				{
     					g_ptDispOpr->ShowPixel(x, y, COLOR_FOREGROUND);
    				}
    				else
    				{
     					/* 使用背景色, 不用描画 */
     					// g_ptDispOpr->ShowPixel(x, y, 0); /* 黑 */
    				}
    				bit--;
    				if (bit == -1)
    				{
     					bit = 7;
    				}
   			}
  		}
 	}
 	else if (ptFontBitMap->iBpp == 8)
 	{
  		for (y = ptFontBitMap->iYTop; y < ptFontBitMap->iYMax; y++)
   			for (x = ptFontBitMap->iXLeft; x < ptFontBitMap->iXMax; x++)
  	 		{
    				//g_ptDispOpr->ShowPixel(x, y, ptFontBitMap->pucBuffer[i++]);
    				if (ptFontBitMap->pucBuffer[i++])
     					g_ptDispOpr->ShowPixel(x, y, COLOR_FOREGROUND);
   			}
 	}
 	else
 	{
  		DBG_PRINTF("ShowOneFont error, can't support %d bpp\n", ptFontBitMap->iBpp);
  		return -1;
 	}
 	return 0;
}

int ShowOnePage(unsigned char *pucTextFileMemCurPos)
{
 	int iLen;
 	int iError;
 	unsigned char *pucBufStart;
 	unsigned int dwCode;
 	PT_FontOpr ptFontOpr;
 	T_FontBitMap tFontBitMap;
 	int bHasNotClrSceen = 1;
 	int bHasGetCode = 0;
 	tFontBitMap.iCurOriginX = 0;
 	tFontBitMap.iCurOriginY = g_dwFontSize;
 	pucBufStart = pucTextFileMemCurPos;
 	
 	while (1)
 	{
  		iLen = g_ptEncodingOprForFile->GetCodeFrmBuf(pucBufStart, g_pucTextFileMemEnd, &dwCode);
  		if (0 == iLen)
  		{
   			/* 文件结束 */
   			if (!bHasGetCode)
   			{
    				return -1;
   			}
   			else
   			{
    				return 0;
   			}
  		}
  		bHasGetCode = 1;
  		pucBufStart += iLen;
  		/* 有些文本, \n\r两个一起才表示回车换行
   		* 碰到这种连续的\n\r, 只处理一次
  		*/
  		if (dwCode == '\n')
  		{
   			g_pucLcdNextPosAtFile = pucBufStart;
   
   			/* 回车换行 */
   			tFontBitMap.iCurOriginX = 0;
   			tFontBitMap.iCurOriginY = IncLcdY(tFontBitMap.iCurOriginY);
   			if (0 == tFontBitMap.iCurOriginY)
   			{
    				/* 显示完当前一屏了 */
    				return 0;
   			}
   			else
   			{
    				continue;
   			}
  		}
  		else if (dwCode == '\r')
  		{
   			continue;
  		}
  		else if (dwCode == '\t')
  		{
   			/* TAB键用一个空格代替 */
   			dwCode = ' ';
  		}
  		DBG_PRINTF("dwCode = 0x%x\n", dwCode);
  		ptFontOpr = g_ptEncodingOprForFile->ptFontOprSupportedHead;
  		while (ptFontOpr)
  		{
   			DBG_PRINTF("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
   			iError = ptFontOpr->GetFontBitmap(dwCode, &tFontBitMap);
   			DBG_PRINTF("%s %s %d, ptFontOpr->name = %s, %d\n", __FILE__, 
   				__FUNCTION__,__LINE__, ptFontOpr->name, iError);
   			if (0 == iError)
   			{
    				DBG_PRINTF("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
    				if (RelocateFontPos(&tFontBitMap))
    				{
     					/* 剩下的LCD空间不能满足显示这个字符 */
     					return 0;
    				}
    				DBG_PRINTF("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
    				if (bHasNotClrSceen)
    				{
     					/* 首先清屏 */
     					g_ptDispOpr->CleanScreen(COLOR_BACKGROUND);
     					bHasNotClrSceen = 0;
    				}
    				DBG_PRINTF("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
    				/* 显示一个字符 */
    				if (ShowOneFont(&tFontBitMap))
    				{
     					return -1;
    				}
    				tFontBitMap.iCurOriginX = tFontBitMap.iNextOriginX;
    				tFontBitMap.iCurOriginY = tFontBitMap.iNextOriginY;
    				g_pucLcdNextPosAtFile = pucBufStart;
    				/* 继续取出下一个编码来显示 */
    				break;
   			}
   			ptFontOpr = ptFontOpr->ptNext;
  		}  
 	}
 	return 0;
}

static void RecordPage(PT_PageDesc ptPageNew)
{
 	PT_PageDesc ptPage;
 	
 	if (!g_ptPages)
 	{
  		g_ptPages = ptPageNew;
 	}
 	else
 	{
  		ptPage = g_ptPages;
  		while (ptPage->ptNextPage)
  		{
   			ptPage = ptPage->ptNextPage;
  		}
  		ptPage->ptNextPage   = ptPageNew;
  		ptPageNew->ptPrePage = ptPage;
 	}
}

int ShowNextPage(void)
{
 	int iError;
 	PT_PageDesc ptPage;
 	unsigned char *pucTextFileMemCurPos;
 	
 	if (g_ptCurPage)
 	{
  		pucTextFileMemCurPos = g_ptCurPage->pucLcdNextPageFirstPosAtFile;
 	}
 	else
 	{
 		pucTextFileMemCurPos = g_pucLcdFirstPosAtFile;
 	}
 		iError = ShowOnePage(pucTextFileMemCurPos);
 		DBG_PRINTF("%s %d, %d\n", __FUNCTION__, __LINE__, iError);
 	if (iError == 0)
 	{
  		if (g_ptCurPage && g_ptCurPage->ptNextPage)
  		{
   			g_ptCurPage = g_ptCurPage->ptNextPage;
   			return 0;
  		}
  		ptPage = malloc(sizeof(T_PageDesc));
  		if (ptPage)
  		{
   			ptPage->pucLcdFirstPosAtFile         = pucTextFileMemCurPos;
   			ptPage->pucLcdNextPageFirstPosAtFile = g_pucLcdNextPosAtFile;
   			ptPage->ptPrePage                    = NULL;
   			ptPage->ptNextPage                   = NULL;
   			g_ptCurPage = ptPage;
   			DBG_PRINTF("%s %d, pos = 0x%x\n", __FUNCTION__, __LINE__, 
   				(unsigned int)ptPage->pucLcdFirstPosAtFile);
   			RecordPage(ptPage);
   			return 0;
  		}
  		else
  		{
   			return -1;
  		}
 	}
 	return iError;
}

int ShowPrePage(void)
{
 	int iError;
 	DBG_PRINTF("%s %d\n", __FUNCTION__, __LINE__);
 	
 	if (!g_ptCurPage || !g_ptCurPage->ptPrePage)
 	{
  		return -1;
 	}
	DBG_PRINTF("%s %d, pos = 0x%x\n", __FUNCTION__, __LINE__, 
		(unsigned int)g_ptCurPage->ptPrePage->pucLcdFirstPosAtFile);
 	iError = ShowOnePage(g_ptCurPage->ptPrePage->pucLcdFirstPosAtFile);
 	if (iError == 0)
 	{
  		DBG_PRINTF("%s %d\n", __FUNCTION__, __LINE__);
  		g_ptCurPage = g_ptCurPage->ptPrePage;
 	}
 	return iError;
}
上面两个文件等到下文再编译检查。
对于这两个文件,理解好前面给出的两张图解很重要。

下文,我们将写一个这个小项目的Makefile并编译、测试。最后再总结一下这个项目,有哪些需要学习的。
另外,如果有时间,后面会完善这个项目,如页的切换用触摸屏,支持在控制台阅读电子书及源码完善等
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值