qt char*转int_Qt在Linux下绘制文字原理-使用FreeType来绘制字形
生活随笔
收集整理的這篇文章主要介紹了
qt char*转int_Qt在Linux下绘制文字原理-使用FreeType来绘制字形
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
原文鏈接
Qt源碼那些事兒-Qt繪制文字原理_使用FreeType來繪制字形?www.cryfeifei.cn前言
Qt在Linux繪制字體是使用的FreeType。
FreeType是一個(gè)用C語言實(shí)現(xiàn)的一個(gè)字體光柵化庫。它可以用來將字符柵格化并映射成位圖以及提供其他字體相關(guān)業(yè)務(wù)的支持。 FreeType并不提供API以運(yùn)行更高級的功能,如文字布局或圖形處理(例如彩色文本渲染、“空洞化”等)。然而,它提供了一個(gè)簡單、易用并統(tǒng)一的接口來訪問字體文件的內(nèi)容,從而極大地簡化了這些任務(wù)。它支持各種字體格式,包括TrueType、Type 1、以及OpenType。 FreeType在兩個(gè)自由軟件許可證的許可下發(fā)布:GNU通用公共許可證或者以及一個(gè)類BSD許可證。因此這個(gè)庫能夠使用于任何類型的項(xiàng)目中,無論其是否是專有軟件。同時(shí)也包括正在使用的主要自由桌面系統(tǒng)軟件。流程很簡單,Qt在繪制字體時(shí),首先將字體中的描述點(diǎn)以及字形信息保存到QPainterPath中。然后再繪制出來。
下面的代碼是我從Qt中扣出來了,這是Qt具體描點(diǎn)到Path的過程,Qt在繪制大號字體的時(shí)候會(huì)調(diào)用下面的邏輯
下面上代碼
代碼
pro文件中加
LIBS += -lfreetype INCLUDEPATH += /usr/include/freetype2頭文件
#include <freetype2/ft2build.h>#include <freetype2/freetype/freetype.h> #include <freetype/freetype.h> #include <freetype/ftoutln.h> static void scaleOutline(FT_Face face, FT_GlyphSlot g, FT_Fixed x_scale, FT_Fixed y_scale, QVector<QPoint>& vectors) {x_scale = FT_MulDiv(x_scale, 1 << 10, face->units_per_EM);y_scale = FT_MulDiv(y_scale, 1 << 10, face->units_per_EM);FT_Vector *p = g->outline.points;const FT_Vector *e = p + g->outline.n_points;while (p < e) {p->x = FT_MulFix(p->x, x_scale);p->y = FT_MulFix(p->y, y_scale);vectors.push_back(QPoint(p->x, p->y));++p;} }// 將字形中的 #define GLYPH2PATH_DEBUG QT_NO_QDEBUG_MACRO // qDebug void addGlyphToPath(FT_Face face, FT_GlyphSlot g, const QFixedPoint &point, QPainterPath *path, FT_Fixed x_scale, FT_Fixed y_scale) {const qreal factor = 1/64.;QVector<QPoint> vectors;scaleOutline(face, g, x_scale, y_scale, vectors);//int xMin = 0;int xMax = 0;foreach (QPoint point, vectors){if (point.x() > xMax)xMax = point.x();if (point.x() < xMin)xMin = point.x();}int glyphWidth = xMax - xMin;QPointF cp = point.toPointF();// convert the outline to a painter pathint i = 0;for (int j = 0; j < g->outline.n_contours; ++j) {int last_point = g->outline.contours[j];GLYPH2PATH_DEBUG() << "contour:" << i << "to" << last_point;QPointF start = QPointF(g->outline.points[i].x*factor, -g->outline.points[i].y*factor);if (!(g->outline.tags[i] & 1)) { // start point is not on curve:if (!(g->outline.tags[last_point] & 1)) { // end point is not on curve:GLYPH2PATH_DEBUG() << " start and end point are not on curve";start = (QPointF(g->outline.points[last_point].x*factor,-g->outline.points[last_point].y*factor) + start) / 2.0;} else {GLYPH2PATH_DEBUG() << " end point is on curve, start is not";start = QPointF(g->outline.points[last_point].x*factor,-g->outline.points[last_point].y*factor);}--i; // to use original start point as control point below}start += cp;GLYPH2PATH_DEBUG() << " start at" << start;path->moveTo(start);QPointF c[4];c[0] = start;int n = 1;while (i < last_point) {++i;c[n] = cp + QPointF(g->outline.points[i].x*factor, -g->outline.points[i].y*factor);GLYPH2PATH_DEBUG() << " " << i << c[n] << "tag =" << (int)g->outline.tags[i]<< ": on curve =" << (bool)(g->outline.tags[i] & 1);++n;switch (g->outline.tags[i] & 3) {case 2:// cubic bezier elementif (n < 4)continue;c[3] = (c[3] + c[2])/2;--i;break;case 0:// quadratic bezier elementif (n < 3)continue;c[3] = (c[1] + c[2])/2;c[2] = (2*c[1] + c[3])/3;c[1] = (2*c[1] + c[0])/3;--i;break;case 1:case 3:if (n == 2) {GLYPH2PATH_DEBUG() << " lineTo" << c[1];path->lineTo(c[1]);c[0] = c[1];n = 1;continue;} else if (n == 3) {c[3] = c[2];c[2] = (2*c[1] + c[3])/3;c[1] = (2*c[1] + c[0])/3;}break;}GLYPH2PATH_DEBUG() << " cubicTo" << c[1] << c[2] << c[3];path->cubicTo(c[1], c[2], c[3]);c[0] = c[3];n = 1;}if (n == 1) {GLYPH2PATH_DEBUG() << " closeSubpath";path->closeSubpath();} else {c[3] = start;if (n == 2) {c[2] = (2*c[1] + c[3])/3;c[1] = (2*c[1] + c[0])/3;}GLYPH2PATH_DEBUG() << " close cubicTo" << c[1] << c[2] << c[3];path->cubicTo(c[1], c[2], c[3]);}++i;} }/////這里是調(diào)用freetype相關(guān)的函數(shù)QPainterPath path;FT_Library library;FT_Face face;FT_Error error = FT_Init_FreeType( &library );QString strFileName = QString::fromUtf8("/home/zhangpf/freeType/FZXBSJW_0.TTF");std::string strFile = strFileName.toStdString();const char* fileName = strFile.c_str();error = FT_New_Face(library, fileName, 0, &face );uint ch = 'h';FT_UInt idxGlyph = FT_Get_Char_Index(face, ch);FT_Set_Char_Size(face, face->units_per_EM << 6, face->units_per_EM << 6, 0, 0);// 這是斜體 // FT_Matrix matrix; // double angle = ( 25.0 / 360 ) * 3.14159 * 2; // 180/12=15 度 // matrix.xx = (FT_Fixed)(cos(angle) * 0x10000); // matrix.xy = (FT_Fixed)(-sin(angle) * 0x10000); // matrix.yx = (FT_Fixed)(sin(angle) * 0x10000); // matrix.yy = (FT_Fixed)(cos(angle) * 0x10000); // FT_Set_Transform(face, &matrix, 0); // 設(shè)置或重置旋轉(zhuǎn)FT_Error err = FT_Load_Glyph (face, idxGlyph, FT_LOAD_NO_BITMAP);FT_BBox bbox = { 0 };FT_Outline_Get_CBox(&face->glyph->outline, &bbox);/* only oblique outline glyphs */if ( face->glyph->format != FT_GLYPH_FORMAT_OUTLINE )return;// 用這個(gè)也可以縮放一半// FT_Outline* outline = &(face->glyph->outline); // FT_Matrix transform; // transform.xx = 0x10000L * 0.5; // transform.yx = 0x00000L; // transform.xy = 0x00000L; // transform.yy = 0x10000L; // FT_Outline_Transform( outline, &transform );QFixedPoint p;p.x = 0;p.y = 0;if (!FT_IS_SCALABLE(face)){qDebug()<<"123"<<endl;}elseaddGlyphToPath(face, face->glyph, p, &path, (face->units_per_EM << 6) / 2, face->units_per_EM << 6); //寬度縮放一半最后在paintevent中可以繪制出來,由于字形的point中有負(fù)數(shù),painter需要transform一下
QPainter painter(this);QTransform transform;transform.translate(500,500);painter.setTransform(transform);painter.drawPath(path);這是Qt繪制文字的一部分邏輯,我扣出來Demo來給大家學(xué)習(xí)。主要是使用了QPainterPath來描述字體中的點(diǎn),以及保存成字體中的貝塞爾曲線。生成QPainterPath來描述具體的字形。代碼中我還添加了縮放的變形,實(shí)際上字體的繪制變形有很多方法。就拿縮放來講,就有這么幾種
// 用這個(gè)也可以縮放一半FT_Outline* outline = &(face->glyph->outline); FT_Matrix transform; transform.xx = 0x10000L * 0.5; transform.yx = 0x00000L; transform.xy = 0x00000L; transform.yy = 0x10000L;FT_Outline_Transform( outline, &transform );// 這是斜體實(shí)現(xiàn),matrix.xx * 0.5 可以縮放 0.5倍 FT_Matrix matrix; double angle = ( 25.0 / 360 ) * 3.14159 * 2; // 25 度 matrix.xx = (FT_Fixed)(cos(angle) * 0x10000); matrix.xy = (FT_Fixed)(-sin(angle) * 0x10000); matrix.yx = (FT_Fixed)(sin(angle) * 0x10000); matrix.yy = (FT_Fixed)(cos(angle) * 0x10000); FT_Set_Transform(face, &matrix, 0); // 設(shè)置或重置旋轉(zhuǎn)//甚至可以在 點(diǎn)->path這一步來做 (face->units_per_EM << 6) / 2,//addGlyphToPath(face, face->glyph, p, &path, (face->units_per_EM << 6) / 2, face->units_per_EM << 6); //寬度縮放一半(face->units_per_EM << 6) / 2,所以大部分UI庫都有自己的實(shí)現(xiàn)方法。這也是freetype靈活的地方.
總結(jié)
以上是生活随笔為你收集整理的qt char*转int_Qt在Linux下绘制文字原理-使用FreeType来绘制字形的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 交强险赔偿限额
- 下一篇: 不同坐标系下角速度_技术 | 西安80坐