HZK16实现电子书

        本文用汉字库点阵和ASCII点阵实现电子书,汉字库点阵来自汉字库文件HZK16,ASCII字符点阵来自ASCII字符点阵数组fontdata_8x16,实际上ASCII字符点阵也可以从HZK16文件中获得,本文并没有这样实现,那样可能会好点,有兴趣的朋友可以那样去实现它。
        这个电子书只是对我上一篇文章《freetype实现电子书》的代码做了些修改。不一样的地方是:现在要打开的电子书是ANSI格式的电子书,从ANSI文件中获得字符编码,然后根据编码从HZK16中获得汉字点阵或从fontdata_8x6中获得ASCII字符点阵。
        ANSI文件没有文件头部,一开始就是字符编码,ASCII字符编码在ANSI文件中用 1 字节存储,汉字在ANSI文件中
是GBK码,用两个字节存储编码。

ANSI文件中GBK(2字节)的合成;
code = pucBuf[0] + (((unsigned int)pucBuf[1])<<8);
GBK码含区码和段码,区码和段码的提取如下(unsigned int code为某汉字的GBK码):
unsigned int area   = (code&0xFF)        - 0xA1;                   //区码
unsigned int where  = ((code&0xFF00)>>8) - 0xA1;           //段码
unsigned char *dots = hzkmem + (area * 94 + where)*32;  //每一区含94个字符,每个字符的点阵占32字节,
                                  //因为点阵为16*16,即2*8(bit) * 16 = 2(byte) * 16 = 32(byte)

我写代码时犯了个错误,调试了不少时间,我那个错误就是对未初始化的指针操作了。
如:
        int *p;
        int b = 0;
        *p = b; //编译没提示,运行就segmentfault了,原因:p没初始化,不知指向哪里。
可以这样初始化:
p = (int *)malloc(sizeof(int));

下面给出源码,也可到这里直接下面:https://download.csdn.net/download/qq_22863733/10402658

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 16 
#define iHeadLen 0
#define DBG_PRINTF(...)
#define HZK_FILE_NAME "HZK16"

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);
             
int OpenTextFile(char *pcFileName);

//unsigned int GetCodeFrmUTF8Buf(unsigned char * pucUTF8Buf);
int show_one_font(int *x,int *y,unsigned int code);
unsigned char * show_line(int * y,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);

unsigned int AsciiGetCodeFrmBuf(unsigned char *pucCurPos);
void lcd_put_chinese(int x, int y, unsigned int code);
void lcd_put_ascii(int x, int y, unsigned int c);
int hzk_init(void);

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;
int *lcdx,*lcdy;

int fd_hzk16;
struct stat hzk_stat;//文件stat结构体
unsigned char *hzkmem;//把文件映射到hzkmem

/*
FT_Library    library;
FT_Face       face;
FT_GlyphSlot  slot;
FT_Matrix     matrix;                 
FT_Vector     pen;                   
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;

T_PageInfo g_tPageInfoHeader;
PT_PageInfo g_ptPageInfoCur;
PT_PageInfo g_ptPages;

#define FONTDATAMAX 4096
static const unsigned char fontdata_8x16[FONTDATAMAX] = {...}

fontdata_8x16的实现太长了,4千多行,我这就省略了,需要的话自行到网上搜。

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;

	}
	
}

/* 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;
		}
	}
}


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;
}


// Show a font for a Unicode.And will renew lcdx after show one font
int show_one_font(int *x,int *y,unsigned int code)
{
	if ((code < (unsigned char)0x80))
	{
		lcd_put_ascii( *x, *y, code);
		*x=*x+8;
	}
	if ((code >= (unsigned char)0x80))
	{
		lcd_put_chinese( *x,  *y, code);
		*x=*x+16;
	}
	    
    	return 0;		
}

//will renew lcdx and lcdy after show one line.
unsigned char * show_line(int * y,unsigned char *pucLineFirsPostAtFile)
{
	unsigned int code = AsciiGetCodeFrmBuf(pucLineFirsPostAtFile);

	while(((*lcdx + FONTSIZE) <= var.xres) &&(code != '\0'))
	{	
		if (code == '\n')
		{
			*y = *y+18;
			*lcdx = 0;
			pucLineFirsPostAtFile=Renew_pucLcdFirstPosAtFile(code,pucLineFirsPostAtFile);
			code = AsciiGetCodeFrmBuf(pucLineFirsPostAtFile);
			return pucLineFirsPostAtFile;
		}
		else if (code == '\r')
		{
			pucLineFirsPostAtFile=Renew_pucLcdFirstPosAtFile(code,pucLineFirsPostAtFile);
			code = AsciiGetCodeFrmBuf(pucLineFirsPostAtFile);
			return pucLineFirsPostAtFile;
		}
		else if (code == '\t')
		{
			/* TAB键用一个空格代替 */
			code = ' ';
		}
		
		show_one_font(lcdx,y,code);
		pucLineFirsPostAtFile=Renew_pucLcdFirstPosAtFile(code,pucLineFirsPostAtFile);
		code = AsciiGetCodeFrmBuf(pucLineFirsPostAtFile);
	}
	
	if((*lcdx + 16) > var.xres || (code == '\0'))
	{
		*lcdx=0;
		*y = *y + 18;
	}
	return pucLineFirsPostAtFile;
}

unsigned char* show_one_page(PT_PageInfo ptCurPageInfo)
{
	PT_PageInfo ptPageToRecord = malloc(sizeof(T_PageInfo));
	unsigned char * puctmp=ptCurPageInfo->pucPagePos;
	
	while(*lcdy<=(var.yres-18))
	{
		 puctmp = show_line(lcdy,puctmp);	
	}
	
	if(ptCurPageInfo->pt_NextPageInfo == NULL)
	{
		ptPageToRecord->pucPagePos=puctmp;
		RecordPage(ptPageToRecord);	
	}
		
	*lcdy=0;
	
	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)
	{
		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;
}


unsigned int AsciiGetCodeFrmBuf(unsigned char *pucCurPos)
{
	unsigned char *pucBuf = pucCurPos;
	unsigned char c = *pucBuf;
	unsigned int pdwCode;
	
	if ((pucBuf < g_pucTextFileMemEnd) && (c < (unsigned char)0x80))
	{
		/* 返回ASCII码 */
		pdwCode = (unsigned int)c;
		return pdwCode;
	}

	if (((pucBuf + 1) < g_pucTextFileMemEnd) && (c >= (unsigned char)0x80))	//这里可以看出ANSI文件中GBK码的构成方式
	{
		/* 返回GBK码 */
		pdwCode = pucBuf[0] + (((unsigned int)pucBuf[1])<<8);
		return pdwCode;
	}

	if (pucBuf < g_pucTextFileMemEnd)
	{
		/* 可能文件有损坏, 但是还是返回一个码, 即使它是错误的 */
		pdwCode = (unsigned int)c;
		return 0;
	}
	else
	{
		/* 文件处理完毕 */
		return 0;
	}
}

void lcd_put_ascii(int x, int y, unsigned int c)
{
	unsigned char *dots = (unsigned char *)&fontdata_8x16[c*16];//从fontdata_8x16[FONTDATAMAX]数组中获得点阵起始位置
	int i, b;
	unsigned char byte;

	for (i = 0; i < 16; i++)//点阵有16行
	{
		byte = dots[i];
		for (b = 7; b >= 0; b--)//点阵有8列
		{
			if (byte & (1<<b))//判断点阵中的各个点是否为1
			{
				/* show */
				lcd_put_pixel(x+7-b, y+i, 0xffffff); /* 白 */
			}
			else
			{
				/* hide */
				lcd_put_pixel(x+7-b, y+i, 0); /* 黑 */
			}
		}
	}
}

void lcd_put_chinese(int x, int y, unsigned int code)
{
	//unsigned int area  = str[0] - 0xA1;
	//unsigned int where = str[1] - 0xA1;
	unsigned int area   = (code&0xFF)        - 0xA1;
	unsigned int where  = ((code&0xFF00)>>8) - 0xA1;
	unsigned char *dots = hzkmem + (area * 94 + where)*32;
	unsigned char byte;

	int i, j, b;
	for (i = 0; i < 16; i++)//16行
		for (j = 0; j < 2; j++)
		{
			byte = dots[i*2 + j];
			for (b = 7; b >=0; b--)
			{
				if (byte & (1<<b))
				{
					/* show */
					lcd_put_pixel(x+j*8+7-b, y+i, 0xffffff); /* 白 */
				}
				else
				{
					/* hide */
					lcd_put_pixel(x+j*8+7-b, y+i, 0); /* 黑 */
				}
				
			}
		}
	
}

int hzk_init(void)
{
	fd_hzk16 = open(HZK_FILE_NAME, O_RDONLY);
	if (fd_hzk16 < 0)
	{
		printf("can't open "HZK_FILE_NAME"\n");
		return -1;
	}
	if(fstat(fd_hzk16, &hzk_stat))
	{
		printf("can't get fstat\n");
		return -1;
	}
	hzkmem = (unsigned char *)mmap(NULL , hzk_stat.st_size, PROT_READ, MAP_SHARED, fd_hzk16, 0);
	if (hzkmem == (unsigned char *)-1)
	{
		printf("can't mmap for hzk16\n");
		return -1;
	}
	return 0;	
}

可以把这个function.c与我freetypes实现电子书的function.c对比一下,主要改了AsciiGetCodeFrmBuf()函数,和更新坐标的函数。

main.c:

基本和freetype实现电子书时一样,只是去掉freetype部分,添加hzk_init()函数,所以使用时要提供HZK16文件,没有这个文件的话,自行搜索下载即可。

#include "function.h"
  
int main(int argc,char** argv)
{
  	char cOpr;
	
	if ( argc != 2 )
	{
	    	fprintf ( stderr, "usage: %s TextFileName\n", argv[0] );
	    	exit( 1 );
	}
	
	lcdx=(int *)malloc(sizeof(int));
	lcdy=(int *)malloc(sizeof(int));
	lcd_init();
	memset(fbmem, 0, screen_size);
	
	hzk_init(); 
	TextFileName = argv[1];  
	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(fd_fb);
	
	return 0;
}


电子书实现效果:



猜你喜欢

转载自blog.csdn.net/qq_22863733/article/details/80252304
今日推荐