文章目录
1. 标准字体的定义
PDF 规范定义了 14 种标准字体(Base14 字体),包括:
• Times 系列:Times-Roman
, Times-Bold
, Times-Italic
, Times-BoldItalic
• Helvetica 系列:Helvetica
, Helvetica-Bold
, Helvetica-Oblique
, Helvetica-BoldOblique
• Courier 系列:Courier
, Courier-Bold
, Courier-Oblique
, Courier-BoldOblique
• Symbol 和 ZapfDingbats
这些字体在 PDF 文档中广泛使用,因此对它们进行特别化处理可以显著优化性能。
标准字体字典的创建
标准字体创建的入口函数
以下是使用Mermaid语法描述的CPDF_Font::GetStockFont
函数的流程图:
流程说明:
- 开始:函数开始执行。
- 将ByteStringView转换为ByteString:将输入的
ByteStringView
转换为ByteString
类型。 - 获取标准字体ID:通过
CFX_FontMapper::GetStandardFontName
函数获取标准字体ID。 - 字体ID是否有效?:检查获取的字体ID是否有效。
• 如果无效,直接返回nullptr
。
• 如果有效,继续执行。 - 获取字体全局实例:通过
CPDF_FontGlobals::GetInstance
获取字体全局实例。 - 查找是否已经存在该字体:在全局字体表中查找是否已经存在该字体。
- 字体是否找到?:检查是否找到了该字体。
• 如果找到,直接返回该字体。
• 如果未找到,继续执行。 - 创建新的字体字典:创建一个新的字体字典对象。
- 设置字体类型为Font:在字体字典中设置字体类型为
Font
。 - 设置字体子类型为Type1:在字体字典中设置字体子类型为
Type1
。 - 设置字体名称:在字体字典中设置字体名称。
- 设置字体编码为WinAnsi:在字体字典中设置字体编码为
WinAnsi
。 - 创建字体对象:使用创建的字体字典对象创建字体对象。
- 将新创建的字体存储在全局字体表中:将新创建的字体存储在全局字体表中。
- 返回字体对象:返回新创建的字体对象。
这个流程图清晰地展示了CPDF_Font::GetStockFont
函数的执行逻辑。
创建字体字典的通用函数
以下是使用Mermaid语法描述的CPDF_Font::Create
函数的流程图:
流程说明:
- 开始:函数开始执行。
- 获取字体子类型:从字体字典中获取
Subtype
字段的值。 - 子类型是否为TrueType?:检查字体子类型是否为
TrueType
。
• 如果是,继续处理TrueType
字体。
• 如果不是,检查其他子类型。 - 获取字体名称的前4个字符:从
BaseFont
字段中提取前4个字符。 - 是否为中文字体?:检查提取的字符是否匹配中文字体名称列表。
• 如果是中文字体,继续处理。
• 如果不是中文字体,直接创建TrueType
字体。 - 获取字体描述字典:从字体字典中获取
FontDescriptor
字段。 - 字体描述是否存在且包含FontFile2?:检查字体描述字典是否存在且是否包含
FontFile2
字段。
• 如果不存在或不包含FontFile2
,创建CID
字体。
• 如果存在且包含FontFile2
,继续处理。 - 创建CID字体:创建
CPDF_CIDFont
对象。 - 创建TrueType字体:创建
CPDF_TrueTypeFont
对象。 - 子类型是否为Type3?:检查字体子类型是否为
Type3
。
◦ 如果是,创建Type3
字体。
◦ 如果不是,继续检查其他子类型。 - 创建Type3字体:创建
CPDF_Type3Font
对象。 - 子类型是否为Type0?:检查字体子类型是否为
Type0
。
◦ 如果是,创建CID
字体。
◦ 如果不是,默认创建Type1
字体。 - 创建CID字体:创建
CPDF_CIDFont
对象。 - 创建Type1字体:创建
CPDF_Type1Font
对象。 - 加载字体:调用
pFont->Load()
加载字体。 - 字体加载是否成功?:检查字体加载是否成功。
◦ 如果成功,返回创建的字体对象。
◦ 如果失败,返回nullptr
。
这个流程图清晰地展示了CPDF_Font::Create
函数的执行逻辑,涵盖了所有子类型的处理路径。
CPDF_Font::Create
函数的主要功能是 根据字体字典中的信息创建并返回一个字体对象。它是 PDF 文档处理中字体管理的核心函数,负责解析字体字典中的属性(如字体子类型),并根据这些属性创建对应的字体对象。
函数的具体功能:
-
解析字体字典:
• 从传入的CPDF_Dictionary
中提取字体子类型(Subtype
)和字体名称(BaseFont
)等关键信息。 -
创建字体对象:
• 根据字体子类型(Subtype
),创建不同类型的字体对象:
◦ TrueType:创建CPDF_TrueTypeFont
对象。
◦ Type3:创建CPDF_Type3Font
对象。
◦ Type0:创建CPDF_CIDFont
对象。
◦ 其他:默认创建CPDF_Type1Font
对象。 -
加载字体:
• 调用字体对象的Load
方法,加载字体数据。如果加载失败,返回nullptr
。 -
返回字体对象:
• 如果字体创建和加载成功,返回创建好的字体对象(RetainPtr<CPDF_Font>
)。
Type1字体字典的解析
以下是使用Mermaid语法描述的CPDF_Type1Font::Load
函数的流程图:
流程说明:
- 开始:函数开始执行。
- 获取Base14字体名称:通过
CFX_FontMapper::GetStandardFontName
获取Base14字体名称。 - 是否是Base14字体?:检查是否是Base14字体。
• 如果不是,直接调用通用加载方法LoadCommon
。
• 如果是,继续处理。 - 获取字体描述符字典:从字体字典中获取
FontDescriptor
字段。 - 字体描述符是否存在且包含Flags?:检查字体描述符是否存在且是否包含
Flags
字段。
• 如果存在且包含Flags
,获取字体标志。
• 如果不存在或不包含Flags
,继续检查是否是符号字体。 - 是否是符号字体?:检查是否是符号字体。
• 如果是,设置为符号字体标志。
• 如果不是,设置为非符号字体标志。 - 是否是固定宽度字体?:检查是否是固定宽度字体。
• 如果是,设置字符宽度为600。
• 如果不是,继续检查字体类型。 - 是否是Symbol字体?:检查是否是Symbol字体。
• 如果是,设置为Adobe Symbol编码。
• 如果不是,继续检查是否是Dingbats字体。 - 是否是Dingbats字体?:检查是否是Dingbats字体。
• 如果是,设置为Zapf Dingbats编码。
• 如果不是,继续检查是否是非符号字体。 - 是否是非符号字体?:检查是否是非符号字体。
◦ 如果是,设置为标准编码。
◦ 如果不是,继续执行。 - 调用通用加载方法:调用
LoadCommon
方法完成字体加载。 - 结束:函数执行结束。
这个流程图清晰地展示了CPDF_Type1Font::Load
函数的执行逻辑,涵盖了所有关键分支和操作。
这里对标准字体进行了特别的预处理
因为 标准字体的属性(如编码、字符宽度、标志等)是已知且固定的,不需要从字体文件中动态加载。
(1) 设置标准字体的标志
if (pFontDesc && pFontDesc->KeyExist("Flags")) {
m_Flags = pFontDesc->GetIntegerFor("Flags");
} else if (IsSymbolicFont()) {
m_Flags = pdfium::kFontStyleSymbolic;
} else {
m_Flags = pdfium::kFontStyleNonSymbolic;
}
• 根据字体描述符中的 Flags
字段,设置字体的标志(如符号字体或非符号字体)。
(2) 设置字符宽度
if (IsFixedFont()) {
std::fill(std::begin(m_CharWidth), std::end(m_CharWidth), 600);
}
• 如果字体是固定宽度字体(如 Courier
),将所有字符的宽度设置为固定值(通常为 600)。
(3) 设置标准字体的编码
if (m_Base14Font == CFX_FontMapper::kSymbol) {
m_BaseEncoding = FontEncoding::kAdobeSymbol;
} else if (m_Base14Font == CFX_FontMapper::kDingbats) {
m_BaseEncoding = FontEncoding::kZapfDingbats;
} else if (FontStyleIsNonSymbolic(m_Flags)) {
m_BaseEncoding = FontEncoding::kStandard;
}
• 根据标准字体的类型,设置对应的编码(如 Symbol
使用 Adobe Symbol 编码,ZapfDingbats
使用 Zapf Dingbats 编码)。
简单字体 通用的加载函数
以下是使用Mermaid语法描述的CPDF_SimpleFont::LoadCommon
函数的流程图:
流程说明:
- 开始:函数开始执行。
- 获取字体描述符:从字体字典中获取
FontDescriptor
字段。 - 字体描述符是否存在?:检查字体描述符是否存在。
• 如果存在,加载字体描述符。
• 如果不存在,继续执行。 - 加载字符宽度信息:从字体描述符中加载字符宽度信息。
- 是否有字体文件?:检查是否有字体文件。
• 如果有,继续检查是否是子集化字体。
• 如果没有,加载替代字体。 - 是否是子集化字体?:检查是否是子集化字体。
• 如果是,截取字体名称。
• 如果不是,继续执行。 - 加载替代字体:如果没有字体文件,加载替代字体。
- 是否是符号字体?:检查是否是符号字体。
• 如果不是,设置为基础编码。
• 如果是,继续执行。 - 加载PDF编码信息:加载PDF编码信息。
- 加载字形映射表:加载字形映射表。
- 清空字符名称数组:清空字符名称数组。
- 是否有字体面?:检查是否有字体面。
◦ 如果没有,直接返回true
。
◦ 如果有,继续检查是否是全大写字体。 - 是否是全大写字体?:检查是否是全大写字体。
◦ 如果是,遍历小写字母范围。
◦ 如果不是,直接检查字体度量信息并返回true
。 - 遍历小写字母范围:遍历小写字母范围。
- 字形索引是否有效且有字体文件?:检查字形索引是否有效且有字体文件。
◦ 如果有效且有字体文件,继续遍历。
◦ 如果无效或没有字体文件,计算对应的大写字母索引。 - 计算对应的大写字母索引:计算对应的大写字母索引。
- 设置字形索引:设置小写字母的字形索引。
- 大写字母宽度是否有效?:检查大写字母宽度是否有效。
◦ 如果有效,设置小写字母的宽度和边界框。
◦ 如果无效,继续遍历。 - 检查字体度量信息:检查字体度量信息。
- 返回true:函数执行结束,返回
true
。
这个流程图清晰地展示了CPDF_SimpleFont::LoadCommon
函数的执行逻辑,涵盖了所有关键分支和操作。
对于标准字体 没有 字体描述符 ,所以这里直接使用替代字体实现 (对于podofo libharu而言,使用的是 内置的字体度量信息)
简单字体 去 加载替代字体
加载替代字体是一个复杂的过程,我会给出流程图,但不会介绍细节
以下是使用Mermaid语法描述的CPDF_SimpleFont::LoadSubstFont
函数的流程图:
流程说明:
- 开始:函数开始执行。
- 是否不使用字体宽度且不是固定间距字体?:检查是否不使用字体宽度且不是固定间距字体。
• 如果是,继续处理。
• 如果不是,跳过字符宽度检查。 - 初始化宽度为0:初始化宽度变量为0。
- 遍历字符宽度表:遍历字符宽度表。
- 字符宽度是否有效?:检查字符宽度是否有效。
• 如果无效,继续遍历。
• 如果有效,继续检查宽度是否未设置。 - 宽度是否未设置?:检查宽度是否未设置。
• 如果未设置,设置宽度。
• 如果已设置,检查宽度是否不一致。 - 宽度是否不一致?:检查宽度是否不一致。
• 如果不一致,结束遍历。
• 如果一致,继续遍历。 - 是否所有字符宽度一致?:检查是否所有字符宽度一致。
• 如果一致,设置为固定间距字体。
• 如果不一致,继续执行。 - 获取字体权重:获取字体权重。
- 权重是否有效?:检查权重是否有效。
◦ 如果无效,设置为正常权重。
◦ 如果有效,继续执行。 - 加载替代字体:加载替代字体。
- 结束:函数执行结束。
这个流程图清晰地展示了CPDF_SimpleFont::LoadSubstFont
函数的执行逻辑,涵盖了所有关键分支和操作。
CPDF_SimpleFont::LoadSubstFont
函数的主要功能是 加载替代字体。当 PDF 文档中指定的字体无法直接加载时(例如字体文件缺失或无法解析),该函数会根据字体的属性(如字体名称、权重、倾斜角度等)选择一个替代字体,以确保文本能够正确渲染。
函数的具体功能:
-
检查字符宽度是否一致:
• 如果函数不使用字体宽度且字体不是固定间距字体,它会遍历字符宽度表,检查所有字符的宽度是否一致。
• 如果所有字符宽度一致,函数会将字体标记为固定间距字体(FixedPitch
)。 -
获取并验证字体权重:
• 从字体属性中获取字体权重(如Normal
、Bold
等)。
• 如果权重无效(不在允许的范围内),函数会将权重设置为默认值(Normal
)。 -
加载替代字体:
• 根据字体名称、是否为 TrueType 字体、字体标志、权重、倾斜角度等属性,调用m_Font.LoadSubst
方法加载一个替代字体。
• 替代字体的选择基于系统可用的字体资源,确保文本能够以相似的样式渲染。
函数的输入和依赖:
-
输入:
• 函数依赖以下成员变量:
◦m_bUseFontWidth
:是否使用字体宽度。
◦m_Flags
:字体的标志(如固定间距、符号字体等)。
◦m_CharWidth
:字符宽度表。
◦m_BaseFontName
:字体名称。
◦m_Font
:字体对象,用于加载替代字体。
◦m_ItalicAngle
:字体的倾斜角度。 -
依赖:
•GetFontWeight()
:获取字体权重。
•m_Font.LoadSubst()
:加载替代字体的核心方法。
函数的输出:
• 函数没有返回值(void
),但它会通过 m_Font.LoadSubst
方法加载一个替代字体,并更新字体的属性(如固定间距标志)。
应用场景:
在以下情况下,LoadSubstFont
函数会被调用:
- 字体文件缺失:PDF 文档中指定的字体文件不存在或无法加载。
- 字体不支持:PDF 文档中指定的字体格式不被当前系统支持。
- 字体属性不完整:字体描述符中缺少必要的信息(如字体文件路径)。
通过加载替代字体,函数确保 PDF 文档中的文本能够以相似的样式渲染,避免出现乱码或无法显示的情况。
示例:
假设 PDF 文档中指定了一个字体 Helvetica-Bold
,但系统中没有该字体文件。LoadSubstFont
函数会:
- 检查字符宽度是否一致。
- 获取字体权重(
Bold
)。 - 根据字体名称
Helvetica-Bold
、权重Bold
等属性,加载一个替代字体(如Arial-Bold
)。
总结:
CPDF_SimpleFont::LoadSubstFont
函数的主要功能是 在无法加载指定字体时,根据字体属性选择一个替代字体。它通过以下步骤实现:
- 检查字符宽度是否一致,标记固定间距字体。
- 获取并验证字体权重。
- 加载替代字体,确保文本能够正确渲染。
这个函数是 PDF 字体处理中的重要环节,确保了文档的兼容性和可读性。
通过内置字体映射器查找并加载替代字体
加载替代字体是一个复杂的过程,我会给出流程图,但不会介绍细节
CFX_FontMapper::FindSubstFont
函数的主要功能是 根据字体名称、类型、标志、权重、倾斜角度等属性,查找并返回一个替代字体对象。该函数通过内置的字体映射器和外部字体信息管理器,选择最合适的字体来替代指定的字体,以确保文本能够正确渲染。
以下是函数的详细流程:
1. 初始化字体权重和属性
- 如果传入的
weight
为 0,将其设置为默认值pdfium::kFontWeightNormal
。 - 如果未启用外部属性标志(
FXFONT_USEEXTERNATTR
),将weight
设置为pdfium::kFontWeightNormal
,并将italic_angle
设置为 0。
2. 处理特殊字体(Symbol 和 ZapfDingbats)
- 如果字体名称为
Symbol
且不是 TrueType 字体,设置替代字体的属性为Chrome Symbol
,并返回内置的 Symbol 字体。 - 如果字体名称为
ZapfDingbats
,设置替代字体的属性为Chrome Dingbats
,并返回内置的 Dingbats 字体。
3. 解析字体名称
- 如果字体名称包含逗号(
,
),将其分为family
(字体家族)和style
(字体样式)。 - 如果字体名称包含连字符(
-
),将其分为family
和style
。 - 根据
family
查找是否匹配内置的 14 种标准字体(Base14)。
4. 获取字体样式和间距属性
- 如果字体是 Base14 字体,根据字体索引获取其样式和间距属性。
- 如果字体不是 Base14 字体,根据字体标志和名称解析其样式和间距属性。
5. 调整字体权重和样式
- 如果字体样式强制为粗体(
ForceBold
),将weight
设置为pdfium::kFontWeightBold
。 - 解析
style
字符串,更新weight
和nStyle
。
6. 处理 CJK 字体
- 如果字体是 CJK(中日韩)字体,设置替代字体的相关属性(如
m_bSubstCJK
、m_WeightCJK
、m_bItalicCJK
)。
7. 匹配已安装的字体
- 根据
family
或subst_name
,在已安装的字体中查找匹配的字体。 - 如果未找到匹配的字体,检查是否支持第三方字体。
8. 调整字体家族和样式
- 如果找到匹配的字体,更新
family
。 - 如果是 Base14 字体,根据样式调整字体索引和
family
。
9. 映射外部字体
- 如果启用了外部字体信息管理器(
m_pFontInfo
),调用MapFont
方法,根据weight
、is_italic
、Charset
、pitch_family
和family
映射字体。 - 如果成功映射到字体,返回外部替代字体。
10. 处理未找到字体的场景
- 如果未找到匹配的字体,返回内置的替代字体。
- 如果是 Symbol 字体,重新调用
FindSubstFont
,去除符号字体标志。 - 如果是 ANSI 字体,返回内置的替代字体。
11. 处理其他字符集
- 如果字符集不是 Symbol 或 ANSI,在
m_FaceArray
中查找匹配的字体。 - 如果找到匹配的字体,返回外部替代字体。
- 如果未找到,返回内置的替代字体。
加载字体编码
以下是使用 Mermaid 语法描述的 CPDF_SimpleFont::LoadPDFEncoding
函数的流程图:
流程说明:
-
获取编码对象:
• 从字体字典中获取Encoding
对象pEncoding
。 -
检查是否存在编码对象:
• 如果不存在pEncoding
,根据m_BaseFontName
是否为Symbol
设置默认编码。
• 如果未嵌入且m_BaseEncoding
为kBuiltin
,设置为WinAnsi
编码。 -
处理名称对象:
• 如果pEncoding
是名称对象,检查是否为AdobeSymbol
或ZapfDingbats
,如果是则直接返回。
• 如果是符号字体且m_BaseFontName
为Symbol
,设置为AdobeSymbol
编码。
• 获取编码字符串bsEncoding
,如果为MacExpertEncoding
,替换为WinAnsiEncoding
。
• 调用GetPredefinedEncoding
获取预定义编码。 -
处理字典对象:
• 如果pEncoding
是字典对象,获取BaseEncoding
字段。
• 如果bTrueType
为真且BaseEncoding
为MacExpertEncoding
,替换为WinAnsiEncoding
。
• 调用GetPredefinedEncoding
获取预定义编码。
• 如果未嵌入或bTrueType
为真且m_BaseEncoding
为kBuiltin
,设置为Standard
编码。
• 调用LoadDifferences
加载差异编码表。
总结:
该流程图详细描述了 CPDF_SimpleFont::LoadPDFEncoding
函数的执行逻辑,涵盖了所有关键分支和操作。通过该函数,系统能够根据字体字典中的编码信息设置字体的编码属性,确保文本能够正确渲染。
CPDF_SimpleFont::LoadPDFEncoding
函数的主要目的是 加载并设置字体的编码信息,以确保 PDF 文档中的文本能够正确解码和渲染。加载编码信息不仅仅是为了加载差异数组(Differences
),还包括处理字体的基础编码、预定义编码以及特殊字体的编码需求。
为什么需要加载这些编码?
-
正确解码文本:
• PDF 文档中的文本通常使用特定的编码(如WinAnsi
、MacRoman
、AdobeSymbol
等)进行存储。
• 如果字体没有正确的编码信息,文本可能无法正确解码,导致乱码或显示错误。 -
处理字体嵌入:
• 如果字体是嵌入的,PDF 文档中可能包含自定义的编码信息(如差异数组Differences
)。
• 加载编码信息可以确保嵌入字体的文本能够正确渲染。 -
支持特殊字体:
• 某些字体(如Symbol
和ZapfDingbats
)有特殊的编码需求。
• 加载编码信息可以确保这些特殊字体的文本能够正确显示。 -
兼容性:
• PDF 规范支持多种编码方式,加载编码信息可以确保 PDF 文档在不同平台和阅读器上的一致性。
编码信息的组成部分
-
基础编码(BaseEncoding):
• 基础编码是字体的默认编码方式,如WinAnsi
、MacRoman
、AdobeSymbol
等。
• 如果字体没有指定编码,系统会根据字体名称和类型设置默认的基础编码。 -
差异数组(Differences):
• 差异数组是 PDF 文档中自定义的编码表,用于覆盖或扩展基础编码。
• 如果字体是嵌入的,PDF 文档可能包含差异数组,以支持自定义字符映射。 -
预定义编码(Predefined Encoding):
• 预定义编码是 PDF 规范中定义的标准化编码方式,如WinAnsi
、MacExpert
等。
• 系统会根据字体名称和编码对象选择最合适的预定义编码。
为什么需要加载差异数组?
差异数组(Differences
)是 PDF 文档中自定义的编码表,用于覆盖或扩展基础编码。加载差异数组的主要目的是:
-
支持自定义字符映射:
• 如果 PDF 文档中使用了自定义字符(如特殊符号或非标准字符),差异数组可以确保这些字符能够正确映射和显示。 -
处理嵌入字体:
• 如果字体是嵌入的,PDF 文档可能包含自定义的编码信息,差异数组可以确保嵌入字体的文本能够正确渲染。 -
覆盖基础编码:
• 差异数组可以覆盖基础编码中的某些字符映射,以满足特定的显示需求。
函数的具体逻辑
-
检查编码对象:
• 如果字体字典中没有编码对象,根据字体名称和类型设置默认的基础编码。 -
处理名称对象:
• 如果编码对象是名称对象(如WinAnsi
、MacRoman
),调用GetPredefinedEncoding
获取预定义编码。 -
处理字典对象:
• 如果编码对象是字典对象,获取BaseEncoding
字段,并调用GetPredefinedEncoding
获取预定义编码。
• 如果未嵌入或字体是 TrueType,设置默认的Standard
编码。
• 调用LoadDifferences
加载差异数组。
总结
加载编码信息的主要目的是 确保 PDF 文档中的文本能够正确解码和渲染。差异数组是编码信息的一部分,用于支持自定义字符映射和嵌入字体的特殊需求。通过加载编码信息,系统能够正确处理字体的基础编码、预定义编码以及自定义的差异数组,确保文本的正确显示和兼容性。
加载字形映射表
CPDF_Type1Font::LoadGlyphMap
函数的主要功能是 加载字体的字形映射表,即将字符码(charcode)映射到字体的字形索引(glyph index)。这个映射表是字体渲染的核心,它决定了字符如何被转换为字形并显示在屏幕上。
以下是该函数的详细流程和解释:
1. 获取字体的底层 FreeType 面对象
• 调用 m_Font.GetFace()
获取字体的 FreeType 面对象 face
。
• 如果没有有效的面对象,函数直接返回。
2. 处理 Apple 平台的特殊逻辑
• 如果目标平台是 Apple 系统(BUILDFLAG(IS_APPLE)
),函数会检查是否使用 Core Text 技术。
• 如果没有平台特定字体(m_Font.GetPlatformFont()
),函数会尝试创建平台字体。
• 如果字体名称为 "DFHeiStd-W5"
,禁用 Core Text。
3. 处理非嵌入式、非符号字体且为 TrueType 字体的场景
• 如果字体是非嵌入的、非符号字体且为 TrueType 字体,函数会尝试使用 Microsoft Symbol 字符映射表(UseTTCharmapMSSymbol
)。
• 遍历所有字符码(charcode
),尝试通过 Unicode 值获取字形索引。
• 如果找到至少一个有效的字形索引,函数会返回。
4. 选择 Unicode 字符映射表
• 如果字体不是 TrueType 字体或未使用 Microsoft Symbol 映射表,函数会选择 Unicode 字符映射表(face->SelectCharMap(fxge::FontEncoding::kUnicode)
)。
• 如果基础编码为内置编码(kBuiltin
),将其设置为标准编码(kStandard
)。
5. 遍历所有字符码并加载字形索引
• 对于每个字符码(charcode
),函数会获取 Adobe 字符名称(GetAdobeCharName
)。
• 如果找到字符名称,函数会将其转换为 Unicode 值(UnicodeFromAdobeName
),并设置到编码表中。
• 调用 face->GetCharIndex
获取字形索引。
• 如果字符名称为 ".notdef"
且字形索引无效,函数会将其映射到空格字符(Unicode 0x20)。
6. 处理符号字体
• 如果字体是符号字体(FontStyleIsSymbolic(m_Flags)
),函数会遍历所有字符码,获取 Adobe 字符名称并转换为 Unicode 值。
• 如果没有找到字符名称,函数会直接使用字符码获取字形索引。
• 如果字形索引有效,函数会获取字形名称并转换为 Unicode 值。
7. 处理非符号字体
• 如果字体不是符号字体,函数会遍历所有字符码,获取 Adobe 字符名称并转换为 Unicode 值。
• 调用 m_Font.GetFace()->GetNameIndex
获取字形索引。
• 如果字符名称为 ".notdef"
或 "space"
,函数会将其映射到空格字符(Unicode 0x20)。
8. 处理 Apple 平台的扩展 GID
• 如果目标平台是 Apple 系统且未使用 Core Text,函数会将扩展 GID(m_ExtGID
)设置为字形索引。
9. 返回
• 函数执行完毕,返回。
详细流程总结
-
获取 FreeType 面对象:
• 如果无效,直接返回。 -
处理 Apple 平台的特殊逻辑:
• 检查是否使用 Core Text,尝试创建平台字体。 -
处理 TrueType 字体:
• 如果字体是 TrueType 字体,尝试使用 Microsoft Symbol 映射表加载字形索引。 -
选择 Unicode 字符映射表:
• 如果字体不是 TrueType 字体,选择 Unicode 字符映射表。 -
遍历字符码并加载字形索引:
• 获取 Adobe 字符名称,转换为 Unicode 值,并获取字形索引。
• 如果字符名称为".notdef"
,映射到空格字符。 -
处理符号字体:
• 如果字体是符号字体,直接使用字符码获取字形索引。 -
处理非符号字体:
• 如果字体不是符号字体,使用 Adobe 字符名称获取字形索引。 -
处理 Apple 平台的扩展 GID:
• 如果未使用 Core Text,设置扩展 GID 为字形索引。 -
返回:
• 函数执行完毕,返回。
在这个 LoadGlyphMap 函数里 Unicode 和 charcode 的区别是什么
在 CPDF_Type1Font::LoadGlyphMap
函数中,Unicode
和 charcode
是两个不同的概念,它们分别代表了字符的两种不同编码方式。以下是它们的区别和具体作用:
1. charcode
(字符码)
• 定义:charcode
是 PDF 文档中使用的字符编码,也称为字符索引或字符编号。
• 范围:通常是 0 到 255(8 位),或者在某些情况下可能更大。
• 作用:
◦ charcode
是 PDF 文档中存储的原始字符编码,用于表示字符在文档中的位置。
◦ 它并不直接对应字符的实际内容,而是需要通过 编码表(如 WinAnsi
、MacRoman
、AdobeSymbol
等)映射到具体的字符。
• 示例:
◦ 在 WinAnsi
编码中,charcode
65 对应字符 "A"
。
◦ 在 AdobeSymbol
编码中,charcode
65 可能对应一个符号字符(如 "Δ"
)。
2. Unicode
(统一码)
• 定义:Unicode
是一种 全球通用的字符编码标准,用于表示几乎所有语言的字符。
• 范围:Unicode
的范围非常大,通常使用 16 位或 32 位编码(如 UTF-16、UTF-32)。
• 作用:
◦ Unicode
用于表示字符的实际内容,确保字符在不同系统和平台上的一致性。
◦ 在字体渲染中,Unicode
是字符的最终表示形式,用于查找字体的字形索引(glyph index
)。
• 示例:
◦ Unicode
值 U+0041
对应字符 "A"
。
◦ Unicode
值 U+0394
对应字符 "Δ"
。
3. charcode
和 Unicode
的关系
• 映射关系:
◦ charcode
需要通过 编码表(如 WinAnsi
、AdobeSymbol
等)映射到 Unicode
。
◦ 在 LoadGlyphMap
函数中,charcode
首先被映射到 Unicode
,然后通过 Unicode
查找字体的字形索引(glyph index
)。
• 具体流程:
1. 获取 charcode
对应的 Adobe 字符名称(GetAdobeCharName
)。
2. 将 Adobe 字符名称转换为 Unicode
值(UnicodeFromAdobeName
)。
3. 使用 Unicode
值查找字体的字形索引(face->GetCharIndex
)。
4. 为什么需要同时使用 charcode
和 Unicode
?
• charcode
的作用:
◦ charcode
是 PDF 文档中存储的原始编码,直接反映了文档的字符布局。
◦ 它依赖于特定的编码表(如 WinAnsi
、AdobeSymbol
),这些编码表是 PDF 文档的一部分。
• Unicode
的作用:
◦ Unicode
是一种通用的字符编码标准,确保字符在不同系统和平台上的一致性。
◦ 字体渲染引擎(如 FreeType)通常使用 Unicode
来查找字形索引,因此需要将 charcode
转换为 Unicode
。
5. 具体代码示例
在 LoadGlyphMap
函数中,charcode
和 Unicode
的使用如下:
// 获取 charcode 对应的 Adobe 字符名称
const char* name = GetAdobeCharName(m_BaseEncoding, m_CharNames, charcode);
// 将 Adobe 字符名称转换为 Unicode 值
wchar_t unicode = UnicodeFromAdobeName(name);
// 设置 Unicode 编码
m_Encoding.SetUnicode(charcode, unicode);
// 使用 Unicode 值查找字体的字形索引
m_GlyphIndex[charcode] = face->GetCharIndex(unicode);
6. 总结
• charcode
是 PDF 文档中使用的字符编码,依赖于特定的编码表(如 WinAnsi
、AdobeSymbol
)。
• Unicode
是一种全球通用的字符编码标准,用于表示字符的实际内容。
• 在 LoadGlyphMap
函数中,charcode
首先被映射到 Unicode
,然后通过 Unicode
查找字体的字形索引。
• 这种设计确保了 PDF 文档中的字符能够正确解码并渲染,同时支持多种编码方式和平台兼容性。