# include <string>
# include <set>
# include <vector>
# include <iostream>
# include <filesystem>
# include <windows.h>
# include <fstream>
# include <algorithm> using namespace std;
std:: unique_ptr< std:: string> GetWinFontData ( std:: wstring font_name) ;
std:: unique_ptr< std:: string> GetWinFontData ( const LOGFONTW& infont) ;
bool GetWinFontData ( std:: string& buffer, HDC hdc, HFONT hf) ;
void GetFontDataTTC ( std:: string& buffer, const std:: string& file_buffer, const std:: string& ttc_buffer) ;
void SaveFontToFile ( const std:: string& font_data, const std:: wstring& font_name) ;
void ListInstalledFonts ( ) ;
std:: unique_ptr< std:: string> GetWinFontData ( std:: wstring font_name)
{ if ( font_name. length ( ) >= LF_FACESIZE) return nullptr ; LOGFONTW lf = { } ; memset ( lf. lfFaceName, 0 , LF_FACESIZE * sizeof ( wchar_t ) ) ; wcsncpy_s ( lf. lfFaceName, font_name. c_str ( ) , ( std:: min) ( font_name. length ( ) , ( size_t) ( LF_FACESIZE - 1 ) ) ) ; return GetWinFontData ( lf) ;
}
std:: unique_ptr< std:: string> GetWinFontData ( const LOGFONTW& infont)
{ bool success = false ; std:: string buffer; buffer. clear ( ) ; HDC hdc = :: CreateCompatibleDC ( nullptr ) ; HFONT hf = CreateFontIndirectW ( & infont) ; if ( hf != nullptr ) { success = GetWinFontData ( buffer, hdc, hf) ; DeleteObject ( hf) ; } ReleaseDC ( 0 , hdc) ; if ( success) return std:: make_unique < std:: string> ( std:: move ( buffer) ) ; else return nullptr ;
}
bool GetWinFontData ( std:: string& buffer, HDC hdc, HFONT hf)
{ HGDIOBJ oldFont = SelectObject ( hdc, hf) ; bool sucess = false ; constexpr DWORD ttcf_const = 0x66637474 ; unsigned fileLen = GetFontData ( hdc, 0 , 0 , nullptr , 0 ) ; unsigned ttcLen = GetFontData ( hdc, ttcf_const, 0 , nullptr , 0 ) ; if ( fileLen != GDI_ERROR) { if ( ttcLen == GDI_ERROR) { buffer. resize ( fileLen) ; sucess = GetFontData ( hdc, 0 , 0 , const_cast < char * > ( buffer. data ( ) ) , ( DWORD) fileLen) != GDI_ERROR; } else { std:: string fileBuffer; fileBuffer. resize ( fileLen) ; if ( GetFontData ( hdc, 0 , 0 , const_cast < char * > ( fileBuffer. data ( ) ) , fileLen) == GDI_ERROR) { sucess = false ; goto Exit; } std:: string ttcBuffer; ttcBuffer. resize ( ttcLen) ; if ( GetFontData ( hdc, ttcf_const, 0 , const_cast < char * > ( ttcBuffer. data ( ) ) , ttcLen) == GDI_ERROR) { sucess = false ; goto Exit; } GetFontDataTTC ( buffer, fileBuffer, ttcBuffer) ; sucess = true ; } } Exit: SelectObject ( hdc, oldFont) ; return sucess;
}
void GetFontDataTTC ( std:: string& buffer, const std:: string& file_buffer, const std:: string& ttc_buffer)
{ uint16_t numTables = _byteswap_ushort ( * ( uint16_t * ) ( file_buffer. data ( ) + 4 ) ) ; unsigned outLen = 12 + 16 * numTables; const char * entry = file_buffer. data ( ) + 12 ; for ( unsigned i = 0 ; i < numTables; i++ ) { uint32_t length = _byteswap_ulong ( * ( uint32_t * ) ( entry + 12 ) ) ; length = ( length + 3 ) & ~ 3 ; entry += 16 ; outLen += length; } buffer. resize ( outLen) ; memcpy ( const_cast < char * > ( buffer. data ( ) ) , file_buffer. data ( ) , 12 + 16 * numTables) ; uint32_t dstDataOffset = 12 + 16 * numTables; const char * srcEntry = file_buffer. data ( ) + 12 ; char * dstEntry = const_cast < char * > ( buffer. data ( ) ) + 12 ; for ( unsigned i = 0 ; i < numTables; i++ ) { uint32_t offset = _byteswap_ulong ( * ( uint32_t * ) ( srcEntry + 8 ) ) ; uint32_t length = _byteswap_ulong ( * ( uint32_t * ) ( srcEntry + 12 ) ) ; length = ( length + 3 ) & ~ 3 ; * ( uint32_t * ) ( dstEntry + 8 ) = _byteswap_ulong ( dstDataOffset) ; memcpy ( const_cast < char * > ( buffer. data ( ) ) + dstDataOffset, ttc_buffer. data ( ) + offset, length) ; dstDataOffset += length; srcEntry += 16 ; dstEntry += 16 ; }
}
void SaveFontToFile ( const std:: string& font_data, const std:: wstring& font_name)
{ try { wstring output_path = L"D:\\Unit_Test\\" + font_name + L".ttf" ; CreateDirectoryW ( L"output" , NULL ) ; ofstream file ( output_path, ios:: binary) ; if ( ! file. is_open ( ) ) { wcerr << L"无法创建文件: " << output_path << endl; return ; } file. write ( font_data. data ( ) , font_data. size ( ) ) ; file. close ( ) ; wcout << L"字体已保存到: " << output_path << endl; } catch ( const exception& e) { cerr << "Error saving font file: " << e. what ( ) << endl; }
}
void ListInstalledFonts ( )
{ HDC hdc = GetDC ( NULL ) ; LOGFONTW lf = { 0 } ; lf. lfCharSet = DEFAULT_CHARSET; EnumFontFamiliesExW ( hdc, & lf, [ ] ( const LOGFONTW* lf, const TEXTMETRICW* , DWORD, LPARAM lParam) -> int { wcout << L"Font: " << lf-> lfFaceName << endl; return 1 ; } , 0 , 0 ) ; ReleaseDC ( NULL , hdc) ;
}
int main ( )
{ ListInstalledFonts ( ) ; auto data1 = GetWinFontData ( L"Arial" ) ; if ( data1) SaveFontToFile ( * data1, L"Arial" ) ; auto data2 = GetWinFontData ( L"Batang" ) ; if ( data2) SaveFontToFile ( * data2, L"Batang" ) ; return 0 ;
}