// dump_metrics12.cpp --- Test for Windows Font Metrics // Copyright (C) 2024 Doug Lyons // This file is public domain software. // To compile: gcc -o dump_metrics12 dump_metrics12.cpp -lgdi32 // Ref: https://learn.microsoft.com/en-us/windows/win32/gdi/character-widths #include #include #define _countof(_Array) (sizeof(_Array) / sizeof(_Array[0])) void dump_metrics(FILE *fout, const LOGFONTA *lplfa, DWORD dwType) { INT i; INT CharSet; CHAR chr[2] = { 0 }; // Stores tested character ABCFLOAT abc[1]; // Array to store the width data for a single character FLOAT Advance; // Width of character char face[LF_FACESIZE + sizeof(" (xxx) ")]; CharSet = lplfa->lfCharSet; HDC hDC = CreateCompatibleDC(NULL); // Get the device context for the desktop display HFONT hFont = CreateFontIndirectA(lplfa); HGDIOBJ hFontOld = SelectObject(hDC, hFont); GetTextFaceA(hDC, _countof(face), face); /* dwType & 0x0f: 0 - RAS, 1 - RAS, 2 - DEV, 3 - PLT, 4 - TT, 6 - TT, 7 - TT, b - DEV */ if ((dwType & 0x0f) == 0 | (dwType & 0x0f) == 1) // Raster Font strncat(face, " (RAS) ", 7); else if ((dwType & 0x0f) == 4 | (dwType & 0x0f) == 6 | (dwType & 0x0f) == 7) // TT Font strncat(face, " (TT) ", 6); else if ((dwType & 0x0f) == 3) // Plotter Font strncat(face, " (PLT) ", 7); else if ((dwType & 0x0f) == 0x0b | (dwType & 0x0f) == 2) // Device Font strncat (face, " (DEV) ", 7); // printf("Face is '%s(%d)-0x%x'\n", face, CharSet, dwType); for(i = 0x20; i <= 0x7f; i++) // ASCII Space to 0x7f character { chr[0] = i; /* Get the ABC widths for the character i. * This function works for both raster and TrueType fonts (& all others). */ if (GetCharABCWidthsFloat(hDC, i, i, abc)) { // Calculatate the Advance width Advance = abc[0].abcfA + abc[0].abcfB + abc[0].abcfC; fprintf(fout, "\"%s-'%s'-0x%02x\",%.2f,%.2f,%.2f,%.2f\n", face, chr, i, abc[0].abcfA, abc[0].abcfB, abc[0].abcfC, Advance); } else { printf("Failed to get character widths for face '%s'.\n", face); } } SelectObject(hDC, hFontOld); DeleteObject(hFont); DeleteDC(hDC); } static int CALLBACK EnumFontsProc( const LOGFONTA *lplf, const TEXTMETRIC *lptm, DWORD dwType, LPARAM lpData) { FILE *fout = (FILE*)lpData; printf("Processing font '%s'\n", lplf->lfFaceName); dump_metrics(fout, lplf, dwType); return TRUE; } int main(int argc, char **argv) { FILE *fout = fopen("dump_metrics12.csv", "w"); fprintf(fout, "lfFaceName, abcfA, abcfB, abcfC, Advance\n"); // Excel CSV Header HDC hDC = CreateCompatibleDC(NULL); EnumFontFamiliesA(hDC, NULL, EnumFontsProc, (LPARAM)fout); DeleteDC(hDC); fclose(fout); return 0; }