Server IP : 92.204.138.22 / Your IP : 18.188.150.210 Web Server : Apache System : Linux ns1009439.ip-92-204-138.us 4.18.0-553.8.1.el8_10.x86_64 #1 SMP Tue Jul 2 07:26:33 EDT 2024 x86_64 User : internationaljou ( 1019) PHP Version : 7.4.33 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : ON | Sudo : ON | Pkexec : ON Directory : /proc/self/root/proc/thread-self/root/usr/share/doc/freetype-devel/tutorial/ |
Upload File : |
// example5.cpp // This program is a simple example that prints a character's outline in the // SVG format to stdout, demonstrating the usage of FT_Outline_Decompose(). // // Developed by Static Jobs LLC and contributed to the FreeType project. // // Copyright (c) 2016 Static Jobs LLC // IT and software engineering jobs in the US, Canada and the UK // https://www.staticjobs.com // // License: MIT (see below) // // The source code was reformatted by Werner Lemberg, also including a few // minor code changes and comments for didactic purposes. // // On a Unix box like GNU/Linux or OS X, compile with // // g++ -o example5 example5.cpp `freetype-config --cflags --libs` // // or // // g++ -o example5 example5.cpp `pkg-config freetype2 --cflags --libs` // // on the command line. // // On other platforms that don't have the `freetype-config' shell script or // the `pkg-config' tool, you have to pass the necessary compiler flags // manually. // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to permit // persons to whom the Software is furnished to do so, subject to the // following conditions: // // The above copyright notice and this permission notice shall be included // in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT // OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR // THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include <iostream> #include <sstream> #include <stdexcept> #include <cstring> #include <cctype> #include <ft2build.h> #include FT_FREETYPE_H #include FT_OUTLINE_H #include FT_BBOX_H using namespace std; struct FreeTypeLibrary { FreeTypeLibrary(); ~FreeTypeLibrary(); FT_Library m_ftLibrary; }; inline FreeTypeLibrary::FreeTypeLibrary() { FT_Error error = FT_Init_FreeType(&m_ftLibrary); if (error) throw runtime_error("Couldn't initialize the library:" " FT_Init_FreeType() failed"); } inline FreeTypeLibrary::~FreeTypeLibrary() { FT_Done_FreeType(m_ftLibrary); } struct FreeTypeFace { FreeTypeFace(const FreeTypeLibrary &library, const char *filename); ~FreeTypeFace(); FT_Face m_ftFace; }; inline FreeTypeFace::FreeTypeFace(const FreeTypeLibrary &library, const char *filename) { // For simplicity, always use the first face index. FT_Error error = FT_New_Face(library.m_ftLibrary, filename, 0, &m_ftFace); if (error) throw runtime_error("Couldn't load the font file:" " FT_New_Face() failed"); } inline FreeTypeFace::~FreeTypeFace() { FT_Done_Face(m_ftFace); } class OutlinePrinter { public: OutlinePrinter(const char *filename); int Run(const char *symbol); private: void LoadGlyph(const char *symbol) const; bool OutlineExists() const; void FlipOutline() const; void ExtractOutline(); void ComputeViewBox(); void PrintSVG() const; static int MoveToFunction(const FT_Vector *to, void *user); static int LineToFunction(const FT_Vector *to, void *user); static int ConicToFunction(const FT_Vector *control, const FT_Vector *to, void *user); static int CubicToFunction(const FT_Vector *controlOne, const FT_Vector *controlTwo, const FT_Vector *to, void *user); private: // These two lines initialize the library and the face; // the order is important! FreeTypeLibrary m_library; FreeTypeFace m_face; ostringstream m_path; // These four variables are for the `viewBox' attribute. FT_Pos m_xMin; FT_Pos m_yMin; FT_Pos m_width; FT_Pos m_height; }; inline OutlinePrinter::OutlinePrinter(const char *filename) : m_face(m_library, filename), m_xMin(0), m_yMin(0), m_width(0), m_height(0) { // Empty body. } int OutlinePrinter::Run(const char *symbol) { LoadGlyph(symbol); // Check whether outline exists. bool outlineExists = OutlineExists(); if (!outlineExists) // Outline doesn't exist. throw runtime_error("Outline check failed.\n" "Please, inspect your font file or try another one," " for example LiberationSerif-Bold.ttf"); FlipOutline(); ExtractOutline(); ComputeViewBox(); PrintSVG(); return 0; } void OutlinePrinter::LoadGlyph(const char *symbol) const { FT_ULong code = symbol[0]; // For simplicity, use the charmap FreeType provides by default; // in most cases this means Unicode. FT_UInt index = FT_Get_Char_Index(m_face.m_ftFace, code); FT_Error error = FT_Load_Glyph(m_face.m_ftFace, index, FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP); if (error) throw runtime_error("Couldn't load the glyph: FT_Load_Glyph() failed"); } // While working on this example, we found fonts with no outlines for // printable characters such as `A', i.e., `outline.n_contours' and // `outline.n_points' were zero. FT_Outline_Check() returned `true'. // FT_Outline_Decompose() also returned `true' without walking the outline. // That is, we had no way of knowing whether the outline existed and could // be (or was) decomposed. Therefore, we implemented this workaround to // check whether the outline does exist and can be decomposed. bool OutlinePrinter::OutlineExists() const { FT_Face face = m_face.m_ftFace; FT_GlyphSlot slot = face->glyph; FT_Outline &outline = slot->outline; if (slot->format != FT_GLYPH_FORMAT_OUTLINE) return false; // Should never happen. Just an extra check. if (outline.n_contours <= 0 || outline.n_points <= 0) return false; // Can happen for some font files. FT_Error error = FT_Outline_Check(&outline); return error == 0; } // FreeType and SVG use opposite vertical directions. void OutlinePrinter::FlipOutline() const { const FT_Fixed multiplier = 65536L; FT_Matrix matrix; matrix.xx = 1L * multiplier; matrix.xy = 0L * multiplier; matrix.yx = 0L * multiplier; matrix.yy = -1L * multiplier; FT_Face face = m_face.m_ftFace; FT_GlyphSlot slot = face->glyph; FT_Outline &outline = slot->outline; FT_Outline_Transform(&outline, &matrix); } void OutlinePrinter::ExtractOutline() { m_path << " <path d='\n"; FT_Outline_Funcs callbacks; callbacks.move_to = MoveToFunction; callbacks.line_to = LineToFunction; callbacks.conic_to = ConicToFunction; callbacks.cubic_to = CubicToFunction; callbacks.shift = 0; callbacks.delta = 0; FT_Face face = m_face.m_ftFace; FT_GlyphSlot slot = face->glyph; FT_Outline &outline = slot->outline; FT_Error error = FT_Outline_Decompose(&outline, &callbacks, this); if (error) throw runtime_error("Couldn't extract the outline:" " FT_Outline_Decompose() failed"); m_path << " '\n" " fill='red'/>\n"; } void OutlinePrinter::ComputeViewBox() { FT_Face face = m_face.m_ftFace; FT_GlyphSlot slot = face->glyph; FT_Outline &outline = slot->outline; FT_BBox boundingBox; FT_Outline_Get_BBox(&outline, &boundingBox); FT_Pos xMin = boundingBox.xMin; FT_Pos yMin = boundingBox.yMin; FT_Pos xMax = boundingBox.xMax; FT_Pos yMax = boundingBox.yMax; m_xMin = xMin; m_yMin = yMin; m_width = xMax - xMin; m_height = yMax - yMin; } void OutlinePrinter::PrintSVG() const { cout << "<svg xmlns='http://www.w3.org/2000/svg'\n" " xmlns:xlink='http://www.w3.org/1999/xlink'\n" " viewBox='" << m_xMin << ' ' << m_yMin << ' ' << m_width << ' ' << m_height << "'>\n" << m_path.str() << "</svg>" << endl; } int OutlinePrinter::MoveToFunction(const FT_Vector *to, void *user) { OutlinePrinter *self = static_cast<OutlinePrinter *>(user); FT_Pos x = to->x; FT_Pos y = to->y; self->m_path << " " "M " << x << ' ' << y << '\n'; return 0; } int OutlinePrinter::LineToFunction(const FT_Vector *to, void *user) { OutlinePrinter *self = static_cast<OutlinePrinter *>(user); FT_Pos x = to->x; FT_Pos y = to->y; self->m_path << " " "L " << x << ' ' << y << '\n'; return 0; } int OutlinePrinter::ConicToFunction(const FT_Vector *control, const FT_Vector *to, void *user) { OutlinePrinter *self = static_cast<OutlinePrinter *>(user); FT_Pos controlX = control->x; FT_Pos controlY = control->y; FT_Pos x = to->x; FT_Pos y = to->y; self->m_path << " " "Q " << controlX << ' ' << controlY << ", " << x << ' ' << y << '\n'; return 0; } int OutlinePrinter::CubicToFunction(const FT_Vector *controlOne, const FT_Vector *controlTwo, const FT_Vector *to, void *user) { OutlinePrinter *self = static_cast<OutlinePrinter *>(user); FT_Pos controlOneX = controlOne->x; FT_Pos controlOneY = controlOne->y; FT_Pos controlTwoX = controlTwo->x; FT_Pos controlTwoY = controlTwo->y; FT_Pos x = to->x; FT_Pos y = to->y; self->m_path << " " "C " << controlOneX << ' ' << controlOneY << ", " << controlTwoX << ' ' << controlTwoY << ", " << x << ' ' << y << '\n'; return 0; } int main(int argc, char **argv) { if (argc != 3) { const char *program = argv[0]; cerr << "This program prints a single character's outline" " in the SVG format to stdout.\n" "Usage: " << program << " font symbol\n" "Example: " << program << " LiberationSerif-Bold.ttf A" << endl; return 1; } const char *symbol = argv[2]; // For simplicity, only accept single-byte characters like `A'. if (strlen(symbol) != 1 || isspace(*symbol)) { cerr << "Error: '" << symbol << "' is not a single printable character" << endl; return 2; } int status; try { const char *filename = argv[1]; OutlinePrinter printer(filename); status = printer.Run(symbol); } catch (const exception &e) { cerr << "Error: " << e.what() << endl; status = 3; } return status; } // EOF