-
-
Save danpla/35292c7c54fc1217b81219aa442dcc37 to your computer and use it in GitHub Desktop.
FreeType test
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
cmake_minimum_required(VERSION 2.8.12) | |
project(ft_test) | |
add_executable( | |
ft_test | |
main.c | |
) | |
target_compile_options( | |
ft_test | |
PRIVATE -std=c99 -Wall -Wextra -pedantic -Wstrict-prototypes) | |
set_target_properties( | |
ft_test | |
PROPERTIES | |
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" | |
) | |
find_package(Freetype REQUIRED) | |
target_include_directories(ft_test PRIVATE ${FREETYPE_INCLUDE_DIRS}) | |
target_link_libraries(ft_test ${FREETYPE_LIBRARIES}) |
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
#include <stdio.h> | |
#include <stdlib.h> | |
#include <ft2build.h> | |
#include FT_FREETYPE_H | |
#include FT_OUTLINE_H | |
#include FT_BBOX_H | |
typedef struct Size { | |
int w; | |
int h; | |
} Size; | |
#define MAX_UNICODE_CP 0x10ffff | |
#define FONT_DPI 72 | |
static FT_Library library; | |
static FT_Face face; | |
static Size* cboxSizeBuf; | |
static void printFtError(const char* description, FT_Error err) | |
{ | |
fprintf(stderr, "%s: 0x%02x\n", description, err); | |
} | |
#define FT_FLOOR(x) ((x) & -64) | |
#define FT_CEIL(x) (((x) + 63) & -64) | |
static void getBBoxPxSize(FT_BBox bbox, int* w, int* h) | |
{ | |
bbox.xMin = FT_FLOOR(bbox.xMin); | |
bbox.xMax = FT_CEIL(bbox.xMax); | |
bbox.yMin = FT_FLOOR(bbox.yMin); | |
bbox.yMax = FT_CEIL(bbox.yMax); | |
*w = (bbox.xMax - bbox.xMin) / 64; | |
*h = (bbox.yMax - bbox.yMin) / 64; | |
} | |
static void shutdown(int exitCode); | |
static void init(const char* fontPath, int ptSize) | |
{ | |
FT_Error err = FT_Init_FreeType(&library); | |
if (err != FT_Err_Ok) { | |
printFtError("Error initializing FreeType", err); | |
shutdown(EXIT_FAILURE); | |
} | |
FT_Int vMajor, vMinor, vPatch; | |
FT_Library_Version(library, &vMajor, &vMinor, &vPatch); | |
printf("FreeType %i.%i.%i\n", vMajor, vMinor, vPatch); | |
printf("Loading %s at %i pt\n", fontPath, ptSize); | |
err = FT_New_Face(library, fontPath, 0, &face); | |
if (err != FT_Err_Ok) { | |
printFtError("Can't open font", err); | |
shutdown(EXIT_FAILURE); | |
} | |
if (!face->charmap) { | |
fprintf(stderr, "Font doesn't contain Unicode charmap\n"); | |
shutdown(EXIT_FAILURE); | |
} | |
err = FT_Set_Char_Size(face, ptSize * 64, 0, FONT_DPI, 0); | |
if (err != FT_Err_Ok) { | |
printFtError("Can't set char size", err); | |
shutdown(EXIT_FAILURE); | |
} | |
cboxSizeBuf = malloc(face->num_glyphs * sizeof(Size)); | |
if (!cboxSizeBuf) { | |
fprintf(stderr, "Can't allocate memory for cboxSizeBuf\n"); | |
shutdown(EXIT_FAILURE); | |
} | |
} | |
static void shutdown(int exitCode) | |
{ | |
if (cboxSizeBuf) | |
free(cboxSizeBuf); | |
if (face) | |
FT_Done_Face(face); | |
if (library) | |
FT_Done_FreeType(library); | |
exit(exitCode); | |
} | |
static void checkCBoxVsBBox(void) | |
{ | |
printf("Checking cbox vs bbox\n"); | |
unsigned cboxSizeBufIdx = 0; | |
for (unsigned cp = 1; cp <= MAX_UNICODE_CP; ++cp) { | |
FT_UInt glyphIdx = FT_Get_Char_Index(face, cp); | |
if (glyphIdx == 0) | |
continue; | |
FT_Error err = FT_Load_Glyph(face, glyphIdx, FT_LOAD_DEFAULT); | |
if (err != FT_Err_Ok) { | |
fprintf(stderr, "Can't load glyph U+%04x\n", cp); | |
printFtError("FreeType error", err); | |
shutdown(EXIT_FAILURE); | |
} | |
FT_BBox cbox; | |
FT_Outline_Get_CBox(&face->glyph->outline, &cbox); | |
Size cboxPxSize; | |
getBBoxPxSize(cbox, &cboxPxSize.w, &cboxPxSize.h); | |
if (cboxSizeBufIdx == face->num_glyphs) { | |
printf( | |
"Font returns more than face->num_glyphs (%li)\n", | |
face->num_glyphs); | |
break; | |
} | |
cboxSizeBuf[cboxSizeBufIdx++] = cboxPxSize; | |
FT_BBox bbox; | |
err = FT_Outline_Get_BBox(&face->glyph->outline, &bbox); | |
if (err != FT_Err_Ok) { | |
fprintf(stderr, "Can't get bbox for U+%04x\n", cp); | |
printFtError("FreeType error", err); | |
shutdown(EXIT_FAILURE); | |
} | |
Size bboxPxSize; | |
getBBoxPxSize(bbox, &bboxPxSize.w, &bboxPxSize.h); | |
if (bboxPxSize.w > cboxPxSize.w || bboxPxSize.h > cboxPxSize.h) | |
printf( | |
"U+%04X bbox > cbox: {%i, %i} > {%i, %i}\n", | |
cp, bboxPxSize.w, bboxPxSize.h, cboxPxSize.w, cboxPxSize.h); | |
} | |
} | |
static void checkBitmapVsCBox(void) | |
{ | |
printf("\nChecking bitmap vs cbox\n"); | |
unsigned cboxSizeBufIdx = 0; | |
for (unsigned cp = 1; cp <= MAX_UNICODE_CP; ++cp) { | |
if (cboxSizeBufIdx == face->num_glyphs) | |
break; | |
FT_UInt glyphIdx = FT_Get_Char_Index(face, cp); | |
if (glyphIdx == 0) | |
continue; | |
FT_Error err = FT_Load_Glyph(face, glyphIdx, FT_LOAD_DEFAULT); | |
if (err != FT_Err_Ok) { | |
fprintf(stderr, "Can't load glyph U+%04x", cp); | |
printFtError("FreeType error", err); | |
break; | |
} | |
err = FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL); | |
if (err != FT_Err_Ok) { | |
fprintf(stderr, "Can't render glyph U+%04X", cp); | |
printFtError("FreeType error", err); | |
break; | |
} | |
int bitmapW = face->glyph->bitmap.width; | |
int bitmapH = face->glyph->bitmap.rows; | |
Size cboxPxSize = cboxSizeBuf[cboxSizeBufIdx++]; | |
if (bitmapW > cboxPxSize.w || bitmapH > cboxPxSize.h) { | |
printf( | |
"U+%04X bitmap > cbox: {%i, %i} > {%i, %i}\n", | |
cp, bitmapW, bitmapH, cboxPxSize.w, cboxPxSize.h); | |
} | |
} | |
} | |
int main(int argc, char* argv[]) | |
{ | |
if (argc != 3) { | |
printf("Please give a path to a font and pt size\n"); | |
return EXIT_FAILURE; | |
} | |
init(argv[1], atoi(argv[2])); | |
checkCBoxVsBBox(); | |
checkBitmapVsCBox(); | |
shutdown(EXIT_SUCCESS); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment