Skip to content

Instantly share code, notes, and snippets.

@danpla
Last active November 20, 2017 13:09
Show Gist options
  • Save danpla/35292c7c54fc1217b81219aa442dcc37 to your computer and use it in GitHub Desktop.
Save danpla/35292c7c54fc1217b81219aa442dcc37 to your computer and use it in GitHub Desktop.
FreeType test
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})
#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