#include #include #include #include FT_FREETYPE_H #include FT_GLYPH_H #include FT_OUTLINE_H #include FT_SYNTHESIS_H #include FT_STROKER_H static FT_Library freetype_library = NULL; #define WIDTH 320 #define HEIGHT 240 // desired stroke thickness in pixels #define STROKE_THICKNESS 8 #define setvector(pv, px, py) (pv).x = ((int) (px)) << 6; (pv).y = ((int) (py)) << 6; #define Float2Fixed(fl) ((FT_Fixed)((fl)*65536.0f)) #define writew(fp, w) tmpword = (w); fwrite(&tmpword, 2, 1, (fp)); #define writel(fp, l) tmplong = (l); fwrite(&tmplong, 4, 1, (fp)); int main(int argc, char *argv[]) { FT_Stroker stroker; FT_UInt points, contours; FT_Outline outline; FT_BBox bbox; FT_Bitmap bm; FT_Vector v; FT_Matrix m; int x, y, xmin, ymin, xmax, ymax, pixelwidth, pixelheight, bytewidth; unsigned char *buf, *ptr; unsigned char *linebuf; unsigned short tmpword; unsigned long tmplong; FILE *fp; FT_Init_FreeType(&freetype_library); FT_Stroker_New(freetype_library, &stroker); FT_Stroker_Set(stroker, (int) ((double) STROKE_THICKNESS * 32.0), FT_STROKER_LINECAP_ROUND, FT_STROKER_LINEJOIN_ROUND, 0); setvector(v, 0, 0); FT_Stroker_BeginSubPath(stroker, &v, 1); FT_Stroker_LineTo(stroker, &v); setvector(v, 0, 0); FT_Stroker_LineTo(stroker, &v); setvector(v, 0, HEIGHT); FT_Stroker_LineTo(stroker, &v); setvector(v, WIDTH, HEIGHT); FT_Stroker_LineTo(stroker, &v); setvector(v, WIDTH, 0); FT_Stroker_LineTo(stroker, &v); setvector(v, 0, 0); FT_Stroker_LineTo(stroker, &v); FT_Stroker_EndSubPath(stroker); FT_Stroker_GetBorderCounts(stroker, FT_STROKER_BORDER_LEFT, &points, &contours); memset(&outline, 0, sizeof(FT_Outline)); FT_Outline_New(freetype_library, 1024, 512, &outline); outline.n_points = 0; outline.n_contours = 0; FT_Stroker_Export(stroker, &outline); #if 1 // this transformation will reduce STROKE_THICKNESS on the y-axis to STROKE_THICKNESS*0.5 // but I don't want this! STROKE_THICKNESS should always be the constant value that has // been set in FT_Stroker_Set() --- no matter which transformation matrix has been applied! m.xx = Float2Fixed(1.0); m.xy = Float2Fixed(0.0); m.yx = Float2Fixed(0.0); m.yy = Float2Fixed(0.5); FT_Outline_Transform(&outline, &m); #endif FT_Stroker_ParseOutline(stroker, &outline, 0); FT_Stroker_GetCounts(stroker, &points, &contours); #if 0 // this transformation will reduce STROKE_THICKNESS on the y-axis to STROKE_THICKNESS*0.5 // but I don't want this! STROKE_THICKNESS should always be the constant value that has // been set in FT_Stroker_Set() --- no matter which transformation matrix has been applied! m.xx = Float2Fixed(1.0); m.xy = Float2Fixed(0.0); m.yx = Float2Fixed(0.0); m.yy = Float2Fixed(0.5); FT_Outline_Transform(&outline, &m); #endif FT_Stroker_Done(stroker); FT_Outline_Get_BBox(&outline, &bbox); FT_Outline_Translate(&outline, -bbox.xMin, -bbox.yMin); FT_Outline_Get_BBox(&outline, &bbox); xmin = bbox.xMin >> 6; ymin = bbox.yMin >> 6; xmax = bbox.xMax >> 6; ymax = bbox.yMax >> 6; if(bbox.xMax & 0x3f) xmax++; if(bbox.yMax & 0x3f) ymax++; pixelwidth = xmax - xmin; pixelheight = ymax - ymin; buf = calloc(pixelwidth * pixelheight, 1); memset(&bm, 0, sizeof(FT_Bitmap)); bm.rows = pixelheight; bm.width = pixelwidth; bm.pitch = pixelwidth; bm.buffer = buf; bm.num_grays = 256; bm.pixel_mode = FT_PIXEL_MODE_GRAY; FT_Outline_Get_Bitmap(freetype_library, &outline, &bm); fp = fopen("dump.bmp", "wb"); bytewidth = pixelwidth * 3 + pixelwidth % 4; linebuf = malloc(bytewidth); writew(fp, 0x4D42); writel(fp, bytewidth * pixelheight + 54); writel(fp, 0); writel(fp, 0x36); writel(fp, 0x28); writel(fp, pixelwidth); writel(fp, pixelheight); writew(fp, 1); writew(fp, 24); writel(fp, 0); writel(fp, 0); writel(fp, 0); writel(fp, 0); writel(fp, 0); writel(fp, 0); ptr = buf + pixelheight * pixelwidth; for(y = 0; y < pixelheight; y++) { unsigned char *l = linebuf; ptr -= pixelwidth; for(x = 0; x < pixelwidth; x++) { unsigned long rgb = ptr[x] * 65793; *l++ = (unsigned char) (rgb & 0x0000ff); *l++ = (unsigned char) ((rgb & 0x00ff00) >> 8); *l++ = (unsigned char) ((rgb & 0xff0000) >> 16); } fwrite(linebuf, bytewidth, 1, fp); } fclose(fp); free(linebuf); free(buf); FT_Outline_Done(freetype_library, &outline); FT_Done_FreeType(freetype_library); return 0; }