Skip to content

Instantly share code, notes, and snippets.

@xylcbd
Created June 14, 2016 08:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save xylcbd/739b31e1bc7cf03ef01c67479db16429 to your computer and use it in GitHub Desktop.
Save xylcbd/739b31e1bc7cf03ef01c67479db16429 to your computer and use it in GitHub Desktop.
freetype demo
#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