当前位置: 首页 > news >正文

freetype封装

文章目录

  • 头文件
  • 源文件
  • 简单使用

参考podofo

头文件

/**
 * SPDX-FileCopyrightText: (C) 2022 Francesco Pretto <ceztko@gmail.com>
 * SPDX-License-Identifier: LGPL-2.0-or-later
 * SPDX-License-Identifier: MPL-2.0
 */

#ifndef PODOFO_FREETYPE_PRIVATE_H
#define PODOFO_FREETYPE_PRIVATE_H
#define _RPCNDR_H_BYTE_REDEFINED
#include <windows.h>
 // Old freetype versions requires <ft2build.h> to be included first
#include <ft2build.h>
#include FT_FREETYPE_H

//#include <podofo/main/PdfDeclarations.h>
#include<string>
#include<vector>
#include<set>

using namespace std;

#define CHECK_FT_RC(rc, func) if (rc != 0)\
    PODOFO_RAISE_ERROR_INFO(PdfErrorCode::FreeTypeError, "Function " #func " failed")

enum class PdfFontFileType : uint8_t
{
    // Table 126 – Embedded font organization for various font types
    Unknown = 0,
    Type1,
    Type1CFF,       ///< Compact Font representation for a Type1 font, as described by Adobe Technical Note #5176 "The Compact Font Format Specification"
    CIDKeyedCFF,    ///< A Compact Font representation of a CID keyed font, as described by Adobe Technical Note #5176 "The Compact Font Format Specification"
    Type3,
    TrueType,       ///< A TrueType/OpenType font that has a "glyf" table
    OpenTypeCFF     ///< OpenType font with a "CFF"/"CFF2" table, as described in ISO/IEC 14496-22
};
namespace FT
{
    FT_Library GetLibrary();
    FT_Face CreateFaceFromFile(const std::string_view& filepath, unsigned faceIndex,
        vector<uint8_t>& buffer);
    FT_Face CreateFaceFromBuffer(const vector<uint8_t>& view, unsigned faceIndex,
        vector<uint8_t>& buffer);
    // Extract a CFF table from a OpenType CFF font
    FT_Face ExtractCFFFont(FT_Face face, vector<uint8_t>& buffer);
    // No check for TTC fonts
    FT_Face CreateFaceFromBuffer(const vector<uint8_t>& view);
    vector<uint8_t> GetDataFromFace(FT_Face face);
    bool TryGetFontFileFormat(FT_Face face, PdfFontFileType& format);
    bool IsPdfSupported(FT_Face face);
}

// Other legacy TrueType tables defined in Apple documentation
// https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6.html
#define TTAG_acnt FT_MAKE_TAG('a', 'c', 'n', 't')
#define TTAG_ankr FT_MAKE_TAG('a', 'n', 'k', 'r')
#define TTAG_kerx FT_MAKE_TAG('k', 'e', 'r', 'x')
#define TTAG_fdsc FT_MAKE_TAG('f', 'd', 's', 'c')
#define TTAG_fmtx FT_MAKE_TAG('f', 'm', 't', 'x')
#define TTAG_fond FT_MAKE_TAG('f', 'o', 'n', 'd')
#define TTAG_gcid FT_MAKE_TAG('g', 'c', 'i', 'd')
#define TTAG_ltag FT_MAKE_TAG('l', 't', 'a', 'g')
#define TTAG_meta FT_MAKE_TAG('m', 'e', 't', 'a')
#define TTAG_xref FT_MAKE_TAG('x', 'r', 'e', 'f')
#define TTAG_Zapf FT_MAKE_TAG('Z', 'a', 'p', 'f')

#endif // PODOFO_FREETYPE_PRIVATE_H

源文件

#include <vector>
#include <cstdint>
#include <string>
#include <memory>
#include <ft2build.h>
#include"freetype_wrap.h"
#include FT_TRUETYPE_TAGS_H
#include FT_TRUETYPE_TABLES_H
#include FT_FONT_FORMATS_H
#include FT_CID_H

using namespace std;


#include<windows.h>
#include <fstream>
#include <string>
#include <vector>
#include <cstdint>
#include <ios>
#include <codecvt>
#include <locale>
 
constexpr unsigned TableDirectoryFixedSize = 12;

namespace {
    struct TTCF_Header {
        uint32_t ttcTag;
        uint16_t majorVersion;
        uint16_t minorVersion;
        uint32_t numFonts;
    };

    struct TT_TableHeader {
        uint32_t tableTag;
        uint32_t checksum;
        uint32_t offset;
        uint32_t length;
    };

    struct TableInfo {
        FT_ULong Tag;
        FT_ULong Size;
    };
}
// 定义 ReadTo 函数,从文件读取数据到 buffer
void ReadTo(vector<uint8_t>& buffer, const string_view& filepath, size_t maxReadSize = 0) {
    // 将 string_view 转换为 string,以确保兼容性
    ifstream file(string(filepath), ios_base::binary); // 打开文件,二进制模式
    if (!file.is_open()) {
        throw runtime_error("Failed to open file: " + string(filepath));
    }

    // 获取文件大小
    file.seekg(0, ios::end);
    streampos fileSize = file.tellg();
    if (fileSize == -1) {
        throw runtime_error("Error reading file size");
    }
    file.seekg(0, ios::beg);

    // 如果指定了最大读取大小,则限制读取大小
    size_t readSize = maxReadSize > 0 ? min((size_t)fileSize, maxReadSize) : (size_t)fileSize;

    // 调整缓冲区大小
    buffer.resize(readSize);

    // 读取数据到缓冲区
    file.read(reinterpret_cast<char*>(buffer.data()), buffer.size());
    if (file.fail() && !file.eof()) {
        throw runtime_error("Error reading from file");
    }
}
static PdfFontFileType determineFormatCFF(FT_Face face);
static unsigned determineFaceSize(FT_Face face, vector<TableInfo>& tables, unsigned& tableDirSize);
static FT_Face createFaceFromBuffer(const vector<uint8_t>& view, unsigned faceIndex);
static bool isTTCFont(FT_Face face);
static bool isTTCFont(const vector<uint8_t>& face);
static bool tryExtractDataFromTTC(FT_Face face, vector<uint8_t>& buffer);
static void getDataFromFace(FT_Face face, vector<uint8_t>& buffer);

 
FT_Library FT::GetLibrary() {
    struct Init {
        Init() : Library(nullptr) {
            if (FT_Init_FreeType(&Library))
            {
                //PODOFO_RAISE_ERROR(PdfErrorCode::FreeTypeError);
            }
        }

        ~Init() {
            FT_Done_FreeType(Library);
        }

        FT_Library Library;
    };

    thread_local Init init;
    return init.Library;
}

FT_Face FT::CreateFaceFromBuffer(const vector<uint8_t>& view, unsigned faceIndex, vector<uint8_t>& buffer) {
    if (isTTCFont(view)) {
        auto face = createFaceFromBuffer(view, faceIndex);
        unique_ptr<struct FT_FaceRec_, decltype(&FT_Done_Face)> face_(face, FT_Done_Face);

        if (!tryExtractDataFromTTC(face, buffer))
            buffer = view;

        return createFaceFromBuffer(buffer, 0);
    }
    else {
        buffer = view;
        return createFaceFromBuffer(buffer, 0);
    }
}

FT_Face FT::ExtractCFFFont(FT_Face face, vector<uint8_t>& buffer) {
    FT_ULong size = 0;
    FT_Error rc = FT_Load_Sfnt_Table(face, TTAG_CFF, 0, nullptr, &size);
    //CHECK_FT_RC(rc, FT_Load_Sfnt_Table);
    buffer.resize(size);
    rc = FT_Load_Sfnt_Table(face, TTAG_CFF, 0, reinterpret_cast<FT_Byte*>(buffer.data()), &size);
    return createFaceFromBuffer(buffer, 0);
}

FT_Face FT::CreateFaceFromBuffer(const vector<uint8_t>& view) {
    return createFaceFromBuffer(view, 0);
}

FT_Face FT::CreateFaceFromFile(const string_view& filepath, unsigned faceIndex, vector<uint8_t>& buffer) {
    ReadTo(buffer, filepath, sizeof(TTAG_ttcf));
    if (isTTCFont(buffer)) {
        FT_Error rc;
        FT_Face face;
        rc = FT_New_Face(FT::GetLibrary(), filepath.data(), faceIndex, &face);
        if (rc != 0)
            return nullptr;

        unique_ptr<struct FT_FaceRec_, decltype(&FT_Done_Face)> face_(face, FT_Done_Face);

        if (tryExtractDataFromTTC(face, buffer))
            return createFaceFromBuffer(buffer, 0);
    }

    ReadTo(buffer, filepath);
    return createFaceFromBuffer(buffer, 0);
}

vector<uint8_t> FT::GetDataFromFace(FT_Face face) {
    vector<uint8_t> buffer;
    if (!isTTCFont(face) || !tryExtractDataFromTTC(face, buffer))
        getDataFromFace(face, buffer);

    return buffer;
}

bool FT::TryGetFontFileFormat(FT_Face face, PdfFontFileType& format) {
    string_view formatstr = FT_Get_Font_Format(face);
    if (formatstr == "TrueType") {
        format = PdfFontFileType::TrueType;
    }
    else if (formatstr == "Type 1") {
        format = PdfFontFileType::Type1;
    }
    else if (formatstr == "CID Type 1") {
        format = PdfFontFileType::Unknown;
        return false;
    }
    else if (formatstr == "CFF") {
        format = determineFormatCFF(face);
    }
    else {
        format = PdfFontFileType::Unknown;
        return false;
    }

    return true;
}

bool FT::IsPdfSupported(FT_Face face) {
    PdfFontFileType format;
    if (!FT::TryGetFontFileFormat(face, format))
        return false;

    return true;
}

FT_Face createFaceFromBuffer(const vector<uint8_t>& view, unsigned faceIndex) {
    FT_Error rc;
    FT_Open_Args openArgs{ };
    openArgs.flags = FT_OPEN_MEMORY;
    openArgs.memory_base = const_cast<FT_Byte*>(reinterpret_cast<const FT_Byte*>(view.data()));
    openArgs.memory_size = static_cast<FT_Long>(view.size());

    FT_Face face;
    rc = FT_Open_Face(FT::GetLibrary(), &openArgs, faceIndex, &face);
    if (rc != 0)
        return nullptr;

    return face;
}

bool isTTCFont(FT_Face face) {
    FT_Error rc;
    FT_ULong size;

    uint32_t tag;
    size = sizeof(uint32_t);
    rc = FT_Load_Sfnt_Table(face, 0, 0, reinterpret_cast<FT_Byte*>(&tag), &size);
    if (rc == 0 && _byteswap_ulong(tag) == TTAG_ttcf)
        return true;

    return false;
}

bool isTTCFont(const vector<uint8_t>& face) {
    uint32_t tag;
    if (face.size() < sizeof(tag))
        return false;

    memcpy(&tag, face.data(), sizeof(tag));
    if (_byteswap_ulong(tag) == TTAG_ttcf)
        return true;

    return false;
}

bool tryExtractDataFromTTC(FT_Face face, vector<uint8_t>& buffer) {
    FT_Error rc;
    FT_ULong size;

    TTCF_Header header;
    size = sizeof(TTCF_Header);
    rc = FT_Load_Sfnt_Table(face, 0, 0, reinterpret_cast<FT_Byte*>(&header), &size);
    //CHECK_FT_RC(rc, FT_Load_Sfnt_Table);
    unsigned numFonts = _byteswap_ulong(header.numFonts);
    vector<uint32_t> offsets(numFonts);
    size = numFonts * sizeof(uint32_t);
    rc = FT_Load_Sfnt_Table(face, 0, sizeof(TTCF_Header), reinterpret_cast<FT_Byte*>(offsets.data()), &size);
    //CHECK_FT_RC(rc, FT_Load_Sfnt_Table);
    if (face->face_index < 0 || static_cast<size_t>(face->face_index) >= offsets.size())
        return false;

    uint32_t faceOffset = _byteswap_ulong(offsets[face->face_index]);

    vector<TableInfo> tables;
    unsigned tableDirSize;
    buffer.resize(determineFaceSize(face, tables, tableDirSize));

    size = tableDirSize;
    rc = FT_Load_Sfnt_Table(face, 0, faceOffset, reinterpret_cast<FT_Byte*>(buffer.data()), &size);
    //CHECK_FT_RC(rc, FT_Load_Sfnt_Table);

    auto tableRecords = reinterpret_cast<TT_TableHeader*>(buffer.data() + TableDirectoryFixedSize);
    unsigned offset = tableDirSize;
    for (FT_ULong i = 0; i < tables.size(); i++) {
        auto& table = tables[i];
        size = table.Size;
        rc = FT_Load_Sfnt_Table(face, table.Tag, 0, reinterpret_cast<FT_Byte*>(buffer.data()) + offset, &size);
        //CHECK_FT_RC(rc, FT_Load_Sfnt_Table);

        tableRecords[i].offset = _byteswap_ulong(offset);
        offset += table.Size;
    }

    return true;
}

void getDataFromFace(FT_Face face, vector<uint8_t>& buffer) {
    FT_Error rc;
    FT_ULong size = 0;

    rc = FT_Load_Sfnt_Table(face, 0, 0, nullptr, &size);
    //CHECK_FT_RC(rc, FT_Load_Sfnt_Table);

    buffer.resize(size);
    rc = FT_Load_Sfnt_Table(face, 0, 0, reinterpret_cast<FT_Byte*>(buffer.data()), &size);
    //CHECK_FT_RC(rc, FT_Load_Sfnt_Table);
}

PdfFontFileType determineFormatCFF(FT_Face face) {
    FT_Error rc;
    FT_ULong size;
    rc = FT_Sfnt_Table_Info(face, 0, nullptr, &size);
    if (rc == 0) {
        return PdfFontFileType::OpenTypeCFF;
    }
    else {
        FT_Bool isCid = 0;
        (void)FT_Get_CID_Is_Internally_CID_Keyed(face, &isCid);
        if (isCid == 1)
            return PdfFontFileType::CIDKeyedCFF;
        else
            return PdfFontFileType::Type1CFF;
    }
}

unsigned determineFaceSize(FT_Face face, vector<TableInfo>& tables, unsigned& tableDirSize) {
    FT_Error rc;
    FT_ULong size;

    rc = FT_Sfnt_Table_Info(face, 0, nullptr, &size);
    //CHECK_FT_RC(rc, FT_Sfnt_Table_Info);

    unsigned faceSize = TableDirectoryFixedSize + (sizeof(TT_TableHeader) * size);
    tableDirSize = faceSize;
    tables.resize(size);
    for (FT_ULong i = 0; i < size; i++) {
        auto& table = tables[i];
        rc = FT_Sfnt_Table_Info(face, i, &table.Tag, &table.Size);
        //CHECK_FT_RC(rc, FT_Sfnt_Table_Info);
        faceSize += table.Size;
    }

    return faceSize;
}

简单使用

#include <iostream>
#include <vector>
#include <string>
#include "freetype_wrap.h" // 假设这是你的头文件路径

using namespace std;

int main() {
    try {
        // 字体文件路径
        //string fontFilePath = "C:/Windows/Fonts/simsun.ttc"; // 替换为实际字体文件路径
        string fontFilePath = "C:/Windows/Fonts/simsunb.ttf";
        // 缓冲区用于存储字体数据
        vector<uint8_t> buffer;

        // 创建 FT_Face 对象
        FT_Face face = FT::CreateFaceFromFile(fontFilePath, 0, buffer);

        if (!face) {
            throw runtime_error("Failed to create FT_Face from file.");
        }

        // 获取字体格式
        PdfFontFileType format;
        if (!FT::TryGetFontFileFormat(face, format)) {
            throw runtime_error("Unsupported or unknown font format.");
        }

        // 输出字体格式
        cout << "Font Format: ";
        switch (format) {
        case PdfFontFileType::TrueType:
            cout << "TrueType" << endl;
            break;
        case PdfFontFileType::Type1:
            cout << "Type 1" << endl;
            break;
        case PdfFontFileType::OpenTypeCFF:
            cout << "OpenType CFF" << endl;
            break;
        case PdfFontFileType::CIDKeyedCFF:
            cout << "CID-Keyed CFF" << endl;
            break;
        case PdfFontFileType::Type1CFF:
            cout << "Type 1 CFF" << endl;
            break;
        default:
            cout << "Unknown" << endl;
            break;
        }

        // 提取字体数据
        vector<uint8_t> extractedData = FT::GetDataFromFace(face);

        // 输出提取的数据大小
        cout << "Extracted Font Data Size: " << extractedData.size() << " bytes" << endl;
        

        // 清理资源
        FT_Done_Face(face);
    }
    catch (const exception& e) {
        cerr << "Error: " << e.what() << endl;
    }

    return 0;
}

相关文章:

  • Java进阶学习笔记95——网络编程
  • langchain系列(五)- LangChain 的tool原理与代码实现
  • SpringSecurity获取当前登录用户信息
  • AI提示词的种类与适合的任务
  • DeepSeek开源周 Day02:从DeepEP开源趋势重新审视大模型Infra
  • WordPress Course Booking System SQL注入漏洞复现 (CVE-2025-22785)(附脚本)
  • 1分钟用DeepSeek编写一个PDF转Word软件
  • springboot志同道合交友网站设计与实现(代码+数据库+LW)
  • HTTP/HTTPS 服务端口监测的简易实现
  • 鸿蒙5.0实战案例:har和hsp的转换
  • 三、大模型微调的多种方法与应用场景
  • 搜索优化:微调模型与RAG技术的深度比较
  • 适配 AGP8.5 版本,各种问题(三)
  • vue3.0将后端返回的word文件流转换为pdf并导出+html2pdf.js将页面导出为pdf
  • C#快速调用DeepSeek接口,winform接入DeepSeek查询资料 C#零门槛接入DeepSeek C#接入DeepSeek源代码下载
  • self-attention部分代码注释
  • Pi-hole v6释出
  • android系统 使用哪些工具可以分析组件间的依赖
  • Dubbo RPC 原理
  • 在WINDOWS系统使用CMake gui编译NLopt配合VSCode使用
  • 抖音引流推广软件/seo黑帽技术
  • 做一个网站需要花费多少钱/搜索引擎优化好做吗
  • 彩票引流推广方法/亚马逊关键词优化怎么做
  • 做那种的视频网站有哪些/网站建设seo优化培训
  • 做网站有哪些软件/网络营销企业是什么
  • 制作小程序需要什么技术/济南seo网站排名关键词优化