-
-
Save ebraminio/4dd7b90a87edf0ed0624aee23e6b3645 to your computer and use it in GitHub Desktop.
Print SVG path from GDI's HFONT using GetGlyphOutlineW
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// gcc a.cc -lgdi32 && a.exe | |
#include <stdint.h> | |
#include <stdio.h> | |
#include <math.h> | |
#include <windows.h> | |
int | |
main () | |
{ | |
HFONT hFont = CreateFont (1000, 0, 0, 0, FW_NORMAL, 0, 0, 0, ANSI_CHARSET, | |
OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, | |
DEFAULT_QUALITY, DEFAULT_PITCH, TEXT ("Tahoma")); | |
HDC hdc = GetDC (NULL); | |
SelectObject (hdc, hFont); | |
GLYPHMETRICS gm = {0}; | |
MAT2 mat2 = {{0, 1}, {0, 0}, {0, 0}, {0, 1}}; | |
unsigned gid = 34; | |
unsigned flags = GGO_GLYPH_INDEX | GGO_NATIVE; | |
DWORD buffer_size = GetGlyphOutlineW (hdc, gid, flags, &gm, 0, NULL, &mat2); | |
if (buffer_size == GDI_ERROR) return 1; | |
unsigned char *buffer = (unsigned char *) malloc (buffer_size); | |
buffer_size = | |
GetGlyphOutlineW (hdc, gid, flags, &gm, buffer_size, buffer, &mat2); | |
if (buffer_size < 0) return 1; | |
uint8_t *ptr = buffer; | |
/* https://github.com/freedesktop/cairo/blob/3a03c1b/src/win32/cairo-win32-font.c#L1690-L1804 | |
*/ | |
while (ptr < buffer + buffer_size) | |
{ | |
auto &header = *(const TTPOLYGONHEADER *) ptr; | |
uint8_t *end_poly = ptr + header.cb; | |
ptr += sizeof (TTPOLYGONHEADER); | |
#define fixed_to_float(fixed) ((float) fixed.value + fixed.fract / 65536.f) | |
#define fixed_round(fixed) (int) roundf (fixed_to_float (fixed)) | |
printf ("M%d,%d", fixed_round (header.pfxStart.x), | |
fixed_round (header.pfxStart.y)); | |
while (ptr < end_poly) | |
{ | |
auto &curve = *(const TTPOLYCURVE *) ptr; | |
ptr += sizeof (TTPOLYCURVE) + sizeof (POINTFX) * (curve.cpfx - 1); | |
switch (curve.wType) | |
{ | |
case TT_PRIM_LINE: | |
for (int i = 0; i < curve.cpfx; ++i) | |
printf ("L%d,%d", | |
fixed_round (curve.apfx[i].x), | |
fixed_round (curve.apfx[i].y)); | |
break; | |
case TT_PRIM_QSPLINE: | |
for (int i = 0; i < curve.cpfx - 1; ++i) | |
{ | |
float cx = fixed_to_float (curve.apfx[i].x), | |
cy = fixed_to_float (curve.apfx[i].y), x, y; | |
if (i + 1 == curve.cpfx - 1) | |
{ | |
x = fixed_to_float (curve.apfx[i + 1].x); | |
y = fixed_to_float (curve.apfx[i + 1].y); | |
} | |
else | |
{ | |
x = (cx + fixed_to_float (curve.apfx[i + 1].x)) / 2.f; | |
y = (cy + fixed_to_float (curve.apfx[i + 1].y)) / 2.f; | |
} | |
printf ("Q%d,%d %d,%d", | |
(int) roundf (cx), (int) roundf (cy), | |
(int) roundf (x), (int) roundf (y)); | |
} | |
break; | |
case TT_PRIM_CSPLINE: | |
for (int i = 0; i < curve.cpfx - 2; i += 2) | |
printf ("C%d,%d %d,%d %d,%d", fixed_round (curve.apfx[i + 0].x), | |
fixed_round (curve.apfx[i + 0].y), | |
fixed_round (curve.apfx[i + 1].x), | |
fixed_round (curve.apfx[i + 1].y), | |
fixed_round (curve.apfx[i + 2].x), | |
fixed_round (curve.apfx[i + 2].y)); | |
#undef fixed_to_float | |
#undef fixed_round | |
break; | |
} | |
} | |
printf ("Z"); | |
} | |
free (buffer); | |
printf ("\n"); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment