本帖最后由 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]
刚刚上传了图片,16x8放大到48x24。优化后的代码理论上可以放大无数倍,不过毕竟不是矢量图形,放大后会出现锯齿,对于低倍数放大应用还行
原子哥的代码取字模怎么都是逐列式的呢? 如果是逐行式,就可以使用LCD开窗口指令快速写字了,大大提高速度啊。
一周热门 更多>