Created
June 14, 2016 08:51
-
-
Save xylcbd/739b31e1bc7cf03ef01c67479db16429 to your computer and use it in GitHub Desktop.
freetype demo
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 <cstdio> | |
#include <cstring> | |
// FreeType headers | |
#include <ft2build.h> | |
#include FT_FREETYPE_H | |
// OpenCV headers | |
#include <opencv2/core/core.hpp> | |
#include <opencv2/highgui/highgui.hpp> | |
#include <memory> | |
#include <functional> | |
#include <iostream> | |
class ScopeExit { | |
public: | |
ScopeExit(std::function<void()> f) : f_(f) {} | |
~ScopeExit() { f_(); } | |
private: | |
std::function<void()> f_; | |
}; | |
static std::vector<uint32_t> local2utf32(const std::string& localContent) | |
{ | |
std::vector<uint32_t> result; | |
//TODO | |
//english only!!!! | |
for (int i = 0; i < localContent.size();i++) | |
{ | |
result.push_back(localContent[i]); | |
} | |
return result; | |
} | |
cv::Mat generateSample(const char* FONT_FILE, const char* STR) | |
{ | |
const int PIXEL_SIZE = 32, COLOR_BLUE = 255, COLOR_GREEN = 255, COLOR_RED = 0; | |
cv::Mat result; | |
// Initialize FreeType | |
FT_Library ft_library; | |
int ret = FT_Init_FreeType(&ft_library); | |
if (ret != 0) { | |
fprintf(stderr, "FT_Init_FreeType() failed.\n"); | |
return result; | |
} | |
SCOPEEXIT(FT_Done_FreeType(ft_library);); | |
FT_Face ft_face; | |
ret = FT_New_Face(ft_library, FONT_FILE, 0, &ft_face); | |
if (ret != 0) { | |
fprintf(stderr, "FT_New_Face() failed.\n"); | |
return result; | |
} | |
ScopeExit ft_face_done([&ft_face]() { | |
FT_Done_Face(ft_face); | |
}); | |
ret = FT_Set_Pixel_Sizes(ft_face, PIXEL_SIZE, PIXEL_SIZE); | |
if (ret != 0) { | |
fprintf(stderr, "FT_Set_Pixel_Sizes() failed.\n"); | |
return result; | |
} | |
// FreeType uses Unicode as glyph index; so we have to convert string from UTF8 to Unicode(UTF32) | |
const std::vector<uint32_t> utf32_str = local2utf32(STR); | |
const size_t utf32_length = utf32_str.size(); | |
// Get total width | |
int total_width = 0; | |
int max_height = 0; | |
for (int i = 0; i < utf32_length; i++) { | |
FT_UInt glyph_index = FT_Get_Char_Index(ft_face, utf32_str[i]); | |
// Have to use FT_LOAD_RENDER. | |
// If use FT_LOAD_DEFAULT, the actual glyph bitmap won't be loaded, | |
// thus bitmap->rows will be incorrect, causing insufficient max_height. | |
ret = FT_Load_Glyph(ft_face, glyph_index, FT_LOAD_RENDER); | |
if (ret != 0) { | |
fprintf(stderr, "FT_Load_Glyph() failed.\n"); | |
return result; | |
} | |
total_width += (ft_face->glyph->advance.x >> 6); | |
FT_Bitmap *bitmap = &(ft_face->glyph->bitmap); | |
int top = (ft_face->ascender >> 6) - ft_face->glyph->bitmap_top; | |
if (top < 0) | |
top = 0; | |
max_height = std::max(max_height, top + (int)bitmap->rows); | |
} | |
// Copy grayscale image from FreeType to OpenCV | |
cv::Mat gray(max_height, total_width, CV_8UC1, cv::Scalar::all(0)); | |
int x = 0; | |
for (int i = 0; i < utf32_length; i++) { | |
FT_UInt glyph_index = FT_Get_Char_Index(ft_face, utf32_str[i]); | |
ret = FT_Load_Glyph(ft_face, glyph_index, FT_LOAD_RENDER); | |
if (ret != 0) { | |
fprintf(stderr, "FT_Load_Glyph() failed.\n"); | |
return result; | |
} | |
FT_Bitmap *bitmap = &(ft_face->glyph->bitmap); | |
cv::Mat glyph_img(bitmap->rows, bitmap->width, CV_8UC1, bitmap->buffer, bitmap->pitch); | |
int top = (ft_face->ascender >> 6) - ft_face->glyph->bitmap_top; | |
if (top < 0) | |
top = 0; | |
cv::Mat gray_part(gray, cv::Rect(std::min((int)(gray.cols - bitmap->width), (int)(x + ft_face->glyph->bitmap_left)), top,bitmap->width, bitmap->rows)); | |
glyph_img.copyTo(gray_part); | |
x += (ft_face->glyph->advance.x >> 6); | |
} | |
// Merge. The grayscale image act as an alpha channel. | |
cv::Mat b(gray.size(), CV_8UC1, cv::Scalar::all(COLOR_BLUE)); | |
cv::Mat g(gray.size(), CV_8UC1, cv::Scalar::all(COLOR_GREEN)); | |
cv::Mat r(gray.size(), CV_8UC1, cv::Scalar::all(COLOR_RED)); | |
for (int i = 0; i < b.rows; i++) { | |
for (int j = 0; j < b.cols; j++) { | |
double alpha = (double)gray.at<uint8_t>(i, j) / 255; | |
b.at<uint8_t>(i, j) *= alpha; | |
g.at<uint8_t>(i, j) *= alpha; | |
r.at<uint8_t>(i, j) *= alpha; | |
} | |
} | |
std::vector<cv::Mat> channels = { b, g, r }; | |
cv::merge(channels, result); | |
return result; | |
} | |
int main() { | |
// Change the following to suit your need. | |
const std::string FONT_FILE = "../res/fonts/Arial/arialbi.ttf"; | |
std::string STR; | |
while (true) | |
{ | |
std::cout << "input content :"; | |
std::getline(std::cin, STR); | |
const cv::Mat result = generateSample(FONT_FILE.c_str(), STR.c_str()); | |
// Show the image | |
cv::imshow("image", result); | |
cv::waitKey(0); | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment