文章目录
1.字体定义的数据设置
const char* my_font = HPDF_LoadTTFontFromFile(pdf, fontPath.c_str(), HPDF_TRUE);
展开 HPDF_LoadTTFontFromFile
HPDF_LoadTTFontFromFile (HPDF_Doc pdf,
const char *file_name,
HPDF_BOOL embedding)
{
HPDF_Stream font_data = HPDF_FileReader_New (pdf->mmgr, file_name);//完成初始化动作
const char * ret = LoadTTFontFromStream (pdf, font_data, embedding, file_name);
}
展开 HPDF_FileReader_New
HPDF_FileReader_New (HPDF_MMgr mmgr, const char *fname)
{
HPDF_FILEP fp = HPDF_FOPEN (fname, "rb");
stream->mmgr = mmgr;
stream->attr = fp;
}
// 该函数创建并初始化一个用于读取文件的流对象。
展开 LoadTTFontFromStream
static const char*
LoadTTFontFromStream (HPDF_Doc pdf,
HPDF_Stream font_data,
HPDF_BOOL embedding,
const char *file_name)
{
HPDF_FontDef def = HPDF_TTFontDef_Load (pdf->mmgr, font_data, embedding);
HPDF_List_Add (pdf->fontdef_list, def); //增加 字体定义到pdf内部的字体定义列表,这一步,和之后的 HPDF_GetFont内的 HPDF_GetFontDef 有关
if (embedding) {
HPDF_MemCpy (pdf->ttfont_tag, (HPDF_BYTE *)"HPDFAA", 6);
HPDF_TTFontDef_SetTagName (def, (char *)pdf->ttfont_tag);
}
return def->base_font;
}
展开 HPDF_TTFontDef_Load
HPDF_FontDef
HPDF_TTFontDef_Load (HPDF_MMgr mmgr,
HPDF_Stream stream,
HPDF_BOOL embedding)
{
HPDF_FontDef fontdef;
HPDF_STATUS ret = LoadFontData (fontdef, stream, embedding, 0);
return fontdef;
}
展开 LoadFontData
LoadFontData
函数的功能是从给定的流中加载字体数据,并解析TrueType字体表以初始化字体定义的相关属性。
static HPDF_STATUS
LoadFontData (HPDF_FontDef fontdef, HPDF_Stream stream, HPDF_BOOL embedding, HPDF_UINT offset)
{
HPDF_TTFontDefAttr attr = (HPDF_TTFontDefAttr)fontdef->attr;
HPDF_STATUS ret;
attr->stream = stream;
attr->embedding = embedding;
if ((ret = HPDF_Stream_Seek (stream, offset, HPDF_SEEK_SET)) != HPDF_OK)
return ret;
if ((ret = LoadTTFTable (fontdef)) != HPDF_OK)
return ret;
ret = ParseHead (fontdef);
if (ret == HPDF_OK) ret = ParseMaxp (fontdef);
if (ret == HPDF_OK) ret = ParseHhea (fontdef);
if (ret == HPDF_OK) ret = ParseCMap (fontdef);
if (ret == HPDF_OK) ret = ParseHmtx (fontdef);
if (ret == HPDF_OK) ret = ParseLoca (fontdef);
if (ret == HPDF_OK) ret = ParseName (fontdef);
if (ret == HPDF_OK) ret = ParseOS2 (fontdef);
if (ret != HPDF_OK)
return ret;
HPDF_TTFTable *tbl = FindTable (fontdef, "glyf");
if (!tbl)
return HPDF_SetError (fontdef->error, HPDF_TTF_MISSING_TABLE, 4);
attr->glyph_tbl.base_offset = tbl->offset;
fontdef->cap_height = (HPDF_UINT16)HPDF_TTFontDef_GetCharBBox (fontdef, (HPDF_UINT16)'H').top;
fontdef->x_height = (HPDF_UINT16)HPDF_TTFontDef_GetCharBBox (fontdef, (HPDF_UINT16)'x').top;
fontdef->missing_width = (HPDF_INT16)((HPDF_UINT32)attr->h_metric[0].advance_width * 1000 / attr->header.units_per_em);
return HPDF_OK;
}
展开 LoadTTFTable
HPDF_STATUS
LoadTTFTable (HPDF_FontDef fontdef)
{
HPDF_TTFontDefAttr attr = (HPDF_TTFontDefAttr)fontdef->attr;
ret += GetUINT32 (attr->stream, &attr->offset_tbl.sfnt_version);
ret += GetUINT16 (attr->stream, &attr->offset_tbl.num_tables);
ret += GetUINT16 (attr->stream, &attr->offset_tbl.search_range);
ret += GetUINT16 (attr->stream, &attr->offset_tbl.entry_selector);
ret += GetUINT16 (attr->stream, &attr->offset_tbl.range_shift);
ret += HPDF_Stream_Read (attr->stream, (HPDF_BYTE *)tbl->tag, &siz);
ret += GetUINT32 (attr->stream, &tbl->check_sum);
ret += GetUINT32 (attr->stream, &tbl->offset);
ret += GetUINT32 (attr->stream, &tbl->length);
return HPDF_OK;
}
其他的几个解析 函数,都是 对传入的 fontdef 的 attr 进行设置
ParseMaxp (fontdef);
ParseHhea (fontdef);
ParseCMap (fontdef);
ParseHmtx (fontdef);
ParseLoca (fontdef);
ParseName (fontdef);
ParseOS2 (fontdef);
这些函数 (`ParseHead`, `ParseMaxp`, `ParseHhea` 和 `ParseCMap`) 对传入的参数 `HPDF_FontDef fontdef` 的处理具有一些相似性。主要包括以下几个方面:
1. **查找表 (`FindTable`):**
每个函数都会首先使用 `FindTable` 函数来查找指定的 TrueType 字体表。例如,在 `ParseHead` 中查找 "head" 表,在 `ParseMaxp` 中查找 "maxp" 表等。如果表不存在,都会通过 `HPDF_SetError` 设置错误状态并返回。
2. **定位表位置 (`HPDF_Stream_Seek`):**
如果找到相应的表,这些函数都会使用 `HPDF_Stream_Seek` 来将流定位到表的起始位置或某个偏移处,以便后续读取表的数据。
3. **读取表数据 (`HPDF_Stream_Read` 或其他获取数据的函数):**
定位到表的起始位置后,各函数会通过多种读取操作(如 `HPDF_Stream_Read`,`GetUINT16`,`GetUINT32` 等)来读取表中的数据。这些读取操作通常会累积返回状态值 (`ret`)。
4. **检查读取操作状态:**
所有函数在读取操作后都会检查返回状态值 (`ret`),以确保操作的成功。如果读取操作失败,则会返回相应的错误代码。
5. **对读取的数据进行处理:**
每个函数在读取数据后都会对这些数据进行处理,并更新 `fontdef` 或 `attr` 的相关字段。例如,`ParseHead` 会计算并设置 `fontdef->font_bbox`,而 `ParseHhea` 会更新 `fontdef->ascent` 和 `fontdef->descent`。
总结起来,这些函数在处理 `HPDF_FontDef` 参数时有以下相似的步骤:
- 查找特定的表。
- 通过流定位到表的位置。
- 读取表的数据。
- 检查操作执行状态。
- 处理和使用读取的数据。
这种结构化的处理方式确保了每个表的数据能够被正确读取和使用,同时也保证了错误能够被有效定位和处理。
至此 LoadFontData 中完成对 HPDF_FontDef fontdef 的设置数据
HPDF_Font font = HPDF_GetFont(pdf, my_font, "UTF-8");
展开 HPDF_GetFont
HPDF_EXPORT(HPDF_Font)
HPDF_GetFont (HPDF_Doc pdf,
const char *font_name,
const char *encoding_name)
{
HPDF_FontDef fontdef = HPDF_GetFontDef (pdf, font_name);
encoder = HPDF_GetEncoder (pdf, encoding_name);
if (encoder->type == HPDF_ENCODER_TYPE_DOUBLE_BYTE)
font = HPDF_Type0Font_New (pdf->mmgr, fontdef, encoder,
pdf->xref); //对于东亚双字节字体会进入此分支(HPDF_Type0Font_New)
else
font = HPDF_TTFont_New (pdf->mmgr, fontdef, encoder, pdf->xref);
HPDF_List_Add (pdf->font_mgr, font);
return font;
}
2.创建字体字典
展开 HPDF_Type0Font_New [[#HPDF_Type0Font_New的解释]]
这段函数创建并初始化一个 Type0 字体对象,处理不同的编码和字体类型,并将所有必要的信息添加到该对象中。
HPDF_Font
HPDF_Type0Font_New(HPDF_MMgr mmgr, HPDF_FontDef fontdef, HPDF_Encoder encoder, HPDF_Xref xref)
{
HPDF_FontAttr attr;
HPDF_CMapEncoderAttr encoder_attr;
HPDF_STATUS ret = 0;
HPDF_Array descendant_fonts;
HPDF_PTRACE((" HPDF_Type0Font_New\n"));
HPDF_Dict font = HPDF_Dict_New(mmgr);
font->header.obj_class |= HPDF_OSUBCLASS_FONT;
font->write_fn = NULL;
font->free_fn = OnFree_Func;
font->attr = attr;
encoder_attr = (HPDF_CMapEncoderAttr)encoder->attr;
attr->writing_mode = encoder_attr->writing_mode;
attr->text_width_fn = TextWidth;
attr->measure_text_fn = MeasureText;
attr->fontdef = fontdef;
attr->encoder = encoder;
attr->xref = xref;
ret += HPDF_Dict_AddName(font, "Type", "Font");
ret += HPDF_Dict_AddName(font, "BaseFont", fontdef->base_font);
ret += HPDF_Dict_AddName(font, "Subtype", "Type0");
ret += HPDF_Dict_AddName(font, "Encoding", "Identity-H");
attr->cmap_stream = CreateCMap(encoder, xref);
ret += HPDF_Dict_Add(font, "ToUnicode", attr->cmap_stream);
descendant_fonts = HPDF_Array_New(mmgr);
HPDF_Dict_Add(font, "DescendantFonts", descendant_fonts);
attr->descendant_font = CIDFontType2_New(font, xref);
attr->type = HPDF_FONT_TYPE0_TT;
HPDF_Array_Add(descendant_fonts, attr->descendant_font);
return font;
}
展开 CIDFontType2_New [[#CIDFontType2_New 解释]]
static HPDF_Font CIDFontType2_New(HPDF_Font parent, HPDF_Xref xref)
{
HPDF_STATUS ret = HPDF_OK;
HPDF_FontAttr attr = (HPDF_FontAttr)parent->attr;
HPDF_FontDef fontdef = attr->fontdef;
HPDF_TTFontDefAttr fontdef_attr = (HPDF_TTFontDefAttr)fontdef->attr;
HPDF_Encoder encoder = attr->encoder;
HPDF_CMapEncoderAttr encoder_attr = (HPDF_CMapEncoderAttr)encoder->attr;
HPDF_Font font;
HPDF_Array array;
HPDF_UINT i;
HPDF_UNICODE tmp_map[65536];
HPDF_Dict cid_system_info;
HPDF_UINT16 max = 0;
HPDF_PTRACE((" HPDF_CIDFontType2_New\n"));
font = HPDF_Dict_New(parent->mmgr);
HPDF_Xref_Add(xref, font);
parent->before_write_fn = CIDFontType2_BeforeWrite_Func;
ret += HPDF_Dict_AddName(font, "Type", "Font");
ret += HPDF_Dict_AddName(font, "Subtype", "CIDFontType2");
ret += HPDF_Dict_AddNumber(font, "DW", fontdef->missing_width);
// Add 'DW2' element
array = HPDF_Array_New(font->mmgr);
HPDF_Dict_Add(font, "DW2", array);
ret += HPDF_Array_AddNumber(array, (HPDF_INT32)(fontdef->font_bbox.bottom));
ret += HPDF_Array_AddNumber(array, (HPDF_INT32)(fontdef->font_bbox.bottom - fontdef->font_bbox.top));
HPDF_MemSet(tmp_map, 0, sizeof(HPDF_UNICODE) * 65536);
for (i = 0; i < 256; i++) {
HPDF_UINT j;
for (j = 0; j < 256; j++) {
if (encoder->to_unicode_fn == HPDF_CMapEncoder_ToUnicode) {
HPDF_UINT16 cid = encoder_attr->cid_map[i][j];
if (cid != 0) {
HPDF_UNICODE unicode = encoder_attr->unicode_map[i][j];
HPDF_UINT16 gid = HPDF_TTFontDef_GetGlyphid(fontdef, unicode);
tmp_map[cid] = gid;
if (max < cid) {
max = cid;
}
}
} else {
HPDF_UNICODE unicode = (i << 8) | j;
HPDF_UINT16 gid = HPDF_TTFontDef_GetGlyphid(fontdef, unicode);
tmp_map[unicode] = gid;
if (max < unicode) {
max = unicode;
}
}
}
}
if (max > 0) {
HPDF_INT16 dw = fontdef->missing_width;
HPDF_UNICODE *ptmp_map = tmp_map;
HPDF_Array tmp_array = NULL;
// Add 'W' element
array = HPDF_Array_New(font->mmgr);
HPDF_Dict_Add(font, "W", array);
for (i = 0; i < max; i++, ptmp_map++) {
HPDF_INT w = HPDF_TTFontDef_GetGidWidth(fontdef, *ptmp_map);
if (w != dw) {
if (!tmp_array) {
HPDF_Array_AddNumber(array, i);
tmp_array = HPDF_Array_New(font->mmgr);
if (!tmp_array) {
return NULL;
}
HPDF_Array_Add(array, tmp_array);
}
HPDF_Array_AddNumber(tmp_array, w);
} else {
tmp_array = NULL;
}
}
// Create "CIDToGIDMap" data
if (fontdef_attr->embedding) {
attr->map_stream = HPDF_DictStream_New(font->mmgr, xref);
if (!attr->map_stream) {
return NULL;
}
HPDF_Dict_Add(font, "CIDToGIDMap", attr->map_stream);
for (i = 0; i < max; i++) {
HPDF_BYTE u[2];
HPDF_UINT16 gid = tmp_map[i];
u[0] = (HPDF_BYTE)(gid >> 8);
u[1] = (HPDF_BYTE)gid;
HPDF_MemCpy((HPDF_BYTE *)(tmp_map + i), u, 2);
}
ret = HPDF_Stream_Write(attr->map_stream->stream, (HPDF_BYTE *)tmp_map, max * 2);
}
} else {
HPDF_SetError(font->error, HPDF_INVALID_FONTDEF_DATA, 0);
return 0;
}
// Create CIDSystemInfo dictionary
cid_system_info = HPDF_Dict_New(parent->mmgr);
HPDF_Dict_Add(font, "CIDSystemInfo", cid_system_info);
ret += HPDF_Dict_Add(cid_system_info, "Registry",
HPDF_String_New(parent->mmgr, encoder_attr->registry, NULL));
ret += HPDF_Dict_Add(cid_system_info, "Ordering",
HPDF_String_New(parent->mmgr, encoder_attr->ordering, NULL));
ret += HPDF_Dict_AddNumber(cid_system_info, "Supplement",
encoder_attr->supplement);
return font;
}
3.创建字体描述字典
展开 CIDFontType2_BeforeWrite_Func [[#CIDFontType2_BeforeWrite_Func 解释]]
函数的主要工作就是在写入 PDF 文档之前,为 CIDType2 字体创建和配置一个字体描述符,并处理字体数据的嵌入,确保所有相关字体信息正确地存储在 PDF 文件中
嵌入 FontFile2
static HPDF_STATUS
CIDFontType2_BeforeWrite_Func(HPDF_Dict obj) {
HPDF_FontAttr font_attr = (HPDF_FontAttr)obj->attr;
HPDF_FontDef def = font_attr->fontdef;
HPDF_TTFontDefAttr def_attr = (HPDF_TTFontDefAttr)def->attr;
HPDF_STATUS ret = 0;
HPDF_PTRACE(("CIDFontType2_BeforeWrite_Func\n"));
if (font_attr->map_stream) {
font_attr->map_stream->filter = obj->filter;
}
if (font_attr->cmap_stream) {
font_attr->cmap_stream->filter = obj->filter;
}
if (!font_attr->fontdef->descriptor) {
HPDF_Dict descriptor = HPDF_Dict_New(obj->mmgr);
HPDF_Array array;
if (def_attr->embedding) {
HPDF_Dict font_data = HPDF_DictStream_New(obj->mmgr, font_attr->xref);
if (!font_data) {
return HPDF_Error_GetCode(obj->error);
}
HPDF_TTFontDef_SaveFontData(font_attr->fontdef, font_data->stream);
ret += HPDF_Dict_Add(descriptor, "FontFile2", font_data);
ret += HPDF_Dict_AddNumber(font_data, "Length1", def_attr->length1);
ret += HPDF_Dict_AddNumber(font_data, "Length2", 0);
ret += HPDF_Dict_AddNumber(font_data, "Length3", 0);
font_data->filter = obj->filter;
}
ret += HPDF_Xref_Add(font_attr->xref, descriptor);
ret += HPDF_Dict_AddName(descriptor, "Type", "FontDescriptor");
ret += HPDF_Dict_AddNumber(descriptor, "Ascent", def->ascent);
ret += HPDF_Dict_AddNumber(descriptor, "Descent", def->descent);
ret += HPDF_Dict_AddNumber(descriptor, "CapHeight", def->cap_height);
ret += HPDF_Dict_AddNumber(descriptor, "Flags", def->flags);
array = HPDF_Box_Array_New(obj->mmgr, def->font_bbox);
ret += HPDF_Dict_Add(descriptor, "FontBBox", array);
ret += HPDF_Dict_AddName(descriptor, "FontName", def_attr->base_font);
ret += HPDF_Dict_AddNumber(descriptor, "ItalicAngle", def->italic_angle);
ret += HPDF_Dict_AddNumber(descriptor, "StemV", def->stemv);
ret += HPDF_Dict_AddNumber(descriptor, "XHeight", def->x_height);
font_attr->fontdef->descriptor = descriptor;
}
HPDF_Dict_AddName(obj, "BaseFont", def_attr->base_font);
HPDF_Dict_AddName(font_attr->descendant_font, "BaseFont", def_attr->base_font);
return HPDF_Dict_Add(font_attr->descendant_font, "FontDescriptor", font_attr->fontdef->descriptor);
}
4. 创建子集化的字体文件
展开 HPDF_TTFontDef_SaveFontData [[#HPDF_TTFontDef_SaveFontData 解释]]
这个函数通过重建和更新相关的字体表,仅嵌入实际使用到的字形,实现字体子集化,以减少PDF文件的大小。
这个函数只在最后保存的时候会被执行,且这个是回调函数
子集化的数据流动如下
数据流程 :HPDF_TTFontDef_SaveFontData==>CreateDescriptor ==> BeforeWrite ==> font->before_write_fn ==> HPDF_Dict_Write ==>WriteTrailer==>HPDF_Xref_WriteToStream==>InternalSaveToStream==>HPDF_SaveToFile 其中 HPDF_TTFontDef_SaveFontData 是处理子集化的函数
HPDF_STATUS
HPDF_TTFontDef_SaveFontData (HPDF_FontDef fontdef,
HPDF_Stream stream)
{
HPDF_TTFontDefAttr attr = (HPDF_TTFontDefAttr)fontdef->attr;
HPDF_TTFTable tmp_tbl[HPDF_REQUIRED_TAGS_COUNT];
HPDF_Stream tmp_stream;
HPDF_UINT32 *new_offsets;
HPDF_UINT i;
HPDF_UINT32 check_sum_ptr = 0;
HPDF_STATUS ret;
HPDF_UINT32 offset_base;
HPDF_UINT32 tmp_check_sum = 0xB1B0AFBA;
HPDF_TTFTable emptyTable;
emptyTable.length = 0;
emptyTable.offset = 0;
HPDF_PTRACE ((" SaveFontData\n"));
ret = WriteUINT32 (stream, attr->offset_tbl.sfnt_version);
ret += WriteUINT16 (stream, HPDF_REQUIRED_TAGS_COUNT);
ret += WriteUINT16 (stream, attr->offset_tbl.search_range);
ret += WriteUINT16 (stream, attr->offset_tbl.entry_selector);
ret += WriteUINT16 (stream, attr->offset_tbl.range_shift);
if (ret != HPDF_OK)
return HPDF_Error_GetCode (fontdef->error);
tmp_stream = HPDF_MemStream_New (fontdef->mmgr, HPDF_STREAM_BUF_SIZ);
if (!tmp_stream)
return HPDF_Error_GetCode (fontdef->error);
offset_base = 12 + 16 * HPDF_REQUIRED_TAGS_COUNT;
new_offsets = HPDF_GetMem (fontdef->mmgr,
sizeof (HPDF_UINT32) * (attr->num_glyphs + 1));
if (!new_offsets) {
HPDF_Stream_Free (tmp_stream);
return HPDF_Error_GetCode (fontdef->error);
}
for (i = 0; i < HPDF_REQUIRED_TAGS_COUNT; i++) {
HPDF_TTFTable *tbl = FindTable (fontdef, REQUIRED_TAGS[i]);
HPDF_UINT32 length;
HPDF_UINT new_offset;
HPDF_UINT32 *poffset;
HPDF_UINT32 value;
if (!tbl) {
tbl = &emptyTable;
HPDF_MemCpy((HPDF_BYTE *)tbl->tag,
(const HPDF_BYTE *)REQUIRED_TAGS[i], 4);
}
if (!tbl) {
ret = HPDF_SetError (fontdef->error, HPDF_TTF_MISSING_TABLE, i);
goto Exit;
}
ret = HPDF_Stream_Seek (attr->stream, tbl->offset, HPDF_SEEK_SET);
if (ret != HPDF_OK)
goto Exit;
length = tbl->length;
new_offset = tmp_stream->size;
if (HPDF_MemCmp ((HPDF_BYTE *)tbl->tag, (HPDF_BYTE *)"head", 4) == 0) {
ret = WriteHeader (fontdef, tmp_stream, &check_sum_ptr);
} else if (HPDF_MemCmp ((HPDF_BYTE *)tbl->tag, (HPDF_BYTE *)"glyf", 4) == 0) {
ret = RecreateGLYF (fontdef, new_offsets, tmp_stream);
} else if (HPDF_MemCmp ((HPDF_BYTE *)tbl->tag, (HPDF_BYTE *)"hmtx", 4) == 0) {
HPDF_UINT j;
HPDF_TTF_LongHorMetric *pmetric;
HPDF_MemSet (&value, 0, 4);
pmetric=attr->h_metric;
for (j = 0; j < attr->num_h_metric; j++) {
// write all the used glyphs and write the last metric in the hMetrics array
if (attr->glyph_tbl.flgs[j] == 1 || j==attr->num_h_metric-1) {
ret += WriteUINT16 (tmp_stream, pmetric->advance_width);
ret += WriteINT16 (tmp_stream, pmetric->lsb);
}
else
{
ret += WriteUINT16 (tmp_stream, value);
ret += WriteINT16 (tmp_stream, value);
}
pmetric++;
}
while (j < attr->num_glyphs) {
if (attr->glyph_tbl.flgs[j] == 1) {
ret += WriteINT16 (tmp_stream, pmetric->lsb);
}
else
ret += WriteINT16 (tmp_stream, value);
pmetric++;
j++;
}
} else if (HPDF_MemCmp ((HPDF_BYTE *)tbl->tag, (HPDF_BYTE *)"loca", 4) == 0) {
HPDF_UINT j;
HPDF_MemSet (&value, 0, 4);
poffset = new_offsets;
if (attr->header.index_to_loc_format == 0) {
for (j = 0; j <= attr->num_glyphs; j++) {
ret += WriteUINT16 (tmp_stream, (HPDF_UINT16)*poffset);
poffset++;
}
} else {
for (j = 0; j <= attr->num_glyphs; j++) {
ret += WriteUINT32 (tmp_stream, *poffset);
poffset++;
}
}
} else if (HPDF_MemCmp ((HPDF_BYTE *)tbl->tag, (HPDF_BYTE *)"name", 4) == 0) {
ret = RecreateName (fontdef, tmp_stream);
} else if (HPDF_MemCmp ((HPDF_BYTE *)tbl->tag, (HPDF_BYTE *)"post", 4) == 0) {
value=0x00030000;
ret += HPDF_Stream_Write (tmp_stream, (HPDF_BYTE *)&value, 4);
HPDF_MemSet (&value, 0, 4);
ret = HPDF_Stream_Write (tmp_stream, (HPDF_BYTE *)&value, 4); // italicAngle
ret += HPDF_Stream_Write (tmp_stream, (HPDF_BYTE *)&value, 4); // underlinePosition + underlineThickness
ret += HPDF_Stream_Write (tmp_stream, (HPDF_BYTE *)&value, 4); // isFixedPitch
ret += HPDF_Stream_Write (tmp_stream, (HPDF_BYTE *)&value, 4); // minMemType42
ret += HPDF_Stream_Write (tmp_stream, (HPDF_BYTE *)&value, 4); // maxMemType42
ret += HPDF_Stream_Write (tmp_stream, (HPDF_BYTE *)&value, 4); // minMemType1
ret += HPDF_Stream_Write (tmp_stream, (HPDF_BYTE *)&value, 4); // maxMemType1
} else {
HPDF_UINT size = 4;
while (length > 4) {
value = 0;
size = 4;
ret = HPDF_Stream_Read (attr->stream, (HPDF_BYTE *)&value, &size);
ret += HPDF_Stream_Write (tmp_stream, (HPDF_BYTE *)&value, size);
length -= 4;
}
value = 0;
size = length;
ret += HPDF_Stream_Read (attr->stream, (HPDF_BYTE *)&value, &size);
ret += HPDF_Stream_Write (tmp_stream, (HPDF_BYTE *)&value, size);
}
tmp_tbl[i].offset = new_offset;
tmp_tbl[i].length = tmp_stream->size - new_offset;
/* pad at 4 bytes */
{
HPDF_UINT size=tmp_tbl[i].length % 4;
HPDF_MemSet (&value, 0, 4);
if (size != 0)
ret += HPDF_Stream_Write (tmp_stream, (HPDF_BYTE *)&value, 4-size);
}
if (ret != HPDF_OK)
goto Exit;
}
/* recalcurate checksum */
for (i = 0; i < HPDF_REQUIRED_TAGS_COUNT; i++) {
HPDF_TTFTable tbl = tmp_tbl[i];
HPDF_UINT32 buf;
HPDF_UINT length = tbl.length;
HPDF_PTRACE((" SaveFontData() tag[%s] length=%u\n",
REQUIRED_TAGS[i], length));
if ((ret = HPDF_Stream_Seek (tmp_stream, tbl.offset, HPDF_SEEK_SET))
!= HPDF_OK)
break;
tbl.check_sum = 0;
while (length > 0) {
HPDF_UINT rlen = (length > 4) ? 4 : length;
buf = 0;
if ((ret = HPDF_Stream_Read (tmp_stream, (HPDF_BYTE *)&buf, &rlen))
!= HPDF_OK)
break;
UINT32Swap (&buf);
tbl.check_sum += buf;
length -= rlen;
}
if (ret != HPDF_OK)
break;
HPDF_PTRACE((" SaveFontData tag[%s] check-sum=%u offset=%u\n",
REQUIRED_TAGS[i], (HPDF_UINT)tbl.check_sum,
(HPDF_UINT)tbl.offset));
ret += HPDF_Stream_Write (stream, (HPDF_BYTE *)REQUIRED_TAGS[i], 4);
ret += WriteUINT32 (stream, tbl.check_sum);
tbl.offset += offset_base;
ret += WriteUINT32 (stream, tbl.offset);
ret += WriteUINT32 (stream, tbl.length);
if (ret != HPDF_OK)
break;
}
if (ret != HPDF_OK)
goto Exit;
/* calucurate checkSumAdjustment.*/
ret = HPDF_Stream_Seek (tmp_stream, 0, HPDF_SEEK_SET);
if (ret != HPDF_OK)
goto Exit;
for (;;) {
HPDF_UINT32 buf;
HPDF_UINT siz = sizeof(buf);
ret = HPDF_Stream_Read (tmp_stream, (HPDF_BYTE *)&buf, &siz);
if (ret != HPDF_OK || siz <= 0) {
if (ret == HPDF_STREAM_EOF)
ret = HPDF_OK;
break;
}
UINT32Swap (&buf);
tmp_check_sum -= buf;
}
if (ret != HPDF_OK)
goto Exit;
HPDF_PTRACE((" SaveFontData new checkSumAdjustment=%u\n",
(HPDF_UINT)tmp_check_sum));
UINT32Swap (&tmp_check_sum);
ret = HPDF_Stream_Seek (tmp_stream, check_sum_ptr, HPDF_SEEK_SET);
if (ret == HPDF_OK) {
ret = HPDF_MemStream_Rewrite (tmp_stream, (HPDF_BYTE *)&tmp_check_sum,
4);
}
if (ret != HPDF_OK)
goto Exit;
attr->length1 = tmp_stream->size + offset_base;
ret = HPDF_Stream_WriteToStream (tmp_stream, stream, 0, NULL);
goto Exit;
Exit:
HPDF_FreeMem (fontdef->mmgr, new_offsets);
HPDF_Stream_Free (tmp_stream);
return ret;
}
5. 引用字体对象,并写入文本
展开 HPDF_Page_SetFontAndSize
HPDF_EXPORT(HPDF_STATUS)
HPDF_Page_SetFontAndSize (HPDF_Page page,
HPDF_Font font,
HPDF_REAL size)
{
char buf[HPDF_TMP_BUF_SIZ];
char *pbuf = buf;
char *eptr = buf + HPDF_TMP_BUF_SIZ - 1;
const char *local_name;
HPDF_PageAttr attr;
attr = (HPDF_PageAttr)page->attr;
local_name = HPDF_Page_GetLocalFontName (page, font);
HPDF_Stream_WriteEscapeName (attr->stream, local_name) // 写入字体对象
HPDF_MemSet (buf, 0, HPDF_TMP_BUF_SIZ);
*pbuf++ = ' ';
pbuf = HPDF_FToA (pbuf, size, eptr);
HPDF_StrCpy (pbuf, " Tf\012", eptr);
HPDF_Stream_WriteStr (attr->stream, buf)
attr->gstate->font = font;
attr->gstate->font_size = size;
attr->gstate->writing_mode = ((HPDF_FontAttr)font->attr)->writing_mode;
return ret;
}
展开 HPDF_Page_GetLocalFontName [[#HPDF_Page_GetLocalFontName 函数解释]]
HPDF_Page_GetLocalFontName
函数用于获取或生成给定PDF页面上指定字体的唯一名称。
const char*
HPDF_Page_GetLocalFontName (HPDF_Page page,
HPDF_Font font)
{
HPDF_PageAttr attr = (HPDF_PageAttr )page->attr;
const char *key;
if (!attr->fonts) {
HPDF_Dict resources;
HPDF_Dict fonts;
resources = HPDF_Page_GetInheritableItem (page, "Resources",
HPDF_OCLASS_DICT);
fonts = HPDF_Dict_New (page->mmgr);
HPDF_Dict_Add (resources, "Font", fonts)
attr->fonts = fonts;
}
/* search font-object from font-resource */
key = HPDF_Dict_GetKeyByObj (attr->fonts, font);
if (!key) {
char fontName[HPDF_LIMIT_MAX_NAME_LEN + 1];
char *ptr;
char *end_ptr = fontName + HPDF_LIMIT_MAX_NAME_LEN;
ptr = (char *)HPDF_StrCpy (fontName, "F", end_ptr);
HPDF_IToA (ptr, attr->fonts->list->count + 1, end_ptr);
HPDF_Dict_Add (attr->fonts, fontName, font)
key = HPDF_Dict_GetKeyByObj (attr->fonts, font);
}
return key;
}
展开 HPDF_Page_ShowText(page, (const char*)buf);
/* Tj */
HPDF_EXPORT(HPDF_STATUS)
HPDF_Page_ShowText (HPDF_Page page,
const char *text)
{
HPDF_STATUS ret = HPDF_Page_CheckState (page, HPDF_GMODE_TEXT_OBJECT);
HPDF_PageAttr attr;
HPDF_REAL tw;
HPDF_PTRACE ((" HPDF_Page_ShowText\n"));
if (ret != HPDF_OK || text == NULL || text[0] == 0)
return ret;
attr = (HPDF_PageAttr)page->attr;
/* no font exists */
if (!attr->gstate->font)
return HPDF_RaiseError (page->error, HPDF_PAGE_FONT_NOT_FOUND, 0);
tw = HPDF_Page_TextWidth (page, text);
if (!tw)
return ret;
if (InternalWriteText (attr, text) != HPDF_OK)
return HPDF_CheckError (page->error);
if (HPDF_Stream_WriteStr (attr->stream, " Tj\012") != HPDF_OK)
return HPDF_CheckError (page->error);
/* calculate the reference point of text */
if (attr->gstate->writing_mode == HPDF_WMODE_HORIZONTAL) {
attr->text_pos.x += tw * attr->text_matrix.a;
attr->text_pos.y += tw * attr->text_matrix.b;
} else {
attr->text_pos.x -= tw * attr->text_matrix.b;
attr->text_pos.y -= tw * attr->text_matrix.a;
}
return ret;
}
## 文本写入解释
(Hello, world!) Tj
在 PDF 内部,文本字符串有两种主要的表示形式:
1. **字面字符串(Literal Strings)**:使用圆括号 `()` 包裹。
2. **十六进制字符串(Hexadecimal Strings)**:使用尖括号 `<>` 包裹。
### 十六进制字符串的作用
当需要以二进制方式或表示包含非 ASCII 字符的数据时,PDF 使用十六进制字符串。例如,在处理 TrueType 或 Type 0 字体的字符编码时,文本可能包含非 ASCII 字符,这些字符在直接作为字面字符串传送时会遇到编码问题。此时,可以使用十六进制字符串来确保数据的正确传输和解释。
HPDF_Page_GetLocalFontName 函数解释
这段代码是用于获取一个特定字体在PDF页面上的本地名称。它属于一个假设的HPDF库的一部分,该库用于创建和操作PDF文档。下面是对这段代码功能的解释:
函数签名
const char* HPDF_Page_GetLocalFontName(HPDF_Page page, HPDF_Font font);
参数
page
: 表示PDF页面的结构体指针。font
: 表示字体的结构体指针。
返回值
- 字体的本地名称(
const char*
),这是在PDF页面资源中使用的字体名称。
函数逻辑
-
初始化资源字典:
- 检查页面属性 (
attr
) 中是否已经存在字体资源 (fonts
)。如果不存在,则创建一个资源字典 (resources
) 和一个字体字典 (fonts
)。 - 将字体字典添加到资源字典中。
- 检查页面属性 (
-
查找字体名称:
- 使用字体对象 (
font
) 在字体字典 (fonts
) 中查找对应的键 (key
)。键就是字体的名称。
- 使用字体对象 (
-
生成新的字体名称:
- 如果没有找到对应的键,则生成一个新的字体名称。新名称的格式为
"F1"
,"F2"
, 等等,其中数字表示字体字典中字体的数量加一。 - 将新生成的字体名称添加到字体字典中,并将字体对象与该名称关联起来。
- 如果没有找到对应的键,则生成一个新的字体名称。新名称的格式为
-
返回字体名称:
- 最后返回找到或生成的字体名称。
代码细节
HPDF_PageAttr attr = (HPDF_PageAttr )page->attr;
: 获取页面属性。HPDF_Dict resources; HPDF_Dict fonts;
: 定义资源字典和字体字典。HPDF_Dict resources = HPDF_Page_GetInheritableItem (page, "Resources", HPDF_OCLASS_DICT);
: 从页面获取资源字典。HPDF_Dict_Add (resources, "Font", fonts);
: 向资源字典中添加字体字典。key = HPDF_Dict_GetKeyByObj (attr->fonts, font);
: 通过字体对象获取字体名称。fontName
: 用于存储新生成的字体名称。HPDF_IToA
: 将整数转换为字符串。HPDF_Dict_Add (attr->fonts, fontName, font);
: 添加字体到字体字典中。
总结
此函数的主要目的是确保每个字体都有一个唯一的名称,并且可以在PDF页面的资源部分正确引用。如果字体名称尚未被分配,则会为其生成一个新的名称。
HPDF_TTFontDef_SaveFontData 解释
这段代码实现了在保存 TrueType 字体数据到指定的流(stream)中的功能。函数 HPDF_TTFontDef_SaveFontData
是 Haru Free PDF 库的一部分。为了更好地理解代码,以下是逐步解析,涵盖了主要的步骤和逻辑:
-
变量和结构初始化:
HPDF_TTFontDefAttr attr
:获取fontdef
属性的指针。HPDF_TTFTable tmp_tbl[HPDF_REQUIRED_TAGS_COUNT]
:临时表记录必需的 TrueType 字体标签(表)的信息。HPDF_Stream tmp_stream
:临时流,用于存放字体数据。- 一些其他的变量也被初始化用于后续的操作。
-
写入字体偏移表:
WriteUINT32
和WriteUINT16
用于写入字体偏移表的数据(包括 sfnt 版本号、搜索范围、表选择器和范围移位计数)。
-
错误处理:
- 如在写入过程中发生错误,则通过
HPDF_Error_GetCode
返回错误码。
- 如在写入过程中发生错误,则通过
-
创建临时流:
- 如果临时流创建失败,则返回错误码。
-
分配新的偏移数组:
- 用来存储每个字形的新偏移位置。
-
遍历并处理必需标签:
- 遍历每个必需标签(例如
head
,glyf
,hmtx
,loca
, 等)。 - 不同标签对应不同的处理逻辑:
head
:调用WriteHeader
函数并获取校验和位置。glyf
:调用RecreateGLYF
函数重新创建 GLYF 数据。hmtx
:写入水平度量(horizontal metrics)。loca
:写入字形偏移位置。name
:调用RecreateName
函数重写名字表。post
:写入 POST 表指定格式版本 3.0。- 对于其他标签:读取并写入数据。
- 遍历每个必需标签(例如
-
填充和对齐:
- 检查每个表的长度是否为 4 的倍数,如果不是则填充0字节以对齐。
-
计算校验和:
- 重新计算所有表的校验和。
- 将表信息(标签、校验和、偏移位置和长度)写入到目标流中。
-
计算并调整
checkSumAdjustment
:- 通过读取每个 4 字节块的数据,累加计算整体校验和,并进行调整。
- 寻找到
head
表中的checkSumAdjustment
字段位置,写入新的校验和调整值。
-
将临时流写入目标流:
- 最后,将临时流中的数据写入到目标流上。
-
清理资源并返回:
- 释放已分配的资源,最终返回结果状态。
此函数主要做了以下几件事:
- 生成和写入字体的偏移表。
- 处理每个标签根据不同的需要进行读取和写入。
- 计算并调整校验和。
- 将数据从临时流写入到目标流中。
这个过程涉及到的标签和表结构,是 TrueType 字体文件格式的实现。此外,代码还处理了内存管理、文件对齐和错误处理等细节。
在嵌入 PDF 文档时,常常仅需包含实际使用到的字体字形(glyph)。这有助于减少文件大小,提高加载性能。在代码中,以下几个部分与字体子集化相关,它们实现了仅包括使用到的字体字形:
-
提取和存储新偏移:
new_offsets = HPDF_GetMem (fontdef->mmgr, sizeof (HPDF_UINT32) * (attr->num_glyphs + 1));
- 这个新偏移数组将记录新生成的仅包含用到字形的字形表(glyf table)中的字形位置。
-
重建
glyf
表:- 在
if (HPDF_MemCmp ((HPDF_BYTE *)tbl->tag, (HPDF_BYTE *)"glyf", 4) == 0)
部分中,调用RecreateGLYF (fontdef, new_offsets, tmp_stream);
- 这个函数(
RecreateGLYF
)负责重新创建glyf
表,仅包括实际使用到的字形,并且更新new_offsets
中的值来反映新的字形位置。
- 在
-
更新
loca
表:- 在
if (HPDF_MemCmp ((HPDF_BYTE *)tbl->tag, (HPDF_BYTE *)"loca", 4) == 0)
部分中,写入新的loca
(字形位置)表:if (attr->header.index_to_loc_format == 0) { for (j = 0; j <= attr->num_glyphs; j++) { ret += WriteUINT16 (tmp_stream, (HPDF_UINT16)*poffset); poffset++; } } else { for (j = 0; j <= attr->num_glyphs; j++) { ret += WriteUINT32 (tmp_stream, *poffset); poffset++; } }
- 这里根据
index_to_loc_format
的模式,重新写入更新后的loca
表,用新的字形位置(new_offsets
)填充。
- 在
-
处理水平字体度量
hmtx
:- 在
if (HPDF_MemCmp ((HPDF_BYTE *)tbl->tag, (HPDF_BYTE *)"hmtx", 4) == 0)
部分,写入水平度量表(horizonal metrics table):HPDF_MemSet (&value, 0, 4); pmetric = attr->h_metric; for (j = 0; j < attr->num_h_metric; j++) { if (attr->glyph_tbl.flgs[j] == 1 || j == attr->num_h_metric - 1) { ret += WriteUINT16 (tmp_stream, pmetric->advance_width); ret += WriteINT16 (tmp_stream, pmetric->lsb); } else { ret += WriteUINT16 (tmp_stream, value); ret += WriteINT16 (tmp_stream, value); } pmetric++; } while (j < attr->num_glyphs) { if (attr->glyph_tbl.flgs[j] == 1) { ret += WriteINT16 (tmp_stream, pmetric->lsb); } else { ret += WriteINT16 (tmp_stream, value); } pmetric++; j++; }
- 这部分代码根据是否使用到该字形,决定写入实际的字形度量信息(advance width 和 left side bearing),未使用到的字形则写入 0。
- 在
-
重新创建
name
表:- 在
if (HPDF_MemCmp ((HPDF_BYTE *)tbl->tag, (HPDF_BYTE *)"name", 4) == 0)
部分中,调用RecreateName (fontdef, tmp_stream);
RecreateName
函数帮助重建名字表以反映子集字体信息。
- 在
通过这些步骤,该代码实现了只包含实际使用到的字形的数据子集化过程。这种方法减少了字体文件的大小,仅嵌入必要的字形信息以提高 PDF 文档的加载和渲染性能。
CIDFontType2_BeforeWrite_Func 解释
这段代码是一个用于在写入 PDF 字体之前进行一些必要的准备工作函数,具体用于处理 CIDType2 字体。在 Haru PDF 库(libharu)中,该函数被称为 CIDFontType2_BeforeWrite_Func
。函数的主要任务是创建和配置字体描述符对象,以及处理字体数据的嵌入等。
代码逐步解释
static HPDF_STATUS CIDFontType2_BeforeWrite_Func(HPDF_Dict obj) {
HPDF_FontAttr font_attr = (HPDF_FontAttr)obj->attr;
HPDF_FontDef def = font_attr->fontdef;
HPDF_TTFontDefAttr def_attr = (HPDF_TTFontDefAttr)def->attr;
HPDF_STATUS ret = 0;
HPDF_PTRACE(("CIDFontType2_BeforeWrite_Func\n"));
这段代码初始化了几个变量:
font_attr
:从obj
的属性中获取字体属性。def
:获取字体定义。def_attr
:获取 TrueType 字体定义属性。ret
:用于跟踪函数的返回状态。
HPDF_PTRACE
是用于调试的宏。
if (font_attr->map_stream) {
font_attr->map_stream->filter = obj->filter;
}
if (font_attr->cmap_stream) {
font_attr->cmap_stream->filter = obj->filter;
}
如果 map_stream
和 cmap_stream
存在,为它们设置过滤器(从 obj
继承)。
if (!font_attr->fontdef->descriptor) {
HPDF_Dict descriptor = HPDF_Dict_New(obj->mmgr);
HPDF_Array array;
如果字体定义没有描述符,创建一个新的字典来作为描述符。
if (def_attr->embedding) {
HPDF_Dict font_data = HPDF_DictStream_New(obj->mmgr, font_attr->xref);
if (!font_data) {
return HPDF_Error_GetCode(obj->error);
}
HPDF_TTFontDef_SaveFontData(font_attr->fontdef, font_data->stream);
ret += HPDF_Dict_Add(descriptor, "FontFile2", font_data);
ret += HPDF_Dict_AddNumber(font_data, "Length1", def_attr->length1);
ret += HPDF_Dict_AddNumber(font_data, "Length2", 0);
ret += HPDF_Dict_AddNumber(font_data, "Length3", 0);
font_data->filter = obj->filter;
}
如果嵌入字体数据:
- 创建一个
font_data
字典流。 - 保存字体数据到
font_data
的流中。 - 将
FontFile2
、Length1
、Length2
和Length3
键添加到font_data
。 - 设置
font_data
的过滤器。
ret += HPDF_Xref_Add(font_attr->xref, descriptor);
ret += HPDF_Dict_AddName(descriptor, "Type", "FontDescriptor");
ret += HPDF_Dict_AddNumber(descriptor, "Ascent", def->ascent);
ret += HPDF_Dict_AddNumber(descriptor, "Descent", def->descent);
ret += HPDF_Dict_AddNumber(descriptor, "CapHeight", def->cap_height);
ret += HPDF_Dict_AddNumber(descriptor, "Flags", def->flags);
array = HPDF_Box_Array_New(obj->mmgr, def->font_bbox);
ret += HPDF_Dict_Add(descriptor, "FontBBox", array);
ret += HPDF_Dict_AddName(descriptor, "FontName", def_attr->base_font);
ret += HPDF_Dict_AddNumber(descriptor, "ItalicAngle", def->italic_angle);
ret += HPDF_Dict_AddNumber(descriptor, "StemV", def->stemv);
ret += HPDF_Dict_AddNumber(descriptor, "XHeight", def->x_height);
font_attr->fontdef->descriptor = descriptor;
}
为描述符添加各种必要的属性,如 Type
、Ascent
、Descent
、CapHeight
、Flags
和 FontBBox
等等。最后,将描述符对象赋值给 font_attr->fontdef->descriptor
。
HPDF_Dict_AddName(obj, "BaseFont", def_attr->base_font);
HPDF_Dict_AddName(font_attr->descendant_font, "BaseFont", def_attr->base_font);
return HPDF_Dict_Add(font_attr->descendant_font, "FontDescriptor", font_attr->fontdef->descriptor);
}
- 为
obj
和descendant_font
添加BaseFont
名称。 - 最终,将创建的描述符添加到
descendant_font
中。
总结
这个函数的主要工作就是在写入 PDF 文档之前,为 CIDType2 字体创建和配置一个字体描述符,并处理字体数据的嵌入,确保所有相关字体信息正确地存储在 PDF 文件中。所有这些操作通过 Haru PDF 库的内部函数调用来完成。
CIDFontType2_New 解释
关键步骤
-
初始化和准备工作:
- 获取和初始化需要的各种属性,如
attr
、fontdef
、fontdef_attr
、encoder
、encoder_attr
等等。 - 初始化一个新的字体字典
font
并添加到xref
中。
- 获取和初始化需要的各种属性,如
-
字典属性设定:
- 为
font
字典添加了基本属性,如Type
、Subtype
和DW
(代表默认宽度)。 - 添加一个二维数组
DW2
,表示字体的其他宽度信息。
- 为
-
创建Unicode到Glyph的映射表:
- 定义并初始化一个大的临时映射表
tmp_map
,大小为65536。 - 遍历编码器的CID到Unicode的映射关系,生成临时的CID到Glyph(GID)的映射。
- 定义并初始化一个大的临时映射表
-
添加非默认宽度映射:
- 如果
max > 0
,说明存在有效的CID映射。为这些CID创建一个宽度数组W
并添加
- 如果
- 为这些CID创建一个宽度数组
W
并添加到字体字典中。- 遍历临时映射表
tmp_map
,为每个非默认宽度的字符添加到W
数组中。如果某些字符的宽度与默认宽度不同,则将其宽度添加到一个临时数组tmp_array
中。 - 如果字体定义允许嵌入,创建一个新的字典流
map_stream
用于存储CID到GID的映射数据,并将其添加到字体字典中。
- 遍历临时映射表
- 创建CIDSystemInfo字典:
- 创建一个新的字典
cid_system_info
,用于存储字体的CID系统信息。 - 为
cid_system_info
添加Registry
、Ordering
和Supplement
属性,并将其添加到字体字典中。
- 创建一个新的字典
最后,函数返回新创建的字体字典对象font
。
详细说明
数据结构
- HPDF_Font: 表示字体的基本数据结构。
- HPDF_Xref: 交叉引用表,维护PDF对象的索引。
- HPDF_FontAttr: 包含字体的属性,如字体定义和编码器。
- HPDF_FontDef: 字体定义,包含字体的详细信息。
- HPDF_TTFontDefAttr: TrueType字体定义的属性。
- HPDF_Encoder: 编码器,负责字符编码的转换。
- HPDF_CMapEncoderAttr: CMap编码器的属性,包含CID和Unicode映射。
主要流程
-
创建新字典并添加基本属性:
- 使用
HPDF_Dict_New
创建一个新的HPDF_Dict
对象作为字体字典font
。 - 使用
HPDF_Xref_Add
将这个字典添加到交叉引用表xref
中。
- 使用
-
添加默认宽度和字体边界:
- 使用
HPDF_Dict_AddName
和HPDF_Dict_AddNumber
为字体字典添加基本属性。 - 创建一个新的数组
array
并添加到字典,用于存储字体的边界信息。
- 使用
-
生成CID到GID的映射:
- 初始化一个大的临时映射表
tmp_map
,每个元素对应一个CID。 - 遍历编码器的映射表,生成CID到GID的临时映射。如果映射有效,更新
max
的值以跟踪最大的CID。
- 初始化一个大的临时映射表
-
创建宽度数组W:
- 如果映射表
tmp_map
有效,将非默认宽度的字符添加到宽度数组W
中。 - 使用
HPDF_Array_AddNumber
和HPDF_Array_Add
将宽度信息添加到数组array
中。
- 如果映射表
-
创建CIDToGIDMap数据:
- 如果字体定义允许嵌入,创建一个新的字典流
map_stream
用于存储CID到GID的映射数据。 - 使用
HPDF_Stream_Write
将映射数据写入字典流。
- 如果字体定义允许嵌入,创建一个新的字典流
-
创建CIDSystemInfo字典:
- 创建一个新的字典
cid_system_info
用于存储CID系统信息。 - 使用
HPDF_Dict_Add
和HPDF_Dict_AddNumber
为字典添加Registry
、Ordering
和Supplement
属性。
- 创建一个新的字典
HPDF_Type0Font_New的解释
这个函数 HPDF_Type0Font_New
用于在 Haru PDF 库中创建一个新的 Type0 字体对象。Type0 字体也称为复合字体,支持多字节编码系统,通常用于 East Asian 字体。下面是对该函数的逐步解释:
-
声明和初始化:
- 声明变量
attr
,encoder_attr
,ret
和descendant_fonts
。 HPDF_PTRACE
是一个跟踪宏,用于日志记录或调试。
- 声明变量
-
创建字体字典对象:
HPDF_Dict font = HPDF_Dict_New(mmgr);
:创建一个新的字典对象来代表字体。font->header.obj_class |= HPDF_OSUBCLASS_FONT;
:标记对象为字体子类。font->write_fn = NULL;
:设置写函数为NULL
。font->free_fn = OnFree_Func;
:设置释放函数为OnFree_Func
。font->attr = attr;
:将属性字段初始化为attr
(这一步会导致后面的问题,我稍后解释)。
-
设置字体属性:
encoder_attr = (HPDF_CMapEncoderAttr)encoder->attr;
:提取编码器的属性。attr->writing_mode = encoder_attr->writing_mode;
:设置写入模式。attr->text_width_fn = TextWidth;
:设置文本宽度计算函数。attr->measure_text_fn = MeasureText;
:设置文本测量函数。attr->fontdef = fontdef;
:设置字体定义。attr->encoder = encoder;
:设置编码器。attr->xref = xref;
:设置交叉引用对象。
-
设置字典项:
ret += HPDF_Dict_AddName(font, "Type", "Font");
:添加 “Type” 项,值为 “Font”。ret += HPDF_Dict_AddName(font, "BaseFont", fontdef->base_font);
:添加 “BaseFont” 项,值为fontdef->base_font
。ret += HPDF_Dict_AddName(font, "Subtype", "Type0");
:添加 “Subtype” 项,值为 “Type0”。
-
设置编码项:
ret += HPDF_Dict_AddName(font, "Encoding", "Identity-H");
:添加 “Encoding” 项,值为 “Identity-H”。attr->cmap_stream = CreateCMap(encoder, xref);
:创建 CMap 流。ret += HPDF_Dict_Add(font, "ToUnicode", attr->cmap_stream);
:添加 “ToUnicode” 项,值为attr->cmap_stream
。
-
创建后代字体:
descendant_fonts = HPDF_Array_New(mmgr);
:创建一个新的数组,用于存储后代字体。HPDF_Dict_Add(font, "DescendantFonts", descendant_fonts);
:向字典添加 “DescendantFonts” 项,值为descendant_fonts
数组。attr->descendant_font = CIDFontType2_New(font, xref);
:创建一个新的 CIDFontType2 后代字体。attr->type = HPDF_FONT_TYPE0_TT;
:设置字体类型为HPDF_FONT_TYPE0_TT
。HPDF_Array_Add(descendant_fonts, attr->descendant_font);
:将后代字体添加到数组中。
-
返回字体字典对象:
- 返回
font
字典对象。
- 返回
注意:
- 在
font->attr = attr;
这一步之前,attr
还没有被初始化。如果attr
是一个结构体指针,你应该在使用前为其分配内存,如attr = (HPDF_FontAttr)HPDF_GetMem(mmgr, sizeof(HPDF_FontAttr_Rec));
。否则会导致未定义行为或崩溃。 - 该代码缺少一些错误处理机制,特别是在内存分配失败或字典添加项失败时,可考虑适当增加错误检查和处理代码。