首页 > 技术知识 > 正文

(一)字符编码介绍

1.1 ASCII码

我们知道, 在计算机内部, 所有的信息最终都表示为一个二进制的字符串. 每一个二进制位(bit)有0和1两种状态, 因此八个二进制位就可以组合出 256种状态, 这被称为一个字节(byte). 也就是说, 一个字节一共可以用来表示256种不同的状态, 每一个状态对应一个符号, 就是256个符号, 从 0000000到11111111.

上个世纪60年代, 美国制定了一套字符编码, 对英语字符与二进制位之间的关系, 做了统一规定. 这被称为ASCII码, 一直沿用至今.

ASCII码一共规定了128个字符的编码, 比如空格”SPACE”是32(二进制00100000), 大写的字母A是65(二进制01000001). 这128个符号(包括32个不能打印出来的控制符号), 只占用了一个字节的后面7位, 最前面的1位统一规定为0.

1.2 非ASCII编码

英语用128个符号编码就够了, 但是用来表示其他语言, 128个符号是不够的. 比如, 在法语中, 字母上方有注音符号, 它就无法用ASCII码表示. 于是, 一些欧洲国家就决定, 利用字节中闲置的最高位编入新的符号. 比如, 法语中的é的编码为130(二进制10000010).这样一来, 这些欧洲国家使用的编码体系, 可以表示最多256个符号.

但是, 这里又出现了新的问题. 不同的国家有不同的字母, 因此, 哪怕它们都使用256个符号的编码方式, 代表的字母却不一样. 比如, 130在法语编码中代表了é, 在希伯来语编码中却代表了字母Gimel (ג), 在俄语编码中又会代表另一个符号.

NOTE: 但是不管怎样, 所有这些编码方式中, 0-127表示的符号是一样的, 不一样的只是128-255的这一段. // MMMMM 至于亚洲国家的文字, 使用的符号就更多了, 汉字就多达10万左右. 一个字节只能表示256种符号, 肯定是不够的, 就必须使用多个字节表达一个符号. 比如, 简体中文常见的编码方式是GB2312, 使用两个字节表示一个汉字, 所以理论上最多可以表示256×256=65536个符号.

上面内容参考自tge7618291的这篇博客https://blog.csdn.net/tge7618291/article/details/7599902 。

(二)编码转换

简体中文是GBK2312格式,要将简体字符显示出来,需要将GBK格式转换成Unicode格式,然后再将Unicode格式转换成utf-8格式,最后才能正常的显示出来。 转换GBK转Unicode:

unsigned short zz_gbk2uni(unsigned char ch, unsigned char cl) { ch -= 0x81; cl -= 0x40; return (ch<=0x7d && cl<=0xbe) ? mb_gb2uni_table[ch*0xbf+cl] : 0x1fff; } Unicode转UTF-8: /***************************************************************************** * 将一个字符的Unicode(UCS-2和UCS-4)编码转换成UTF-8编码. * * 参数: * unic 字符的Unicode编码值 * pOutput 指向输出的用于存储UTF8编码值的缓冲区的指针 * outsize pOutput缓冲的大小 * * 返回值: * 返回转换后的字符的UTF8编码所占的字节数, 如果出错则返回 0 . * * 注意: * 1. UTF8没有字节序问题, 但是Unicode有字节序要求; * 字节序分为大端(Big Endian)和小端(Little Endian)两种; * 在Intel处理器中采用小端法表示, 在此采用小端法表示. (低地址存低位) * 2. 请保证 pOutput 缓冲区有最少有 6 字节的空间大小! ****************************************************************************/ int enc_unicode_to_utf8_one(unsigned long unic, unsigned char *pOutput, int outSize) { if(pOutput == NULL) return 0; if(outSize < 6) return 0; if ( unic <= 0x0000007F ) { // * U-00000000 – U-0000007F: 0xxxxxxx *pOutput = (unic & 0x7F); return 1; } else if ( unic >= 0x00000080 && unic <= 0x000007FF ) { // * U-00000080 – U-000007FF: 110xxxxx 10xxxxxx *(pOutput+1) = (unic & 0x3F) | 0x80; *pOutput = ((unic >> 6) & 0x1F) | 0xC0; return 2; } else if ( unic >= 0x00000800 && unic <= 0x0000FFFF ) { // * U-00000800 – U-0000FFFF: 1110xxxx 10xxxxxx 10xxxxxx *(pOutput+2) = (unic & 0x3F) | 0x80; *(pOutput+1) = ((unic >> 6) & 0x3F) | 0x80; *pOutput = ((unic >> 12) & 0x0F) | 0xE0; return 3; } else if ( unic >= 0x00010000 && unic <= 0x001FFFFF ) { // * U-00010000 – U-001FFFFF: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx *(pOutput+3) = (unic & 0x3F) | 0x80; *(pOutput+2) = ((unic >> 6) & 0x3F) | 0x80; *(pOutput+1) = ((unic >> 12) & 0x3F) | 0x80; *pOutput = ((unic >> 18) & 0x07) | 0xF0; return 4; } else if ( unic >= 0x00200000 && unic <= 0x03FFFFFF ) { // * U-00200000 – U-03FFFFFF: 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx *(pOutput+4) = (unic & 0x3F) | 0x80; *(pOutput+3) = ((unic >> 6) & 0x3F) | 0x80; *(pOutput+2) = ((unic >> 12) & 0x3F) | 0x80; *(pOutput+1) = ((unic >> 18) & 0x3F) | 0x80; *pOutput = ((unic >> 24) & 0x03) | 0xF8; return 5; } else if ( unic >= 0x04000000 && unic <= 0x7FFFFFFF ) { // * U-04000000 – U-7FFFFFFF: 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx *(pOutput+5) = (unic & 0x3F) | 0x80; *(pOutput+4) = ((unic >> 6) & 0x3F) | 0x80; *(pOutput+3) = ((unic >> 12) & 0x3F) | 0x80; *(pOutput+2) = ((unic >> 18) & 0x3F) | 0x80; *(pOutput+1) = ((unic >> 24) & 0x3F) | 0x80; *pOutput = ((unic >> 30) & 0x01) | 0xFC; return 6; } return 0; } (三)生成中文图像 与上上一篇介绍的内容相似,只是一个中文占用两个字节,按两个字节处理一个中文字就可以正常显示了。 /************************************************************ *Copyright (C),lcb0281at163.com lcb0281atgmail.com *BlogAddr: caibiao-lee.blog.csdn.net *FileName: debug_font_osd.c *Description:字符和文字生成图片 *Date: 2020-02-03 *Author: Caibiao Lee *Version: V1.0 *Others: *History: ***********************************************************/ #include <stdlib.h> #include <stdio.h> #include <string.h> #include “SDL/SDL.h” #include “SDL/SDL_ttf.h” #include “debug_font_osd.h” #define CHINESET_STRING “阿标在学习中” #define FONT_PATH “./font/hisi_osd.ttf” int string_to_bmp(char *pu8Str) { SDL_PixelFormat *fmt; TTF_Font *font; SDL_Surface *text, *temp; if (TTF_Init() < 0 ) { fprintf(stderr, “Couldnt initialize TTF: %s\n”,SDL_GetError()); SDL_Quit(); } font = TTF_OpenFont(FONT_PATH, 80); if ( font == NULL ) { fprintf(stderr, “Couldnt load %d pt font from %s: %s\n”,18,”ptsize”, SDL_GetError()); } SDL_Color forecol = { 0xff, 0xff, 0xff, 0xff }; text = TTF_RenderUTF8_Solid(font, pu8Str, forecol); fmt = (SDL_PixelFormat*)malloc(sizeof(SDL_PixelFormat)); memset(fmt,0,sizeof(SDL_PixelFormat)); fmt->BitsPerPixel = 16; fmt->BytesPerPixel = 2; fmt->colorkey = 0xffffffff; fmt->alpha = 0xff; temp = SDL_ConvertSurface(text,fmt,0); SDL_SaveBMP(temp, “save.bmp”); SDL_FreeSurface(text); SDL_FreeSurface(temp); TTF_CloseFont(font); TTF_Quit(); return 0; } int CreateTimeBmpPicture(void) { time_t l_stTime; struct tm l_stTm; struct tm *l_pstTm=&l_stTm; char s8Contenx[128]={0}; time(&l_stTime); localtime_r(&l_stTime,l_pstTm); snprintf(s8Contenx,sizeof(s8Contenx), “20%02d-%02d-%02d-%02d:%02d:%02d”,\ (l_pstTm->tm_year-100), (1+l_pstTm->tm_mon), l_pstTm->tm_mday,\ l_pstTm->tm_hour, l_pstTm->tm_min, l_pstTm->tm_sec); printf(“string: %s \n”,s8Contenx); string_to_bmp(s8Contenx); } int CreateChinesePicture(void) { int i = 0; char l_s32Len = 0; char l_arrs8Str[64] = {0}; char l_arrs8UTFBuf[64] = {0}; char l_arrss8Contenx[64] = {0}; unsigned short usUnicode=0; unsigned int usUtfLen=0; unsigned int u32ContenxOffest=0; snprintf(l_arrs8Str,sizeof(l_arrs8Str),”%s”,CHINESET_STRING); l_s32Len = strlen(l_arrs8Str); printf(” len = %d \n”,l_s32Len); for(i=0;i<l_s32Len;) { usUnicode=zz_gbk2uni((unsigned char)l_arrs8Str[i++],(unsigned char)l_arrs8Str[i++]); usUtfLen= enc_unicode_to_utf8_one(usUnicode,l_arrs8UTFBuf,64); if(usUtfLen<0) { printf(“%s %d out len error \n”,__FUNCTION__,__LINE__); break; }; memcpy(&l_arrss8Contenx[u32ContenxOffest],l_arrs8UTFBuf,usUtfLen); u32ContenxOffest+=usUtfLen; } string_to_bmp(l_arrss8Contenx); return 0; } int main(void) { printf(“hello world \n”); //CreateTimeBmpPicture(); CreateChinesePicture(); return 0; } 工程文件结构: biao@ubuntu:~/nfs/OSD/font$ tree -L 2
<

├── bin

│ └── objs

├── debug_font_osd.c

├── debug_font_osd.h

├── font

│ ├── hisi_osd.ttf

│ └── hisi_osd.ttf_df

├── GBK_To_Unicode.c

├── GBK_To_Unicode.h

├── inc

│ ├── freetype2

│ ├── ft2build.h

│ └── SDL

├── lib

│ ├── libfreetype.a

│ ├── libfreetype.so

│ ├── libfreetype.so.6

│ ├── libSDL-1.2.so.0

│ ├── libSDL.a

│ ├── libSDLmain.a

│ ├── libSDL.so

│ ├── libSDL_ttf-2.0.so.0

│ ├── libSDL_ttf.a

│ ├── libSDL_ttf.so

│ └── pkgconfig

├── Makefile

├── save.bmp

└── test

8 directories, 20 files

biao@ubuntu:~/nfs/OSD/font$ 生成的图片显示为:

如果需要将中文字符添加视频流中去,可以参考上一篇博客的内容。 第一个生成时间图像的工程可以从下面获取: GitHub: freetype_SDL_Dl_ttf_debug CSDN : freetype_SDL_Dl_ttf_debug.tar.gz

原文链接:https://blog.csdn.net/li_wen01/article/details/105025120

猜你喜欢