无法使用 libzip 和 FreeType 直接从 ZIP 加载 TTF 文件

Posted

技术标签:

【中文标题】无法使用 libzip 和 FreeType 直接从 ZIP 加载 TTF 文件【英文标题】:Cannot load TTF file directly from a ZIP using libzip and FreeType 【发布时间】:2012-12-28 05:20:40 【问题描述】:

我正在尝试使用 libzip 和 FreeType 直接从 ZIP 存档加载 TTF 文件。

特别是,我正在使用 FT_Open_Face 函数,该函数可以从自定义读取/关闭函数(ft_zip_readft_zip_close)中读取。但是尽管文件显然已被完全读取,FT_Open_Face 返回FT_Err_Unknown_File_Format。直接从磁盘打开同一个文件可以正常工作。

我真的不知道如何调试这个,有人可以帮忙吗?

我现在唯一能想到的问题是我的ft_zip_read函数不支持查找,文档says:

可以调用此函数来执行查找或跳过操作 “计数”为 0。非零返回值表示错误。

它确实被 count 0 调用了几次,但我看不到任何使用 libzip 进行搜索的方法。

unsigned long ft_zip_read(FT_Stream stream, unsigned long offset,
                          unsigned char* buffer, unsigned long count)

    zip_file* file = static_cast<zip_file*>(stream->descriptor.pointer);
    return zip_fread(file, buffer + offset, count);


void ft_zip_close(FT_Stream stream)

    zip_file* file = static_cast<zip_file*>(stream->descriptor.pointer);
    zip_fclose(file);


FT_Face load_zipped_face(const std::string& name, unsigned int size,
                         const std::string& zip_path)

    FT_Library library;
    FT_Error error = FT_Init_FreeType(&library);
    if (error)
        throw freetype_error_string("Failed to initialise FreeType", error);

    int zip_error;
    zip* zip = zip_open(zip_path.c_str(), 0, &zip_error);
    if (!zip) 
        std::ostringstream message_stream;
        message_stream << "Error loading ZIP (" << zip_path <<  "): "
                       << zip_error;
        throw message_stream.str();
    

    std::string face_path = name + ".ttf";

    struct zip_stat stat;
    if (zip_stat(zip, face_path.c_str(), 0, &stat))
        throw std::string("zip_stat failed");

    zip_file* file = zip_fopen(zip, face_path.c_str(), 0);
    if (file == 0)
        throw face_path + ": " + strerror(errno);

    FT_StreamDesc descriptor;
    descriptor.pointer = file;

    FT_StreamRec* stream = new FT_StreamRec;
    stream->base = 0;
    stream->size = stat.size;
    stream->descriptor = descriptor;
    stream->read = &ft_zip_read;
    stream->close = &ft_zip_close;

    FT_Open_Args open_args;
    open_args.flags = FT_OPEN_STREAM;
    open_args.stream = stream;

    FT_Face face;
    error = FT_Open_Face(library, &open_args, 0, &face);

    zip_close(zip);

    if (error == FT_Err_Unknown_File_Format)
        throw std::string("Unsupported format");
    else if (error)
        throw freetype_error_string("Unknown error loading font", error);

    error = FT_Set_Pixel_Sizes(face, 0, size);
    if (error)
        throw freetype_error_string("Unable to set pixel sizes", error);

    return face;

【问题讨论】:

【参考方案1】:

寻求真理

为了能够在压缩数据流中查找,您需要将流解压缩到您希望查找的点(存在一些例外情况,例如具有重置标记和索引的流只需要从前一个标记开始解压缩)。如果经常这样做,这只是效率低下(更不用说您需要自己编写代码)。

现在考虑一下,您不想将整个面部加载到内存中并为字体文件使用自定义 IO 的唯一原因是它是否太大而无法保存在内存中;这样就使得 FT 的流 IO 接口必须寻找。

你能做什么?

如果文件足够小: 将其全部读入内存并使用FT_New_Memory_Face 从内存中加载人脸。

如果文件太大,以至于您不希望将整个面部一次放入内存中,请将字体文件提取到一个临时文件中并从中读取。 (使用 windows/unix/cstdio 临时文件 API 有一个表现良好的临时文件)

如果以上都不适合您,那么您可以在 libzip 之上实现自己的缓存和可搜索的 zip 流并将其传递给 FT。这可能很麻烦并且涉及一些工作,所以我会亲自与另外两个中的一个一起去:)

【讨论】:

以上是关于无法使用 libzip 和 FreeType 直接从 ZIP 加载 TTF 文件的主要内容,如果未能解决你的问题,请参考以下文章

libzip开发笔记:libzip库介绍ubuntu平台编译和工程模板

Cpp 使用 libzip 强制写入 zip

OpenCV 显示中文汉字,未使用CvxText和FreeType库

CentOS 7编译安装PHP 7.4提示No package 'libzip' found或者(libzip >= 0.11)

JVM 在 libzip.so 崩溃

运行 `pip install` 的 Ubuntu 出现错误“无法构建以下必需的软件包:* freetype”