【嵌入式】利用freetype字型庫(繪製中文)
阿新 • • 發佈:2018-12-23
終極目標:利用freetype開源字型庫,實現在圖片上書寫一行字型大小變化的詩句(比如首字型增大) |
目錄
(一) 樹莓派3b+freetype2.4.10
1. 下載
我是在PC上下載好Linux版本,用teamviewer傳到派上的;也可以直接在pi上下載。
官網連結:https://sourceforge.net/projects/freetype/files/freetype2/
注意:
Linux系統下需要的版本為:freetype-2.*.*.tar.br2
;版本自選。
我選擇的是2.4.10,可任選
用teamviewer直接傳檔案到/home/pi目錄下:
2. 解壓及配置
- 進入命令模式
- 解壓(
對應版本
):
tar -xjf freetype-2.4.10.tar.bz2
- 進入安裝包:
cd freetype-2.4.10/
- 配置:
./configure
配置完成如圖:
- 編譯:(需要幾分鐘時間)
make
編譯完成如圖:
- 直接將庫安裝到根目錄/usr/local/裡,所以需要加sudo:
sudo make install
完成如圖:
3. 新增字型庫
- 檢視本地字型庫目錄
樹莓派:/usr/share/fonts
Windows:C:\Windows\Fonts
經檢視,我的pi目錄下沒有宋體(simhei.ttf)、(simsun.ttc)的字型檔案,我從pc上傳了一份過去,注意填寫的接收地址。
4. 一個簡單的Demo
- 新建資料夾
freetype_test
- 將剛才傳輸的
simsun.ttc
字型庫樣式複製到freetype_test
資料夾下 - 在
freetype_test
資料夾下建立test.cpp
- 編寫程式碼(這裡的原始碼我是參照網上的,先直接拖進去試試水)
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <ft2build.h>
#include FT_FREETYPE_H
#define WIDTH 80
#define HEIGHT 80
/* origin is the upper left corner */
unsigned char image[HEIGHT][WIDTH];
/* Replace this function with something useful. */
void
draw_bitmap( FT_Bitmap* bitmap,
FT_Int x,
FT_Int y)
{
FT_Int i, j, p, q;
FT_Int x_max = x + bitmap->width;
FT_Int y_max = y + bitmap->rows;
for ( i = x, p = 0; i < x_max; i++, p++ )
{
for ( j = y, q = 0; j < y_max; j++, q++ )
{
if ( i < 0 || j < 0 ||
i >= WIDTH || j >= HEIGHT )
continue;
image[j][i] |= bitmap->buffer[q * bitmap->width + p];
}
}
}
void
show_image( void )
{
int i, j;
for ( i = 0; i < HEIGHT; i++ )
{
for ( j = 0; j < WIDTH; j++ )
putchar( image[i][j] == 0 ? ' '
: image[i][j] < 128 ? '+'
: '*' );
putchar( '\n' );
}
}
int
main( int argc,
char** argv )
{
FT_Library library;
FT_Face face;
FT_GlyphSlot slot;
FT_Matrix matrix; /* transformation matrix */
FT_Vector pen; /* untransformed origin */
FT_Error error;
char* filename;
char* text;
double angle;
int target_height;
int n, num_chars;
if ( argc != 3 )
{
fprintf ( stderr, "usage: %s font sample-text\n", argv[0] );
exit( 1 );
}
filename = argv[1]; /* first argument */
text = argv[2]; /* second argument */
num_chars = strlen( text );
angle = ( 0.0 / 360 ) * 3.14159 * 2; /* use 25 degrees */
target_height = HEIGHT;
error = FT_Init_FreeType( &library ); /* initialize library */
/* error handling omitted */
error = FT_New_Face( library, argv[1], 0, &face ); /* create face object */
/* error handling omitted */
#if 0
/* use 50pt at 100dpi */
error = FT_Set_Char_Size( face, 50 * 64, 0,
100, 0 ); /* set character size */
/* pixels = 50 /72 * 100 = 69 */
#else
FT_Set_Pixel_Sizes(face, 24, 0);
#endif
/* error handling omitted */
slot = face->glyph;
/* set up matrix */
matrix.xx = (FT_Fixed)( cos( angle ) * 0x10000L );
matrix.xy = (FT_Fixed)(-sin( angle ) * 0x10000L );
matrix.yx = (FT_Fixed)( sin( angle ) * 0x10000L );
matrix.yy = (FT_Fixed)( cos( angle ) * 0x10000L );
/* the pen position in 26.6 cartesian space coordinates; */
/* start at (0,40) relative to the upper left corner */
pen.x = 0 * 64;
pen.y = ( target_height - 40 ) * 64;
for ( n = 0; n < num_chars; n++ )
{
/* set transformation */
FT_Set_Transform( face, &matrix, &pen );
/* load glyph image into the slot (erase previous one) */
error = FT_Load_Char( face, text[n], FT_LOAD_RENDER );
if ( error )
continue; /* ignore errors */
/* now, draw to our target surface (convert position) */
draw_bitmap( &slot->bitmap,
slot->bitmap_left,
target_height - slot->bitmap_top );
/* increment pen position */
pen.x += slot->advance.x;
pen.y += slot->advance.y;
}
show_image();
FT_Done_Face ( face );
FT_Done_FreeType( library );
return 0;
}
- 儲存
- 回到命令列介面
- 編譯
gcc -o test test.cpp -I/usr/local/include/freetype2/ -lfreetype -lm
- 執行
./test ./simsun.ttc cungu
- 結果
配置成功!
5.freetype2+opencv3在圖片上繪製中文
參考連結:http://lib.csdn.net/article/opencv/53782?tdsourcetag=s_pcqq_aiomsg
- 新建
freetype_test
資料夾,把simhei.ttf
字型庫和圖片lena.jpg
複製進來,新建freetype_test.cpp
程式
- 執行測試()
g++ -o freetype_test freetype_test.cpp `pkg-config --cflags --libs opencv` -I/usr/local/include/freetype2/ -lfreetype -lm
- 原始碼
#include <ft2build.h>
#include FT_FREETYPE_H
#include <highgui.h>
#include <wchar.h>
#include <assert.h>
#include <locale.h>
#include <ctype.h>
#include <opencv2/opencv.hpp>
#include<iostream>
using namespace std;
using namespace cv;
class CvText
{
//================================================================
//================================================================
public:
/**
* 裝載字型檔檔案
*/
CvText(const char *freeType);
virtual ~CvText();
//================================================================
//================================================================
/**
* 獲取字型。目前有些引數尚不支援。
*
* \param font 字型型別, 目前不支援
* \param size 字型大小/空白比例/間隔比例/旋轉角度
* \param underline 下畫線
* \param diaphaneity 透明度
*
* \sa setFont, restoreFont
*/
void getFont(int *type,
CvScalar *size = NULL, bool *underline = NULL, float *diaphaneity = NULL);
/**
* 設定字型。目前有些引數尚不支援。
*
* \param font 字型型別, 目前不支援
* \param size 字型大小/空白比例/間隔比例/旋轉角度
* \param underline 下畫線
* \param diaphaneity 透明度
*
* \sa getFont, restoreFont
*/
void setFont(int *type,
CvScalar *size = NULL, bool *underline = NULL, float *diaphaneity = NULL);
/**
* 恢復原始的字型設定。
*
* \sa getFont, setFont
*/
void restoreFont();
//================================================================
//================================================================
/**
* 輸出漢字(顏色預設為黑色)。遇到不能輸出的字元將停止。
*
* \param img 輸出的影象
* \param text 文字內容
* \param pos 文字位置
*
* \return 返回成功輸出的字元長度,失敗返回-1。
*/
int putText(cv::Mat &frame, const char *text, CvPoint pos);
/**
* 輸出漢字(顏色預設為黑色)。遇到不能輸出的字元將停止。
*
* \param img 輸出的影象
* \param text 文字內容
* \param pos 文字位置
*
* \return 返回成功輸出的字元長度,失敗返回-1。
*/
int putText(cv::Mat &frame, const wchar_t *text, CvPoint pos);
/**
* 輸出漢字。遇到不能輸出的字元將停止。
*
* \param img 輸出的影象
* \param text 文字內容
* \param pos 文字位置
* \param color 文字顏色
*
* \return 返回成功輸出的字元長度,失敗返回-1。
*/
int putText(cv::Mat &frame, const char *text, CvPoint pos, CvScalar color);
/**
* 輸出漢字。遇到不能輸出的字元將停止。
*
* \param img 輸出的影象
* \param text 文字內容
* \param pos 文字位置
* \param color 文字顏色
*
* \return 返回成功輸出的字元長度,失敗返回-1。
*/
int putText(cv::Mat &frame, const wchar_t *text, CvPoint pos, CvScalar color);
//================================================================
//================================================================
private:
// 輸出當前字元, 更新m_pos位置
void putWChar(cv::Mat &frame, wchar_t wc, CvPoint &pos, CvScalar color);
//================================================================
//================================================================
private:
FT_Library m_library; // 字型檔
FT_Face m_face; // 字型
//================================================================
//================================================================
// 預設的字型輸出引數
int m_fontType;
CvScalar m_fontSize;
bool m_fontUnderline;
float m_fontDiaphaneity;
//================================================================
//================================================================
};
int main()
{
cv::Mat img = imread("lena.jpg");
CvText text("simhei.ttf");
const char *msg = "黑 體freetype";//字型檔要求輸入中文時中間必須有一個間隔
float p = 0.5;
text.setFont(NULL, NULL, NULL, &p); // 透明處理
text.putText(img, msg, cvPoint(30, 30), CV_RGB(255, 255, 0));
imshow("freetype_test", img);
waitKey(-1);
return 0;
}
CvText::CvText(const char *freeType)
{
assert(freeType != NULL);
// 開啟字型檔檔案, 建立一個字型
if (FT_Init_FreeType(&m_library)) throw;
if (FT_New_Face(m_library, freeType, 0, &m_face)) throw;
// 設定字型輸出引數
restoreFont();
// 設定C語言的字符集環境
setlocale(LC_ALL, "");
}
// 釋放FreeType資源
CvText::~CvText()
{
FT_Done_Face(m_face);
FT_Done_FreeType(m_library);
}
// 設定字型引數:
//
// font - 字型型別, 目前不支援
// size - 字型大小/空白比例/間隔比例/旋轉角度
// underline - 下畫線
// diaphaneity - 透明度
void CvText::getFont(int *type, CvScalar *size, bool *underline, float *diaphaneity)
{
if (type) *type = m_fontType;
if (size) *size = m_fontSize;
if (underline) *underline = m_fontUnderline;
if (diaphaneity) *diaphaneity = m_fontDiaphaneity;
}
void CvText::setFont(int *type, CvScalar *size, bool *underline, float *diaphaneity)
{
// 引數合法性檢查
if (type)
{
if (type >= 0) m_fontType = *type;
}
if (size)
{
m_fontSize.val[0] = fabs(size->val[0]);
m_fontSize.val[1] = fabs(size->val[1]);
m_fontSize.val[2] = fabs(size->val[2]);
m_fontSize.val[3] = fabs(size->val[3]);
}
if (underline)
{
m_fontUnderline = *underline;
}
if (diaphaneity)
{
m_fontDiaphaneity = *diaphaneity;
}
FT_Set_Pixel_Sizes(m_face, (int)m_fontSize.val[0], 0);
}
// 恢復原始的字型設定
void CvText::restoreFont()
{
m_fontType = 0; // 字型型別(不支援)
m_fontSize.val[0] = 30; // 字型大小
m_fontSize.val[1] = 0.5; // 空白字元大小比例
m_fontSize.val[2] = 0.1; // 間隔大小比例
m_fontSize.val[3] = 0; // 旋轉角度(不支援)
m_fontUnderline = false; // 下畫線(不支援)
m_fontDiaphaneity = 1.0; // 色彩比例(可產生透明效果)
// 設定字元大小
FT_Set_Pixel_Sizes(m_face, (int)m_fontSize.val[0], 0);
}
// 輸出函式(顏色預設為黑色)
int CvText::putText(cv::Mat &frame, const char *text, CvPoint pos)
{
return putText(frame, text, pos, CV_RGB(255, 255, 255));
}
int CvText::putText(cv::Mat &frame, const wchar_t *text, CvPoint pos)
{
return putText(frame, text, pos, CV_RGB(255, 255, 255));
}
//
int CvText::putText(cv::Mat &frame, const char *text, CvPoint pos, CvScalar color)
{
if (frame.empty()) return -1;
if (text == NULL) return -1;
//
int i;
for (i = 0; text[i] != '\0'; ++i)
{
wchar_t wc = text[i];
// 解析雙位元組符號
if (!isascii(wc)) mbtowc(&wc, &text[i++], 2);
// 輸出當前的字元
putWChar(frame, wc, pos, color);
}
return i;
}
int CvText::putText(cv::Mat &frame, const wchar_t *text, CvPoint pos, CvScalar color)
{
if (frame.empty