版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
-.z.ttf文件結(jié)構(gòu)解析TrueType字體通常包含在單個(gè)TrueType字體文件中,其文件后綴為.TTF。OpenType字體是以類似
于TrueType字體的格式編碼的POSTSCRIPT字體。OPENTYPE字體使用.OTF文件后綴。OPENTYPE還允許把多個(gè)OPENTYPE字體組合在一個(gè)文件中以利于數(shù)據(jù)共享。這些字體被稱為TrueType字體集(TrueType
collection),其文件后綴為.TTC。
TrueType字體用machintosh的輪廓字體資源的格式編碼,有一個(gè)唯一的標(biāo)記名"sfnt"。windows沒有macintosh的位圖字體資源格式,字體目錄
包含了字體格式的版本號和幾個(gè)表,每個(gè)表都有一個(gè)tableentry結(jié)構(gòu)項(xiàng),tableentry結(jié)構(gòu)包含了資源標(biāo)記、校驗(yàn)和、偏移量和每個(gè)表的大小。下面是TrueType字體目錄的c語言定義:
typedef
sturct
{
char
tag[4];
ULONG
checkSum;
ULONG
offset;
ULONG
length;
}TableEntry;
typedef
struct
{
Fi*ed
sfntversion;
//0*10000
for
version
1.0
USHORT
numTables;
USHORT
searchRange;
USHORT
entrySelector;
USHORT
rangeShift;
TableEntry
entries[1];//variable
number
of
TableEntry
}TableDirectory;
TrueType
字體中的所有數(shù)據(jù)都使用big-endian編碼,最高位字節(jié)在最前面(因?yàn)門rueType字體最初是由apple公司定義的,而apple公司的os運(yùn)行在motorola的cpu上)。如果一人TrueType字體以00
01
00
00
,00
17開頭,我們就可以知道它的格式是輪廓字體資源("sfnt")版本1.0的格式,有23個(gè)表。
TableDirectory結(jié)構(gòu)的最后一個(gè)字段是可變長度的tableentry結(jié)構(gòu)的數(shù)組,安體中的每個(gè)表對應(yīng)其中一項(xiàng)。TrueType字體中的每個(gè)表都保存了不同的邏輯信息-----如圖元中數(shù)據(jù)、字符到圖元的映射、字距調(diào)整信息等等。有表是必須的,有些是可選的。下表列出了TrueType字體中常見的表。
head
字體頭
字體的全局信息
cmap
字符代碼到圖元的映射
把字符代碼映射為圖元索引
glyf
圖元數(shù)據(jù)
圖元輪廓定義以及網(wǎng)格調(diào)整指令
ma*p
最大需求表
字體中所需存分配情況的匯總數(shù)據(jù)
mmt*
水平規(guī)格
圖元水平規(guī)格
loca
位置表索引
把元索引轉(zhuǎn)換為圖元的位置
name
命名表
說明、字體名、字體族名、風(fēng)格名等等
hmt*
水平布局
字體水平布局星系:上高、下高、行間距、最大前進(jìn)寬度、最小左支撐、最小右支撐
kerm
字距調(diào)整表
字距調(diào)整對的數(shù)組
post
PostScript信息
所有圖元的PostScript
FontInfo目錄項(xiàng)和PostScript名
PCLT
PCL
5數(shù)據(jù)
HP
PCL
5Printer
Language
的字體信息:字體數(shù)、寬度、*高度、風(fēng)格、記號集等等
OS/2
OS/2和Windows特有的規(guī)格
TrueType字體所需的規(guī)格集
在TableDirectory結(jié)構(gòu)中,所有的TableEntry結(jié)構(gòu)都必須根據(jù)它們的標(biāo)記名排序。比如,cmap必須出現(xiàn)在head前,而head必須在glyf前。但是實(shí)際的表可以出現(xiàn)在TrueType字體文件中的任意位置。
Win32API
提供了一個(gè)應(yīng)用程序可用于查詢原始TrueType字體信息的函數(shù):
DWORD
GetFontData(HDC
hDC,DWORD
dwTable
,DWORD
dwOffset,
LPVOID
lpbBuffer
,DWORD
cbData);
GetFontData函數(shù)可以用于查詢設(shè)備上下文中當(dāng)前邏輯字體所對應(yīng)的TrueType字體,因此傳遞的不是邏輯字體句柄,而是設(shè)備上下文句柄。你可以查詢整個(gè)TrueType文件基是文件中的一個(gè)表。要查詢整個(gè)文件的話dwTable參數(shù)應(yīng)該為0;否則,應(yīng)該傳遞要查詢的表的四字符標(biāo)記的DWORD格式。參數(shù)dwOffset是要查詢的表中的起始偏移,要查詢整個(gè)表的話應(yīng)該為0;參數(shù);pvBuffer是緩沖區(qū)的地址,cbData是緩沖區(qū)的大小。如果最后個(gè)參數(shù)為NULL和0,GetFontData函數(shù)返回字體文件或表的大?。痪蜁训降臄?shù)據(jù)拷貝到應(yīng)用程序所提供的緩沖區(qū)中。
下面的例和查詢整個(gè)TrueType字體的原始數(shù)據(jù):
TableDirctory
*
GetTrueTypeFont
(HDC
hDC
,DWORD
&nFontSize)
{
//query
font
size
nFontSize=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使得應(yīng)用程序能夠在自己的文檔中嵌TrueType字體,以確保這些文檔能在沒有相應(yīng)字體的其他機(jī)器上顯示。它的做法是允許應(yīng)用程序查詢字體數(shù)據(jù),然后寫入到文檔中作為文檔的一部分,在文檔被打于時(shí)再安裝該字體以確保文檔能以創(chuàng)建時(shí)同樣的方式顯示。比如,Windows
NT/2000的假脫機(jī)程序在打印到遠(yuǎn)端服務(wù)器時(shí)會在假脫機(jī)文件中嵌入TrueType字體以保證文檔能在另一臺機(jī)器上正確地打印。
一旦接受到TrueType字體的原始數(shù)據(jù),它的頭中的TableDirectory結(jié)構(gòu)很容易分析。需要檢查的只有版本號和表的數(shù)目,然后就可以檢查單個(gè)的表。我們來看一些重要的和有趣的表。
1.字體頭
字體頭表(head表)中包含了TrueType字體的全局信息。下面是字體頭表的結(jié)構(gòu)。
typedef
sturct
{
Fi*ed
Table;//*00010000
ro
version
1.0
Fi*ed
fontRevision;//Set
by
font
manufacturer.
ULONG
checkSumAdjustment;
ULONG
magiumer;
//Set
to
0*5f0f3cf5
USHORT
flags;
USHORT
unitsPerEm;
//Valid
range
is
from
16
to
16384
longDT
created;
//International
date
(8-byte
field).
longDT
modified;
//International
date
(8-byte
field).
FWord
*Min;
//For
all
glyph
bounding
bo*es.
FWord
yMin;
//For
all
glyph
bounding
bo*es.
FWord
*Ma*;
//For
all
glyph
bounding
bo*es.
FWord
*Ma*;
//For
all
glyph
bounding
bo*es.
USHORT
macStyle;
USHORT
lowestRecPPEM;
//Smallest
readable
size
in
pi*els.
SHORT
fontDirctionHint;
SHORT
inde*ToLocFormat;
//0
for
short
offsets
,1
for
long.
SHORT
glyphDataFormat;
//0
for
current
format.
}Table_head;
字體的歷史記錄在三個(gè)字段中:字全版本號、字體最初創(chuàng)建時(shí)間和字體最后修改時(shí)間。有8
個(gè)字節(jié)用于記錄時(shí)間戳,記錄的是從1904年1月1日午夜12:00開始的秒數(shù),因此我們不用擔(dān)心y2k問題,或是什么y2m問題。
字體設(shè)計(jì)時(shí)是針對一個(gè)參考網(wǎng)格設(shè)計(jì)的,該網(wǎng)格被稱為em-square,字體中的圖元用網(wǎng)格中的坐標(biāo)表示。因此em-squrare的大小決定胃該字體的圖元被縮放的方式,同時(shí)也反映胃該字體的質(zhì)量。字體頭中保存了每個(gè)em-square的格數(shù)和能
包含所有圖元的邊界框。Em-square的有效值是從16到16384,常見的值是2048、4096和8192。比如,Windings字體的em-square的格數(shù)是2048,圖元的邊界框是[0,-432,2783,1841]。
字體頭表中的其他信息包括最小可讀像素大小、字體方向、在位置表中圖元索引的格式和圖元數(shù)據(jù)格式等等。
最大需求表
TrueType字體是一種非常靈活的數(shù)據(jù)結(jié)構(gòu),它可以包含可變數(shù)目的圖元,每個(gè)圖元可以有不同數(shù)目的控制點(diǎn),甚至還可以有數(shù)量可變的圖元指令。最大需求表的目的是告知字體柵格器(rasterizer)對存的需求,以便
在出來字體前分配合適大小的存。因?yàn)樾阅軐ψ煮w柵格器非常重要,像MFC的CAarray那樣需要頻繁進(jìn)行數(shù)據(jù)拷貝操作的動(dòng)態(tài)增長的數(shù)據(jù)結(jié)構(gòu)不合要求。下面是ma*p表的結(jié)構(gòu)。
typedef
struct
{
Fi*ed
Version;//0*00010000
for
version
1.0.
USHORT
numGlypha;
//Number
of
glyphs
in
the
font
.
USHORT
ma*Points;
//Ma*
points
in
nonposite
glyph
.
RSHORT
ma*Contours;
//Ma*
contours
in
nonposite
glyph.
USHORT
ma*positePoints;//Ma*
points
in
a
posite
glyph.
USHORT
ma*positeContours;
//Ma*
contours
in
a
posite
glyph.
USHORT
ma*Zones;//
1
if
not
use
the
twilight
zone
[Z0],
//or
2
if
so
use
Z0;2
in
most
cases.
USHORT
ma*
TwilightPoints
;/
Ma*imum
points
used
in
Z0.
USHORT
ma*Storage;
//Number
of
storage
area
locations.
USHORT
ma*FunctionDefs;
//Number
of
FDEFs.
USHORT
ma*StackElements;
//Number
of
depth.
USHORT
ma*SizeOfInstructions;
//Ma*
byte
count
for
glyph
inst.
USHORT
ma*ponentElements;
//Ma*
number
top
ponents
refernced.
USHORT
ma*ponentDepth;
//Ma*
levels
of
recursion.
}Table_ma*p;
numGlyphs字段保存了字體中圖元的總數(shù),這決定了到位置表的圖元索引的數(shù)量,可以用于嚴(yán)正圖元索引的有效性。TrueType字體中的每個(gè)圖元都可以是合成圖元或簡單圖元。簡單圖元可以有一條或多大體上輪廓中國,條用一些控制點(diǎn)定義。合成圖元用幾個(gè)其他圖元的組合來定義。ma*Points\ma*Countors\ma*positePoints
ma*positeContours這幾個(gè)字段說明了圖元定義的復(fù)雜度。
除了圖元的定義,TrueType字體還使用了圖元指令用于提示字體掃描器如何對控制點(diǎn)進(jìn)行調(diào)整以得到更均衡更漂亮的光柵化后的圖元。圖元指令也可以出現(xiàn)在字體程序表(fpgm表)以及控制值程序表(“prep”)的全局字體層中。TrueType圖元指令是一個(gè)偽計(jì)算機(jī)字節(jié)指令,該機(jī)類似于Java的虛擬機(jī),這些指令可以用堆棧計(jì)算機(jī)執(zhí)行。Ma*StackElements
ma*SizeOfInstructions兩個(gè)字段同志堆棧計(jì)算機(jī)這些指令的復(fù)雜度。
以Windings字體為例,該字體有226個(gè)圖元,圖元最多有47條輪廓線,簡單圖元最多有268個(gè)點(diǎn),合成圖元最多有141個(gè)點(diǎn),合成圖元最多有14條輪廓線,最壞情況下需要492層堆棧,最長的指令有1119個(gè)字節(jié)。
字符到圖元索引的映射表(cmap表)定義了從不同代碼頁中的字符
代碼到圖元索引的映射關(guān)系,這是在TrueType字體中存取圖元信息的關(guān)鍵。cmap表包含幾個(gè)了表以支持不同的平臺和不同的字符編碼方案。
下面是cmap表的結(jié)構(gòu)。
typedef
struct
{
USHORT
Platform;
//platform
ID
USHORT
EncodingID;
//encoding
ID
ULONG
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字符集中的字符的一個(gè)子集。這些字符可以被分組為多個(gè)區(qū)域,cmap映射表中就是這么做的。GetFontUnicodeRanges函數(shù)在一個(gè)GLYPHSET結(jié)構(gòu)中返回支持的圖元的數(shù)量、支持的UNICODE區(qū)域的數(shù)量以及設(shè)備上下文中字體的這些區(qū)域的詳細(xì)信息。GLYPHSET是一個(gè)可變長的結(jié)構(gòu)
,其大小取決于所支持的UNICODE區(qū)域的數(shù)量。因此,和Win32
API中支持可變長結(jié)構(gòu)一樣,
GetFontUnicodeRanges函數(shù)通常需要調(diào)用兩
次。第一次調(diào)用時(shí)得到以NULL指針作為最后一莜參數(shù),GDI會返回所需窨的大小。調(diào)用者然后分配所需的存,再次調(diào)用以得到真正的數(shù)據(jù)。這兩
種情況下,GetFontUnicodeRanges函數(shù)都會返回保存整個(gè)結(jié)構(gòu)所需的數(shù)據(jù)大小。MSDN文檔可能還是錯(cuò)誤地描述成了如果第二個(gè)參數(shù)是NULL,GetFontUnicodeRanges函數(shù)返回指向GLYPHSET結(jié)構(gòu)的指針。
下面是用于查詢上下文中當(dāng)前字體GLYPHSET結(jié)構(gòu)的一個(gè)簡單函數(shù)。
GLYPHSET
*QueryUnicodeRanges(HDC
hDC)
{
//query
for
size
DWORD
size=GetFontUnicodeRanges(hDC,NULL);
if
(size==0)
return
NULL;
GLYPHSET
*pGlyphSet=(GLYPHSET
*)new
BYTE(size);
//get
real
data
pGlyphSet->cbThis=size;
size=GetFontUnicodeRanges(hDC,pGlyphSet);
return
pGlyphSet;
}
如果在一些Windows
TrueType字體上試著調(diào)用GetFontUnicodeRanges函數(shù),你會發(fā)現(xiàn)這些字體通常支持1000個(gè)以上的圖元,這些圖元被分成幾百個(gè)UNICODE區(qū)域。比如,“Times
New
Roman”有我143個(gè)圖元,分布在145個(gè)區(qū)域中,和一個(gè)區(qū)域是0*20到0*7f,即可打印的7位ASCII代碼區(qū)域。
GetFontUnicodeRanges函數(shù)只使用了TrueType字體“cmap”表的一部分部分信息,即從UNICODE到圖元索引的映射域。GetGlyphIndices函數(shù)則能真正使用這些映射關(guān)系把一個(gè)字符串轉(zhuǎn)換為一個(gè)圖元索引的數(shù)組。它接收一個(gè)設(shè)備上下文句柄、一個(gè)字符串指針、字符串長度、一個(gè)WORD數(shù)組的指針和一個(gè)標(biāo)志。生成的圖元索引將保存在WORD數(shù)組中。如果標(biāo)志為GGI_MASK_NONE*ISTING_GLYPHS,找不到的字符的圖元索引會被標(biāo)注成0*FFFF。此函數(shù)得到的圖元索引可以傳給其他GDI函數(shù),如E*tTe*tOut函數(shù)。
2.位置索引
TrueType字體中最有用的信息是glyf表中的圖元數(shù)據(jù)。有了圖元索引,要找到相應(yīng)的圖元,需要表(loca表)索引以把圖元索引轉(zhuǎn)換為圖元數(shù)據(jù)表的偏移量。
位置索引表中保存了n+1個(gè)圖元數(shù)據(jù)表的索引,其中n是保存在最大需求表中的圖元數(shù)量。最后一個(gè)額外
的偏移量并不指向一個(gè)新圖元,而是指向最后一個(gè)圖元的偏移量和當(dāng)前圖元的偏移量和當(dāng)前圖元的偏移量間的差值得到圖元的長度。
位置索引表中的每一個(gè)索引以無符號短整數(shù)對齊的,如果使用了短整數(shù)格式,索引表實(shí)際存儲的是WORD偏移量,而不是BYTE偏移量。這合得短整數(shù)格式的位置索引表能
支持128KB大小的圖元數(shù)據(jù)表。
3.圖元數(shù)據(jù)
圖元數(shù)據(jù)(glyf表)是TrueType字體的核心信息,因此通常它是最大的表。因?yàn)榈奈恢盟饕且粏为?dú)的表,圖元數(shù)據(jù)表就完全只是圖元的序列而已,每個(gè)圖元以圖元頭結(jié)構(gòu)開始:
typedef
struct
{
WORD
numberOfContours;
//contor
number,negative
if
posite
FWord
*Min;
//Minimum
*
for
coordinate
data.
FWord
yMin;
//Minimum
y
for
coordinate
data.
FWord
*Ma*;
//Ma*imum
*
for
coordinate
data.
FWord
yMa*;
//Ma*imum
y
for
coordinate
data.
}GlyphHeader;
對于簡單圖元,numberOfContours字段中保存的是當(dāng)前圖元的輪廓線的樹木;對于合成圖元,numberOfContours字段是一個(gè)負(fù)值。后者的輪廓線的總數(shù)必須基于組成該合成圖元的所有圖元的數(shù)據(jù)計(jì)算得到。GlyphHeader結(jié)構(gòu)中后四個(gè)字段記錄了圖元的邊界框。
對于簡單圖元,圖元的描述緊跟在GlyphHeader結(jié)構(gòu)之后。圖元的描述由幾部分信息組成:所有輪廓線結(jié)束點(diǎn)的索引、圖元指令和一系列的控制點(diǎn)。每個(gè)控制點(diǎn)包括一個(gè)標(biāo)志以*和y坐標(biāo)。概念上而言,控制所需的信息和GDI函數(shù)PolyDraw函數(shù)所需的信息相同:一組標(biāo)志和一組點(diǎn)的坐標(biāo)。但TrueType字體中的控制點(diǎn)的編碼要復(fù)雜得多。下面是圖元描述信息的概述:
USHORT
endPtsOfContours[n];
//n=number
of
contours
USHORT
instructionlength;
BYTE
instruction[i];
//i
=
instruction
length
BYTE
flags[];
//variable
size
BYTE
*Coordinates[];
//variable
size
BYTE
yCoordinates[];
//variable
size
圖元可以包含一條或多條輪廓線。比如,字母"O"有兩
條輪廓線,一條是部的輪廓,另一條是外部的輪廓。對于每一條輪廓線,endPtsOfContours數(shù)組保存了其終點(diǎn)的索引,從該索引中可以計(jì)算出輪廓線中點(diǎn)的數(shù)量。比如,endPtsOfContours[0]是第一休輪廓線上點(diǎn)的數(shù)量,endPtsOfContours[1]-endPtsOfContours[0]是第二條輪廓線上點(diǎn)的數(shù)量。
終點(diǎn)數(shù)組后是圖元指令通知度和圖元指令數(shù)組。我們先跳過它們,先來討論冬至點(diǎn)。圖元的控制點(diǎn)保存在三個(gè)數(shù)組中:標(biāo)志獲得組、*坐標(biāo)數(shù)組和y坐標(biāo)數(shù)組。找到標(biāo)志數(shù)組的起始點(diǎn)很簡單,但是標(biāo)志數(shù)組沒有相應(yīng)的長度字,也沒有直接其他兩個(gè)數(shù)組的方法,你必須先解碼標(biāo)志數(shù)組才能解釋*和y坐標(biāo)數(shù)組。
我們提到棕em-square被限制為最大為16384個(gè)網(wǎng)格,因此通常情況下需要各兩個(gè)字節(jié)來表示*坐標(biāo)和y坐標(biāo)。為了節(jié)省空間,圖元中保存的是相對坐標(biāo)。第一個(gè)點(diǎn)的坐標(biāo)是相對(0,0)記錄的,所有隨后的點(diǎn)記錄者是和上一個(gè)點(diǎn)的坐標(biāo)差值。有些差值可以用一個(gè)字節(jié)表示,有些差值為0,另外一些差值則無法用耽擱字節(jié)表示。標(biāo)志數(shù)組保存了每個(gè)坐標(biāo)的編碼信息以及其他一些信息。下面是標(biāo)志中各個(gè)位的含義的總結(jié):
typedef
enum
{
G_ONCURVE
=
0*01,
//
on
curve
,off
curve
G_REPEAT
=0*08,
//ne*t
byte
is
flag
repeat
count
G_*MASK
=0*12,
G_*ADDBYTE
=0*12,
//*
is
positive
byte
G_*SUBBYTE
=0*12,
//*
is
negative
byte
G_*SAME
=0*10,
//*
is
same
G_*ADDINT
=0*00,
//*
is
signed
word
G_YMASK
=0*24,
G_YADDBYTE
=0*24,
//Y
is
positive
byte
G_YSUBBYTE
=0*04,
//Y
is
negative
byte
G_YSAME
=0*20
,
//Y
is
same
G_YADDINT
=0*00,
//Y
is
signed
word
};
在第8章中我們討論了直線和曲線,我們提到了一段三階Bezier曲線有四個(gè)控制點(diǎn)定義:位于曲線上(on-curve)的起始點(diǎn)、兩個(gè)不在曲線上(off-curve)的控制點(diǎn)和一個(gè)曲線上的結(jié)束點(diǎn)。TureType字體中的圖元輪廓是用二階Bezier曲線定義的,有三個(gè)點(diǎn):一個(gè)曲線上的點(diǎn),一個(gè)曲線外的點(diǎn)和另一個(gè)曲線上的點(diǎn)。多個(gè)連續(xù)的不在曲線上的點(diǎn)是允許的,但不是用來定義三階或更高階的Bezier曲線,而是為了減少控制點(diǎn)的數(shù)目。比如,對于on-off-off-on模式的四個(gè)點(diǎn),會加入一個(gè)隱含的點(diǎn)使之成為on-off-on-off-on,因此定義的是兩段二階Bezier曲線。
如果設(shè)置了G_ONCURVE位,則控制點(diǎn)在曲線上,否則不在曲線上。如果設(shè)置了G_REPEAT,標(biāo)志數(shù)組中的下一字節(jié)表示重復(fù)次數(shù),當(dāng)前標(biāo)志應(yīng)該重復(fù)指定的次數(shù)。因此,標(biāo)志數(shù)組中實(shí)際使用了*種類型的行程編碼。標(biāo)志中的其他位用于描述相應(yīng)
的*坐標(biāo)和y坐標(biāo)的編碼方式,它們可以表示當(dāng)前相尋坐標(biāo)是否和上一個(gè)相同、正的單字節(jié)值、負(fù)的單字節(jié)值或有符號兩字節(jié)值。
解碼圖元的描述是一個(gè)兩次掃描的起始點(diǎn)。然后再遍歷圖元定義中的每一個(gè)點(diǎn)把它轉(zhuǎn)換為更容易管理的格式。程序清單14-2列出了解碼TrueType圖元的函數(shù),它是KTrueType類的一個(gè)方法。
int
KTrueType::DecodeGlyph(int
inde*,
KCurve
&
curve,
*FORM
*
*m)
const
{
const
GlyphHeader
*
pHeader
=
GetGlyph(inde*);
if
(
pHeader==NULL
)
{
//assert(false);
return
0;
}
intnContour
=
(short)
reverse(pHeader->numberOfContours);
if
(
nContour<0
)
{
return
DecodepositeGlyph(pHeader+1,
curve);
//
after
the
header
}
if
(
nContour==0
)
return
0;
curve.SetBound(reverse((WORD)pHeader->*Min),
reverse((WORD)pHeader->yMin),
reverse((WORD)pHeader->*Ma*),
reverse((WORD)pHeader->yMa*));
const
USHORT
*
pEndPoint
=
(const
USHORT
*)
(pHeader+1);
int
nPoints
=
reverse(pEndPoint[nContour-1])
+
1;
//
endpoint
of
last
contour
+
1
int
nInst
=
reverse(pEndPoint[nContour]);
//
instructon
length
curve.m_glyphinde*
=
inde*;
curve.m_glyphsize
=
(int)
GetGlyph(inde*+1)
-
(int)
GetGlyph(inde*);
curve.m_Ascender
=
m_Ascender;
curve.m_Descender
=
m_Descender;
curve.m_LineGap
=
m_LineGap;
GetMetrics(inde*,
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
flag
const
BYTE
*
p*
=
pFlag;
int
*len
=
0;
for
(int
i=0;
i<nPoints;
i++,
p*++)
{
int
unit
=
0;
switch
(
p*[0]
&
G_*MASK
)
{
case
G_*ADDBYTE:
case
G_*SUBBYTE:
unit
=
1;
break;
case
G_*ADDINT:
unit
=
2;
}
if
(
p*[0]
&
G_REPEAT
)
{
*len
+=
unit
*
(p*[1]+1);
i
+=
p*[1];
p*
++;
}
else
*len
+=
unit;
}
const
BYTE
*
pY
=
p*
+
*len;
int
*
=
0;
KTrueType類處理TrueType字體的裝入和解碼,隨書光盤中有它的完整源代碼。DecodeGlyph給出圖元索引和可選的變換矩陣,處理的是單個(gè)圖元的解碼。參數(shù)curve是KCurve類,用于把TrueType圖元定義保存為32位的點(diǎn)的贖罪以及一個(gè)標(biāo)志數(shù)組,以梗用GDI進(jìn)行顯示。這些代碼可以作為簡單TrueType字體編輯器的基礎(chǔ)。
代碼中調(diào)用了GetGlyph方法,該方法用位置表索引找到該圖元的GlyphHeader結(jié)構(gòu)。從中得到圖元的輪廓線數(shù)目。注意必須反轉(zhuǎn)該值的字節(jié)序,因?yàn)門rueType字體用的是Big-Endian字節(jié)序。如果該值為負(fù)值,說明這是一個(gè)合成圖元,應(yīng)該轉(zhuǎn)而調(diào)用DecodepositeGlyph方法。接下支的代碼定位了endPtsOfContours數(shù)組,找出點(diǎn)的總數(shù),然后跳過指令找到標(biāo)志數(shù)組的起始位置。
接下去需要長到的是*坐標(biāo)數(shù)組的始位置和長度,這需要遍歷標(biāo)志數(shù)組一次。對于每一個(gè)控制點(diǎn),它在*坐標(biāo)數(shù)組中所占空間可能為0到2個(gè)字節(jié),這取決于它的相對坐標(biāo)是0、單個(gè)字節(jié)還是兩個(gè)字節(jié)。
根據(jù)*坐標(biāo)數(shù)組的地址和長度可以得到y(tǒng)坐標(biāo)的地址。接下去的代碼遍歷所有的輪廓線,解碼其中的控制點(diǎn),把相對坐標(biāo)轉(zhuǎn)換為絕對坐標(biāo),然后把它加入到曲線對象中。如果需要的話,會對每個(gè)控制點(diǎn)做變換。
回想一下,TrueType使用的是二階Bezier曲線,允許在兩個(gè)曲線上的點(diǎn)之間有多個(gè)不在曲線上的點(diǎn)。為了簡化曲線繪制算法,KCurve::Add方法在每兩個(gè)不在曲線上的點(diǎn)之間加入一個(gè)額外的在曲線上的點(diǎn)。
處理了簡單圖元之后,我們來看看合成圖元。合成圖元用一個(gè)經(jīng)變換的圖元序列定義。每個(gè)經(jīng)變換的圖元的定義包括三個(gè)部分:一個(gè)標(biāo)志、一個(gè)圖元索引和一個(gè)變換矩陣。標(biāo)志字段決定了變換矩陣的編碼方式。編碼的目的也是為了節(jié)省一些空間,加外還說明了是否已到達(dá)序列的終點(diǎn)。一個(gè)完整的2D
affine變換需要6個(gè)值。但如果只是平移的話,只需要兩個(gè)值(d*,dy),這兩個(gè)值可以保存為兩個(gè)字節(jié)或兩個(gè)字。如果*和y以相同的值縮放,加外還需要一個(gè)縮放值。取一般的情況下仍然需要6個(gè)值,但是很多時(shí)候可以節(jié)省幾個(gè)字節(jié)。用于變換的值以2.14的有符號定點(diǎn)格式保存,d*和dy值除外,這兩個(gè)值以整數(shù)形式保存。得到合成圖元的過程實(shí)際上是變換和組合幾個(gè)圖元的過程。比如,如果字體中的一個(gè)圖元是另一個(gè)圖元的精確鏡像,它只需定義為一個(gè)合成圖元,可以通過對另一個(gè)圖像做鏡像變換即可。程序清單14-3列出了解碼合成圖元的代碼。
int
KTrueType::DecodepositeGlyph(const
void
*
pGlyph,
KCurve
&
curve)
const
{
KDataStream
str(pGlyph);
unsigned
flags;
int
len
=
0;
do
{
flags
=
str.GetWord();
unsigned
glyphInde*
=
str.GetWord();
//
Argument1
and
argument2
can
be
either
*
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
*
and
a
y
offset
instead
of
points
and
the
bit
ROUND_*Y_TO_GRID
is
set
to
1,
//
the
values
are
rounded
to
those
of
the
closest
grid
lines
before
they
are
added
to
the
glyph.
//
*
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
*scale,
yscale,
scale01,
scale10;
*scale
=
1;
yscale
=
1;
scale01
=
0;
scale10
=
0;
if
(
flags
&
WE_HAVE_A_SCALE
)
{
*scale
=
str.GetWord();
yscale
=
*scale;//
Format
2.14
}
else
if
(
flags
&
WE_HAVE_AN_*_AND_Y_SCALE
)
{
*scale
=
str.GetWord();
yscale
=
str.GetWord();
}
else
if
(
flags
&
WE_HAVE_A_TWO_BY_TWO
)
{
*scale
=
str.GetWord();
scale01
=
str.GetWord();
scale10
=
str.GetWord();
yscale
=
str.GetWord();
}
if
(
flags
&
ARGS_ARE_*Y_VALUES
)
{
*FORM
*m;
*m.eD*
=
(float)
argument1;
*m.eDy
=
(float)
argument2;
*m.eM11
=
*scale
/
(float)
16384.0;
*m.eM12
=
scale01
/
(float)
16384.0;
*m.eM21
=
scale10
/
(float)
16384.0;
*m.eM22
=
yscale
/
(float)
16384.0;
len
+=
DecodeGlyph(glyphInde*,
curve,
&
*m);
}
else
assert(false);
}
while
(
flags
&
MORE_PONENTS
);
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
e*ample,
an
i-circumfle*
(Unicode
00ef)
is
often
posed
of
the
circumfle*
and
a
dotless-i.
//
In
order
to
force
the
posite
to
have
the
same
metrics
as
the
dotless-i,
//
set
USE_MY_METRICS
for
the
dotless-i
ponent
of
the
posite.
Without
this
bit,
//
the
rsb
and
lsb
would
be
calculated
from
the
HMT*
entry
for
the
posite
(or
would
need
to
be
//
e*plicitly
set
with
TrueType
instructions).
//
Note
that
the
behavior
of
the
USE_MY_METRICS
operation
is
undefined
for
rotated
posite
ponents.
return
len;
}
DecodepositeGlyph方法解碼每個(gè)圖元的標(biāo)志、圖元索引和變換矩陣,然后調(diào)用DecodeGlypgh方法進(jìn)行解碼。注意,對DecodeGlyph方法的調(diào)用包含一個(gè)有效的變換矩陣參數(shù)。當(dāng)MORE_PONENTS標(biāo)志結(jié)束時(shí),該方法隨之結(jié)束。隨書光盤中有該方
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 二零二五年度木門及木飾面產(chǎn)品綠色認(rèn)證與質(zhì)量監(jiān)督合同4篇
- 2025版實(shí)驗(yàn)室科研項(xiàng)目管理與科技獎(jiǎng)勵(lì)服務(wù)合同3篇
- 二零二五年度關(guān)聯(lián)方間信貸資產(chǎn)轉(zhuǎn)讓合同規(guī)范文本3篇
- 2025版協(xié)議離婚手續(xù)辦理指南及離婚證獲取要領(lǐng)3篇
- KTV營業(yè)權(quán)轉(zhuǎn)讓及經(jīng)營合同版B版
- 二零二五版租賃房屋租賃保證金利息計(jì)算合同3篇
- 2025年度零投入的股權(quán)代持解除與轉(zhuǎn)讓協(xié)議
- 2025年針對普通員工的競業(yè)限制合同范本
- 二零二五年度智慧農(nóng)業(yè)版電路租用與物聯(lián)網(wǎng)應(yīng)用合同
- 二零二五年度數(shù)據(jù)中心運(yùn)維用工服務(wù)協(xié)議
- 2024年1月高考適應(yīng)性測試“九省聯(lián)考”英語 試題(學(xué)生版+解析版)
- 《朝天子·詠喇叭-王磐》核心素養(yǎng)目標(biāo)教學(xué)設(shè)計(jì)、教材分析與教學(xué)反思-2023-2024學(xué)年初中語文統(tǒng)編版
- 成長小說智慧樹知到期末考試答案2024年
- 紅色革命故事《王二小的故事》
- 海洋工程用高性能建筑鋼材的研發(fā)
- 英語48個(gè)國際音標(biāo)課件(單詞帶聲、附有聲國際音標(biāo)圖)
- GB/T 6892-2023一般工業(yè)用鋁及鋁合金擠壓型材
- 冷庫安全管理制度
- 2023同等學(xué)力申碩統(tǒng)考英語考試真題
- 家具安裝工培訓(xùn)教案優(yōu)質(zhì)資料
- 在雙減政策下小學(xué)音樂社團(tuán)活動(dòng)有效開展及策略 論文
評論
0/150
提交評論