点阵字模缩放显示代码

2019-08-17 07:11发布

本帖最后由 EDA3rd 于 2017-6-18 14:08 编辑

根据野火开发板的代码优化修改而来,出处参考野火的显示任意大小字符实验,但是原始代码开辟了128*128=16kB的ram空间,太浪费了,于是优化了一一下

分步版本,每个bit 映射为一个字节,占用大量内存,:
[mw_shl_code=c,true]/***********************缩放字体****************************/
//#define ZOOMMAXBUFF (48*48)
//#define TEMPBUFF (16*16*8)
u8 zoom_buf[ZOOMMAXBUFF] = {0};        //用于缩放的缓存,最大支持到128*128
u8 temp_buf[TEMPBUFF] = {0};//存储数字0~9的16x8字模
const unsigned char test_char[10][16] =
{
{0x00,0x00,0x00,0x18,0x24,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x24,0x18,0x00,0x00},/*"0",0*/
{0x00,0x00,0x00,0x10,0x70,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x7C,0x00,0x00},/*"1",1*/
{0x00,0x00,0x00,0x3C,0x42,0x42,0x42,0x04,0x04,0x08,0x10,0x20,0x42,0x7E,0x00,0x00},/*"2",2*/
{0x00,0x00,0x00,0x3C,0x42,0x42,0x04,0x18,0x04,0x02,0x02,0x42,0x44,0x38,0x00,0x00},/*"3",3*/
{0x00,0x00,0x00,0x04,0x0C,0x14,0x24,0x24,0x44,0x44,0x7E,0x04,0x04,0x1E,0x00,0x00},/*"4",4*/
{0x00,0x00,0x00,0x7E,0x40,0x40,0x40,0x58,0x64,0x02,0x02,0x42,0x44,0x38,0x00,0x00},/*"5",5*/
{0x00,0x00,0x00,0x1C,0x24,0x40,0x40,0x58,0x64,0x42,0x42,0x42,0x24,0x18,0x00,0x00},/*"6",6*/
{0x00,0x00,0x00,0x7E,0x44,0x44,0x08,0x08,0x10,0x10,0x10,0x10,0x10,0x10,0x00,0x00},/*"7",7*/
{0x00,0x00,0x00,0x3C,0x42,0x42,0x42,0x24,0x18,0x24,0x42,0x42,0x42,0x3C,0x00,0x00},/*"8",8*/
{0x00,0x00,0x00,0x18,0x24,0x42,0x42,0x42,0x26,0x1A,0x02,0x02,0x24,0x38,0x00,0x00},/*"9",9*/
};
/**
* @brief  缩放字模,缩放后的字模由1个像素点由8个数据位来表示
                                                                                0x01表示笔迹,0x00表示空白区
* @param  src_w :原始字符宽度
* @param  src_h :原始字符高度
* @param  dst_w :缩放后的字符宽度
* @param  dst_h:缩放后的字符高度
* @param  src_buf :字库输入指针        注意:1pixel 1bit
* @param  dst_buf :缩放后的字符输出指针 注意: 1pixel 8bit
* @param  en_cn :0为英文,1为中文
* @retval 无
*/
u8* ZoomChar(   u32 src_w,        //原始字符宽度
                u32 src_h,                //原始字符高度
                u32 dst_w,        //缩放后的字符宽度
                u32 dst_h,        //缩放后的字符高度
                u8 *src_buf,        //字库输入指针        注意:1pixel 1bit
                u8 *dst_buf, //缩放后的字符输出指针 注意: 1pixel 8bit
                u8 en_cn)                //0为英文,1为中文        
{
        u8 *tempbuff_ptr,*zoombuf_ptr;
        //根据源字模及目标字模大小,设定运算比例因子,左移16是为了把浮点运算转成定点运算
        u32 xpos_inc=(src_w<<16)/dst_w+1; //16<<16=16*(2^16) = 16 *65536 = 1048576
    u32 ypos_inc=(src_h<<16)/dst_h+1;  //原本的16/128 = 1/8 , 再乘上65536 = 8192
    //得到坐标单位增量,在目标字模上,坐标标移动1,源字模坐标移动1/8。也就是说,当目标字模画完8个点,原始坐标才取完1个点,正好1:8的比例,16*16 -> 128*128
        
        u32 ypos=0;
        u32 y,x;
        u8 *p_line;
        
        u16 byte_cnt;
    u8 i;
   
        //检查参数是否合法
        if(src_w >= 32) return NULL;                                                                                                //字库不允许超过32像素,
    //128/32=4,也就是说,最多放大4倍
        if(src_w * src_h == 0) return NULL;        
        if(src_w * src_h >= 1024 ) return NULL;                                         //限制输入最大 32*32
   
        if(dst_w * dst_h == 0) return NULL;        
        if(dst_w * dst_h >= ZOOMMAXBUFF ) return NULL; //限制最大缩放 128*128
        tempbuff_ptr = (u8*)temp_buf;
        
        //为方便运算,字库的数据由1 pixel/1bit 映射到1pixel/8bit,所以16*16的大小变为16*8*16=2048= 128*16
        //0x01表示笔迹,0x00表示空白区
        if(en_cn == 0x00)//英文
        {
                //英文和中文字库上下边界不对,可在此处调整。需要注意tempBuff防止溢出
                        for(byte_cnt=0;byte_cnt<src_h*src_w/8;byte_cnt++)        
                        {
                                for(i = 0;i <8;i++)
                                        {                                                
                                                //把源字模数据由位映射到字节
                                                //src_buf里bitX为1,则tempbuff_ptr里整个字节值为1
                                                //src_buf里bitX为0,则tempbuff_ptr里整个字节值为0
                                                *tempbuff_ptr++ = (src_buf[byte_cnt] & (0x80>>i ))?1:0;
                                        }
                        }
        }
        //zoom过程
        tempbuff_ptr = (u8*) temp_buf;        //映射后的源数据指针
        zoombuf_ptr = (u8*) zoom_buf;        //输出数据的指针
   
        for (y = 0; y < dst_h; y++)        // y < 16行遍历假设高为128
    {
                u32 xpos =0;//横坐标
        p_line = tempbuff_ptr + (src_w * (ypos>>16)); //p_line = 行首指针,指向 temp_buf
        for (x=0;x<dst_w;x++) /*行内像素遍历*/ //假设 dst_w = 128,比例因子为1/8<<16
        {
            zoombuf_ptr[x]=p_line[xpos >>16]; //把源字模数据复制到目标指针中,每次偏移 1/8,当到达增量满1时,跨入下一个原始像素
            xpos += xpos_inc;                        //按比例偏移源像素点
        }
        ypos += ypos_inc;                    //按比例偏移源像素点
        zoombuf_ptr+=dst_w;        //下一行
    }
        dst_buf = (u8*)zoom_buf;
    return dst_buf;
}

void DrawCharEx(u16 x, //字符显示位置x
                u16 y, //字符显示位置y
                u16 font_w, //字符宽度
                u16 font_h,  //字符高度
//                u8 *c,                                                //字模数据
                u16 drawmode)                //是否反 {MOD}显示
{
    u32 xcnt = 0, ycnt = 0;
    u8 *c = zoom_buf;
    u16 x0 = x;
    ZoomChar(8, 16, font_w, font_h ,(u8 *)test_char, zoom_buf, 0);
        for ( ycnt = 0; ycnt < font_h; ycnt++ )
        {
                        for ( xcnt = 0; xcnt < 24; xcnt++ )
                        {
                                        if ( *c++)
                                                LCD_Fast_DrawPoint(x, y, POINT_COLOR);
                                        else
                                                LCD_Fast_DrawPoint(x, y, BACK_COLOR);
                    x++;
                    if(x>=lcddev.width){return;}//超区域
                        }
            y++;//下一行
            if(y>=lcddev.height){return;}//超区域
            x = x0;//返回左端
            
        }
}

void printf_char(u16 font_w, u16 font_h)
{
    u32 xcnt = 0, ycnt = 0;
    u8 *c = zoom_buf;
//    ZoomChar(8, 16, 24, 48 ,(u8 *)test_char, zoom_buf, 0);
        for ( ycnt = 0; ycnt < font_h; ycnt++ )
        {
                        //逐位处理要显示的颜 {MOD}
                        for ( xcnt = 0; xcnt < font_w; xcnt++ )
                        {
                                        //缩放后的字模数据,以一个字节表示一个像素位
                                        //整个字节值为1表示该像素为笔迹
                                        //整个字节值为0表示该像素为背景
                                        if ( *c++)
                                                printf("*");
                                        else
                                                printf(" ");
                        }
            printf(" ");
        }

[/mw_shl_code]优化版,精简映射过程,节省内存空间,只占用(原字符bit数*8)字节的临时空间:[mw_shl_code=c,true]
//#define TEMPBUFF (16*16*8)
u8 temp_buf[TEMPBUFF] = {0};
/**
* @brief  缩放字模,缩放后的字模由1个像素点由8个数据位来表示
                                                                                0x01表示笔迹,0x00表示空白区
* @param  src_w :原始字符宽度
* @param  src_h :原始字符高度
* @param  dst_w :缩放后的字符宽度
* @param  dst_h:缩放后的字符高度
* @param  src_buf :字库输入指针        注意:1pixel 1bit
* @param  dst_buf :缩放后的字符输出指针 注意: 1pixel 8bit
* @param  en_cn :0为英文,1为中文
* @retval 无
*/
u8* ZoomChar(   u32 src_w,        //原始字符宽度
                u32 src_h,                //原始字符高度
                u32 dst_w,        //缩放后的字符宽度
                u32 dst_h,        //缩放后的字符高度
                u8 *src_buf,        //字库输入指针        注意:1pixel 1bit
                u8 *dst_buf, //缩放后的字符输出指针 注意: 1pixel 8bit
                u8 en_cn)                //0为英文,1为中文        
{
        u8 *tempbuff_ptr;
        u16 byte_cnt;
    u8 i;

        //检查参数是否合法
        if(src_w >= 32) return NULL;                                                                                                //字库不允许超过32像素,
    //128/32=4,也就是说,最多放大4倍
        if(src_w * src_h == 0) return NULL;        
        if(src_w * src_h >= 1024 ) return NULL;                                         //限制输入最大 32*32

        if(dst_w * dst_h == 0) return NULL;        
        if(dst_w * dst_h >= ZOOMMAXBUFF ) return NULL; //限制最大缩放 128*128
        tempbuff_ptr = (u8*)temp_buf;
        
        //为方便运算,字库的数据由1 pixel/1bit 映射到1pixel/8bit,所以16*16的大小变为16*8*16=2048= 128*16
        //0x01表示笔迹,0x00表示空白区
        if(en_cn == 0x00)//英文
        {
                //英文和中文字库上下边界不对,可在此处调整。需要注意tempBuff防止溢出
                        for(byte_cnt=0;byte_cnt<src_h*src_w/8;byte_cnt++)        
                        {
                                for(i = 0;i <8;i++)
                                        {                                                
                                                //把源字模数据由位映射到字节
                                                //src_buf里bitX为1,则tempbuff_ptr里整个字节值为1
                                                //src_buf里bitX为0,则tempbuff_ptr里整个字节值为0
                                                *tempbuff_ptr++ = (src_buf[byte_cnt] & (0x80>>i ))?1:0;
                                        }
                        }
        }
    return NULL;
}

void MyDrawCharEx(u16 x, //字符显示位置x                u16 y, //字符显示位置y
                u16 font_w, //字符宽度
                u16 font_h,  //字符高度
                u16 drawmode)                //是否反 {MOD}显示
{
    u32 xcnt = 0, ycnt = 0;
    u16 x0 = x;
        u8 *p_line;
    u32 src_w = 8;
    u32 src_h = 16;
    u32 xpos, ypos=0;
    u32 xpos_inc=(src_w<<16)/font_w+1; //16<<16=16*(2^16) = 16 *65536 = 1048576
    u32 ypos_inc=(src_h<<16)/font_h+1;  //原本的16/128 = 1/8 , 再乘上65536 = 8192

    ZoomChar(8, 16, font_w, font_h ,(u8 *)test_char, NULL, 0);

        for ( ycnt = 0; ycnt < font_h; ycnt++ )
        {
        xpos =0;//横坐标
        p_line = temp_buf + (src_w * (ypos>>16)); //p_line = 行首指针,指向 temp_buf
        for ( xcnt = 0; xcnt < font_w; xcnt++ )
        {
            if (p_line[xpos >>16])
                LCD_Fast_DrawPoint(x, y, POINT_COLOR);
            else
                LCD_Fast_DrawPoint(x, y, BACK_COLOR);
            xpos += xpos_inc;
            x++;
            if(x>=lcddev.width){return;}//超区域
        }
        ypos += ypos_inc;                    //按比例偏移源像素点
        y++;//下一行
        if(y>=lcddev.height){return;}//超区域
        x = x0;//返回左端
        }
}[/mw_shl_code]
QQ图片20170618134658.jpg









友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
3条回答
正点原子
1楼-- · 2019-08-17 10:29
 精彩回答 2  元偷偷看……
EDA3rd
2楼-- · 2019-08-17 11:51
本帖最后由 EDA3rd 于 2017-6-18 13:59 编辑
正点原子 发表于 2017-6-18 13:32
这个不错啊,有实际缩放显示效果么?比如16*16的字模,我可以放大成24*24,32*32,48*48这样子的?放大后效 ...

刚刚上传了图片,16x8放大到48x24。优化后的代码理论上可以放大无数倍,不过毕竟不是矢量图形,放大后会出现锯齿,对于低倍数放大应用还行
EDA3rd
3楼-- · 2019-08-17 14:25
正点原子 发表于 2017-6-18 13:32
这个不错啊,有实际缩放显示效果么?比如16*16的字模,我可以放大成24*24,32*32,48*48这样子的?放大后效 ...

原子哥的代码取字模怎么都是逐列式的呢? 如果是逐行式,就可以使用LCD开窗口指令快速写字了,大大提高速度啊。

一周热门 更多>