diff --git a/Code/thermal_printer/Makefile b/Code/thermal_printer/Makefile index e1bd127..737dfef 100644 --- a/Code/thermal_printer/Makefile +++ b/Code/thermal_printer/Makefile @@ -1,13 +1,13 @@ CC = gcc CFLAGS = -g -Wall -LDFLAUS = -INCLUDES = -LIBS = -lwiringPi -lm -lcrypt -lpthread -lrt +LDFLAGS = +INCLUDES = -I /usr/include/freetype2 +LIBS = -lwiringPi -lm -lcrypt -lpthread -lfreetype -lrt MAIN = devterm_thermal_printer.elf -SRCS = printer.c devterm_thermal_printer.c utils.c +SRCS = printer.c devterm_thermal_printer.c utils.c ftype.c utf8-utils.c OBJS = $(SRCS:.c=.o) .PHONY: depend clean diff --git a/Code/thermal_printer/NotoSansCJK-Regular.ttf b/Code/thermal_printer/NotoSansCJK-Regular.ttf new file mode 100644 index 0000000..271526f Binary files /dev/null and b/Code/thermal_printer/NotoSansCJK-Regular.ttf differ diff --git a/Code/thermal_printer/config.h b/Code/thermal_printer/config.h index 8777c38..076b8ad 100644 --- a/Code/thermal_printer/config.h +++ b/Code/thermal_printer/config.h @@ -172,6 +172,8 @@ #define MAXPIXELS 72 #endif +#define FONT_MODE_0 0 // Internal +#define FONT_MODE_1 1 // External //extract bits #define LAST(k,n) ((k) & ((1<<(n))-1)) @@ -188,7 +190,9 @@ typedef struct _FONT { uint8_t width;//in bits uint8_t height; + uint8_t mode;//0 internal pcf font array,1 external ttf font file const uint8_t *data; + char*file; }FONT; typedef struct _ImageCache{ @@ -222,6 +226,9 @@ typedef struct _CONFIG FONT*font; ImageCache *img; FILE*fp; + + FT_Face *face; + FT_Library *ft; int (*printf)(struct _CONFIG*, char*, ...); @@ -230,7 +237,9 @@ typedef struct _CONFIG typedef struct _SerialCache{ uint8_t idx; - uint8_t data[77];//384/5 + uint8_t utf8idx;//0-4 + // uint8_t data[77];//384/5, minium size font 5 pixel + uint32_t data[MAX_DOTS];// }SerialCache; typedef struct _TimeRec{ diff --git a/Code/thermal_printer/devterm_thermal_printer.c b/Code/thermal_printer/devterm_thermal_printer.c index ebd9cbd..82ad8cd 100644 --- a/Code/thermal_printer/devterm_thermal_printer.c +++ b/Code/thermal_printer/devterm_thermal_printer.c @@ -19,16 +19,15 @@ #include "pcf_6x12-ISO8859-1_6x12.h" #include "pcf_7x14-ISO8859-1_7x14.h" - #include "ttf_Px437_PS2thin1_8x16.h" #include "ttf_Px437_PS2thin2_8x16.h" - - #include "config.h" #include "utils.h" #include "printer.h" +#include "ftype.h" + SerialCache ser_cache; uint8_t cmd[10]; @@ -43,6 +42,10 @@ ImageCache img_cache; FONT current_font; +FT_Face face; + +FT_Library ft; + CONFIG g_config; TimeRec battery_chk_tm; @@ -72,7 +75,7 @@ void reset_cmd(){ } void init_printer(){ - + char *error = NULL; memset(cmd,0,10); newline = 0; @@ -95,11 +98,23 @@ void init_printer(){ current_font.width=8;current_font.height=16; current_font.data= font_ttf_Px437_PS2thin2_8x16; */ - current_font.width=8;current_font.height=16; current_font.data= font_ttf_Px437_PS2thin1_8x16; - - + current_font.width = 16; + current_font.height = 16; + current_font.data= font_ttf_Px437_PS2thin1_8x16; + current_font.file = "NotoSansCJK-Regular.ttf"; + current_font.mode = 1; + ser_cache.idx=0; - + ser_cache.utf8idx = 0; + + if( init_ft(current_font.file, &face,&ft,current_font.width,current_font.height,&error)) { + g_config.face = &face; + g_config.ft = &ft; + }else { + g_config.face = null; + g_config.ft = null; + } + g_config.line_space=0; g_config.align = ALIGN_LEFT; g_config.reverse = 0; @@ -249,6 +264,7 @@ NULL */ for(i=0;i<6;i++){ + printer_set_font_mode(FONT_MODE_0); printer_set_font(cfg,1); reset_cmd(); @@ -264,6 +280,7 @@ NULL //--------------------------------------------- for(i=1;i<4;i++){ + printer_set_font_mode(FONT_MODE_0); printer_set_font(cfg,0); reset_cmd(); for(j=0;jorient); } - + printer_set_font_mode(FONT_MODE_0); printer_set_font(cfg,0); reset_cmd(); for(j=0;jorient); - + printer_set_font_mode(FONT_MODE_0); printer_set_font(cfg,0); reset_cmd(); for(j=0;jfont->height,cfg->orient); -//-------------------------------------------------------------- +//-------------------------------------------------------------- + printer_set_font_mode(FONT_MODE_0); printer_set_font(cfg,0); reset_cmd(); @@ -378,39 +399,52 @@ NULL } +void printer_set_font_mode(CONFIG*cfg, int mode){ + cfg->font->mode = mode; + return; +} void printer_set_font(CONFIG*cfg,uint8_t fnbits){ uint8_t ret; ret = MID(fnbits,0,3); + + if(cfg->font->mode == 0) { + if(ret==0) { + cfg->font->width = 8 ; + cfg->font->height = 16; + cfg->font->data = font_ttf_Px437_PS2thin1_8x16; + } + + if(ret==1){ + cfg->font->width = 5; + cfg->font->height = 7; + cfg->font->data = font_pcf_5x7_ISO8859_1_5x7; + } + + if(ret==2){ + cfg->font->width = 6; + cfg->font->height = 12; + cfg->font->data = font_pcf_6x12_ISO8859_1_6x12; + } + + if(ret==3){ + cfg->font->width = 7; + cfg->font->height = 14; + cfg->font->data = font_pcf_7x14_ISO8859_1_7x14; + } + + if(ret == 4){ + cfg->font->width = 8 ; + cfg->font->height = 16; + cfg->font->data = font_ttf_Px437_PS2thin2_8x16; + } + } - if(ret==0) { - cfg->font->width = 8 ; + if(cfg->font->mode == 1 ){ + cfg->font->width = 16; cfg->font->height = 16; - cfg->font->data = font_ttf_Px437_PS2thin1_8x16; + } - if(ret==1){ - cfg->font->width = 5; - cfg->font->height = 7; - cfg->font->data = font_pcf_5x7_ISO8859_1_5x7; - } - - if(ret==2){ - cfg->font->width = 6; - cfg->font->height = 12; - cfg->font->data = font_pcf_6x12_ISO8859_1_6x12; - } - - if(ret==3){ - cfg->font->width = 7; - cfg->font->height = 14; - cfg->font->data = font_pcf_7x14_ISO8859_1_7x14; - } - - if(ret == 4){ - cfg->font->width = 8 ; - cfg->font->height = 16; - cfg->font->data = font_ttf_Px437_PS2thin2_8x16; - } } void parse_cmd(CONFIG*cfg,uint8_t *cmd, uint8_t cmdidx){ @@ -599,6 +633,7 @@ void parse_cmd(CONFIG*cfg,uint8_t *cmd, uint8_t cmdidx){ void parse_serial_stream(CONFIG*cfg,uint8_t input_ch){ uint16_t a; + uint8_t bskip; if(cfg->state == GET_IMAGE){ cfg->img->cache[cfg->img->idx] = input_ch; @@ -647,11 +682,33 @@ void parse_serial_stream(CONFIG*cfg,uint8_t input_ch){ cmd_idx++; break; default: - ser_cache.data[ser_cache.idx]=input_ch; - ser_cache.idx++; - + if(input_ch < 128) { + ser_cache.data[ser_cache.idx]=input_ch; + ser_cache.idx++; + }else {//utf8 + //10xxxxxx bskip == 1 + bskip = get_slice_len(input_ch); + + if(bskip == 1) { + //append this to int32_t [8:8:8:8] 0xffffffff 4294967295 + ser_cache.data[ser_cache.idx] |= input_ch << (8 * (ser_cache.utf8idx+1)); + ser_cache.utf8idx++; + if( ser_cache.utf8idx >= get_slice_len( ser_cache.data[ser_cache.idx] & 0xff) ) { + ser_cache_idx++; + ser_cache.utf8idx=0;//next character + } + } + + if(bskip > 1) { + ser_cache.utf8idx =0; + ser_cache.data[ser_cache.idx] = input_ch; + } + + } + //read utf8 codename + // a = (ser_cache.idx+1)*current_font.width+(ser_cache.idx)*0+ g_config.margin.width; - if( a >= MAX_DOTS) + if( a >= MAX_DOTS)//got enough points to print { print_lines8(cfg); reset_cmd(); diff --git a/Code/thermal_printer/ftype.c b/Code/thermal_printer/ftype.c new file mode 100644 index 0000000..97e4dc3 --- /dev/null +++ b/Code/thermal_printer/ftype.c @@ -0,0 +1,104 @@ +#include "ftype.h" + +#include "utf8-utils.h" + +static const UTF32 utf32_space[2] = {' ', 0}; + +FT_Face face; +FT_Library ft; + +bool init_ft (const char *ttf_file, FT_Face *face, FT_Library *ft, + int req_size_w,int req_size_h, char **error) +{ + + bool ret = false; + if (FT_Init_FreeType (ft) == 0) { + if (FT_New_Face(*ft, ttf_file, 0, face) == 0) { + + if(FT_Set_Pixel_Sizes(*face, req_size_w, req_size_h) == 0){ + ret = true; + } else { + if (error) + *error = strdup ("Can't set font size"); + } + + } else { + if (error) + *error = strdup ("Can't load TTF file"); + } + + }else{ + if (error) + *error = strdup ("Can't init freetype library"); + } + + return ret; +} + +/*=========================================================================== + done_ft + Clean up after we've finished wih the FreeType librar + =========================================================================*/ +void done_ft(FT_Library ft) +{ + FT_Done_FreeType (ft); +} + +/*=========================================================================== + + face_get_line_spacing + + Get the nominal line spacing, that is, the distance between glyph + baselines for vertically-adjacent rows of text. This is "nominal" because, + in "real" typesetting, we'd need to add extra room for accents, etc. + + =========================================================================*/ +int face_get_line_spacing (FT_Face face) +{ + return face->size->metrics.height / 64; + // There are other possibilities the give subtly different results: + // return (face->bbox.yMax - face->bbox.yMin) / 64; + // return face->height / 64; +} + +int get_slice_len(const char lb) { + + if( ( lb & 0x80 ) == 0 ) return 1; + else if( ( lb & 0xE0) == 0xC0) return 2; + else if( ( lb & 0xF0) == 0xE0) return 3; + else if( ( lb & 0xF8) == 0xF0) return 4; + return 1; +} + +UTF32 *cjk_utf8_to_utf32 (const char *word) +{ + assert (word != NULL); + int l = strlen(word); + int u8l = utf8_strlen(word); + + char buf[5]; + + UTF32 *ret = malloc ((u8l + 1) * sizeof (UTF32)); + int i=0,j=0; + int bskip=1; + + while( i 1) { + ret[j] = (UTF32)utf8_to_utf32(buf); + }else { + ret[j] = (UTF32)buf[0]; + } + + j++; + i+=bskip; + } + + ret[u8l] = 0; + return ret; +} + + diff --git a/Code/thermal_printer/ftype.h b/Code/thermal_printer/ftype.h new file mode 100644 index 0000000..e3e7e13 --- /dev/null +++ b/Code/thermal_printer/ftype.h @@ -0,0 +1,26 @@ +#ifndef FTYPE_H +#define FTYPE_H + +#include +#include +#include +#include + +#include +#include + +#ifndef UTF8 +typedef unsigned char UTF8; +#endif + +#ifndef UTF32 +typedef int32_t UTF32; +#endif + +bool init_ft (const char *ttf_file, FT_Face *face, FT_Library *ft, + int req_size_w,int req_size_h, char **error); + + +int get_slice_len(const char lb); + +#endif diff --git a/Code/thermal_printer/printer.h b/Code/thermal_printer/printer.h index 7279697..837cf67 100644 --- a/Code/thermal_printer/printer.h +++ b/Code/thermal_printer/printer.h @@ -37,6 +37,7 @@ uint8_t invert_bit(uint8_t a); uint8_t print_image8(CONFIG*); void print_cut_line(CONFIG*); +void printer_set_font_mode(int); void printer_set_font(CONFIG*cfg,uint8_t fnbits); void parse_serial_stream(CONFIG*cfg,uint8_t input_ch); diff --git a/Code/thermal_printer/utf8-utils.c b/Code/thermal_printer/utf8-utils.c new file mode 100644 index 0000000..4257e84 --- /dev/null +++ b/Code/thermal_printer/utf8-utils.c @@ -0,0 +1,83 @@ +/* Freetype GL - A C OpenGL Freetype engine + * + * Distributed under the OSI-approved BSD 2-Clause License. See accompanying + * file `LICENSE` for more details. + */ +#include +#include "utf8-utils.h" + +// ----------------------------------------------------- utf8_surrogate_len --- +size_t +utf8_surrogate_len( const char* character ) +{ + size_t result = 0; + char test_char; + + if (!character) + return 0; + + test_char = character[0]; + + if ((test_char & 0x80) == 0) + return 1; + + while (test_char & 0x80) + { + test_char <<= 1; + result++; + } + + return result; +} + +// ------------------------------------------------------------ utf8_strlen --- +size_t +utf8_strlen( const char* string ) +{ + const char* ptr = string; + size_t result = 0; + + while (*ptr) + { + ptr += utf8_surrogate_len(ptr); + result++; + } + + return result; +} + +uint32_t +utf8_to_utf32( const char * character ) +{ + if( !character ) + { + return -1; + } + + if( ( character[0] & 0x80 ) == 0x0 ) + { + return character[0]; + } + + if( ( character[0] & 0xE0 ) == 0xC0 ) + { + return ( ( character[0] & 0x3F ) << 6 ) | ( character[1] & 0x3F ); + } + + if( ( character[0] & 0xF0 ) == 0xE0 ) + { + return ( ( character[0] & 0x1F ) << ( 6 + 6 ) ) | ( ( character[1] & 0x3F ) << 6 ) | ( character[2] & 0x3F ); + } + + if( ( character[0] & 0xF8 ) == 0xF0 ) + { + return ( ( character[0] & 0x0F ) << ( 6 + 6 + 6 ) ) | ( ( character[1] & 0x3F ) << ( 6 + 6 ) ) | ( ( character[2] & 0x3F ) << 6 ) | ( character[3] & 0x3F ); + } + + if( ( character[0] & 0xFC ) == 0xF8 ) + { + return ( ( character[0] & 0x07 ) << ( 6 + 6 + 6 + 6 ) ) | ( ( character[1] & 0x3F ) << ( 6 + 6 + 6 ) ) | ( ( character[2] & 0x3F ) << ( 6 + 6 ) ) | ( ( character[3] & 0x3F ) << 6 ) | ( character[4] & 0x3F ); + } + + return 0xFFFD; // invalid character +} diff --git a/Code/thermal_printer/utf8-utils.h b/Code/thermal_printer/utf8-utils.h new file mode 100644 index 0000000..a626201 --- /dev/null +++ b/Code/thermal_printer/utf8-utils.h @@ -0,0 +1,68 @@ +/* Freetype GL - A C OpenGL Freetype engine + * + * Distributed under the OSI-approved BSD 2-Clause License. See accompanying + * file `LICENSE` for more details. + */ +#ifndef __UTF8_UTILS_H__ +#define __UTF8_UTILS_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { + +namespace ftgl { +#endif + +/** + * @file utf8-utils.h + * @author Marcel Metz + * + * defgroup utf8-utils UTF-8 Utilities + * + * @{ + */ + + /** + * Returns the size in bytes of a given UTF-8 encoded character surrogate + * + * @param character An UTF-8 encoded character + * + * @return The length of the surrogate in bytes. + */ + size_t + utf8_surrogate_len( const char* character ); + + /** + * Return the length of the given UTF-8 encoded and + * NULL terminated string. + * + * @param string An UTF-8 encoded string + * + * @return The length of the string in characters. + */ + size_t + utf8_strlen( const char* string ); + + /** + * Converts a given UTF-8 encoded character to its UTF-32 LE equivalent + * + * @param character An UTF-8 encoded character + * + * @return The equivalent of the given character in UTF-32 LE + * encoding. + */ + uint32_t + utf8_to_utf32( const char * character ); + +/** + * @} + */ + +#ifdef __cplusplus +} +} +#endif + +#endif /* #define __UTF8_UTILS_H__ */