1、简介
在嵌入式设备开发过程中,我们可能需要用到各种大小的字体,由于嵌入式设备的Flash限制,我们不能把各种大小的字体放入到设备的Flash中。因此,在某些场景下,考虑软件对字体放大的方式,达到我们的需求。比如我们可以在Flash中放入font16的字体,然后对这个字体进行正数倍放大(比如放大到font48);
2、处理流程
字模处理流程:
- 将字模转换成二值图像;
注意所用的字模参数为:字模采用阴码,列行式,取模顺序逆向
#include <stdio.h>
#include <string.h>
#include <string.h>
#include <math.h>
#include <stdint.h>
#include <stdlib.h>
#define BASE_FONTS_SIZE 16
//char in[BASE_FONTS_SIZE*BASE_FONTS_SIZE/8] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};
//char in[BASE_FONTS_SIZE*BASE_FONTS_SIZE/8] = {0x04,0xD4,0x54,0x5F,0x54,0xD4,0x04,0x00,0x04,0xD4,0x54,0x5F,0x54,0xD4,0x04,0x00,0x04,0xF5,0x57,0x55,0x57,0xF5,0x04,0x00,0x04,0xF5,0x57,0x55,0x57,0xF5,0x04,0x00};
char in[BASE_FONTS_SIZE*BASE_FONTS_SIZE/8] = {0xFC,0x84,0x84,0xFC,0x00,0x22,0xAA,0xAB,0xAA,0xBE,0x2A,0xAB,0x2A,0xA2,0x00,0x00,0x3F,0x10,0x10,0x3F,0x00,0x0A,0x56,0x9F,0x72,0x06,0x0A,0x4F,0x32,0x5A,0xE3,0x00};
char out[BASE_FONTS_SIZE*BASE_FONTS_SIZE] = {0,};
// 获取函数
uint32_t get_line(uint32_t len)
{
uint32_t fonts;
fonts = sqrt(len*8);
return fonts/8;
}
// 获取字体大小
uint32_t get_fonts(uint32_t len)
{
uint32_t fonts;
fonts = sqrt(len*8);
return fonts;
}
// 字模转化为二值图像,比如16*16的字模,可以转成16*16的数组,字模采用阴码,列行式,取模顺序逆向
int ch_to_arr(const char *pIn, int inLen, char *pOut)
{
char ch;
int i, j, k;
int line, fonts;
if (!pIn || !pOut)
{
return -1;
}
line = get_line(inLen);
fonts = get_fonts(inLen);
for(i=0; i<line; i++)
{
for(j=0; j<fonts; j++)
{
ch = pIn[i*fonts+j];
for(k=0; k<8; k++)
{
if ((ch>>k)&0x01)
{
pOut[(k+i*8)*fonts+j] = 1;
}
else
{
pOut[(k+i*8)*fonts+j] = 0;
}
}
}
}
return 0;
}
- 将二值图像等比例放大;
int font16_to_fontx(char *pArrFont16, uint32_t arrFont16Len, char *pOutFontx, uint32_t fontxLen, uint32_t zoom)
{
int i, j;
int m, n;
char *pFont;
uint32_t zoomx;
uint32_t zoomy;
uint32_t inFont;
uint32_t outFontx;
if(!pArrFont16 || !pOutFontx)
{
return -1;
}
if((fontxLen < arrFont16Len*zoom*zoom) || (zoom==0))
{
return -1;
}
pFont = malloc(fontxLen);
if (!pFont)
{
return -1;
}
inFont = sqrt(arrFont16Len);
outFontx = inFont * zoom;
printf("outFontx:%d\n", outFontx);
memset(pOutFontx, 0, fontxLen);
// 将单点放大
for(i=0; i<inFont; i++)
{
for(j=0; j<inFont; j++)
{
// 如果这个点为1,那么单点放大
if (pArrFont16[i*inFont + j] == 1)
{
pFont[zoom*i*outFontx+zoom*j] = 1;
}
}
}
for(i=0; i<outFontx; i++)
{
for(j=0; j<outFontx; j++)
{
// 如果这个点为1,那么将1变成4个
if (pFont[i*outFontx+j] == 1)
{
// 填充行
if (outFontx-i > zoom)
{
zoomx = zoom;
}
else
{
zoomx = outFontx-i;
}
// 填充行
if(outFontx-j > zoom)
{
zoomy = zoom;
}
else
{
zoomy = outFontx-i;
}
for(n=0; n<zoomx; n++)
{
for(m=0; m<zoomy; m++)
{
pOutFontx[(i+n)*outFontx + m + j] = 1;
}
}
}
}
}
free(pFont);
return 0;
}
- 做插值处理,优化放大后的字体,使其更平滑;
int font_interpolation(char *pFontin, uint32_t fontLen)
{
int i, j;
int sum = 0;
int cnt= 0;
char *pFontmp;
int fontSize = sqrt(fontLen);
if (!pFontin)
{
return -1;
}
pFontmp = (char *)malloc(fontLen);
if (!pFontmp)
{
return -1;
}
memcpy(pFontmp, pFontin, fontLen);
for(i=0; i<fontSize; i++)
{
for(j=0; j<fontSize; j++)
{
if (pFontin[i*fontSize+j] == 0)
{
sum = 0;
cnt = 0;
// 左边
if(j-1>=0)
{
cnt ++;
sum += pFontin[i*fontSize + j - 1];
}
// 右边
if(j+1<fontSize)
{
cnt ++;
sum += pFontin[i*fontSize + j + 1];
}
// 下边
if(i-1>=0)
{
cnt++;
sum += pFontin[(i-1)*fontSize + j];
}
// 下边
if(i+1<fontSize)
{
cnt++;
sum += pFontin[(i+1)*fontSize + j];
}
if (sum * 2 >= cnt)
{
pFontmp[i*fontSize+j] = 1;
}
}
}
}
memcpy(pFontin, pFontmp, fontLen);
return 0;
}
3、运行Demo
结合上述函数,可以用如下demo进行展示:
int main(void)
{
char *pOut;
uint32_t zoom = 4;
uint32_t pOutLen = 0;
ch_to_arr(in, sizeof(in), out);
print(out, BASE_FONTS_SIZE);
printf("\n\n");
pOutLen = BASE_FONTS_SIZE*BASE_FONTS_SIZE*zoom*zoom;
pOut = malloc(pOutLen);
if (!pOut)
{
return -1;
}
if (font16_to_fontx(out, sizeof(out), pOut, pOutLen, zoom))
{
free(pOut);
return -1;
}
print(pOut, BASE_FONTS_SIZE*zoom);
//printf("\n\n");
//gray_print(pOut,pOutLen);
printf("\n\n");
if (zoom>2)
{
font_interpolation(pOut, pOutLen);
print(pOut, BASE_FONTS_SIZE*zoom);
}
//printf("\n\n");
//gray_print(pOut,pOutLen);
//printf("\n\n");
free(pOut);
return 0;
}
“曦”字实际放大效果如下(从font16到font48):
1、原图:
2、等比例放大(放大三倍):
3、 插值处理之后的效果: