当前位置:主页 > 平面设计

最新发布

关于TrueType字体的结构
关于TrueType字体的结构

        TrueType字体通常包含在单个TrueType字体文件中,其文件后缀为.TTF。OpenType字体是以类似于TrueType字体的格式编码的POSTSCRIPT字体。OPENTYPE字体使用.OTF文件后缀。OPENTYPE还允许把多个OPENTYPE字体组合在一个文件中以利于数据共享。这些字体被称为TrueType字体集(TrueType collection),其文件后缀为.TTC。TrueType字体用machintosh的轮廓字体资源的格式编码,有一个唯一的标记名"sfnt"。windows没有macintosh的位图字体资源格式,字体目录包含了字体格式的版本号和几个表,每个表都有一个tableentry结构项,tableentry结构包含了资源标记、校验和、偏移量和每个表的大小。下面是TrueType字体目录的c语言定义:typedef sturct{char tag[4];ULONG checkSum;ULONG offset;ULONG length;}TableEntry;typedef struct{Fixed sfntversion; //0x10000 for version 1.0USHORT numTables;USHORT searchRange;USHORT entrySelector;USHORT rangeShift;TableEntry entries[1];//variable number of TableEntry}TableDirectory;TrueType 字体中的所有数据都使用big-endian编码,最高位字节在最前面(因为TrueType字体最初是由apple公司定义的,而apple公司的os运行在motorola的cpu上)。如果一人TrueType字体以00 01 00 00 ,00 17开头,我们就可以知道它的格式是轮廓字体资源("sfnt")版本1.0的格式,有23个表。TableDirectory结构的最后一个字段是可变长度的tableentry结构的数组,安体中的每个表对应其中一项。TrueType字体中的每个表都保存了不同的逻辑信息-----如图元中数据、字符到图元的映射、字距调整信息等等。有表是必须的,有些是可选的。下表列出了TrueType字体中常见的表。head 字体头 字体的全局信息cmap 字符代码到图元的映射 把字符代码映射为图元索引glyf 图元数据 图元轮廓定义以及网格调整指令maxp 最大需求表 字体中所需内存分配情况的汇总数据mmtx 水平规格 图元水平规格loca 位置表索引 把元索引转换为图元的位置name 命名表 版权说明、字体名、字体族名、风格名等等hmtx 水平布局 字体水平布局星系:上高、下高、行间距、最大前进宽度、最小左支撑、最小右支撑kerm 字距调整表 字距调整对的数组post PostScript信息 所有图元的PostScript FontInfo目录项和PostScript名PCLT PCL 5数据 HP PCL 5Printer Language 的字体信息:字体数、宽度、x高度、风格、记号集等等OS/2 OS/2和Windows特有的规格 TrueType字体所需的规格集在TableDirectory结构中,所有的TableEntry结构都必须根据它们的标记名排序。比如,cmap必须出现在head前,而head必须在glyf前。但是实际的表可以出现在TrueType字体文件中的任意位置。Win32API 提供了一个应用程序可用于查询原始TrueType字体信息的函数:DWORD GetFontData(HDC hDC,DWORD dwTable ,DWORD dwOffset, LPVOID lpbBuffer ,DWORD cbData);GetFontData函数可以用于查询设备上下文中当前逻辑字体所对应的TrueType字体,因此传递的不是逻辑字体句柄,而是设备上下文句柄。你可以查询整个TrueType文件基是文件中的一个表。要查询整个文件的话dwTable参数应该为0;否则,应该传递要查询的表的四字符标记的DWORD格式。参数dwOffset是要查询的表中的起始偏移,要查询整个表的话应该为0;参数;pvBuffer是缓冲区的地址,cbData是缓冲区的大小。如果最后个参数为NULL和0,GetFontData函数返回字体文件或表的大小;就会把到的数据拷贝到应用程序所提供的缓冲区中。下面的例和查询整个TrueType字体的原始数据:TableDirctory * GetTrueTypeFont (HDC hDC ,DWORD &nFontSize){//query font sizenFontSize=GetFontData(hDC,0,0,NULL,0);TableDirectory * pFont =(TableDirectory *)new BYTE(nFontSize);if (pFont==NULL)return NULL;GetFontData(hDC,0,0,pFont,nFontSize);return pFont;}GetFontData使得应用程序能够在自己的文档中内嵌TrueType字体,以确保这些文档能在没有相应字体的其他机器上显示。它的做法是允许应用程序查询字体数据,然后写入到文档中作为文档的一部分,在文档被打于时再安装该字体以确保文档能以创建时同样的方式显示。比如,Windows NT/2000的假脱机程序在打印到远端服务器时会在假脱机文件中内嵌入TrueType字体以保证文档能在另一台机器上正确地打印。一旦接受到TrueType字体的原始数据,它的头中的TableDirectory结构很容易分析。需要检查的只有版本号和表的数目,然后就可以检查单个的表。我们来看一些重要的和有趣的表。1.字体头字体头表(head表)中包含了TrueType字体的全局信息。下面是字体头表的结构。typedef sturct{Fixed Table;//x00010000 ro version 1.0Fixed fontRevision;//Set by font manufacturer.ULONG checkSumAdjustment;ULONG magicNumer; //Set to 0x5f0f3cf5USHORT flags;USHORT unitsPerEm; //Valid range is from 16 to 16384longDT created; //International date (8-byte field).longDT modified; //International date (8-byte field).FWord xMin; //For all glyph bounding boxes.FWord yMin; //For all glyph bounding boxes.FWord xMax; //For all glyph bounding boxes.FWord xMax; //For all glyph bounding boxes.USHORT macStyle;USHORT lowestRecPPEM; //Smallest readable size in pixels.SHORT fontDirctionHint;SHORT indexToLocFormat; //0 for short offsets ,1 for long.SHORT glyphDataFormat; //0 for current format.}Table_head;字体的历史记录在三个字段中:字全版本号、字体最初创建时间和字体最后修改时间。有8 个字节用于记录时间戳,记录的是从1904年1月1日午夜12:00开始的秒数,因此我们不用担心y2k问题,或是什么y2m问题。字体设计时是针对一个参考网格设计的,该网格被称为em-square,字体中的图元用网格中的坐标表示。因此em-squrare的大小决定胃该字体的图元被缩放的方式,同时也反映胃该字体的质量。字体头中保存了每个em-square的格数和能包含所有图元的边界框。Em-square的有效值是从16到16384,常见的值是2048、4096和8192。比如,Windings字体的em-square的格数是2048,图元的边界框是[0,-432,2783,1841]。字体头表中的其他信息包括最小可读像素大小、字体方向、在位置表中图元索引的格式和图元数据格式等等。最大需求表TrueType字体是一种非常灵活的数据结构,它可以包含可变数目的图元,每个图元可以有不同数目的控制点,甚至还可以有数量可变的图元指令。最大需求表的目的是告知字体栅格器(rasterizer)对内存的需求,以便在出来字体前分配合适大小的内存。因为性能对字体栅格器非常重要,像MFC的CAarray那样需要频繁进行数据拷贝操作的动态增长的数据结构不合要求。下面是maxp表的结构。typedef struct{Fixed Version;//0x00010000 for version 1.0.USHORT numGlypha; //Number of glyphs in the font .USHORT maxPoints; //Max points in noncomposite glyph .RSHORT maxContours; //Max contours in noncomposite glyph.USHORT maxCompositePoints;//Max points in a composite glyph.USHORT maxCompositeContours; //Max contours in a composite glyph.USHORT maxZones;// 1 if not use the twilight zone [Z0],//or 2 if so use Z0;2 in most cases.USHORT max TwilightPoints ;/ Maximum points used in Z0.USHORT maxStorage; //Number of storage area locations.USHORT maxFunctionDefs; //Number of FDEFs.USHORT maxStackElements; //Number of depth.USHORT maxSizeOfInstructions; //Max byte count for glyph inst.USHORT maxComponentElements; //Max number top components refernced.USHORT maxComponentDepth; //Max levels of recursion.}Table_maxp;numGlyphs字段保存了字体中图元的总数,这决定了到位置表的图元索引的数量,可以用于严正图元索引的有效性。TrueType字体中的每个图元都可以是合成图元或简单图元。简单图元可以有一条或多大体上轮廓中国,条用一些控制点定义。合成图元用几个其他图元的组合来定义。maxPoints\maxCountors\maxCompositePoints maxCompositeContours这几个字段说明了图元定义的复杂度。除了图元的定义,TrueType字体还使用了图元指令用于提示字体扫描器如何对控制点进行调整以得到更均衡更漂亮的光栅化后的图元。图元指令也可以出现在字体程序表(fpgm表)以及控制值程序表(“prep”)的全局字体层中。TrueType图元指令是一个伪计算机字节指令,该机类似于Java的虚拟机,这些指令可以用堆栈计算机执行。MaxStackElements maxSizeOfInstructions两个字段同志堆栈计算机这些指令的复杂度。以Windings字体为例,该字体有226个图元,图元最多有47条轮廓线,简单图元最多有268个点,合成图元最多有141个点,合成图元最多有14条轮廓线,最坏情况下需要492层堆栈,最长的指令有1119个字节。字符到图元索引的映射表(cmap表)定义了从不同代码页中的字符代码到图元索引的映射关系,这是在TrueType字体中存取图元信息的关键。cmap表包含几个了表以支持不同的平台和不同的字符编码方案。下面是cmap表的结构。typedef struct{USHORT Platform; //platform IDUSHORT EncodingID; //encoding IDULONG TableOffset ;//offset to encoding table  typedef struct {WCHAR wcLow;USHORT cGlyphs;}typedef struct{DWORD cbThis; //sizeof (GLYPHSET)+sizeof(WCRANGE)+(cRanges-1)DWORD flAccel;DWORD cGlyphsSupported;DWORD cRanges;WCRANGE ranges[1]; //ranges[cRanges]}GLYPHSET;DWORD GetFontUnicodeRanges(HDC hDC,LPGLYPHSET lpgs);DWORD GetGlyphIndices(HDC hDC,LPCTSTR lpstr,int c ,LPWORD pgi,DWORD fl);通常一种字体只提供UNICODE字符集中的字符的一个子集。这些字符可以被分组为多个区域,cmap映射表中就是这么做的。GetFontUnicodeRanges函数在一个GLYPHSET结构中返回支持的图元的数量、支持的UNICODE区域的数量以及设备上下文中字体的这些区域的详细信息。GLYPHSET是一个可变长的结构,其大小取决于所支持的UNICODE区域的数量。因此,和Win32 API中支持可变长结构一样, GetFontUnicodeRanges函数通常需要调用两次。第一次调用时得到以NULL指针作为最后一莜参数,GDI会返回所需窨的大小。调用者然后分配所需的内存,再次调用以得到真正的数据。这两种情况下,GetFontUnicodeRanges函数都会返回保存整个结构所需的数据大小。MSDN文档可能还是错误地描述成了如果第二个参数是NULL,GetFontUnicodeRanges函数返回指向GLYPHSET结构的指针。下面是用于查询上下文中当前字体GLYPHSET结构的一个简单函数。GLYPHSET *QueryUnicodeRanges(HDC hDC){//query for sizeDWORD size=GetFontUnicodeRanges(hDC,NULL);if (size==0) return NULL;GLYPHSET *pGlyphSet=(GLYPHSET *)new BYTE(size);//get real datapGlyphSet->cbThis=size;size=GetFontUnicodeRanges(hDC,pGlyphSet);return pGlyphSet;}如果在一些Windows TrueType字体上试着调用GetFontUnicodeRanges函数,你会发现这些字体通常支持1000个以上的图元,这些图元被分成几百个UNICODE区域。比如,“Times New Roman”有我143个图元,分布在145个区域中,和一个区域是0x20到0x7f,即可打印的7位ASCII代码区域。GetFontUnicodeRanges函数只使用了TrueType字体“cmap”表的一部分部分信息,即从UNICODE到图元索引的映射域。GetGlyphIndices函数则能真正使用这些映射关系把一个字符串转换为一个图元索引的数组。它接收一个设备上下文句柄、一个字符串指针、字符串长度、一个WORD数组的指针和一个标志。生成的图元索引将保存在WORD数组中。如果标志为GGI_MASK_NONEXISTING_GLYPHS,找不到的字符的图元索引会被标注成0xFFFF。此函数得到的图元索引可以传给其他GDI函数,如ExtTextOut函数。2.位置索引TrueType字体中最有用的信息是glyf表中的图元数据。有了图元索引,要找到相应的图元,需要表(loca表)索引以把图元索引转换为图元数据表内的偏移量。位置索引表中保存了n+1个图元数据表的索引,其中n是保存在最大需求表中的图元数量。最后一个额外的偏移量并不指向一个新图元,而是指向最后一个图元的偏移量和当前图元的偏移量和当前图元的偏移量间的差值得到图元的长度。位置索引表中的每一个索引以无符号短整数对齐的,如果使用了短整数格式,索引表实际存储的是WORD偏移量,而不是BYTE偏移量。这合得短整数格式的位置索引表能支持128KB大小的图元数据表。3.图元数据图元数据(glyf表)是TrueType字体的核心信息,因此通常它是最大的表。因为的位置索引是一张单独的表,图元数据表就完全只是图元的序列而已,每个图元以图元头结构开始:typedef struct{WORD numberOfContours; //contor number,negative if compositeFWord xMin; //Minimum x for coordinate data.FWord yMin; //Minimum y for coordinate data.FWord xMax; //Maximum x for coordinate data.FWord yMax; //Maximum y for coordinate data.}GlyphHeader;对于简单图元,numberOfContours字段中保存的是当前图元的轮廓线的树木;对于合成图元,numberOfContours字段是一个负值。后者的轮廓线的总数必须基于组成该合成图元的所有图元的数据计算得到。GlyphHeader结构中后四个字段记录了图元的边界框。对于简单图元,图元的描述紧跟在GlyphHeader结构之后。图元的描述由几部分信息组成:所有轮廓线结束点的索引、图元指令和一系列的控制点。每个控制点包括一个标志以x和y坐标。概念上而言,控制所需的信息和GDI函数PolyDraw函数所需的信息相同:一组标志和一组点的坐标。但TrueType字体中的控制点的编码要复杂得多。下面是图元描述信息的概述:USHORT endPtsOfContours[n]; //n=number of contoursUSHORT instructionlength;BYTE instruction[i]; //i = instruction lengthBYTE flags[]; //variable sizeBYTE xCoordinates[]; //variable sizeBYTE yCoordinates[]; //variable size图元可以包含一条或多条轮廓线。比如,字母"O"有两条轮廓线,一条是内部的轮廓,另一条是外部的轮廓。对于每一条轮廓线,endPtsOfContours数组保存了其终点的索引,从该索引中可以计算出轮廓线中点的数量。比如,endPtsOfContours[0]是第一休轮廓线上点的数量,endPtsOfContours[1]-endPtsOfContours[0]是第二条轮廓线上点的数量。终点数组后是图元指令通知度和图元指令数组。我们先跳过它们,先来讨论冬至点。图元的控制点保存在三个数组中:标志获得组、x坐标数组和y坐标数组。找到标志数组的起始点很简单,但是标志数组没有相应的长度字,也没有直接其他两个数组的方法,你必须先解码标志数组才能解释x和y坐标数组。我们提到棕em-square被限制为最大为16384个网格,因此通常情况下需要各两个字节来表示x坐标和y坐标。为了节省空间,图元中保存的是相对坐标。第一个点的坐标是相对(0,0)记录的,所有随后的点记录者是和上一个点的坐标差值。有些差值可以用一个字节表示,有些差值为0,另外一些差值则无法用耽搁字节表示。标志数组保存了每个坐标的编码信息以及其他一些信息。下面是标志中各个位的含义的总结:typedef enum{G_ONCURVE = 0x01, // on curve ,off curveG_REPEAT =0x08, //next byte is flag repeat countG_XMASK =0x12,G_XADDBYTE =0x12, //X is positive byteG_XSUBBYTE =0x12, //X is negative byteG_XSAME =0x10, //X is sameG_XADDINT =0x00, //X is signed wordG_YMASK =0x24,G_YADDBYTE =0x24, //Y is positive byteG_YSUBBYTE =0x04, //Y is negative byteG_YSAME =0x20 , //Y is sameG_YADDINT =0x00, //Y is signed word};在第8章中我们讨论了直线和曲线,我们提到了一段三阶Bezier曲线有四个控制点定义:位于曲线上(on-curve)的起始点、两个不在曲线上(off-curve)的控制点和一个曲线上的结束点。TureType字体中的图元轮廓是用二阶Bezier曲线定义的,有三个点:一个曲线上的点,一个曲线外的点和另一个曲线上的点。多个连续的不在曲线上的点是允许的,但不是用来定义三阶或更高阶的Bezier曲线,而是为了减少控制点的数目。比如,对于on-off-off-on模式的四个点,会加入一个隐含的点使之成为on-off-on-off-on,因此定义的是两段二阶Bezier曲线。如果设置了G_ONCURVE位,那么控制点在曲线上,否则不在曲线上。如果设置了G_REPEAT,标志数组中的下一字节表示重复次数,当前标志应该重复指定的次数。因此,标志数组中实际使用了某种类型的行程编码。标志中的其他位用于描述相应的x坐标和y坐标的编码方式,它们可以表示当前相寻坐标是否和上一个相同、正的单字节值、负的单字节值或有符号两字节值。解码图元的描述是一个两次扫描的起始点。然后再遍历图元定义中的每一个点把它转换为更容易管理的格式。程序清单14-2列出了解码TrueType图元的函数,它是KTrueType类的一个方法。int KTrueType::DecodeGlyph(int index, KCurve & curve, XFORM * xm) const{const GlyphHeader * pHeader = GetGlyph(index);if ( pHeader==NULL ){// assert(false);return 0;}int nContour = (short) reverse(pHeader->numberOfContours);if ( nContour<0 ){return DecodeCompositeGlyph(pHeader+1, curve); // after the header}if ( nContour==0 )return 0;curve.SetBound(reverse((WORD)pHeader->xMin), reverse((WORD)pHeader->yMin),reverse((WORD)pHeader->xMax), reverse((WORD)pHeader->yMax));const USHORT * pEndPoint = (const USHORT *) (pHeader+1);int nPoints = reverse(pEndPoint[nContour-1]) + 1; // endpoint of last contour + 1int nInst = reverse(pEndPoint[nContour]); // instructon lengthcurve.m_glyphindex = index;curve.m_glyphsize = (int) GetGlyph(index+1) - (int) GetGlyph(index);curve.m_Ascender = m_Ascender;curve.m_Descender = m_Descender;curve.m_LineGap = m_LineGap;GetMetrics(index, curve.m_advancewidth, curve.m_lsb);if ( curve.m_glyphsize==0 )return 0;curve.m_instrsize = nInst;const BYTE * pFlag = (const BYTE *) & pEndPoint[nContour] + 2 + nInst; // first byte in flagconst BYTE * pX = pFlag;int xlen = 0;for (int i=0; i<nPoints; i++, pX++){int unit = 0;switch ( pX[0] & G_XMASK ){case G_XADDBYTE:case G_XSUBBYTE:unit = 1;break;case G_XADDINT:unit = 2;}if ( pX[0] & G_REPEAT ){xlen += unit * (pX[1]+1);i += pX[1];pX ++;}elsexlen += unit;}const BYTE * pY = pX + xlen;int x = 0; KTrueType类处理TrueType字体的装入和解码,随书光盘中有它的完整源代码。DecodeGlyph给出图元索引和可选的变换矩阵,处理的是单个图元的解码。参数curve是KCurve类,用于把TrueType图元定义保存为32位的点的赎罪以及一个标志数组,以梗用GDI进行显示。这些代码可以作为简单TrueType字体编辑器的基础。代码中调用了GetGlyph方法,该方法用位置表索引找到该图元的GlyphHeader结构。从中得到图元的轮廓线数目。注意必须反转该值的字节序,因为TrueType字体用的是Big-Endian字节序。如果该值为负值,说明这是一个合成图元,应该转而调用DecodeCompositeGlyph方法。接下支的代码定位了endPtsOfContours数组,找出点的总数,然后跳过指令找到标志数组的起始位置。接下去需要长到的是x坐标数组的始位置和长度,这需要遍历标志数组一次。对于每一个控制点,它在x坐标数组中所占空间可能为0到2个字节,这取决于它的相对坐标是0、单个字节还是两个字节。根据x坐标数组的地址和长度可以得到y坐标的地址。接下去的代码遍历所有的轮廓线,解码其中的控制点,把相对坐标转换为绝对坐标,然后把它加入到曲线对象中。如果需要的话,会对每个控制点做变换。回想一下,TrueType使用的是二阶Bezier曲线,允许在两个曲线上的点之间有多个不在曲线上的点。为了简化曲线绘制算法,KCurve::Add方法在每两个不在曲线上的点之间加入一个额外的在曲线上的点。处理了简单图元之后,我们来看看合成图元。合成图元用一个经变换的图元序列定义。每个经变换的图元的定义包括三个部分:一个标志、一个图元索引和一个变换矩阵。标志字段决定了变换矩阵的编码方式。编码的目的也是为了节省一些空间,加外还说明了是否已到达序列的终点。一个完整的2D affine变换需要6个值。但如果只是平移的话,只需要两个值(dx,dy),这两个值可以保存为两个字节或两个字。如果x和y以相同的值缩放,加外还需要一个缩放值。取一般的情况下仍然需要6个值,但是很多时候可以节省几个字节。用于变换的值以2.14的有符号定点格式保存,dx和dy值除外,这两个值以整数形式保存。得到合成图元的过程实际上是变换和组合几个图元的过程。比如,如果字体中的一个图元是另一个图元的精确镜像,它只需定义为一个合成图元,可以通过对另一个图像做镜像变换即可。程序清单14-3列出了解码合成图元的代码。int KTrueType::DecodeCompositeGlyph(const void * pGlyph, KCurve & curve) const{KDataStream str(pGlyph);unsigned flags;int len = 0;do{flags = str.GetWord();unsigned glyphIndex = str.GetWord();// Argument1 and argument2 can be either x and y offsets to be added to the glyph or two point numbers.// In the latter case, the first point number indicates the point that is to be matched to the new glyph.// The second number indicates the new glyph's "matched" point. Once a glyph is added, its point numbers// begin directly after the last glyphs (endpoint of first glyph + 1).// When arguments 1 and 2 are an x and a y offset instead of points and the bit ROUND_XY_TO_GRID is set to 1,// the values are rounded to those of the closest grid lines before they are added to the glyph.// X and Y offsets are described in FUnits.signed short argument1;signed short argument2;if ( flags & ARG_1_AND_2_ARE_WORDS ){argument1 = str.GetWord(); // (SHORT or FWord) argument1;argument2 = str.GetWord(); // (SHORT or FWord) argument2;}else{argument1 = (signed char) str.GetByte();argument2 = (signed char) str.GetByte();}signed short xscale, yscale, scale01, scale10;xscale = 1;yscale = 1;scale01 = 0;scale10 = 0;if ( flags & WE_HAVE_A_SCALE ){xscale = str.GetWord();yscale = xscale; // Format 2.14}else if ( flags & WE_HAVE_AN_X_AND_Y_SCALE ){xscale = str.GetWord();yscale = str.GetWord();}else if ( flags & WE_HAVE_A_TWO_BY_TWO ){xscale = str.GetWord();scale01 = str.GetWord();scale10 = str.GetWord();yscale = str.GetWord();}if ( flags & ARGS_ARE_XY_VALUES ){XFORM xm;xm.eDx = (float) argument1;xm.eDy = (float) argument2;xm.eM11 = xscale / (float) 16384.0;xm.eM12 = scale01 / (float) 16384.0;xm.eM21 = scale10 / (float) 16384.0;xm.eM22 = yscale / (float) 16384.0;len += DecodeGlyph(glyphIndex, curve, & xm);}elseassert(false);}while ( flags & MORE_COMPONENTS );if ( flags & WE_HAVE_INSTRUCTIONS ){unsigned numInstr = str.GetWord();for (unsigned i=0; i<numInstr; i++)str.GetByte();}// The purpose of USE_MY_METRICS is to force the lsb and rsb to take on a desired value.// For example, an i-circumflex (Unicode 00ef) is often composed of the circumflex and a dotless-i.// In order to force the composite to have the same metrics as the dotless-i,// set USE_MY_METRICS for the dotless-i component of the composite. Without this bit,// the rsb and lsb would be calculated from the HMTX entry for the composite (or would need to be// explicitly set with TrueType instructions).// Note that the behavior of the USE_MY_METRICS operation is undefined for rotated composite components.return len;}DecodeCompositeGlyph方法解码每个图元的标志、图元索引和变换矩阵,然后调用DecodeGlypgh方法进行解码。注意,对DecodeGlyph方法的调用包含一个有效的变换矩阵参数。当MORE_COMPONENTS标志结束时,该方法随之结束。随书光盘中有该方法完整的源代码。解码后的TrueType字体的图元要用GDI绘制还有一个小问题需要处理。GDI只绘制三阶Bezier曲线,因此从图元表解码所得的二阶Bezier曲线的控制点需要转换为三阶Bezier曲线的控制点。通过对Bezier曲线原始数学定义的研究,可以得到如下用GDI绘制二阶Bezier曲线的简单例程。//draw a 2nd-degree Bezier curve segmentBOOL Bezier2(HDC hDC,int & x0,int & y0, int x1, int y1, int x2 ,int y2){// p0 p1 p2 - > p0 (p0 + 2p1)/3 (2p1+p2)/3, p2POINT P[3] = { { (x0+2*x1)/3,(y0+2*y1)/3},{(2*x1+x2)/3,(2*y1+y2)/3},{x2,y2} };x0=x2;y0=y2;return PolyBezierTo(hDC,P,3);}对于用三个控制点(p0,p1,p2)定义的二阶Bezier曲线,相应的三阶Bezier曲线的控制点为(p0,(p0+2*p1)/3,(2*p1+p2)/3,p2)。4.图元指令程序清单14-2和14-3给人的印象是TrueType字体的栅格器可以通过扫描和转换图元的轮廓来轻松地实现,比如,用GDI和StrokeAndFillPath函数来填充图元轮廓绘制出来的路径。这种简单的字体栅格器的实现并不是很有用,除非它只用于高分辨诣的设备如打印机等。简单栅格器得到的图像笔画粗细不一,有信息的遗漏,有字符特征的损失以及不对称等缺陷。当点阵变小是,情况不会更糟。总之,简单字体栅格器在小尺寸时会产生字迹模糊的结果。在大尺寸时会产生不好看的结果,只有在点阵增大时结果才会改善。当在大的em-square(典型的是2048)中定义的图元轮廓缩小为小得多的网格时(如32*32),不可避免会损失精度并引入误差。TrueType解决这个问题的方法是控制图元轮廓从em-square到栅格网格的缩放过程,使得到的结果看起来效果更好,和原始图元的设计尽量接近。这种技术被称为网格调整(grid fitting),它想达到的目标有:消除网格位置的可能影响,保证笔画的粗细和网格的相对位置无关。控制图元中关键位置的尺寸保持对称性和衬线等 重要的图元设计细节。TrueType字体中网格调整的需求在两个地方中编码:控制值表(control value table)和每个图元的网格调整指令。控制值表("cvt"表)用于保存一个数组,这些值被称为网格调整指令。比如,对于有衬线的字体,基线、衬线高度、大写字母笔划的宽度等值都或以是被控制的值。它们可以以字体设计者已知的次序保存在控制值表中,然后用它们的索引来引用。在字体光栅化过程中,控制值表中的值根据点阵的大小缩放。在网络调整指令中引用这些值可以保证使用的值与网枸的位置无关。比如,如果水平线[14,0,25,200]可以用CVT表中的两个值定义为[14,0,14+CVT[stem_width],0+CVT[cap_height]],那么该线的宽度和高度会和所在网格的相对位置无关,保持不变。每一个图元的定义中附加有一个指令序列,该指令序列被称为图元指令,该背景令序列用于控制此图元的网格高速。图元指令线用控制值表中的值,以保证在索引图元中这些值相同。图元指令是一种基于堆栈的伪计算机的指令。堆栈计算机常用于计算机语言的解释性实现。比如,Forth(用于嵌入式系统的一种强大而简洁的语言)、RPL(HP计算器使用的语言)和Java虚拟机都是堆栈计算机。堆栈计算机通常没有寄存器,所有的计算都在堆栈上进行(有些堆栈计算机使用分开的控制堆栈和数据堆栈)。比如,压入指令把一个值压入堆栈,弹出指令从堆栈中弹出上面的值,二元加法指令弹出上面的两个值 ,然后把它们的和压入堆栈。字体知道帮你解决更多字体问题 http://www.zhaozi.cn/zhidao/

7 次浏览
使用11px及10px的清晰汉字字体
使用11px及10px的清晰汉字字体

注:以下效果在WindowsXP和Photoshop CS下测试通过。在Photoshop中要想得到清晰的汉字,就需要关闭抗锯齿功能。但是这样当字体小于12px的时候,系统默认的宋体就变得一团糟,而黑体或者其他的外挂字体也都纷纷变得很难看在确保系统安装有繁体中文及日文支持后,可在Photoshop中使用PMingLiU和MS UI Gothic字体。最简单的安装方法就是用IE打开任意网站,将字符编码改为繁体中文和日文,系统就会自动安装相应的字符。PMingLiU可支持到11px的大小,允许中文简体和繁体字符。MS UI Gothic其实是日文字体,因此只支持日文字库中有的汉字,比如“够”就不存在日文字库中。由于日文中的汉字大部分是繁体中文,因此输入的时候要使用支持繁体字符的输入法(如微软拼音)。字体范例如下:可以看到11px时候的MS UI Gothic就已经是10px大小,只不过间距略大而已。其实要发现隐藏的非中文名称字体也不困难,进入Windows的fonts目录,凡是字节数在1M以上的英文名称字体,其中就很可能包含了汉字字形。不过据我试验结果,10px已经是已经汉字字体中最小的了。

3 次浏览
象素字简介及象素字体查找好去处
象素字简介及象素字体查找好去处

      象素字体, 一共分3种, bitmap, vector和postscript, pixel font属于bitmap, 是由一个个点组成的, 目前最流行的仍然是pixel字体, 已经流行了接近3年. 如果你不知道何为pixel font, 请先了解一下, 学一下使用方法, 不要乱用. 下面是需要注意的:使用tips: 查找象素字体:http://www.zhaozi.cn/s/en/xiangsuzi/国内比较著名一家提供免费字体的网站,特点是能够提供输入文字查看字体效果http://www.04.jp.org国内也很多人用pixel font, 但基本上是用日本的04系列. 所以我劝你用别了, 太滥了呀!http://www.hi-type.com 或 http://www.hi-type.de唉, 你不走运, 这是极出色的字体网站, Micromedia 的MX系列, 右边的panel上用的字体, 就是来自hi-type. 我刚试过, 连不上, 可能down了. 注册后可以免费下载:http://www.zetuei.com日本网站绝影, 光看名字就知道是cool!http://www.superlooper.desuperlooper有近20款出色字体, 不少设计网站都有使用.http://www.miniml.com如果你从没看过miniml, 你应该检讨一下要不要在这行混下去. 这是带动pixel font潮流的鼻祖. Hooge, Kroge, Standard三种字体是目前网上设计网站中用得最多的字体. 看上去有点像04, 但个人认为比04要好. 他们的字体以前是免费下载的, 红了之后开始收费, 好在我下得快.http://www.tint.de里面有目前做得最小的pixel font, 只有4 pointhttp://www.etherbrian.com有种很好看的字体, 自己去看http://www.fountain.nu不错的付费网站, 但几是块买个来做logo也不贵吧http://www.cubadust.com还是要给钱买的http://www.orgdot.com/aliasfonts极出色的alias font(same as pixel font)根据地.http://net.jp.org/jafont这里没有字体下, 但有大量日本字体网站的连结.http://www.wpdfd.com/wpdtypo3a.htm付费的, 但有pixel font的介绍http://2theleft.rdx.net/fontpage2.htm里面有很多适合做logo的字体http://fenotype.com好像是楼上的另一个家, 里面有几十种出色字体免费下载.http://www.myeye25.comcool死了的pixel fonthttp://www.myfonts.com我告诉你, 给钱买的就是不同http://www.dafont.com/en没甚么好介绍的, 字体太多, 但质素比一般网站收藏的好http://www.koenhachmang.com有些很好看的字体, 但现在我也找不到, 你找找看.

7 次浏览
多种方法玩好Windows系统字体
多种方法玩好Windows系统字体

    Windows系统中的字体,平时往往很难引起人们的注意;可是对于那些追求时尚、注重个性的朋友来说,系统字体就成了他们美化系统的一种表达方式。为了帮助那些追求个性化的朋友更好地用好字体,管好字体,本文下面就从多种角度出发,向大家推荐几则系统字体管理技巧,希望能对大家有所用处!  1、从效果出发,改善字体视觉感受  无论是在Word文档编辑窗口中,还是网页浏览窗口中,一旦将其中的文本文字尺寸设置得稍微大一些,我们的人眼就会感觉到文字字体的边缘位置处明显有锯齿现象,很显然这种现象会影响我们的视觉感受。尽管通过安装一些特殊的字体控制软件或换用其他的文字字体,可以改善原字体的锯齿现象,但这些操作都比较费时间而且也比较麻烦;事实上,我们完全可以借助Windows系统自身的力量,来轻松地改善字体的视觉显示效果,下面就是该方法的具体实施步骤:  首先用鼠标右键单击Windows系统桌面的空白位置处,从随后出现的右键菜单中单击“属性”命令,打开系统的显示属性设置窗口;  其次单击该窗口中的“外观”选项卡,并在对应的选项设置界面中单击“效果”按钮,打开如图1所示的效果设置对话框;  下面选中该设置对话框中的“使用下列方式使屏幕字体的边缘平滑”复选项,同时单击该选项下面的下拉按钮,从弹出的下拉列表中选中“ClearType”项目,并单击一下“确定”按钮;之后再打开Word文档编辑窗口或网页浏览窗口,看看其中的文字字体显示效果是不是更平滑了一些!?  2、从共享出发,扩大字体共享范围  多个操作系统共存于一台计算机中已经是常有的事情了,比方说安装了Windows 98操作系统后又安装了

7 次浏览
关于字体的一个惊人发现……
关于字体的一个惊人发现……

古代的茶壶工匠喜欢在献给皇室的茶壶最隐秘处刻上自己的名字,虽然被发现要杀头,但还是有人不惜冒险一试。如今,这花样玩到了微软公司身上。  此人名叫胡万进。他从1997年起便一直为微软制作字库,所以在word97及以后的版本中,你按如下试试,便会大吃一惊。  1、在WORD文档中,用隶书或幼圆输入一个“胡”,或“卞、扎、珐、翟”这几个字  2、把字体大小设为初号;  3、把“显示比例”换成500%;       4、在“格式”中找到“字体”,然后选“空心”――这时候你看到了什么?     哈哈,此人这一招厉害!不知比尔・盖茨知道了会不会晕倒! “淠 讫 V 扎 哟 A 汩 浞 珐 杌 柿 砼 \ e 镁 秫 耒 V 翟 卯 卞 畋 曰 莱隹”等字同样存在此现象……     胡万进先生是我国汉字字符编码标准的起草人之一,现任《中国计算机用户》副主编、中国电子信息产业发展研究院下属的《开放系统世界》杂志执行总编。但对于此事,胡万进先生在电话中婉拒了记者的采访要求,并表示这是很早以前的事,现在不是很愿意再去谈它。他还说,此事涉及很多技术方面的问题。          信息产业部电子工业标准化研究所是我国国标汉字字符编码体系主要起草单位之一,该所的研究人员戴女士说,她们早就知道这件事情,并称,如果追溯可能要说到上世纪90年代初期之前。          戴女士说,当时有一些人有自己的做字公司,主营业务主要就是向别人卖字库。也许是从知识产权等方面考虑,他们在一些字体中加入了自己的一些特别的记号。她说,在目前的国标汉字中并不存在这样的现象。          微软称尽快答复          对于微软在当时汉化office软件时是否知情等问题,微软中国公司公关部的杨小姐表示,目前还不知道相关事宜,但是会尽快就记者的采访要求给出答复。          能够在word中显出“胡万进印”字样的汉字,除了胡之外,还有其他一些生僻字。这批汉字库符合2000年3月17日颁布的GB2311体系的字符编码的标准。该标准的起草单位为信息产业部电子工业标准化研究所等,主要起草人:陈忆M、黄疆、胡万进、张建国、陈壮。 

4 次浏览
Windows系统造字功能详细用法
Windows系统造字功能详细用法

Windows造字功能详解     经常进行文字编辑的朋友难免会碰到一些无法输入的怪字,这是因为这些字用得很少所以电脑字库中并没有这些字。此时用Windows的TrueType造字程序就是最佳选择。在此我们就分造字、输入和备份三方面进行详细介绍。  一、造字  点击开始→所有程序→附件→TrueType造字程序,进入造字程序窗口。此时会弹出一个“选择代码”对话框,双击对话框中的方格选定代码,在此我们就双击AAB0行的第二格选定代码AAB1后进入编辑窗口开始造字。此时我们仍可从菜单栏的“编辑/选择代码”改选其它代码。字形的绘制一般有以下3种方法。1.最直接的操作当然是利用窗口左侧工具栏中的工具,单击选择工具栏中的直线、矩形或画笔等工具,直接在编辑区按拖动绘出字形,这需要较多耐力,老实说要画出一个漂亮的字相当困难。  2.组合法,就是从几个字中各取出一部分来组合成字,这样较能保持字体风格。以制作“M”字为例进行操作。点击菜单栏的“编辑→复制字符…”,打开复制字符对话框,点击字体按钮,选择宋体。在“形状”输入框中输入“伟”字,点击确定返回编辑窗口,可以看到伟字出现在编辑区。使用矩形选项工具选中多余部分按Delete键删除,只留下“亻”。点击菜单栏的“窗口→参照…”,打开参照对话框,同样设定为宋体,在“形状”输入框中输入“说”字,确定后会多出一个参照区,点击工具栏中的任意形状选择工具,按住左键沿“兑”周围拖动一圈选定。把选定的“兑”拖动到编辑区,拖动“兑”四周的尺寸柄调整适当大小与“亻”组成“M”字。点击菜单栏的编辑→保存字符。一个宋体的“M”字就造好了。.复制法,直接在画图程序或其它图形处理软件中绘制好需要的字,选中复制到造字程序的编辑窗口粘贴即可。以画图程序为例:用“A”文字工具输入“伟”“说”二字,字号48、字体随意,使用橡皮工具擦除多余部分,用“选定”工具(要选中透明化处理)把剩下的“亻”“兑”二部分拖到一起组成“M”字,用“选定”工具选中“M”复制,进入造字程序编辑窗口按“Ctrl+V”粘贴。这个方法最好用,可以同时做好几个字,甚至可以把你喜欢的图形或自己的相片做成字,当然只能是单色图。注意:绘制时字图的像素要控制在64×64以内,而且背景色一定要纯白色。  按以上方法保存的字体默认在所有的字体中通用,不管你选择什么字体都只会显示我们做的宋体的字。如果你想让造的字也会随字体实际行动选择而改变字体,则必须为需要的每一种字体造一个字。在为每一种字体造字前必须先点击菜单栏的文件→字体链接。打开字体链接对话框,选中“与所选择的字体链接”,选中相应链接字体后单击确定,输入链接文件名保存,此时切记字体链接文件一定要保存在非系统分区,如D:\造字\目录下。注意:同一个字的不同字体字符代码必需相同,即该字符在宋体中的代码为AAB1那么它在楷体中的代码也必需是AAB1。二、输入  1.内码输入法(即区位输入法),采用内码输入法,只要输入字的代码即可调用相应字,如:键入aab1就可以在文档中输入“M”字。不过要记住编码比较麻烦。如果找不到内码输入法,你可以右击Windows任务栏的输入法切换按钮→选择“设置”→单击“添加…”按钮→从键盘布局/输入法的下拉列表中选择“中文(简体)-内码”,单击确定进行添加,这可能需要用到Windows安装盘。  2.直接调用,点击造字程序菜单栏的“编辑→复制字符…”,在“代码”输入框中输入AAB1,选中出现在“形状”输入框中的“M”字,按“Ctrl+C”复制,再粘贴到需要输入的位置。 3.字符映射,点击“开始→所有程序→附件→系统工具→字符映射表”,运行字符映射表,从字体下拉列表中选择“所有字体(专用字符)”,我们造字就出现在下面的格子内,双击我们要用的字“M”,可以看到“M”字出现在复制字符的输入框中,单击“复制”按钮,然后到需要输入的位置粘贴即可。如果你要找的字符链接到其它字体如楷体,则字体要选择“楷体(专用字符)”,以此类推。4.输入法链接,在造字程序中完成造字保存后,点击菜单栏的编辑→输入法链接……,输入文件名保存到D:\造字\目录下。在弹出的外码对话框中分别键入各种输入法的外码,每输入一种外码都要按空格键确认,然后单击注册按钮,此时如果系统问你“没有完成撰写,你想完成这个词吗?”请选否。现在就可以用已链接的输入法输入了。这种方法只对少数几种输入法有效。5.造词法,打开五笔输入法,右击输入法工具栏,选择手工造词…,采用上述方法在“词语”的输入框输入“M”,按输入法规则输入外码wsh后单击“添加”按钮,关闭该窗口。以后就可以像输入常用字一样了。各种输入法造词功能名称和调用方法略有不同:智能五笔是在定义字词符号→自定义字词,而智能ABC调用时须在编码前加u等等,请参看各自的帮助说明。这种方法较好,对任何输入法都有效,只是备份词库麻烦点,不过那是本来就应该备份的吧。

10 次浏览
为什么有些字体安装好后有的字打不出来
为什么有些字体安装好后有的字打不出来

这是因为这些字库是应用在台港澳地区常用的繁体系统中的,他们打字时输入的文字都是繁体字,所以有些字库必须要在繁体输入的情况下才能打出来的.(例如金梅字库等),或者你可以输入简体字,然后到网上找一专门做简繁转换的在线工具,如:http://www.zifuhua.cn/ft.htm 转换以后直接将文字复制过来就OK了。如果使用繁体字依然无法显示出来,可能是字库了字数不全,所以就无法打出来这个字了。 

13 次浏览
为什么在安装字体时会出现文件损坏?
为什么在安装字体时会出现文件损坏?

这个是因为你下载的字库与你的系统产生冲突,特别是xp系统,因为有很多字体都是在win98或更早的版本下开发的,与现在的XP以上的系统不兼容,比如早期的金桥字体、昆仑字体、文鼎字体等,解决这个问题很麻烦,关系到字体的映射问题,但是找字网里的这些字体,多数都是成功升级的兼容XP系统的版本

9 次浏览
PS将照片制作成油画艺术效果
PS将照片制作成油画艺术效果

原图效果图 教程步骤如下:一 打开原图图像<图像大小 将照片分辨率减小到1000与1000以下备注  PS滤镜“调色刀”属于色块化的操作。如果PP的分辨率太高,调色刀所产生的最大色块也不够大,调色刀的效果就

6 次浏览
妙用PS滤镜制作绚丽的光束效果
妙用PS滤镜制作绚丽的光束效果

本教程制作都是用滤镜来完成。从简单的一个光源开始,多次经过变形及调色,最终变成绚丽的彩色光束。整个制作过程比较简单,不过滤镜的效果有很多随机性,可能做出的效果会有点差异。最终效果1、新建一个800 * 800 像素的文件,背景填充黑色,然后执行:滤镜 > 渲染 > 镜头光晕,参数设置如下图。2、再执行:滤镜 > 渲染 > 光照效果,设置为3色点光后删除最右边的光源(选中直接按Delete 删除)。3、执行:滤镜 > 扭曲 > 极坐标,选中平面坐标到极坐标。

14 次浏览
共计26043条记录 上一页 1.. 1429 1430 1431 1432 1433 1434 1435 ..2605 下一页