海思多媒體(MPP)開發(6)——區域管理(REGION&OSD中文顯示)

(一)字符編碼介紹

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, 使用兩個字節表示一個漢字, 所以理論上最多可以表示256x256=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, "Couldn't initialize TTF: %s\n",SDL_GetError());  
        SDL_Quit();
    }  

    font = TTF_OpenFont(FONT_PATH, 80); 
    if ( font == NULL ) 
    {  
        fprintf(stderr, "Couldn't 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

完整region工程可以到「目錄與序言」提供的地址去獲取

 

本專欄第一篇文章「目錄與序言」列出了專欄的完整目錄,按目錄順序閱讀,有助於你的理解。

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章