Libharu实现子集化和字体内嵌流程

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页面资源中使用的字体名称。

函数逻辑

  1. 初始化资源字典:

    • 检查页面属性 (attr) 中是否已经存在字体资源 (fonts)。如果不存在,则创建一个资源字典 (resources) 和一个字体字典 (fonts)。
    • 将字体字典添加到资源字典中。
  2. 查找字体名称:

    • 使用字体对象 (font) 在字体字典 (fonts) 中查找对应的键 (key)。键就是字体的名称。
  3. 生成新的字体名称:

    • 如果没有找到对应的键,则生成一个新的字体名称。新名称的格式为 "F1", "F2", 等等,其中数字表示字体字典中字体的数量加一。
    • 将新生成的字体名称添加到字体字典中,并将字体对象与该名称关联起来。
  4. 返回字体名称:

    • 最后返回找到或生成的字体名称。

代码细节

  • 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 库的一部分。为了更好地理解代码,以下是逐步解析,涵盖了主要的步骤和逻辑:

  1. 变量和结构初始化

    • HPDF_TTFontDefAttr attr:获取 fontdef 属性的指针。
    • HPDF_TTFTable tmp_tbl[HPDF_REQUIRED_TAGS_COUNT]:临时表记录必需的 TrueType 字体标签(表)的信息。
    • HPDF_Stream tmp_stream:临时流,用于存放字体数据。
    • 一些其他的变量也被初始化用于后续的操作。
  2. 写入字体偏移表

    • WriteUINT32WriteUINT16 用于写入字体偏移表的数据(包括 sfnt 版本号、搜索范围、表选择器和范围移位计数)。
  3. 错误处理

    • 如在写入过程中发生错误,则通过 HPDF_Error_GetCode 返回错误码。
  4. 创建临时流

    • 如果临时流创建失败,则返回错误码。
  5. 分配新的偏移数组

    • 用来存储每个字形的新偏移位置。
  6. 遍历并处理必需标签

    • 遍历每个必需标签(例如 head, glyf, hmtx, loca, 等)。
    • 不同标签对应不同的处理逻辑:
      • head:调用 WriteHeader 函数并获取校验和位置。
      • glyf:调用 RecreateGLYF 函数重新创建 GLYF 数据。
      • hmtx:写入水平度量(horizontal metrics)。
      • loca:写入字形偏移位置。
      • name:调用 RecreateName 函数重写名字表。
      • post:写入 POST 表指定格式版本 3.0。
      • 对于其他标签:读取并写入数据。
  7. 填充和对齐

    • 检查每个表的长度是否为 4 的倍数,如果不是则填充0字节以对齐。
  8. 计算校验和

    • 重新计算所有表的校验和。
    • 将表信息(标签、校验和、偏移位置和长度)写入到目标流中。
  9. 计算并调整 checkSumAdjustment

    • 通过读取每个 4 字节块的数据,累加计算整体校验和,并进行调整。
    • 寻找到 head 表中的 checkSumAdjustment 字段位置,写入新的校验和调整值。
  10. 将临时流写入目标流

    • 最后,将临时流中的数据写入到目标流上。
  11. 清理资源并返回

    • 释放已分配的资源,最终返回结果状态。

此函数主要做了以下几件事:

  • 生成和写入字体的偏移表。
  • 处理每个标签根据不同的需要进行读取和写入。
  • 计算并调整校验和。
  • 将数据从临时流写入到目标流中。

这个过程涉及到的标签和表结构,是 TrueType 字体文件格式的实现。此外,代码还处理了内存管理、文件对齐和错误处理等细节。

在嵌入 PDF 文档时,常常仅需包含实际使用到的字体字形(glyph)。这有助于减少文件大小,提高加载性能。在代码中,以下几个部分与字体子集化相关,它们实现了仅包括使用到的字体字形:

  1. 提取和存储新偏移

    • new_offsets = HPDF_GetMem (fontdef->mmgr, sizeof (HPDF_UINT32) * (attr->num_glyphs + 1));
    • 这个新偏移数组将记录新生成的仅包含用到字形的字形表(glyf table)中的字形位置。
  2. 重建 glyf

    • if (HPDF_MemCmp ((HPDF_BYTE *)tbl->tag, (HPDF_BYTE *)"glyf", 4) == 0) 部分中,调用 RecreateGLYF (fontdef, new_offsets, tmp_stream);
    • 这个函数(RecreateGLYF)负责重新创建 glyf 表,仅包括实际使用到的字形,并且更新 new_offsets 中的值来反映新的字形位置。
  3. 更新 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)填充。
  4. 处理水平字体度量 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。
  5. 重新创建 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_streamcmap_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 的流中。
  • FontFile2Length1Length2Length3 键添加到 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;
    }

为描述符添加各种必要的属性,如 TypeAscentDescentCapHeightFlagsFontBBox 等等。最后,将描述符对象赋值给 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);
}
  • objdescendant_font 添加 BaseFont 名称。
  • 最终,将创建的描述符添加到 descendant_font 中。

总结

这个函数的主要工作就是在写入 PDF 文档之前,为 CIDType2 字体创建和配置一个字体描述符,并处理字体数据的嵌入,确保所有相关字体信息正确地存储在 PDF 文件中。所有这些操作通过 Haru PDF 库的内部函数调用来完成。

CIDFontType2_New 解释

关键步骤
  1. 初始化和准备工作:

    • 获取和初始化需要的各种属性,如attrfontdeffontdef_attrencoderencoder_attr等等。
    • 初始化一个新的字体字典font并添加到xref中。
  2. 字典属性设定:

    • font字典添加了基本属性,如TypeSubtypeDW(代表默认宽度)。
    • 添加一个二维数组DW2,表示字体的其他宽度信息。
  3. 创建Unicode到Glyph的映射表:

    • 定义并初始化一个大的临时映射表tmp_map,大小为65536。
    • 遍历编码器的CID到Unicode的映射关系,生成临时的CID到Glyph(GID)的映射。
  4. 添加非默认宽度映射:

    • 如果max > 0,说明存在有效的CID映射。为这些CID创建一个宽度数组W并添加
  • 为这些CID创建一个宽度数组W并添加到字体字典中。
    • 遍历临时映射表tmp_map,为每个非默认宽度的字符添加到W数组中。如果某些字符的宽度与默认宽度不同,则将其宽度添加到一个临时数组tmp_array中。
    • 如果字体定义允许嵌入,创建一个新的字典流map_stream用于存储CID到GID的映射数据,并将其添加到字体字典中。
  1. 创建CIDSystemInfo字典:
    • 创建一个新的字典cid_system_info,用于存储字体的CID系统信息。
    • cid_system_info添加RegistryOrderingSupplement属性,并将其添加到字体字典中。

最后,函数返回新创建的字体字典对象font

详细说明

数据结构
  • HPDF_Font: 表示字体的基本数据结构。
  • HPDF_Xref: 交叉引用表,维护PDF对象的索引。
  • HPDF_FontAttr: 包含字体的属性,如字体定义和编码器。
  • HPDF_FontDef: 字体定义,包含字体的详细信息。
  • HPDF_TTFontDefAttr: TrueType字体定义的属性。
  • HPDF_Encoder: 编码器,负责字符编码的转换。
  • HPDF_CMapEncoderAttr: CMap编码器的属性,包含CID和Unicode映射。
主要流程
  1. 创建新字典并添加基本属性:

    • 使用HPDF_Dict_New创建一个新的HPDF_Dict对象作为字体字典font
    • 使用HPDF_Xref_Add将这个字典添加到交叉引用表xref中。
  2. 添加默认宽度和字体边界:

    • 使用HPDF_Dict_AddNameHPDF_Dict_AddNumber为字体字典添加基本属性。
    • 创建一个新的数组array并添加到字典,用于存储字体的边界信息。
  3. 生成CID到GID的映射:

    • 初始化一个大的临时映射表tmp_map,每个元素对应一个CID。
    • 遍历编码器的映射表,生成CID到GID的临时映射。如果映射有效,更新max的值以跟踪最大的CID。
  4. 创建宽度数组W:

    • 如果映射表tmp_map有效,将非默认宽度的字符添加到宽度数组W中。
    • 使用HPDF_Array_AddNumberHPDF_Array_Add将宽度信息添加到数组array中。
  5. 创建CIDToGIDMap数据:

    • 如果字体定义允许嵌入,创建一个新的字典流map_stream用于存储CID到GID的映射数据。
    • 使用HPDF_Stream_Write将映射数据写入字典流。
  6. 创建CIDSystemInfo字典:

    • 创建一个新的字典cid_system_info用于存储CID系统信息。
    • 使用HPDF_Dict_AddHPDF_Dict_AddNumber为字典添加RegistryOrderingSupplement属性。

HPDF_Type0Font_New的解释

这个函数 HPDF_Type0Font_New 用于在 Haru PDF 库中创建一个新的 Type0 字体对象。Type0 字体也称为复合字体,支持多字节编码系统,通常用于 East Asian 字体。下面是对该函数的逐步解释:

  1. 声明和初始化

    • 声明变量 attr, encoder_attr, retdescendant_fonts
    • HPDF_PTRACE 是一个跟踪宏,用于日志记录或调试。
  2. 创建字体字典对象

    • 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(这一步会导致后面的问题,我稍后解释)。
  3. 设置字体属性

    • 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;:设置交叉引用对象。
  4. 设置字典项

    • 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”。
  5. 设置编码项

    • 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
  6. 创建后代字体

    • 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);:将后代字体添加到数组中。
  7. 返回字体字典对象

    • 返回 font 字典对象。

注意

  • font->attr = attr; 这一步之前,attr 还没有被初始化。如果 attr 是一个结构体指针,你应该在使用前为其分配内存,如 attr = (HPDF_FontAttr)HPDF_GetMem(mmgr, sizeof(HPDF_FontAttr_Rec));。否则会导致未定义行为或崩溃。
  • 该代码缺少一些错误处理机制,特别是在内存分配失败或字典添加项失败时,可考虑适当增加错误检查和处理代码。
  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

丁金金

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值