-
点阵字库生成工具
2008-06-17 15:18:20
经过这两天的摸索和实践,终于做好了第一版点阵字库生成工具,开心 ^o^
之前做TFT Driver的时候,一直期望能有一个比较好用的点阵字库生成工具,但是从网上找到的都是需要注册之后才可以生成任意大小的字库~不方便!
其实老早就想自己写一个了,但是苦于一直没有太多精力~
前几天西藏大学的学生咨询有关藏文字库的问题,突然感觉,是时候自己写一个字库生成工具了~虽然目前还不能对藏文的编码等有了解,但是做一个简体汉字字库的生成工具,也是必要的了~~ 也是希望能为像我一样苦于不能找到一个简单易用的字库生成器的朋友们提供一个免费开放的小软件 :-)
言归正传。
MFC提供了一些API帮助用户方便的从各种系统字库中提取需要的点阵数据。大致上是使用这个函数:
DWORD GetGlyphOutline( UINT nChar,
UINT nFormat,
LPGLYPHMETRICS lpgm,
DWORD cbBuffer,
LPVOID lpBuffer,
const MAT2 FAR* lpmat2 ) const;
这个函数的各个参数的用法可以去查MSDN,利用这个函数的典型应用如下:int FontSize = 48;
CString FontName = "宋体";
int ch = 'A';
//////////////////////////////////////////////////////
CDC dcScreen;
dcScreen.CreateDC("DISPLAY", NULL, NULL, NULL);
CFont newfont;
newfont.CreateFont(FontSize,
0,
0,
0,
0,
0,
0,
0,
DEFAULT_CHARSET,
OUT_CHARACTER_PRECIS,
CLIP_CHARACTER_PRECIS,
DEFAULT_QUALITY,
DEFAULT_PITCH|FF_DONTCARE,
FontName);
CFont *poldfont=dcScreen.SelectObject(&newfont);
//////////////////////////////////////////////////////
GLYPHMETRICS pGL;
MAT2 mat2 = {
{0, 1},
{0, 0},
{0, 0},
{0, 1},
};// 获取字符ch的点阵数据的大小
int len =dcScreen.GetGlyphOutline(ch, GGO_BITMAP, &pGL, 0, NULL, &mat2);
// 申请空间unsigned char *pBuf = new unsigned char [len];
// 保存点阵数据
dcScreen.GetGlyphOutline(ch, GGO_BITMAP, &pGL, len, pBuf, &mat2);
// 接下来就可以利用pBuf里的数据来显示了// 最后记得释放掉pBuf,并还原Screen DC的字体
dcScreen.SelectObject(poldfont);
delete []pBuf;使用上面的代码可以很方便的拿到字符ch的点阵数据。这里需要注意的是,获取到的点阵数据是横向取点,第一个点保存在第一个字节的最高位,另外,点阵数据的每一行都是要做4字节对齐的。
也就是说,48*48的点阵数据,它的每一行实际是8个字节,而不是48/8=6字节!
为了做4字节对齐,可以使用这样的方法来得到每一行的宽度:int FontWidth = ((FontSize + 31) >> 5) << 2;
上面的公式在网上随处可见,也是典型的有效的快速做对齐的方法。
由于在写这个软件的时候可能不仅仅这一个地方需要做对齐的操作,所以索性就写了一个对齐函数:
static const int sc_PowerMap[] = {
0, 0, 1, 0, 2, 0, 0, 0, 3,
};
int Power(int n)
{
if((n > 0) && (n < sizeof(sc_PowerMap) / sizeof(int)))
return sc_PowerMap[n];
return -1;
}#define ALIGN(num, align) (((((num) + (align) * 8 - 1) >> (3 + Power(align)))) << Power(align))
利用宏ALIGN就可以求得num的align字节对齐的结果,比如:ALIGN(32, 4)即可得到32做4字节对齐
当然,这里写的这个宏是有一定的局限性的,它只能做2的n次幂个字节的对齐,即,只能做1字节、2字节、4字节、8字节等对齐操作。不过,一般情况下这已经足够用了,因为很少有人变态到在二进制的计算机里使用3字节或5字节对齐这样的数据存储方式~~
得到字符的点阵数据之后,问题接踵而来。正如之前转的那个《根据所选择的 TrueType 字体生成点阵数据》里叙述的那样,GetGlyphOutline()函数得到的点阵数据仅仅是下图中的BlackBox的范围内的数据。
而通常情况下我们希望得到的点阵数据是完整的lfHeight*gmCellIncX这么大范围内的数据。所以,有必要将BlackBox这幅“点阵图像”按照Origin所指示的原点给它移动到我们希望的字符范围的中间。
在阅读《根据所选择的 TrueType 字体生成点阵数据》一文时,其实并没有搞清楚上面的图中的各个参数是如何得到的。通过GetGlyphOutline()函数中的LPGLYPHMETRICS参数,可以得到BlackBoxX和BlackBoxY,以及gmCellIncX和gmCellIncY,以及Origin坐标等信息。但是在调试的过程中发现,gmCellIncY为0 ?由于机器上的MSDN出了问题,没办法查它的意义,所以只好硬着头皮尝试。另外还发现,Origin坐标中的y坐标看起来并不是以字符外框的左上角为原点计算的。后来以为是以左下角为原点计算,所以只需要:
off_x = Origin.x;
off_y = lfHeight - Origin.y;
就可以得到字符在框框中的起始坐标了,但是实际操作的时候发现,其实并不是这样的……因为在对某个字符的数据跟踪的时候发现,BlackBoxY的值是16(16号字体下),Orign.y是14,这简直是不可能的!因为off_y = 16-14=2,而如果起始y坐标是2的话,那么BlackBoxY已经是16个像素高了,再向下移动2个像素就会超出字符的外框啊~
结果这个问题导致了调试过程中经常由于内存操作越界而导致堆block损坏!
后来再回头去看《根据所选择的 TrueType 字体生成点阵数据》一文发现,原来Origin坐标的计算方法不是这样的,需要配合另外一个函数GetTextMetrics()来实现。最后,完整的获取点阵数据的函数如下:
int CHZKCreatorDlg::GetFontData(int ch, CString FontName, int FontSize, void *pBuf/*=NULL*/, int x_off/*=0*/, int y_off/*=0*/)
{
// 小于4号的字体不再输出
if(FontSize < 4)
{
if(pBuf == NULL)
return FontSize;
else
{
memset(pBuf, 0, FontSize);
return FontSize;
}
}
size_t RetSize = 0;
//////////////////////////////////////////////////////
CDC dcScreen;
dcScreen.CreateDC("DISPLAY", NULL, NULL, NULL);
CFont newfont;
newfont.CreateFont(FontSize,
0,
0,
0,
0,
0,
0,
0,
DEFAULT_CHARSET,
OUT_CHARACTER_PRECIS,
CLIP_CHARACTER_PRECIS,
DEFAULT_QUALITY,
DEFAULT_PITCH|FF_DONTCARE,
FontName);
CFont *poldfont=dcScreen.SelectObject(&newfont);
//////////////////////////////////////////////////////
TEXTMETRIC tm;
GLYPHMETRICS pGL;
MAT2 mat2 = {
{0, 1},
{0, 0},
{0, 0},
{0, 1},
};
dcScreen.GetTextMetrics(&tm);
int len =dcScreen.GetGlyphOutline(ch, GGO_BITMAP, &pGL, 0, NULL, &mat2);
//////////////////////////////////////////////////////
//int Truelen = (ch & 0xff00) != 0 ? ALIGN(FontSize, 4) : ALIGN(FontSize / 2, 4);
int Truelen = (ch & 0xff00) != 0 ? ALIGN(FontSize, 1) : ALIGN(FontSize / 2, 1);
int Fontlen = ALIGN(pGL.gmBlackBoxX, 4);
int TransLen = Truelen > Fontlen ? Fontlen : Truelen;
int FontOffY = tm.tmAscent - pGL.gmptGlyphOrigin.y;
int FontOffX = pGL.gmptGlyphOrigin.x < 0 ? 0 : pGL.gmptGlyphOrigin.x;
RetSize = Truelen * FontSize;
if(pBuf != NULL)
{
memset(pBuf, 0, RetSize);
if(len > 0)
{
unsigned char *pSrc = new unsigned char [len];
unsigned char *pDest = (unsigned char *)pBuf;
dcScreen.GetGlyphOutline(ch, GGO_BITMAP, &pGL, len, pSrc, &mat2);
for(int i = 0; i < len / Fontlen; i++)
{
memcpy(pDest + i * Truelen, pSrc + i * Fontlen, TransLen);
}
delete []pSrc;
ConvertMetrux(pDest, Truelen, FontSize, x_off + FontOffX, y_off + FontOffY);
}
}
dcScreen.SelectObject(poldfont);
return RetSize;
}中间的循环memcpy的过程是将GetGlyphOutline()得到的数据copy至输出Buffer中,在这个过程中需要注意,由于希望输出的点阵数据的每行是1字节对齐而不是4字节对齐,所以copy长度需要计算一下。
最后,使用ConvertMetrux()函数来完成对点阵数据的偏移操作,以便将点阵数据放到外框的中间位置上去。其中,可以注意到,FontOffX和FontOffY就是根据Origin计算得到的需要做的偏移量。另外,x_off和y_off是希望留出一个比较灵活的结果,让用户可以对字体在点阵中的位置进行微调,最后,将Origin和用户微调的程度结合起来送给ConvertMetrux函数来完成数据在矩阵内的搬移。有关数据的搬移,今天就先不介绍啦,哈,卖个关子先~(嘿嘿,其实是怕出丑啦,代码写的比较烂
)利用上面的这个函数就可以比较好的获取字符ch的点阵数据了。剩下的工作就是做一个循环,把所有的ch都调用一下这个函数,然后将得到的数据写入到文件里就OK啦~^o^
先把工具放出来让大家看看吧:-)
工具下载:http://www.lupaworld.com/223681/viewspace_101386.html
目前支持简体中文GB2312和英文ASCII
-
【转】根据所选择的 TrueType 字体生成点阵数据
2008-06-10 10:03:24
在找藏文字库制作工具的时候,很不幸并没有找到相关软件,不过找到了一些truetype字库,于是依稀记得网上有相关truetype转点阵的帖子,索性搜了一下,结果看到下面这篇文章,觉得不错,于是转过来备用,呵呵~~
TrueType字体在Windows平台下的应用很多,但是涉及到具体的操作层面上中文资料还是很少,遇到了不少问题苦恼了一阵子。
1、 通过 CFontDialog 进行字体选择,但是正常情况下得到的字体列表示当前系统中所有支持的字体,当然也包括其它一些非 TrueType 字体,要在 CFontDialog 的列表中剔出非 TrueType 的字体很简单,只需在配置 CFontDialog 时如下设置:
CFontDialog dlg;
dlg.m_cf.Flags |= CF_TTONLY; //only enum TrueType2、 要遍历所选择的字体中所包含的所有字符,这个我们不禁想到可以通过 .ttf文件的解析来完成,但是如何得到选择的字体所对应的 .ttf文件哪?同实际的操作,得知在CfontDialog中显示的字体的名称和所对应的.ttf文件不是一一对应的关系,例如:选择的字体为 Arial 那么在 System/Fonts/下却没有 Arial.ttf 的文件,在网上找了很多例子都不能百分百无误的实现,在 codeproject 中有一个例子 Sample 通过注册表的方法来查找,但是同样存在上面的问题。而且即使能够找到相对应的.ttf文件,要解析这个文件也很有困难,因为存在 ttc的问题(即:一个是一个ttf的集合,一个文件里面有可能定义几种 TrueType 字体),这样还要根据选择的字体然后在读取ttf文件的过程中进行比较,找到描述这种这种字体的部分,后来发现选择的字体有可能和文档中定义的 TrueType 字体名称不一致,因为有中文字体的存在,这一部分我并没有进行测试。因为在之后的解决过程找到了另外一种解决的方法。
DWORD CDC::GetFontData( DWORD dwTable, DWORD dwOffset, LPVOID lpData, DWORD cbData ) const;
Remarks
Retrieves font-metric information from a scalable font file. The information to retrieve is identified
by specifying an offset into the font file and the length of the information to return. An application
can sometimes use the GetFontData member function to save a TrueType font with a document. To do this,
the application determines whether the font can be embedded and then retrieves the entire font file,
specifying 0 for the dwTable, dwOffset, and cbData parameters.通过上面的函数可以轻易的得到选入DC中的TrueType字体的 ttf文件中的数据,但是如果想得到整个的字体文件还是会存在ttc的问题,因为这个函数得到的数据是其中选择的那种字体的数据,但是对于各个数据段 offset的定义却是针对于整个文档的,如果直接引用就会有问题,也没有找到其他更好的解决方法,但是却可以准确地得到关于其中任意一个Table的数 据,刚刚好对于字符集中所包含的字符的定于存在于"cmap" Table中,问题解决了,如下:
// Macro to pack a TrueType table name into a DWORD.
其中具体的一些操作也可以参照 msdn 中的文章。之后就是解析ttf文件了,这要参考MS发布的TrueType Font规格书了,当然即使看懂了规格书,要自己做解析程序也是短时间难以完成的,还是让我们来找找有没有其他的 已经有了的经验,在这里就要提到一个开源的项目了 fontforge 这是个日本人和台湾人维护的一个项目,可以支持多种字体进行解析和编辑,可以是个 Linux 下的程序,不过我们可以使用 Cygwin 来使这个程序在 Windows下运行起来,具体请参考 freefonts.oaka.org,但是这个程序太复杂太庞大了,我们一时半会 还不能理出头绪来,幸好在 cle.linux.org 看到 fontfoge 中有一个小工具叫做 showttf.c 可以简单的对于ttf文件进行解析,下载过来,进行编译,很有效。之后将其改进成可以只针对于“cmap”数据进行解析,并得到字体中支持字符的分段。
#define MAKETABLENAME(ch1, ch2, ch3, ch4) (\
(((DWORD)(ch4)) << 24) | \
(((DWORD)(ch3)) << 16) | \
(((DWORD)(ch2)) << 8) | \
((DWORD)(ch1))
)
DWORD tag = MAKETABLENAME( ''c'',''m'',''a'',''p'' );
DWORD size = m_pFontDC->GetFontData(tag,0, NULL, 0);
unsigned char *pBuffer = new unsigned char[size];
m_pFontDC->GetFontData(tag,0,pBuffer,size);
//do something with pBuffer
delete[] pBuffer;/*
3、通过选入字体的DC得到字体的点阵数据,这个处理依靠如下的函数,
read a short(2 bytes) from a stream
**/
static int Getushort(unsigned char **ttf) {
unsigned char ch1 = **(ttf);
(*ttf)++;
unsigned char ch2 = **(ttf);
(*ttf)++;
return( (ch1<<8)|ch2 );
}
/*
read a long(4 bytes) from a stream
**/
static int Getlong(unsigned char **ttf) {
unsigned char ch1 = **(ttf);
(*ttf)++;
unsigned char ch2 = **(ttf);
(*ttf)++;
unsigned char ch3 = **(ttf);
(*ttf)++;
unsigned char ch4 = **(ttf);
(*ttf)++;
return( (ch1<<24)|(ch2<<16)|(ch3<<8)|ch4 );
}
/*
Parse the table of "cmap"
**/
BOOL ReadttfEncodings(unsigned char *start_addr)
{
BOOL bResult = TRUE;
unsigned char *ttf = start_addr;
//local variable
int i;
int nencs, version;
int enc = 0;
int platform, specific;
int offset, encoff;
int format, len;
int segCount;
unsigned short *endchars,*startchars;
version = Getushort(&ttf);
nencs = Getushort(&ttf);
if ( version!=0 && nencs==0 )
nencs = version;/* Sometimes they are backwards */
for ( i=0; i < nencs; ++i )
{
platform = Getushort(&ttf);
specific = Getushort(&ttf);
ōffset = Getlong(&ttf);
if ( platform==3 /*&& (specific==1 || specific==5)*/)
{
enc = 1;
encoff = offset;
} else if ( platform==1 && specific==0 && enc!=1 )
{
enc = 2;
encoff = offset;
} else if ( platform==1 && specific==1 )
{
enc = 1;
encoff = offset;
} else if ( platform==0 ) {
enc = 1;
encoff = offset;
}
if ( platform==3 )
{
//MS Symbol
}
else if ( platform==1 )
{
//Mac Roman;
}
else if ( platform==0 )
{
//Unicode Default
}
else{}
}
if ( enc!=0 )
{
//reset pointer address
ttf = start_addr + encoff;
format = Getushort(&ttf);
if ( format!=12 && format!=10 && format!=8 )
{
len = Getushort(&ttf);
/*Language*/ Getushort(&ttf);
}
else
{
/* padding */ Getushort(&ttf);
len = Getlong(&ttf);
/*Format*/ Getlong(&ttf);
}
if ( format==0 )
{
//can''t be supported
bResult = FALSE;
}
else if ( format==4 )
{
//Format 4 (Windows unicode),only supported Format 4
segCount = Getushort(&ttf)/2;
/* searchRange = */ Getushort(&ttf);
/* entrySelector = */ Getushort(&ttf);
/* rangeShift = */ Getushort(&ttf);
endchars = new unsigned short[segCount];
for ( i=0; i < segCount; ++i )
endchars[i] = Getushort(&ttf);
if ( Getushort(&ttf)!=0 )
{
//Expected 0 in true type font;
}
startchars = new unsigned short[segCount];
for ( i=0; i < segCount; ++i )
startchars[i] = Getushort(&ttf);
//do something with endchars & startchars
delete[] startchars;
delete[] endchars;
}
else if ( format==6 )
{
/* Apple''s unicode format */
/* Well, the docs say it''s for 2byte encodings, but Apple actually*/
/* uses it for 1 byte encodings which don''t fit into the require-*/
/* ments for a format 0 sub-table. See Zapfino.dfont */
//can''t be supported
bResult = FALSE;
}
else if ( format==2 )
{
//can''t be supported
bResult = FALSE;
}
else if ( format==12 )
{
//can''t be supported
bResult = FALSE;
}
else if ( format==8 )
{
// fprintf(stderr,"I don''t support mixed 16/32 bit
// characters (no unicode surogates), format=%d", format);
// can''t be supported
bResult = FALSE;
}
else if ( format==10 )
{
//fprintf(stderr,"I don''t support 32 bit characters format=%d", format);
//can''t be supported
bResult = FALSE;
}
else
{
//fprintf(stderr,"Eh? Unknown encoding format=%d", format);
//can''t be supported
bResult = FALSE;
}
}
return bResult;
}DWORD GetGlyphOutline( UINT nChar,
UINT nFormat,
LPGLYPHMETRICS lpgm,
DWORD cbBuffer,
LPVOID lpBuffer,
const MAT2 FAR* lpmat2 ) const;
Remarks
Retrieves the outline curve or bitmap for an outline character in the current font.具体请参考 msdn 可以得到 anti-alias 等多种格式的数据。 但是这个有一个问题就是如果对应一个字体的size的各个参数,这里面的麻烦很多,后来总结如下如下:

还有补充的就是 GetGlyphOutline 数据是有一定的对齐方式的,要进行一些处理,代码如下:BOOL CreateFontMatrix(int iAA,
UINT nChar,
unsigned char **pOutPut,
int *iBytesPreLine,
int *iLine,
int *iBaseLine,
int *iBox_x,
int *iBox_y)
{
unsigned char *pBuf;
TEXTMETRIC tm;
GLYPHMETRICS glyph;
int width,height,box_x,box_y,ori_x,ori_y,size,iAdjust;
BOOL bRel = TRUE;
MAT2 mat2 =
{
{ 0, 1, },
{ 0, 0, },
{ 0, 0, },
{ 0, 1, }
};
//Get glyph outline
memset(&glyph,0,sizeof(GLYPHMETRICS));
size = m_pFontDC->GetGlyphOutline(nChar,m_nFormat,&glyph,0,NULL,&mat2);
if (size >= 0) // if char is space, the size may be zero
{
int count = 0;
int data = 0;
pBuf = new unsigned char[size];
m_pFontDC->GetTextMetrics(&tm);
m_pFontDC->GetGlyphOutline(nChar,m_nFormat,&glyph,size,pBuf,&mat2);
ori_x = glyph.gmptGlyphOrigin.x;
//if ori_x is negative,set ori_x zero
ori_x = (ori_x < 0) ? 0 : ori_x;
ori_y = tm.tmAscent - glyph.gmptGlyphOrigin.y;
box_x = glyph.gmBlackBoxX;
box_y = glyph.gmBlackBoxY;
width = glyph.gmCellIncX;
iAdjust = (box_x+3)&0xfffc; //DWORD align
if((box_x + ori_x) > width)
box_x = width - ori_x;
height= m_pLf->lfHeight;
//convert
int index = 0;
if (iAA == AA_2)
{
width = (width%4 == 0)?width/4:(width/4+1); //here,to 2bits/pix
*pOutPut = new unsigned char[width*height + 1];
memset(*pOutPut,0,width*height + 1);
//if size == 0 all data is 0
if(size > 0)
{
for (int i = 0; i < box_y; i++)
{
for (int j = 0; j < box_x; j++)
{
//int k = pBuf[i*iAdjust + j];
data = AA2_GRAG_MATRIX[pBuf[i*iAdjust + j]];
index = (i + ori_y)*width + (j + ori_x)/4;
switch((j + ori_x)%4)
{
case 0:
(*pOutPut)[index] |= (data<<6)&0xC0;
break;
case 1:
(*pOutPut)[index] |= (data<<4)&0x30;
break;
case 2:
(*pOutPut)[index] |= (data<<2)&0x0C;
break;
case 3:
(*pOutPut)[index] |= data&0x03;
break;
default:
{}
}
}//end j
}//end i
}
}//end AA 2*2
else if (iAA == AA_4)
{
width = (width%2 == 0)?width/2:(width/2+1); //here,to 4bits/pix
*pOutPut = new unsigned char[width*height + 1];
memset(*pOutPut,0,width*height + 1);
//if size == 0 all data is 0
if(size > 0)
{
for (int i = 0; i < box_y; i++)
{
for (int j = 0; j < box_x; j++)
{
ASSERT(pBuf[i*iAdjust + j] <= 17);
data = AA4_GRAG_MATRIX[pBuf[i*iAdjust + j]];
index = (i + ori_y)*width + (j + ori_x)/2;
switch((j + ori_x)%2)
{
case 0:
(*pOutPut)[index] |= (data<<4)&0xF0;
break;
case 1:
(*pOutPut)[index] |= data&0x0F;
break;
default:
{}
}
}//end j
}//end i
}
}//end AA 4*4
else //start Normal
{
//Note: monochrome bitmap,the first data in pBuff is on the Left-bottom
// one bit per pix
width = (width%8 == 0)?width/8:(width/8+1); //here,to 4bits/pix
if (width == 0)
width = 1;
*pOutPut = new unsigned char[width*height + 1];
memset(*pOutPut,0,width*height + 1);
//if size == 0 all data is 0
if(size > 0)
{
for (int i = 0; i < box_y; i++)
{
for (int j = 0; j < width; j++)
{
(*pOutPut)[(i + ori_y)*width + j] |= data<<(8-ori_x);
data = pBuf[i*(size/box_y) + j];
(*pOutPut)[(i + ori_y)*width + j] |= data>>ori_x;
}//end j
}//end i
}
}//end else(normal bitmap)
if(pBuf != NULL)
delete[] pBuf;
//set return result
*iBytesPreLine = width;
*iLine = height;
*iBaseLine = tm.tmAscent;
*iBox_x = glyph.gmCellIncX;//box_x;
*iBox_y = box_y;
bRel = TRUE;
}
else//if size
bRel = FALSE;
return bRel}
-
LRC歌词读取和排序算法
2008-06-05 15:41:16
代码写了其实挺久了,现在突然想起来,鼓励自己下下,呵呵
代码是为了给SPCE3200做一个微型mp3播放器而做的。界面仿千千静听,使用软件解码器解mp3,滚动条、文件列表,基本功能差不多都有了,后来突然想到为它增加歌词显示,这样才算比较完整。
所以就开始要写lrc的解释程序了。之前对lrc有一点了解,知道它最主要的就是用时间标签表达每一句歌词需要显示的时间。
所以,lrc解释程序的最主要任务就是分析时间标签,然后将实际的歌词拿出来~~~
看代码吧:
#include <string.h>
#include "lrc.h"
#define isnumeric(a) (((a >= '0') && (a <= '9')) ? 1 : 0)void CopyLrcInfo(LRC_INFO *DstInfo, LRC_INFO *SrcInfo)
{
DstInfo->Time = SrcInfo->Time;
DstInfo->Prev = SrcInfo->Prev;
DstInfo->Next = SrcInfo->Next;
strcpy(DstInfo->LrcText, SrcInfo->LrcText);
}LRC_INFO *GetFirstOfList(LRC_QUEUE *List)
{
return &List->List[List->First];
}u16_t InsertList(LRC_QUEUE *List, u32_t Time, char LrcText[])
{
int InsertPos = -1;
u16_t i;
LRC_INFO *lp = &List->List[List->Last];
if(List->Length == 0)
{
List->List[0].Time = Time;
strcpy(List->List[0].LrcText, LrcText);
List->List[0].Prev = (void*)0;
List->List[0].Next = (void*)0;
List->First = 0;
List->Last = 0;
List->Length = 1;
InsertPos = 0;
}
else
{
for(i = List->Length; i != 0; i--)
{
if(lp->Time <= Time)
{
if(i == List->Length)
{
List->Last = List->Length;
lp->Next = &List->List[List->Length];
List->List[List->Length].Prev = lp;
List->List[List->Length].Next = (void*)0;
// List->First = List->Length;
// lp->Prev = &List->List[List->Length];
// List->List[List->Length].Prev = (void*)0;
// List->List[List->Length].Next = lp;
}
else
{
LRC_INFO *temp = lp->Next;
lp->Next = &List->List[List->Length];
List->List[List->Length].Prev = lp;
List->List[List->Length].Next = temp;
temp->Prev = &List->List[List->Length];
}
List->List[List->Length].Time = Time;
strcpy(List->List[List->Length].LrcText, LrcText);
InsertPos = (List->Length = List->Length + 1);
break;
}
else if(i == 1)
{
List->First = List->Length;
lp->Prev = &List->List[List->Length];
List->List[List->Length].Prev = (void*)0;
List->List[List->Length].Next = lp;
List->List[List->Length].Time = Time;
strcpy(List->List[List->Length].LrcText, LrcText);
InsertPos = (List->Length = List->Length + 1);
// List->Last = List->Length;
// lp->Next = &List->List[List->Length];
// List->List[List->Length].Prev = lp;
// List->List[List->Length].Next = (void*)0;
// List->List[List->Length].Time = Time;
// strcpy(List->List[List->Length].LrcText, LrcText);
// InsertPos = (List->Length = List->Length + 1);
}
lp = lp->Prev;
}
}
return InsertPos;
}u32_t GetLrcInfo(char *LrcFile, u32_t FileSize, LRC_QUEUE *List)
{
s32_t ōffsetTime = 0;
u32_t CurOffset = 0;
u32_t CurTime = 0;
u32_t TempOffset;
int Flag = 0;memset(List, 0, sizeof(*List));
// List->Length = 0;
// List->First = 0;
// List->Last = 0;
// List->List[0].Prev = (void*)0;
// List->List[0].Next = (void*)0;do {
if(LrcFile[CurOffset++] == '[')
{
if(Flag == 0)
if(strncmp(&LrcFile[CurOffset], "offset:", 7) == 0)
{
CurOffset += 7;
if(LrcFile[CurOffset] == '-')
{
Flag = -1;
CurOffset++;
}
else
Flag = 1;
while(LrcFile[CurOffset] != ']')
{
OffsetTime *= 10;
OffsetTime += LrcFile[CurOffset++] - '0';
}
OffsetTime = OffsetTime / 10 * Flag;
}
if(isnumeric(LrcFile[CurOffset]))
{
char *lrc;
Flag = 1;
CurTime = (((LrcFile[CurOffset] - '0') * 10 + (LrcFile[CurOffset + 1] - '0')) * 60 +
((LrcFile[CurOffset + 3] - '0') * 10 + LrcFile[CurOffset + 4] - '0')) * 100;
CurOffset += 5;
if(LrcFile[CurOffset] == '.')
{
CurTime += (LrcFile[CurOffset + 1] - '0') * 10 + LrcFile[CurOffset + 2] - '0';
CurOffset += 3;
}
CurOffset++;
TempOffset = CurOffset;
while((LrcFile[TempOffset] == '[') && isnumeric(LrcFile[TempOffset + 1]))
{
while((LrcFile[TempOffset] != ']') && (TempOffset < FileSize))
TempOffset++;
TempOffset++;
}
lrc = &LrcFile[TempOffset];
while((LrcFile[TempOffset] != 0x0d) && (LrcFile[TempOffset] != 0x0a) && (TempOffset < FileSize))
TempOffset++;
LrcFile[TempOffset] = '\0';
InsertList(List, CurTime + OffsetTime, lrc);
}
// else
// {
// while(LrcFile[CurOffset++] != ']');
// }
}
} while(CurOffset < FileSize);
return 0;
}头文件:
#ifndef __LRC_H__
#define __LRC_H__#define MAX_LINE 128
#define MAX_LINE_LEN 255
typedef int s32_t;
typedef unsigned int u32_t;
typedef unsigned short u16_t;
typedef unsigned char u8_t;typedef struct _LRC_INFO {
u32_t Time;
char LrcText[MAX_LINE_LEN];
struct _LRC_INFO *Prev;
struct _LRC_INFO *Next;
} LRC_INFO;typedef struct {
LRC_INFO List[MAX_LINE];
u16_t Length;
u16_t First;
u16_t Last;
} LRC_QUEUE;u32_t GetLrcInfo(char *LrcFile, u32_t FileSize, LRC_QUEUE *List);
LRC_INFO *GetFirstOfList(LRC_QUEUE *List);
#endif代码主体部分用来从lrc数据的开头开始解析时间标签,检测到一个标签就将对应的歌词提取出来,并放入一个链表中。
采用链表是为了方便排序。在这段代码中同时提供了典型的链表排序的过程,这样,扫描以便lrc数据,就可以将所有的时间标签以及对应的歌词提取出来,并顺序放到链表中~~
程序中虽然用到了链表,但是并没有使用动态内存分配,因为本身这个程序是给嵌入式平台写的,确切的说,是一个“裸奔”的嵌入式平台,呵呵~~
这个代码在vc下验证通过,不过之前的那个vc project找不到了,真是无语~~ 唉,我还是挺邋遢的一人~经常弄丢自己的东西
-
呵呵,又开了个blog
2008-06-05 14:22:05
看来我是个好动的人~~
之前一直在163上写东西(嘻嘻,说是“一直”,其实没写几个字儿 ^o^),最近突然发现lupa也还不错,就索性在这边也来维护一个空间~
其实最主要的是想给自己换换环境,lupa是个以技术为主的社区,想想自己在单片机和嵌入式摸爬滚打时间也不算短了,但是总不晓得拿什么东西出来~ 有时候看其他人的日志,满篇的文章,看的我心里痒痒~~
所以,索性就在lupa开坛做法~ 督促自己坚持分享和记录吧
