NXP

LPC54608生成PDF文件

2019-07-12 11:24发布

主机环境:Win10 64bit 开发环境:MDK5.23 目标板:LPC54608 之前在NXP论坛里得到了一块LPC54608开发板,最吸引人的地方是带了一块屏,如下图:
这也是第一次接触NXP的开发板,之前一直都是用的ST的MCU,NXP的库跟ST的还是差别蛮大的,自我感觉ST的开发入手要快一些,而NXP的相对慢一些,入手开发板之后就看了库里面自带的一些基本驱动例程,只熟悉了一下基本外设的开发,之前有次在群里看到有人询问单片机生成PDF的问题,突然觉得有些兴趣所以就有了前面的libHaru学习笔记,libHaru库是一个十分不错的库,对于PDF的实现来说也是相当齐全的,在PC上使用是完全没有问题的,但在资源紧张的MCU上,还是有些困难的,因此就想找一下适用于MCU的生成PDF的库,结果不太理想,都是一些需要实现动态内存管理的平台才行,而且这些库都是把生成的数据放在了内存中,直到保存文件时才写入到文件中,这对于一般只有几十或者几百KB级别的单片机来说更不可能了,于是乎,萌发了自己动手写一个基本的能用于MCU的生成PDF文件的库,我称之为libpdf,其中的接口参考了libHaru,如下所示:
当然有些接口还没有实现,但基本的操作还是可以的,等以后再逐渐完善吧,pdflib是生成pdf文件的,因此要基于Fatfs来实现文件的操作,pdflib库只有两个文件,也相应的参考了pdfgen库,该库在后面有链接, 头文件如下: #ifndef __PDFLIB_H__ #define __PDFLIB_H__ #include "ff.h" /*----- standard C library functions -----------------------------------------*/ #define LPDF_FOPEN f_open #define LPDF_FCLOSE f_close #define LPDF_FREAD f_read #define LPDF_FWRITE f_write #define LPDF_FFLUSH f_sync #define LPDF_FSEEK f_seek #define LPDF_FTELL f_tell #define LPDF_FEOF f_eof #define LPDF_FERROR f_error #define LPDF_RENAME f_rename #define LPDF_REMOVE f_unlink #define LPDF_MALLOC malloc #define LPDF_FREE free #define LPDF_FILE FIL #define LPDF_TIME time #define LPDF_PRINTF printf #define LPDF_SPRINTF sprintf #define LPDF_FPRINTF f_printf #define LPDF_VOID void #define LPDF_SIN sin #define LPDF_COS cos /* native OS integer types */ typedef signed int LPDF_INT; typedef unsigned int LPDF_UINT; /* 32bit integer types */ typedef signed int LPDF_INT32; typedef unsigned int LPDF_UINT32; /* 16bit integer types */ typedef signed short LPDF_INT16; typedef unsigned short LPDF_UINT16; /* 8bit integer types */ typedef signed char LPDF_INT8; typedef unsigned char LPDF_UINT8; /* 8bit binary types */ typedef unsigned char LPDF_BYTE; /* float type (32bit IEEE754) */ typedef float LPDF_REAL; /* double type (64bit IEEE754) */ typedef double LPDF_DOUBLE; /* boolean type (0: False, !0: True) */ typedef signed int LPDF_BOOL; /* error-no type (32bit unsigned integer) */ typedef unsigned long LPDF_STATUS; #define LPDF_OK 0 #define LPDF_FAILED 1 /*----- font state -----------------------------------------------------------*/ #define LPDF_FONT_INVALID 0x00FF #define LPDF_FONT_COURIER 0x0000 #define LPDF_FONT_COURIER_B 0x0001 #define LPDF_FONT_COURIER_O 0x0002 #define LPDF_FONT_COURIER_OB 0x0003 #define LPDF_FONT_HELVETICA 0x0004 #define LPDF_FONT_HELVETICA_B 0x0005 #define LPDF_FONT_HELVETICA_O 0x0006 #define LPDF_FONT_HELVETICA_BO 0x0007 #define LPDF_FONT_TIMES_R 0x0008 #define LPDF_FONT_TIMES_B 0x0009 #define LPDF_FONT_TIMES_I 0x000A #define LPDF_FONT_TIMES_BI 0x000B #define LPDF_FONT_SYMBOL 0x000C #define LPDF_FONT_ZAP 0x000D /*----- Graphis mode ---------------------------------------------------------*/ #define LPDF_GMODE_PAGE_DESCRIPTION 0x0001 #define LPDF_GMODE_PATH_OBJECT 0x0002 #define LPDF_GMODE_TEXT_OBJECT 0x0004 #define LPDF_GMODE_CLIPPING_PATH 0x0008 #define LPDF_GMODE_SHADING 0x0010 #define LPDF_GMODE_INLINE_IMAGE 0x0020 #define LPDF_GMODE_EXTERNAL_OBJECT 0x0040 #define LPDF_GMODE_INVALID 0x0080 #define LPDF_GMODE_OVER 0x0100 #define OBJ_MAX_NUM 256 /* Page的结构信息是否需要树形结构 */ typedef enum { OBJ_info, OBJ_stream, OBJ_font, OBJ_page, OBJ_catalog, OBJ_pages, OBJ_image, }LPDF_ObjType; typedef struct { LPDF_ObjType objType; LPDF_UINT16 objIdx; LPDF_UINT16 height; LPDF_UINT16 width; LPDF_UINT16 length; LPDF_UINT gMode; LPDF_BYTE fontType; LPDF_BYTE fontSize; LPDF_BYTE pState; LPDF_VOID *doc; }LPDF_Obj; typedef struct { LPDF_Obj obj[OBJ_MAX_NUM]; LPDF_UINT32 offset; LPDF_UINT16 objNumber; LPDF_FILE file; }LPDF_Doc_Rec; typedef LPDF_Doc_Rec *LPDF_Doc; typedef LPDF_Obj *LPDF_Page; typedef LPDF_Obj *LPDF_Image; extern const char *font_list[]; /*----- LPDF Interfaces-------------------------------------------------------*/ const char * LPDF_GetVersion(void); LPDF_Doc LPDF_New(void); LPDF_Page LPDF_AddPage(LPDF_Doc pdf); LPDF_STATUS LPDF_SaveToFile(LPDF_Doc pdf,const char *file_name); LPDF_STATUS LPDF_Free(LPDF_Doc pdf); LPDF_STATUS LPDF_Page_CheckState(LPDF_Page page, LPDF_UINT mode); LPDF_STATUS LPDF_Page_SetFontAndSize(LPDF_Page page, const char *font_name, LPDF_UINT8 size); LPDF_STATUS LPDF_Page_SaveParams(LPDF_Page page); LPDF_STATUS LPDF_Page_SaveContext(LPDF_Page page); LPDF_STATUS LPDF_Page_BeginText(LPDF_Page page); LPDF_STATUS LPDF_Page_EndText(LPDF_Page page); LPDF_UINT16 LPDF_Page_GetHeight(LPDF_Page page); LPDF_UINT16 LPDF_Page_GetWidth(LPDF_Page page); LPDF_STATUS LPDF_Page_SetHeight(LPDF_Page page, LPDF_UINT16 value); LPDF_STATUS LPDF_Page_SetWidth(LPDF_Page page, LPDF_UINT16 value); LPDF_STATUS LPDF_Page_ShowText(LPDF_Page page, const char *text); LPDF_STATUS LPDF_Page_MoveTextPos(LPDF_Page page, LPDF_INT x, LPDF_INT y); LPDF_STATUS LPDF_Page_TextOut(LPDF_Page page, LPDF_UINT16 x, LPDF_UINT16 y, const char *text); LPDF_STATUS LPDF_Page_SetRGBStroke(LPDF_Page page, LPDF_REAL r, LPDF_REAL g, LPDF_REAL b); LPDF_STATUS LPDF_Page_SetRGBFill(LPDF_Page page, LPDF_REAL r, LPDF_REAL g, LPDF_REAL b); LPDF_STATUS LPDF_Page_MoveTo (LPDF_Page page, LPDF_UINT16 x, LPDF_UINT16 y); LPDF_STATUS LPDF_Page_LineTo (LPDF_Page page, LPDF_UINT16 x, LPDF_UINT16 y); LPDF_STATUS LPDF_Page_Stroke(LPDF_Page page); LPDF_STATUS LPDF_Page_ClosePathStroke(LPDF_Page page); LPDF_STATUS LPDF_Page_DrawImage(LPDF_Page page, LPDF_Image image, LPDF_UINT16 x, LPDF_UINT16 y, LPDF_UINT16 width, LPDF_UINT16 height); #endif 源文件如下: #include #include #include #include #include "pdflib.h" #define LPDF_INVALID_OBJECT 0x1033 static char pdf_buf[512]; #define LPDF_VERSIOIN_TEXT "0.0.1" #define LPDF_FILE_HEADER_LEN 15 #define LPDF_BASEFONT_NUM 14 const char LPDF_FILE_HEADER[] = "%%PDF-1.4 %%xAAxBBxCCxDD "; const char *font_list[] = { "Courier", "Courier-Bold", "Courier-Oblique", "Courier-BoldOblique", "Helvetica", "Helvetica-Bold", "Helvetica-Oblique", "Helvetica-BoldOblique", "Times-Roman", "Times-Bold", "Times-Italic", "Times-BoldItalic", "Symbol", "ZapfDingbats", NULL }; const char * LPDF_GetVersion(void) { return LPDF_VERSIOIN_TEXT; } LPDF_Doc LPDF_New(void) { static LPDF_Doc_Rec pdf; LPDF_INT length = 0, i = 0; LPDF_UINT writeBytes = 0; FRESULT fr; fr = LPDF_FOPEN(&pdf.file,"/tmp.pdf",FA_CREATE_ALWAYS|FA_WRITE); if(fr) { LPDF_PRINTF("create tmp.pdf failed! "); return NULL; } LPDF_FPRINTF(&pdf.file,LPDF_FILE_HEADER); /* 写入文件头 */ pdf.offset = LPDF_FILE_HEADER_LEN; pdf.obj[0].objIdx = pdf.offset; length = LPDF_SPRINTF(pdf_buf,"1 0 obj << /Type /Catalog /Pages 17 0 R >> endobj "); LPDF_FWRITE(&pdf.file,pdf_buf,length,&writeBytes); pdf.offset += length; pdf.obj[1].objIdx = pdf.offset; length = LPDF_SPRINTF(pdf_buf,"2 0 obj << /Creator (light pdf library 0.0.1) " "/Auther (anobodykey) >> endobj "); LPDF_FWRITE(&pdf.file,pdf_buf,length,&writeBytes); pdf.offset += length; for(i = 0; i < LPDF_BASEFONT_NUM-2; i++) { pdf.obj[2+i].objIdx = pdf.offset; length = LPDF_SPRINTF(pdf_buf,"%d 0 obj << /Type /Font /Subtype /Type1 " "/BaseFont /%s /Encoding /WinAnsiEncoding >> " "endobj ",3+i,font_list[i]); LPDF_FWRITE(&pdf.file,pdf_buf,length,&writeBytes); pdf.offset += length; } for(; i < LPDF_BASEFONT_NUM; i++) { pdf.obj[2+i].objIdx = pdf.offset; length = LPDF_SPRINTF(pdf_buf,"%d 0 obj << /Type /Font /Subtype /Type1 " "/BaseFont /%s >> endobj ",3+i,font_list[i]); LPDF_FWRITE(&pdf.file,pdf_buf,length,&writeBytes); pdf.offset += length; } pdf.objNumber = 3+i; return (LPDF_Doc)&pdf; } LPDF_STATUS LPDF_SaveToFile(LPDF_Doc pdf,const char *file_name) { LPDF_UINT16 i = 0, child_pages = 0; LPDF_INT length = 0; LPDF_UINT writeBytes = 0; pdf->obj[16].objIdx = pdf->offset; child_pages = (pdf->objNumber-2-LPDF_BASEFONT_NUM)/3 ; length = LPDF_SPRINTF(pdf_buf,"17 0 obj << /Types /Pages /Count %d /Kids [ ",child_pages); LPDF_FWRITE(&pdf->file,pdf_buf,length,&writeBytes); pdf->offset += length; for(i = 0; i < child_pages; i++) { length = LPDF_SPRINTF(pdf_buf,"%d 0 R ",18+i*3); LPDF_FWRITE(&pdf->file,pdf_buf,length,&writeBytes); pdf->offset += length; } length = LPDF_SPRINTF(pdf_buf,"] >> endobj "); LPDF_FWRITE(&pdf->file,pdf_buf,length,&writeBytes); pdf->offset += length; LPDF_FPRINTF(&pdf->file,"xref 0 %d 0000000000 65535 f ",pdf->objNumber+1); for(i = 0 ; i < pdf->objNumber; i++) { LPDF_FPRINTF(&pdf->file,"%10.10d 00000 n ",pdf->obj[i].objIdx); } LPDF_FPRINTF(&pdf->file,"trailer << /Size %d /Root 1 0 R /Info 2 0 R >> startxref %d %%%%EOF", pdf->objNumber+1,pdf->offset); LPDF_FCLOSE(&pdf->file); LPDF_REMOVE(file_name); LPDF_RENAME("tmp.pdf",file_name); return LPDF_OK; } LPDF_STATUS LPDF_Free(LPDF_Doc pdf) { memset(pdf,sizeof(LPDF_Doc_Rec),0); return LPDF_OK; } LPDF_Page LPDF_AddPage(LPDF_Doc pdf) { LPDF_INT length = 0,i = 0; LPDF_Page page = NULL; LPDF_UINT writeBytes = 0; pdf->obj[pdf->objNumber].objIdx = pdf->offset; length = LPDF_SPRINTF(pdf_buf,"%d 0 obj << /Type /Page /Parent 4 0 R /Contents %d 0 R " "/Resources << /ProcSet [/PDF /TEXT /ImageB /ImageC /ImageI] " "/Font << ",pdf->objNumber+1,pdf->objNumber+2); LPDF_FWRITE(&pdf->file,pdf_buf,length,&writeBytes); pdf->offset += length; while(font_list[i]) { length = LPDF_SPRINTF(pdf_buf,"/F%d %d 0 R ",i+1,3+i); LPDF_FWRITE(&pdf->file,pdf_buf,length,&writeBytes); pdf->offset += length; i+=1; } LPDF_FPRINTF(&pdf->file,">> >> "); pdf->offset += 4; page = (LPDF_Page)&pdf->obj[pdf->objNumber]; page->width = 595; page->height = 842; page->gMode = LPDF_GMODE_INVALID; page->fontType = LPDF_FONT_INVALID; page->doc = pdf; return page; } LPDF_STATUS LPDF_Page_SetHeight(LPDF_Page page, LPDF_UINT16 value) { page->height = value; return LPDF_OK; } LPDF_STATUS LPDF_Page_SetWidth(LPDF_Page page, LPDF_UINT16 value) { page->width = value; return LPDF_OK; } LPDF_UINT16 LPDF_Page_GetHeight(LPDF_Page page) { if(page) { return page->height; } return LPDF_OK; } LPDF_UINT16 LPDF_Page_GetWidth(LPDF_Page page) { if(page) { return page->width; } return LPDF_OK; } LPDF_STATUS LPDF_Page_CheckState(LPDF_Page page, LPDF_UINT mode) { if(!page) return LPDF_INVALID_OBJECT; if(!(page->gMode&mode)) return LPDF_FAILED; return LPDF_OK; } LPDF_STATUS LPDF_Page_SetFontAndSize(LPDF_Page page, const char *font_name, LPDF_UINT8 size) { LPDF_Doc pdf = (LPDF_Doc)page->doc; LPDF_INT i = 0,length = 0; LPDF_UINT writeBytes = 0; LPDF_STATUS ret = LPDF_Page_CheckState(page,LPDF_GMODE_TEXT_OBJECT|LPDF_GMODE_PAGE_DESCRIPTION); if(LPDF_OK != ret) return ret; while(font_list[i]) { if(0 == strcmp(font_list[i],font_name)) { page->fontType = i; page->fontSize = size; length = LPDF_SPRINTF(pdf_buf,"/F%d %d Tf ",i+1,size); LPDF_FWRITE(&pdf->file,pdf_buf,length,&writeBytes); pdf->offset += length; page->length += length; return LPDF_OK; } i+=1; } return LPDF_OK; } LPDF_STATUS LPDF_Page_SaveParams(LPDF_Page page) { LPDF_INT length; LPDF_UINT writeBytes = 0; LPDF_Doc pdf = (LPDF_Doc)page->doc; LPDF_STATUS ret = LPDF_Page_CheckState(page,LPDF_GMODE_INVALID); if(LPDF_OK != ret) return ret; /* 对于每个page来说该接口只能调用一次即在GMODE为INVALID的模式下 */ length = LPDF_SPRINTF(pdf_buf,"/MediaBox [ 0 0 %d %d ] >> endobj ", page->width, page->height); LPDF_FWRITE(&pdf->file,pdf_buf,length,&writeBytes); pdf->offset += length; pdf->obj[pdf->objNumber+1].objIdx = pdf->offset; length = LPDF_SPRINTF(pdf_buf,"%d 0 obj <> stream ", pdf->objNumber+2, pdf->objNumber+3); LPDF_FWRITE(&pdf->file,pdf_buf,length,&writeBytes); pdf->offset += length; page->length = 0; page->gMode = LPDF_GMODE_PAGE_DESCRIPTION; return LPDF_OK; } LPDF_STATUS LPDF_Page_SaveContext(LPDF_Page page) { LPDF_INT length; LPDF_UINT writeBytes = 0; LPDF_Doc pdf = (LPDF_Doc)page->doc; LPDF_STATUS ret = LPDF_Page_CheckState(page,LPDF_GMODE_PAGE_DESCRIPTION); if(LPDF_OK != ret) return ret; /* 对于每个page来说该接口只能调用一次即在GMODE为PAGE_DESCRIPTION的模式下 */ length = LPDF_SPRINTF(pdf_buf,"endstream endobj "); LPDF_FWRITE(&pdf->file,pdf_buf,length,&writeBytes); pdf->offset += length; pdf->obj[pdf->objNumber+2].objIdx = pdf->offset; length = LPDF_SPRINTF(pdf_buf,"%d 0 obj %d endobj ", pdf->objNumber+3,page->length); LPDF_FWRITE(&pdf->file,pdf_buf,length,&writeBytes); pdf->offset += length; pdf->objNumber += 3; page->gMode = LPDF_GMODE_OVER; return LPDF_OK; } LPDF_STATUS LPDF_Page_BeginText(LPDF_Page page) { LPDF_Doc pdf = (LPDF_Doc)page->doc; LPDF_STATUS ret = LPDF_Page_CheckState(page,LPDF_GMODE_PAGE_DESCRIPTION); if(LPDF_OK != ret) return ret; LPDF_FPRINTF(&pdf->file,"BT "); pdf->offset += 3; page->length += 3; page->gMode = LPDF_GMODE_TEXT_OBJECT; return LPDF_OK; } LPDF_STATUS LPDF_Page_EndText(LPDF_Page page) { LPDF_Doc pdf = (LPDF_Doc)page->doc; LPDF_STATUS ret = LPDF_Page_CheckState(page,LPDF_GMODE_TEXT_OBJECT); if(LPDF_OK != ret) return ret; LPDF_FPRINTF(&pdf->file,"ET "); pdf->offset += 3; page->length += 3; page->gMode = LPDF_GMODE_PAGE_DESCRIPTION; return LPDF_OK; } LPDF_STATUS LPDF_Page_ShowText(LPDF_Page page, const char *text) { LPDF_INT length = 0; LPDF_UINT writeBytes = 0; LPDF_Doc pdf = (LPDF_Doc)page->doc; LPDF_STATUS ret = LPDF_Page_CheckState(page,LPDF_GMODE_TEXT_OBJECT); if(LPDF_OK != ret) return ret; if(LPDF_FONT_INVALID == page->fontType) return LPDF_OK; length = LPDF_SPRINTF(pdf_buf,"(%s) Tj ",text); LPDF_FWRITE(&pdf->file,pdf_buf,length,&writeBytes); pdf->offset += length; page->length += length; return LPDF_OK; } LPDF_STATUS LPDF_Page_MoveTextPos(LPDF_Page page, LPDF_INT x, LPDF_INT y) { LPDF_INT length = 0; LPDF_UINT writeBytes = 0; LPDF_Doc pdf = (LPDF_Doc)page->doc; LPDF_STATUS ret = LPDF_Page_CheckState(page,LPDF_GMODE_TEXT_OBJECT); if(LPDF_OK != ret) return ret; length = LPDF_SPRINTF(pdf_buf,"%d %d Td ",x,y); LPDF_FWRITE(&pdf->file,pdf_buf,length,&writeBytes); pdf->offset += length; page->length += length; return LPDF_OK; } LPDF_STATUS LPDF_Page_TextOut(LPDF_Page page, LPDF_UINT16 x, LPDF_UINT16 y, const char *text) { return LPDF_OK; } LPDF_STATUS LPDF_Page_SetRGBStroke(LPDF_Page page, LPDF_REAL r, LPDF_REAL g, LPDF_REAL b) { LPDF_INT length = 0; LPDF_UINT writeBytes = 0; LPDF_Doc pdf = (LPDF_Doc)page->doc; LPDF_STATUS ret = LPDF_Page_CheckState(page,LPDF_GMODE_TEXT_OBJECT|LPDF_GMODE_PAGE_DESCRIPTION); if(LPDF_OK != ret) return ret; length = LPDF_SPRINTF(pdf_buf,"%.1f %.1f %.1f RG ",r,g,b); LPDF_FWRITE(&pdf->file,pdf_buf,length,&writeBytes); pdf->offset += length; page->length += length; return LPDF_OK; } LPDF_STATUS LPDF_Page_SetRGBFill(LPDF_Page page, LPDF_REAL r, LPDF_REAL g, LPDF_REAL b) { LPDF_INT length = 0; LPDF_UINT writeBytes = 0; LPDF_Doc pdf = (LPDF_Doc)page->doc; LPDF_STATUS ret = LPDF_Page_CheckState(page,LPDF_GMODE_TEXT_OBJECT|LPDF_GMODE_PAGE_DESCRIPTION); if(LPDF_OK != ret) return ret; length = LPDF_SPRINTF(pdf_buf,"%.1f %.1f %.1f rg ",r,g,b); LPDF_FWRITE(&pdf->file,pdf_buf,length,&writeBytes); pdf->offset += length; page->length += length; return LPDF_OK; } LPDF_STATUS LPDF_Page_MoveTo (LPDF_Page page, LPDF_UINT16 x, LPDF_UINT16 y) { LPDF_INT length = 0; LPDF_UINT writeBytes = 0; LPDF_Doc pdf = (LPDF_Doc)page->doc; LPDF_STATUS ret = LPDF_Page_CheckState(page,LPDF_GMODE_PAGE_DESCRIPTION|LPDF_GMODE_PATH_OBJECT); if(LPDF_OK != ret) return ret; length = LPDF_SPRINTF(pdf_buf,"%d %d m ",x,y); LPDF_FWRITE(&pdf->file,pdf_buf,length,&writeBytes); pdf->offset += length; page->length += length; page->gMode = LPDF_GMODE_PATH_OBJECT; return LPDF_OK; } LPDF_STATUS LPDF_Page_LineTo (LPDF_Page page, LPDF_UINT16 x, LPDF_UINT16 y) { LPDF_INT length = 0; LPDF_UINT writeBytes = 0; LPDF_Doc pdf = (LPDF_Doc)page->doc; LPDF_STATUS ret = LPDF_Page_CheckState(page,LPDF_GMODE_PATH_OBJECT); if(LPDF_OK != ret) return ret; length = LPDF_SPRINTF(pdf_buf,"%d %d l ",x,y); LPDF_FWRITE(&pdf->file,pdf_buf,length,&writeBytes); pdf->offset += length; page->length += length; return LPDF_OK; } LPDF_STATUS LPDF_Page_Stroke(LPDF_Page page) { LPDF_Doc pdf = (LPDF_Doc)page->doc; LPDF_STATUS ret = LPDF_Page_CheckState(page,LPDF_GMODE_PATH_OBJECT); if(LPDF_OK != ret) return ret; LPDF_FPRINTF(&pdf->file,"S "); pdf->offset += 2; page->length += 2; page->gMode = LPDF_GMODE_PAGE_DESCRIPTION; return LPDF_OK; } LPDF_STATUS LPDF_Page_DrawImage(LPDF_Page page, LPDF_Image image, LPDF_UINT16 x, LPDF_UINT16 y, LPDF_UINT16 width, LPDF_UINT16 height) { return LPDF_OK; } 对于pdf文件结构可以去查看pdf参考手册,这里我看的是pdf-1.4参考手册,该库的测试代码我是在基于LPC54608库中的sdcard_fatfs示例改编的,关键代码如下:
测试代码很简单,生成了一个含有两个page的pdf文件,在第一页中用了不同的字体来显示同一个字符串,可以参考libHaru中的font_demo示例,第二页中是画了一个立方体图,下载代码到目标板,并运行该示例,串口终端输出如下:
拔下板上的SD卡,插入到PC上,可以看到red.pdf文件
使用pdf阅读器打开该文件,截图如下:
pdflib库目前来说还是比较简单的,需慢慢完善, pdfgen库链接如下:https://github.com/AndreRenaud/PDFGen pdflib下载链接:上传了半天没反应,有需要的可以去我的资源里面找下,这里就不放链接了。