DM36x IPNC OSD显示中文 --- 基础知识篇

为了简单起见,只显示GB2312(简体中文)字符

一、GB2312汉字编码

1.区位码

在国标GB2312—80中规定,所有的国标汉字及符号分配在一个94行、94列的方阵中,方阵的每一行称为一个“区”,编号为01区到94区,每一列称为一个“位”,编号为01位到94位,方阵中的每一个汉字和符号所在的区号和位号组合在一起形成的四个阿拉伯数字就是它们的“区位码”。区位码的前两位是它的区号,后两位是它的位号。用区位码就可以唯一地确定一个汉字或符号,反过来说,任何一个汉字或符号也都对应着一个唯一的区位码。汉字“母”字的区位码是3624,表明它在方阵的36区24位,问号“?”的区位码为0331,则它在03区31位。

2.机内码

汉字的机内码是指在计算机中表示一个汉字的编码。机内码与区位码稍有区别。如上所述,汉字区位码的区码和位码的取值均在1~94之间,如直接用区位码作为机内码,就会与基本ASCII码混淆。为了避免机内码与基本ASCII码的冲突,需要避开基本ASCII码中的控制码(00H~1FH),还需与基本ASCII码中的字符相区别。为了实现这两点,可以先在区码和位码分别加上20H,在此基础上再加80H(此处“H”表示前两位数字为十六进制数)。经过这些处理,用机内码表示一个汉字需要占两个字节,分别 称为高位字节和低位字节,这两位字节的机内码按如下规则表示:
高位字节 = 区码 + 20H + 80H(或区码 + A0H)
低位字节 = 位码 + 20H + 80H(或位码 + AOH)
由于汉字的区码与位码的取值范围的十六进制数均为01H~5EH(即十进制的01~94),所以汉字的高位字节与低位字节的取值范围则为A1H~FEH(即十进制的161~254)。
例如,汉字“啊”的区位码为1601,区码和位码分别用十六进制表示即为1001H,它的机内码的高位字节为B0H,低位字节为A1H,机内码就是B0A1H。

根据上面的概念,可以使用以下程序将所有的GB2312编码字符保存在一个文件中:

#include <stdio.h>
int main()
{
    int area_code,location_code;
    unsigned char c[3]={0};
    FILE * fp = fopen("gb2312_table.c","wb");
    char buf[100];
    if(fp)
    {
        sprintf(buf,"#include \"gb2312.h\"\n\nunsigned short gb2312_table[]=\n{\n");
        fwrite(buf,1,strlen(buf),fp);
        for(area_code=1;area_code<95;area_code++)//区码为1-94
        {
            fputc('\t',fp);
            c[0]=area_code + 0xA0;//区码 + A0H 转换为机内码 高字节
            for(location_code=1;location_code<95;location_code++)//位码为1-94
            {
                c[1]=location_code+0xA0;//位码 + A0H 转换为机内码 低字节
                if(area_code == 1 && location_code == 1)
                    sprintf(buf," 0x%02X%02X",c[0],c[1]);
                else
                    sprintf(buf,",0x%02X%02X",c[0],c[1]);
                fwrite(buf,1,strlen(buf),fp);
            }
            fputc('\n',fp);//每区一行
        }
        sprintf(buf,"\n};\n\nint GetGB2312TableLen()\n{\n\treturn sizeof(gb2312_table)/sizeof(unsigned short);\n}\n");
        fwrite(buf,1,strlen(buf),fp);
        fclose(fp);
    }
    return 0;
}

这里多生成了一个函数GetGB2312TableLen,用于获取gb2312_table大小.

下面是一个GB2312区位码查询、转换、区位码全表网址:
http://www.mytju.com/classcode/tools/QuWeiMa.asp

二、UNICODE编码

Unicode是一个涵盖了目前全世界使用的所有已知字符的单一编码方案,也就是说Unicode为每一个字符提供唯一的编码。UTF-16是unicode的16位编码方式,是一种定长多字节编码,用2个字节表示一个unicode字符,AF16UTF16是UTF-16编码字符集。
UTF-8是unicode的8位编码方式,是一种变长多字节编码,这种编码可以用1、2、3个字节表示一个unicode字符,AL32UTF8,UTF8、UTFE是UTF-8编码字符集.
为了方便编码之间的转换,下面的实现均在linux下进行,因为在linux下有libiconv库供我们进行编码转换使用,这里还需要注意,通过使用iconv函数转换编码为unicode宽字符时,如果不是转换为utf-16be或者utf-16le指定的字节序,转换后的字符串最前面会多两个字节用于识别unicode字符串的字节序,开头两个字节为FE FF时为Big-Endian,为FF FE时为Little-Endian.
下面是两个编码转换函数,在具体实现中需要包含iconv.h头文件,如果iconv_open函数失败,perror打印错误信息为"无效参数",解决方法参考博文: http://blog.csdn.net/zxwangyun/article/details/9171057
这个函数将UTF8编码字符串转换为GB2312字符串,转换后的每个字符用2Byte存储,高位在前低位在后
static int Utf8ToGb2312(char *sOut, int iMaxOutLen/*BYTE*/, const char *sIn, int iInLen/*BYTE*/)
{  
    char *pIn = (char *)sIn;  
    char *pOut = sOut;  
    size_t ret;  
    size_t iLeftLen=iMaxOutLen;  
    iconv_t cd = iconv_open("gb2312", "utf-8");  
    if (cd == (iconv_t) - 1)  
    {  
        perror("iconv_open()");
        return -1;  
    }  
    size_t iSrcLen=iInLen;
    ret = iconv(cd, &pIn,&iSrcLen, &pOut,&iLeftLen);  
    if (ret == (size_t) - 1)  
    {  
        perror("iconv()");
        iconv_close(cd);  
        return -1;  
    }  
    iconv_close(cd);  
    return (iMaxOutLen - iLeftLen);  
}

有些字符串中可能还包含有ASCII字符,转换后的GB2312编码的字符串可用下面的代码进行检测字符为中文还是ASCII字符
    len = Utf8ToGb2312((char*)gb2312,sizeof(gb2312),utf8,strlen(utf8));
    printf("UTF8 TEXT LEN:%d converted len=%d\n",strlen(utf8),len);
    for(i=0;i<len;i++)
    {
        if(gb2312[i]<128)//为ANSC字符,每个字符用1个Byte存储
        {
            printf("ASCII Encode \t-- code:%c \n",gb2312[i]);
        }
        else//为GB2312(简体中文),每个字用两个Byte存储
        {
            printf("GB2312 Encode \t-- Area code:%02d%02d Machine code:0x%04x\n",gb2312[i]- 0xA0,gb2312[i+1]-0xA0,(gb2312[i]<<8)|gb2312[i+1]);
            i++;//别忘了GB2312字符需要2个Byte
        }
    }

这个函数将GB2312编码字符串转换为UTF-16BE(大端字节序)字符串,转换后的每个字符用2Byte存储,高位在前低位在后
static int Gb2312ToUtf16be(char *sOut, int iMaxOutLen/*BYTE*/, const char *sIn, int iInLen/*BYTE*/)
{  
    char *pIn = (char *)sIn;  
    char *pOut = sOut;  
    size_t ret;  
    size_t iLeftLen=iMaxOutLen;  
    iconv_t cd = iconv_open("UTF-16BE", "gb2312");  
    if (cd == (iconv_t) - 1)  
    {  
        perror("iconv_open()");
        return -1;  
    }  
    size_t iSrcLen=iInLen;
    ret = iconv(cd, &pIn,&iSrcLen, &pOut,&iLeftLen);  
    if (ret == (size_t) - 1)  
    {  
        perror("iconv()");
        iconv_close(cd);  
        return -1;  
    }  
    iconv_close(cd);  
    return (iMaxOutLen - iLeftLen);  
}

UNICODE字符串区分ASCII字符和中文字符很简单,如果是UTF-16BE编码的Unicode字符串(每个字符都用2个Byte来存储),只需要看高8位是否为0即可,如果为0,则为ASCII字符

三、ASCII编码

ASCII字符中的可见字符为33-126(ASCII值)共94个字符(0-31为控制字符,32为空格,略过),以下为94个ascii可见字符:
!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~

四、freetype2入门

参看 http://blog.chinaunix.net/uid-190095-id-3123383.html中的例子即可对ft2进行简单使用
这里是一个更详细的ft2的文档: http://blog.sina.com.cn/s/blog_4ab2ba570100y7fm.html

五、ffmpeg libswscale库简单使用

libswscale库使用很简单,下面是一个一幅24bit的bmp图片数据转换为yuv数据的例子,这里将yuv数据直接存储在了一个数组并保存在一个文件中.
需要注意的是,如果直接将YUV数据进行显示,可能和原bmp图片相比是上下颠倒的,所以在转换前,最好将该24bit的bmp图片进行垂直翻转后再进行转换.

#include <stdio.h>
#include "bmp_header.h"

//包含swscale.h头文件
#ifdef __cplusplus
extern "C"{
#endif
#include "libavformat/avformat.h"
#include "libswscale/swscale.h"
#ifdef __cplusplus
}
#endif

int save_bgr24_to_yuv420p(const char * src_bmp24_file,const char * dst_yuv_data_file)
{
    FILE *fp = NULL;
    struct SwsContext *pSwsCtx=NULL;
    uint8_t * bmp_data = NULL;
    int data_size = 0;
    int w=0,h=0;

    fp = fopen(src_bmp24_file, "rb");//打开图片
    if(fp)
    {
        // 位图文件头
#ifdef _WIN32
        BITMAPFILEHEADER bmpheader={0};
        BITMAPINFO bmpinfo={0};
        fread(&bmpheader,sizeof(BITMAPFILEHEADER),1,fp);
        fread(&bmpinfo.bmiHeader,sizeof(BITMAPINFOHEADER),1,fp);
        w = bmpinfo.bmiHeader.biWidth;
        h = bmpinfo.bmiHeader.biHeight;
        data_size = bmpheader.bfSize - bmpheader.bfOffBits;
#else
        FileHead bmp_head;
        Infohead bmp_info;
        fread(&bmp_head,sizeof(FileHead),1,fp);
        fread(&bmp_info,sizeof(Infohead),1,fp);
        w = bmp_info.biWidth;
        h = bmp_info.biHeight;
        data_size = bmp_head.bfSize - bmp_head.bfOffBits;
#endif
        if(h<0)h=-h;
        if(data_size != w * h * 3)
        {
            printf("not 24 bit bmp,file size = %d,w=%d,h=%d\n",data_size,w,h);
            fclose(fp);
            return -1;
        }
        bmp_data = (uint8_t *)malloc(data_size);
        memset(bmp_data,0,data_size);
        if(bmp_data)
        {
            fread(bmp_data,data_size,1,fp);
        }
        fclose(fp);
        fp = NULL;
    }
    if(bmp_data)
    {
        pSwsCtx = sws_getContext(
            w,
            h,
            PIX_FMT_BGR24,
            w,
            h,
            PIX_FMT_YUV420P,
            SWS_POINT/*SWS_BILINEAR*/,
            NULL,
            NULL,
            NULL);
        if(pSwsCtx)
        {
            uint8_t *data[4]={bmp_data,NULL,NULL,NULL};
            int linesize[4]    ={w*3,0,0,0};
            int height        = 0;
            uint8_t * buffer    = NULL;
            AVFrame * yuv_frame = avcodec_alloc_frame();
            buffer = (unsigned char *)av_malloc(avpicture_get_size(PIX_FMT_YUV420P,w,h));
            memset(buffer,0,avpicture_get_size(PIX_FMT_YUV420P,w,h));
            avpicture_fill((AVPicture*)yuv_frame,(uint8_t *)buffer,PIX_FMT_YUV420P,w,h);
            height = sws_scale(
                pSwsCtx,
                data,
                linesize,
                0,
                h,
                yuv_frame ->data,
                yuv_frame ->linesize);
            fp = fopen(dst_yuv_data_file,"w");
            if(fp)
            {
                char buf[1024]={0};
                int i=0;
                sprintf(buf,"/*********************Y***************************/\nunsigned char data_Y[]={");
                fwrite(buf,1,strlen(buf),fp);
                for(i=0;i<yuv_frame ->linesize[0]*height;i++)
                {
                    if(!(i%16))
                    {
                        sprintf(buf,"\n\t");
                        fwrite(buf,strlen(buf),1,fp);
                    }
                    if(i)
                    {
                        sprintf(buf,",0x%02X",*(yuv_frame ->data[0]+i));
                    }
                    else
                    {
                        sprintf(buf," 0x%02X",*(yuv_frame ->data[0]+i));
                    }
                    fwrite(buf,strlen(buf),1,fp);
                }
                sprintf(buf,"\n};\n//%d bytes\n/**************end of Y***************************/\n\n",yuv_frame ->linesize[0]*h);
                fwrite(buf,strlen(buf),1,fp);
                sprintf(buf,"/********************UV***************************/\nunsigned char data_UV[]={");
                fwrite(buf,1,strlen(buf),fp);
                for(i=0;i<yuv_frame ->linesize[1]*height/2;i++)
                {
                    if(!(i%8))
                    {
                        sprintf(buf,"\n\t");
                        fwrite(buf,strlen(buf),1,fp);
                    }
                    if(i)
                    {
                        sprintf(buf,",0x%02X,0x%02X",*(yuv_frame ->data[1]+i),*(yuv_frame ->data[2]+i));
                    }
                    else
                    {
                        sprintf(buf," 0x%02X,0x%02X",*(yuv_frame ->data[1]+i),*(yuv_frame ->data[2]+i));
                    }
                    fwrite(buf,strlen(buf),1,fp);
                }
                sprintf(buf,"\n};\n//%d bytes\n/*************end of UV***************************/\n\n",yuv_frame ->linesize[1]*h);
                fwrite(buf,strlen(buf),1,fp);
                fclose(fp);
                fp = NULL;
            }
            av_free(yuv_frame);
            av_free(buffer);

            sws_freeContext(pSwsCtx);
            pSwsCtx = NULL;
        }
        free(bmp_data);
        bmp_data = NULL;
    }
    return 0;
}

其中bmp_header.h定义linux下的BMP头结构体,定义如下

#ifndef __BMP_HEADER_H__
#define __BMP_HEADER_H__

#ifndef _WIN32
typedef long BOOL;
typedef long LONG;
typedef unsigned char BYTE;
typedef unsigned long DWORD;
typedef unsigned short WORD;
typedef struct {
    WORD    bfType;//2
    DWORD   bfSize;//4
    WORD    bfReserved1;//2
    WORD    bfReserved2;//2
    DWORD   bfOffBits;//4
}__attribute__((packed))FileHead;

typedef struct{
    DWORD      biSize;//4
    LONG       biWidth;//4
    LONG       biHeight;//4
    WORD       biPlanes;//2
    WORD       biBitCount;//2
    DWORD      biCompress;//4
    DWORD      biSizeImage;//4
    LONG       biXPelsPerMeter;//4
    LONG       biYPelsPerMeter;//4
    DWORD      biClrUsed;//4
    DWORD      biClrImportant;//4
}__attribute__((packed))Infohead;

#endif//_WIN32

#endif //__BMP_HEADER_H__

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值