C++字体库开发之字体包解析十二
parse.h
#ifndef FONT_SUBSET_EXPORT_H #define FONT_SUBSET_EXPORT_H #ifndef FONT_SUBSET_API # ifdef FONT_SUBSET_LIBRATY # ifdef _MSC_VER # if defined FONT_SUBSET_LIBRATY # define FONT_SUBSET_API __declspec(dllexport) # else # define FONT_SUBSET_API __declspec(dllimport) # endif # else # define FONT_SUBSET_API __attribute__((visibility("default"))) # endif # else # define FONT_SUBSET_API # endif #endif struct FontTTCByteData{ unsigned char *buffer = nullptr; unsigned int length = 0; }; struct FontSubSetByteDatas { struct One{ unsigned char *buffer = nullptr; unsigned int length = 0; char* familyName = nullptr; unsigned int nameLength = 0; } *subsets; unsigned int size = 0; }; FONT_SUBSET_API FontSubSetByteDatas createSubsetFonts(FontTTCByteData ttcSteam); FONT_SUBSET_API FontSubSetByteDatas createSubsetFonts(const char* path); FONT_SUBSET_API void releaseSubsetFonts(FontSubSetByteDatas datas); FONT_SUBSET_API bool isTTC(FontTTCByteData ttcSteam); #endif // FONT_SUBSET_EXPORT_Hparse.cpp
#include "sfntly/data/memory_byte_array.h" #include "sfntly/font_factory.h" #include "sfntly/port/file_input_stream.h" #include "sfntly/port/memory_output_stream.h" #include "sfntly/table/core/name_table.h" #include "sfntly/tag.h" #include <iostream> #include "unicode/ustring.h" #include "parseTTC.h" #include "sfntly/port/memory_input_stream.h" FONT_SUBSET_API FontSubSetByteDatas createSubsetFonts(sfntly::InputStream* inputStream) { using namespace sfntly; FontFactoryPtr factory; factory.Attach(FontFactory::GetInstance()); // File based FontBuilderArray font_builder_array; factory->LoadFontsForBuilding(inputStream, &font_builder_array); // 创建输出流数组 FontSubSetByteDatas fontSubSetByteDatas; fontSubSetByteDatas.subsets = new FontSubSetByteDatas::One[font_builder_array.size()]; fontSubSetByteDatas.size = font_builder_array.size(); for (int index = 0; index < fontSubSetByteDatas.size; ++index) { const auto& font_builder = font_builder_array.at(index); NameTableBuilderPtr name_builder = down_cast<NameTable::Builder*>( font_builder->GetTableBuilder(Tag::name)); // // Change the font name. // auto findName = name_builder->Has(PlatformId::kWindows, // WindowsEncodingId::kUnicodeUCS2, // WindowsLanguageId::kEnglish_UnitedStates, // NameId::kFontFamilyName); NameEntryBuilderPtr neb = name_builder->NameBuilder(PlatformId::kWindows, WindowsEncodingId::kUnicodeUCS2, WindowsLanguageId::kEnglish_UnitedStates, NameId::kFontFamilyName); UChar* name = neb->name_entry()->Name(); // U_STRING_DECL(new_name, "Timothy", 7); // neb->SetName(new_name); // Build the font. FontPtr font; font.Attach(font_builder->Build()); // auto digest = font->digest(); // Serialize and reload the serialized font. MemoryOutputStream os; factory->SerializeFont(font, &os); // ByteArrayPtr new_ba = new MemoryByteArray(os.Get(), os.Size()); auto fileStream = new unsigned char[os.Size()]; std::copy(os.Get(), os.Get() + os.Size(), fileStream); int32_t nameLen = u_strlen(name); auto asciiName = new char[nameLen * 2]; u_austrncpy(asciiName, name, nameLen + 1); // auto copyChar = u_austrncpy(asciiName, name, nameLen + 1); // auto asciiNameLen = strlen(copyChar); // asciiName[asciiNameLen + 1] = '\0'; fontSubSetByteDatas.subsets[index].familyName = asciiName; fontSubSetByteDatas.subsets[index].nameLength = strnlen_s(asciiName, nameLen * 2); fontSubSetByteDatas.subsets[index].buffer = fileStream; fontSubSetByteDatas.subsets[index].length = os.Size(); delete[] name; } return fontSubSetByteDatas; } FONT_SUBSET_API FontSubSetByteDatas createSubsetFonts(const char* path) { using namespace sfntly; sfntly::FileInputStream is; if(!is.Open(path)) { std::cout << path << " file open is fail!" << std::endl; return {}; } std::shared_ptr<void> finally(nullptr, [&is](...) { is.Close(); }); return createSubsetFonts(&is); } FONT_SUBSET_API FontSubSetByteDatas createSubsetFonts(FontTTCByteData ttcSteam) { using namespace sfntly; sfntly::MemoryInputStream memoryInputStream; memoryInputStream.Attach(ttcSteam.buffer, ttcSteam.length); return createSubsetFonts(&memoryInputStream); } FONT_SUBSET_API void releaseSubsetFonts(FontSubSetByteDatas datas) { for (int i = 0; i < datas.size; ++i) { delete[] datas.subsets[i].buffer; delete[] datas.subsets[i].familyName; } delete[] datas.subsets; } FONT_SUBSET_API bool isTTC(FontTTCByteData ttcSteam) { using namespace sfntly; sfntly::MemoryInputStream memoryInputStream; memoryInputStream.Attach(ttcSteam.buffer, ttcSteam.length); std::vector<uint8_t> tag(4); memoryInputStream.Read(&tag); memoryInputStream.Unread(&tag); return Tag::ttcf == GenerateTag(tag[0], tag[1], tag[2], tag[3]); } FONT_SUBSET_API std::string getFontFormat(FontTTCByteData ttcSteam) { using namespace sfntly; sfntly::MemoryInputStream memoryInputStream; memoryInputStream.Attach(ttcSteam.buffer, ttcSteam.length); std::vector<uint8_t> tag(4, 0); memoryInputStream.Read(&tag); memoryInputStream.Unread(&tag); auto format = GenerateTag(tag[0], tag[1], tag[2], tag[3]); if(0x00010000 == format) return "ttf"; if(0x4f54544f == format) return "otf"; return std::string((char*)tag[0], 4); }main.cpp
#include "parse.h" #include <iostream> #include <fstream> int main() { const char* path = "C:\\Users\\Downloads\\msyh.ttc"; auto fontDatas = createSubsetFonts(path); if(0 == fontDatas.size) { std::cout << path << " parse fail!" << std::endl; return 1; } for (int i = 0; i < fontDatas.size; ++i) { // write file std::ofstream outFile((const char*)fontDatas.subsets[i].familyName, std::ios::binary); if (!outFile) { // error continue; } outFile.write(reinterpret_cast<const char*>(fontDatas.subsets[i].buffer), fontDatas.subsets[i].length * sizeof(uint8_t)); outFile.close(); } releaseSubsetFonts(fontDatas); return 0; }参考
https://github.com/googlei18n/sfntly
https://pkg.go.dev/golang.org/x/image/font/sfnt#Collection
C++字体库开发之字体列表十一-CSDN博客