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

7

我正在尝试直接从ZIP归档文件中使用libzipFreeType加载TTF文件。

特别地,我正在使用FT_Open_Face函数读取自定义读取/关闭函数 (ft_zip_readft_zip_close)。但是,虽然文件显然已完全读取,但FT_Open_Face返回FT_Err_Unknown_File_Format。直接从磁盘打开相同的文件运行良好。

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

我现在唯一能想象到的问题就是我的ft_zip_read函数不支持寻找,文档

此函数可能被调用以执行具有“计数”的搜索或跳过操作。非零返回值表示错误。

实际上会多次使用计数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个回答

0

寻求真相

为了能够在压缩的数据流中进行搜索,您需要将流解压缩到您希望搜索的位置(一些例外情况存在,例如具有重置标记和索引的流只需自上一个标记以来解压缩)。如果经常这样做,这只是纯粹的低效率(更不用说您需要自己编写代码了)。

现在考虑一下,您想要不将整个字体加载到内存中,并且对于字体文件使用自定义IO的唯一原因是它太大而无法保留在内存中;因此,这使得FT的流IO接口必须进行搜索。

你可以做什么?

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

如果文件太大,以至于您不想一次性将整个面部加载到内存中,请将字体文件提取到临时文件中并从中读取。(使用Windows / Unix / Cstdio临时文件API以获得良好的临时文件)

如果以上两种方法都不适合您,那么您可以在libzip的基础上实现自己的缓存和可寻址zip流,并将其传递给FT。这可能会很麻烦,需要一些工作,所以我个人建议选择其中之一 :)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接