/* * * This program outline_decompose.c is intended to illustrate strange * behaviors observed in freetype 2.1.0 and freetype 2.3.7 function * FT_Outline_Decompose() * * Usage: outline_decompose * * For example: outline_decompose MonoType.ttf M * * The font files should be available in the directory ./fonts * */ #include #include #include #include #include #include FT_ERRORS_H #include FT_FREETYPE_H #include FT_OUTLINE_H #include FT_GLYPH_H #define TRUE 1 #define FALSE 0 /* decomposition tracking index */ int tracking_index = 0; int end_point_expected = FALSE; typedef struct Payload_ { FT_Outline outline; int user; int shift; // int delta; FT_Pos delta; } Payload; /* * the next two global variables path_begun and path_ended are used * by the test for FT_Outline_Decompose. */ /* path_begun is used my the function move_to below */ int path_begun = 0; /* path_ended is used by the functions line_to, conic_to and cubic_to below */ int path_ended = 0; /* * This function returns 1 if the point, passed to it, is the end point of a contour * otherwise it returns 0 */ int is_a_contour_end_point(FT_Outline outline, FT_Vector* to, FT_Pos delta, int shift) { int i; int to_point_index; /* Get index of 'to' in outline.points */ i = 0; to_point_index = 0; printf("Input point is (%d,%d)\n", to->x, to->y); to->x = (to->x + delta)>>shift; to->y = (to->y + delta)>>shift; printf("Transformed back input point is (%d,%d)\n", to->x, to->y); printf("Starting to scan from %d.\n", tracking_index); i = tracking_index; while (i < (outline.n_points)) { if ( (((outline.points) + i)->x == to->x) && (((outline.points) + i)->y == to->y) ) { to_point_index = i; break; } i++; } printf("To_point index is %d.\n", to_point_index); /* update tracking index */ tracking_index = to_point_index +1; if (tracking_index >= outline.n_points) { tracking_index = 0; } /* Check if index is a contour end-point */ i = 0; while (i < outline.n_contours) { printf("Index of to_point is %d, contour end-point is %d\n", to_point_index, *((outline.contours) + i)); if (to_point_index == (*((outline.contours) + i)) ) { return 1; } i++; } return 0; } /* * Below are the functions move_to, line_to, conic_to & cubic_to * They use global variables end_point_expected, path_begun and path_ended declared above * */ int move_to( FT_Vector* to, void* payload ) { FT_Outline outline; FT_Pos delta = ((Payload *)payload)->delta; int shift = ((Payload *)payload)->shift; printf("Path begun. Entering move_to().\n"); path_begun++; end_point_expected = TRUE; outline = ((Payload *)payload)->outline; if (is_a_contour_end_point(outline, to, delta, shift) == 1) { printf("Path Ended inside move_to().\n"); path_ended++; } printf("\n"); ((Payload *)payload)->user = 0; return 0; } int line_to( FT_Vector* to, void* payload ) { FT_Outline outline; FT_Pos delta = ((Payload *)payload)->delta; int shift = ((Payload *)payload)->shift; printf("Entering line_to().\n"); outline = ((Payload *)payload)->outline; if (is_a_contour_end_point(outline, to, delta, shift) == 1) { printf("Path Ended inside line_to().\n"); path_ended++; } printf("\n"); ((Payload *)payload)->user = 0; return 0; } int conic_to( FT_Vector* control, FT_Vector* to, void* payload ) { FT_Outline outline; FT_Pos delta = ((Payload *)payload)->delta; int shift = ((Payload *)payload)->shift; outline = ((Payload *)payload)->outline; printf("Entering conic_to().\n"); if (is_a_contour_end_point(outline, to, delta, shift) == 1) { printf("Path ended inside conic_to().\n"); path_ended++; } printf("\n"); ((Payload *)payload)->user = 0; return 0; } int cubic_to( FT_Vector* control1, FT_Vector* control2, FT_Vector* to, void* payload ) { FT_Outline outline; FT_Pos delta = ((Payload *)payload)->delta; int shift = ((Payload *)payload)->shift; printf("Entering cubic_to().\n"); outline = ((Payload *)payload)->outline; if (is_a_contour_end_point(outline, to, delta, shift) == 1) { printf("Path ended inside of cubic_to().\n"); path_ended++; } printf("\n"); ((Payload *)payload)->user = 0; return 0; } //=============================================================================== // // Outline_Decompose // //=============================================================================== int main(int argc, char **argv) { #define CHAR_WIDTH_DEFAULT_SIZE 64 #define CHAR_HEIGHT_DEFAULT_SIZE 64 #define SHIFT 10 #define DELTA 5 FT_Library library = NULL; FT_Face face = NULL; FT_Glyph glyph = NULL; FT_Error error, err_dec; char file_face[80]; char char_test; int passed; int i, j; FT_Outline_Funcs func_interface; static FT_Vector last_point; int user; Payload payload; if( argc != 3 ) { printf("Invalid number of arguments.\n"); printf("You entered: "); i=0; while (i<(argc-1)) { printf("%s ",argv[i]); i++; } printf("%s\n",argv[i]); i=0; printf("CORRECT USAGE: outline_decompose \n"); printf("For example: outline_decompose FreeMono.ttf O\n"); printf("The font files should be available in the directory ./fonts\n"); return 0; } strcpy(file_face,"./fonts/"); strcat(file_face,argv[1]); char_test = argv[2][0]; printf("Decomposing the outline of the character %c of the font %s\n\n", char_test, file_face); error = FT_Init_FreeType( &library ); if( (error != 0) || (library == NULL) ) { printf("Cannot initialize a new FreeType library object.\n"); return 0; } error = FT_New_Face( library, file_face, 0, &face ); if( (error != 0) || (face == NULL) ) { printf("Cannot create a handle to face object.\n"); return 0; } if( FT_IS_SCALABLE(face) ) { error = FT_Set_Char_Size( face, CHAR_WIDTH_DEFAULT_SIZE, CHAR_HEIGHT_DEFAULT_SIZE, 0, 0 ); if( error != 0 ) { printf("Cannot set the character dimensions of a given face object.\n"); return 0; } FT_Set_Transform( face, 0, 0 ); } FT_Load_Char(face, char_test, 0); if( (face->glyph->format != FT_GLYPH_FORMAT_OUTLINE)) { printf("The glyph format is not outline.\n"); return 0; } error = FT_Get_Glyph( face->glyph, &glyph ); if (error != 0) { printf("Cannot get Glyph.\n"); return 0; } func_interface.shift = SHIFT; func_interface.delta = DELTA; func_interface.move_to = (FT_Outline_MoveToFunc) move_to; func_interface.line_to = (FT_Outline_LineToFunc) line_to; func_interface.conic_to = (FT_Outline_ConicToFunc) conic_to; func_interface.cubic_to = (FT_Outline_CubicToFunc) cubic_to; /* Initialize global variables */ path_begun = 0; path_ended = 0; payload.outline = face->glyph->outline; payload.user = -1; payload.shift = func_interface.shift; payload.delta = func_interface.delta; FT_Outline outline = face->glyph->outline; i=0; printf("The number of points in this outline is %d.\n\n", outline.n_points); while (i < (outline.n_points)) { printf("Outline point %d is (%d,%d)\n", i, ((outline.points) + i)->x, ((outline.points) + i)->y); i++; } i=0; printf("\nOutline end-of-contour points are: "); while (i < (outline.n_contours)) { if (i < ((outline.n_contours)-1)) { printf("%d, ", *((outline.contours) + i) ); } else { printf("%d\n\n", *((outline.contours) + i) ); } i++; } /* initializing decomposition tracking index */ tracking_index = 0; end_point_expected = FALSE; err_dec = FT_Outline_Decompose(&face->glyph->outline, &func_interface, (void *) &payload); printf("Decomposing the outline of the character %c of the font %s\n\n", char_test, file_face); printf("Number of paths started is %d, number of paths ended is %d\n", path_begun, path_ended); printf("Number of contours in the decomposed outline: %d.\n\n", outline.n_contours); user = payload.user; if ((user != 0) && (user != 1)) { printf("The function did not decompose the outline.\n"); return 0; } else { if (err_dec != 0) { printf("The decomposition of the character %c failed.]n", char_test); return 0; } else { if (path_begun == outline.n_contours) { printf("The function did emit a 'move_to' operation to start the decomposition of all contours in the outline of the char %c.\n", char_test); } else { printf("The function did not emit a 'move_to' operation to start the decomposition of all contours in the outline of the char %c.\n", char_test); } if (path_ended == outline.n_contours) { printf("The decomposition did close the decomposititon of all the contours in the outline of char %c.\n", char_test); } else { printf("The decomposition did not close the decomposititon of all the contours in the outline of char %c.\n", char_test); } } } // Clean-up if(face) { FT_Done_Face(face); } if(library) { FT_Done_FreeType(library); } }