Android — Не удается загрузить файл TTF напрямую из ZIP с использованием libzip и FreeType

Я пытаюсь загрузить файл TTF прямо из ZIP-архива, используя libzip а также FreeType.

В частности, я использую FT_Open_Face функция, которая может читать из пользовательских функций чтения / закрытия (ft_zip_read а также ft_zip_close). Но хотя файл, по-видимому, полностью прочитан, FT_Open_Face возвращается FT_Err_Unknown_File_Format, Открытие того же файла непосредственно с диска работает нормально.

Я действительно не знаю, как отладить это, кто-нибудь может помочь?

Единственное, что я могу себе представить, это проблема сейчас, это то, что мой ft_zip_read функция не поддерживает поиск, документация говорит:

Эта функция может быть вызвана для выполнения операции поиска или пропуска с
«количество», равное 0. Тогда ненулевое возвращаемое значение указывает на ошибку.

И он действительно вызывается со счетчиком 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;
}

6

Решение

В поисках правды

Чтобы иметь возможность искать в сжатом потоке данных, вам нужно распаковывать поток до точки, к которой вы хотите обратиться (существуют некоторые исключения, такие как потоки, у которых сброшены маркеры, а индексы должны распаковываться только после предыдущего маркера). Это просто неэффективно, если это делается часто (не говоря уже о том, что вам нужно написать код для него самостоятельно).

Если подумать, единственная причина, по которой вы не хотите загружать все лицо в память и иметь собственный ввод-вывод для файла шрифта, заключается в том, что он слишком велик для хранения в памяти; так что это делает поиск обязательным для потокового интерфейса ввода-вывода FT.

Что ты можешь сделать?

Если файл достаточно мал: Прочитайте все это в память и используйте FT_New_Memory_Face загрузить лицо по памяти.

Если файл слишком большой так что вы не хотите, чтобы все лицо было в памяти сразу, извлеките файл шрифта во временный файл и прочитайте его. (Используйте API временного файла windows / unix / cstdio, чтобы получить временный файл с хорошим поведением)

Если ни один из вышеперечисленных вам не подходит затем вы можете реализовать собственный кеширующий и доступный поток zip поверх libzip и передать его в FT. Это, вероятно, громоздко и требует некоторой работы, так что я бы пошел с одним из двух других лично 🙂

0

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]