DM36x IPNC OSD显示中文 --- 基本数据准备篇

经过上一篇的叙述,基本原理搞清楚后,便需要对我们在OSD上显示中文作数据准备,
首先是需要将gb2312关键区(也就是实际有文字存在的区)中的汉字转换为图片,在实际的转换中,并不像上一篇中GB2312编码转换为UNICODE描述一样,
使用libiconv库中的iconv函数将94x94的gb2312编码表直接传递给iconv函数会转换失败(错误提示不完整的多字节字符或宽字符).为了简化这其中的转换难度,目前使用的是查表的方法将GB2312编码转换为UNICODE编码,
这样就要求先准备好GB2312 UNICODE对照表,这个表网上有各种形式的,但是通过我花了很长时间查找也没有找到合适自己需求的,主要是网上的GB2312区位码不全,都会丢掉某些区中的某些编码,这样会有个问题,
就是我们转换后的数据需要记录我们中间丢失了哪些编码,对应的位置等等.会造成后续程序执行效率降低和设计难度加大.这里我是直接将94x94个GB2312编码都转换为对应的unicode编码,保存在一个数组中(很占篇幅,这里不贴实际数据了),通过查找下标的方式查找对应的UNICODE编码.
将对应的GB2312编码转换为UNICODE编码后,接下来就是使用Freetype2将该UNICODE码提取出对应的字符映像,并转换为位图,保存在磁盘上了,下面是其中的核心程序:
//linux下保存24位bmp图像,数据结构FileHead、Infohead见上一篇
int save_bmp24(char * filename,int width,int height,unsigned char *data)
{
    FileHead bmp_head;
    Infohead bmp_info;
    int size = width*height*3;
    FILE *fp = fopen(filename,"wb");
    if(!fp)
    {
        perror("open file error");
        return -1;
    }

    bmp_head.bfType=0x4d42;
    bmp_head.bfSize=size+sizeof(FileHead)+sizeof(Infohead);//24+head+info no quad    
    bmp_head.bfReserved1=bmp_head.bfReserved2=0;
    bmp_head.bfOffBits=bmp_head.bfSize-size;

    bmp_info.biSize=40;
    bmp_info.biWidth=width;
    bmp_info.biHeight=-height;//如果为正数,转换出来的图片还需要进行垂直翻转
    bmp_info.biPlanes=1;
    bmp_info.biBitCount = 24;
    bmp_info.biCompress=0;
    bmp_info.biSizeImage=size;
    bmp_info.biXPelsPerMeter=0;
    bmp_info.biYPelsPerMeter=0;
    bmp_info.biClrUsed=0;
    bmp_info.biClrImportant=0;

    fwrite(&bmp_head,1,sizeof(FileHead),fp);
    fwrite(&bmp_info,1,sizeof(Infohead),fp);
    fwrite(data,1,size,fp);
    fclose(fp);
    return 0;
}

//转换函数,这里是一个区转换为一个图片
int convert(const char * font_file,int font_width,int font_height)
{
    FT_Library library = NULL;
    FT_Face face = NULL;
    int error;
    int char_index;
    int char_code;
    
    unsigned char * bmpdata = NULL,*pdata;//保存一个字的图片数据
    int isVert = 0;//是否垂直布局,中文为垂直布局
    FT_Bitmap *ft_bmp;
    
    unsigned short  unicode;//用于存储unicode
    int index=0;
    int area,location;
    char testfilename[100];
    
    unsigned char *image = NULL, *pimage;//一个区转换为一张图片
    int temp;
    
    if(font_width <= 0 && font_height <= 0)
    {
        printf("invalidate font size.\n");
        return -1;
    }
    if(font_width <= 0)
        font_width = font_height;
    if(font_height <= 0)
        font_height = font_width;
    if(font_width % 2)//4字节对齐,这里先保证宽度为4pixel对齐
    {
        printf("invalidate font size.\n");
        return -1;
    }
    setlocale(LC_ALL,"zh_CN.UTF-8");

    do
    {
        //下面开始初始化FT2库
        error = FT_Init_FreeType(&library);
        if (error)
        {
            printf("can not init free type library!\n");
            break;
        }

        error = FT_New_Face(library, font_file, 0, &face);
        if (error)
        {
            printf("create new face falied!\n");
            break;
        }
        isVert = FT_HAS_VERTICAL(face);    
        error = FT_Set_Pixel_Sizes(face, font_width, font_height);//设置字体大小
        if (error)
        {
            printf("set font size error!\n");
            break;
        }
        bmpdata = malloc(font_width * font_height * 3);
        if(!bmpdata)
        {
            printf("outof memory.\n");
            break;
        }
        image = malloc(94 * font_width * font_height * 3);//这里要求font_size必须为偶数
        if(!image)
        {
            printf("outof memory.\n");
            break;
        }

#if 0
        //打印字体相关信息
        printf("file has %d faces\n", face->num_faces);
        printf("%s  italic or oblique,%s bold\n", face->style_flags & FT_STYLE_FLAG_ITALIC ?"support":"not support",face->style_flags & FT_STYLE_FLAG_BOLD ?"support":"not support");
        printf("file family name %s\n", face->family_name);
        printf("file style name %s\n", face->style_name);
        printf("face index %d\n", face->face_index);
        printf("number of char %d\n", face->num_glyphs);
        printf("number of fixed bitmap %d\n", face->num_fixed_sizes);
        printf("Char size %d\n", face->size);
        printf("has %d fixed sizes\n",face->num_fixed_sizes);
        for(i=0;i<face->num_fixed_sizes;i++)
        {
            printf("supported size %d:width=%d,heigh=%d\n",i+1,face->available_sizes[i].width,face->available_sizes[i].height);
        }
#endif
        error = FT_Select_Charmap(face,FT_ENCODING_UNICODE);//这里使用UNICODE映射表,便于使用UNICODE码(char code)来获取char index
        if(error)
        {
            printf("select char map error.\n");
            break;
        }
        //printf("code %x\n",face ->charmap ->encoding);
        switch(face ->charmap ->encoding)
        {
            case FT_ENCODING_MS_GB2312:    printf("USE GB2312 CODE\n");break;
            case FT_ENCODING_MS_BIG5:    printf("USE BIG5 CODE\n");break;
            case FT_ENCODING_UNICODE:    printf("USE UNICODE CODE\n");break;
            default:
                printf("UNKNOWN CODE\n");
                goto done;
                break;
        }
        
        //实际有字体的区码为(0-8) (15-86)区(区号从0开始 ) = 9 + 72 = 81个区
        for(area = 0;area < 87;area ++)//1- 87区
        {
            if( (area >8 && area < 15)/* 8 - 15区跳过*/
                ||(area > 86 && area < 94)/* 87 - 94 区跳过*/
            )
            {
                continue;
            }
            memset(image,0,94 * font_width * font_height * 3);
            pimage = image;
            for(location = 0;location < 94;location++)//1 - 94位
            {
                index = area * 94 + location;
                if(Gb2312ToUnicode(gb2312_table[index],&unicode) < 0)
                {
                    printf("get unicode code error.gb2312 code 0x%04X\n",gb2312_table[index]);
                    continue;
                }
                char_code = unicode;
                if(!char_code)
                {
                    printf("\ninvalidate char code.\n");
                    continue;
                }
                char_index = FT_Get_Char_Index(face,char_code);
                error = FT_Load_Glyph(face, char_index,  FT_LOAD_DEFAULT | FT_LOAD_MONOCHROME);
                if (error)
                {
                    printf("\nload char error!\n");
                    goto done;
                }
                if (face->glyph->format != FT_GLYPH_FORMAT_BITMAP)
                {
                    error = FT_Render_Glyph(face->glyph, FT_RENDER_MODE_MONO);
                    if (error)
                    {
                        printf("\nrender char failed!\n");
                        goto done;
                    }
                }

                /*
                单色位图图像数据的表示方法:
                在单色位图图像中,只有两种颜色,黑色或白色,每一个像素只需要一个比特就能够完成表示,为了清楚比特0或1具体表示哪一种颜色,可以通过查询调色板。
                在单色位图图像中,调色板只包含两种颜色,每一种颜色用R G B 0 四个字节表示 (在实际的字节流中,顺序是 B G R 0)
                所以,位图图像数据中的0 代表调色板中 第一种颜色的颜色值, 1 代表调色板中 第二种颜色的颜色值。
                一行单色位图数据的存储格式规定:
                每一扫描行的字节数必需是4的整倍数,当不够4的整数倍时,需要加0补齐
                以 720 × 450 的单色位图图像为例
                水平扫描行的长度为720,则需要720比特来表示一个扫描行,即需要 720/8=90字节来表示,但是 90不是 4 的整数倍,因此需要用0补齐,直至为4的整数倍,即需要额外的2个填充字节。
                最终,长度为720的水平扫描行使用了 92 个字节来表示。
                NOTE:非8位位图可用函数FT_Bitmap_Convert进行转换
                */
                //转换为4字节对齐
                ft_bmp = &face->glyph->bitmap;
#if 0
                //dump位图信息
                printf("bit_map_left %d bit_map_top %d\n", face->glyph->bitmap_left,face->glyph->bitmap_top);
                printf("int rows:%d\n",ft_bmp ->rows);
                printf("int width:%d\n",ft_bmp ->width);
                printf("int pitch:%d\n",ft_bmp ->pitch);
                printf("short num_grays:%d\n",ft_bmp ->num_grays);
                printf("char pixel_mode:%d\n",ft_bmp ->pixel_mode);
                if(isVert)
                {
                    printf("VERT:(w:%ld h:%ld)(bearingX:%ld bearingY:%ld Advance:%ld)\n",face->glyph->metrics.width/64,face->glyph->metrics.height/64,
                        face->glyph->metrics.vertBearingX/64,face->glyph->metrics.vertBearingY/64,face->glyph->metrics.horiAdvance/64);
                }
                else
                {
                    printf("HORI:(w:%ld h:%ld)(bearingX:%ld bearingY:%ld Advance:%ld)\n",face->glyph->metrics.width/64,face->glyph->metrics.height/64,
                        face->glyph->metrics.horiBearingX/64,face->glyph->metrics.horiBearingY/64,face->glyph->metrics.vertAdvance/64);
                }
                printf("xMin=%ld, yMin=%ld, xMax=%ld, yMax=%ld\n",face ->bbox.xMin,face ->bbox.yMin,face ->bbox.xMax,face ->bbox.yMax);
#endif        

                switch(ft_bmp ->pixel_mode)
                {
                    case FT_PIXEL_MODE_MONO://单色位图
                        {
                            //将数据转换到24位
                            int topblank     = 0;//字型顶部距离位图顶部空行数目
                            int leftblank     = 0;//字型左边距离位图左边空列数目
                            int rightblank     = 0;//字型右边距离位图右边空列数目
                            int pitch     = 0;//每个扫描行占用几个字节
                            int width    = ft_bmp ->width;//实际字型宽度
                            int height    = ft_bmp ->rows; //实际字型高度
                            unsigned char * ft_bmp_buff = ft_bmp ->buffer;
                            int i,j,k;
                            if(isVert)
                            {
                                topblank     = face->glyph->metrics.vertBearingY/64;
                                leftblank     = font_width/2 + face->glyph->metrics.vertBearingX/64;
                            }
                            else
                            {
                                topblank    = font_height * 2 /3 - face->glyph->metrics.horiBearingY/64;
                                leftblank     = face->glyph->metrics.horiBearingX/64;
                            }
                            if(topblank < 0)topblank     = 0;
                            if(leftblank < 0)leftblank     = 0;
                            rightblank = font_width - width - leftblank;
                            if(rightblank < 0)rightblank    = 0;
                            pitch =  ft_bmp ->width / 8;
                            if(pitch% ft_bmp ->pitch)
                                pitch = pitch + (ft_bmp ->pitch - pitch %ft_bmp ->pitch);
                            //printf("PITCH=%d\n",pitch);
                
                            //转换1bit位图数据到24bit位图数据
                            printf("begin convert.area %d ----> %d\r",area,location);
                            memset(bmpdata,0,font_width * font_height * 3);
                            pdata = bmpdata;
                            pdata += topblank *font_width * 3;//跳过上边距
                            for(i=0;i<height;i++)
                            {
                                pdata += leftblank * 3;
                                k = 7;
                                for(j=0;j<width;j++)
                                {
                                    if(ft_bmp_buff[j/8] & (1 << k) )
                                    {
                                        //pdata[0] = 255;//蓝
                                        pdata[1] = 255;//绿
                                        pdata[2] = 255;//红
                                    }
                                    k--;
                                    if(k<0)k=7;
                                    pdata += 3;
                                }
                                ft_bmp_buff += pitch;
                                pdata += rightblank * 3;
                            }
                            /*if(!(font_width %4))
                            {
                                sprintf(testfilename,"./testbmp/%d_%d.bmp",area,location );
                                printf("\nsave bmp file [%s]\n",testfilename);
                                if(save_bmp24(testfilename,font_width ,font_height,bmpdata))
                                {
                                    printf("save bmp file [%s] error.\n",testfilename);
                                }
                            }*/
    
                        }
                        break;
                    default:
                        printf("位图为非单色图片.\n");
                        goto done;
                        break;
                }//switch
                pdata = bmpdata;
                pimage = image + location * font_width * 3;                
                for(temp=0;temp<font_height;temp++)
                {
                    memcpy(pimage,pdata,font_width * 3);
                    pdata += font_width * 3;
                    pimage += 94 * font_width *3;
                }
#ifndef _WIN32
                usleep(10);
#else
                Sleep(10);
#endif
            }//for( 1 - 94 位 )
            //保存图片
            sprintf(testfilename,"./testbmp/area%d_%dx%d.bmp",area,font_width,font_height);
            //printf("\nsave bmp file [%s]\n",testfilename);
            if(save_bmp24(testfilename,94 * font_width,font_height,image))
            {
                printf("save bmp file [%s] error.\n",testfilename);
            }
        }//for( 1 - 94 区)
        printf("\nConvert Done.\n");

    }while (0);
done:
#if 0    //出现莫名其妙的错误,注释了
    fprintf(stderr,"begin cleanup.\n");
    if(bmpdata)
    {
        free(bmpdata);
        bmpdata = NULL;
    }
    if(image)
    {
        free(image);
        image = NULL;
    }
    if(face)
    {
        FT_Done_Face(face);
        face = NULL;
    }
    if(library)
    {
        FT_Done_FreeType(library);
        library = NULL;
    }
#endif
    return 0;
}

这里上传几个程序转换的图片:

14x16:

16x18:


20x24:

28x32:

将编码转换为图片后,需要将bmp24图片数据转换为yuv420p数据,利用libswscale库进行转换的核心代码已经在上一篇贴了,这里不再重贴.
下面是转换后的结果,当然也可以直接将数据保存为一个二进制文件,而不是一个C源程序文件
/*********************Y***************************/
unsigned char data_Y[]={
     0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10
    ,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10
    ,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10
    ,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10
    ......
    ,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10
    ,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10
    ,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10
    ,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10
};
//37224 bytes
/**************end of Y***************************/

/********************UV***************************/
unsigned char data_UV[]={
     0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80
    ,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80
    ,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80
    ,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80
    ......
    ,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80
    ,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80
    ,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x12,0x92,0x80,0x80,0x80,0x80
    ,0x80,0x80,0x80,0x80
};
//18612 bytes
/*************end of UV***************************/

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值