FreeTypeを使う 新しいページはコチラ
提供: yonewiki
(→サンプル4.公式サイトのErik Mollerさん作成その2 Qt版) |
(→サンプル4.公式サイトのErik Mollerさん作成その2 Qt版) |
||
1,230行: | 1,230行: | ||
こういう作業をすることは勉強にはなりません。これを当たり前のようにこなしてから、どうすることが正しかったのかを考えることが大事です。でも今回は管理人には必要ない知識なので、ここではやりません。人が作ったものを使いこなすのは大変だということです。ユーザ数が少ない。文献がすくなければなおさら面倒です。必要に駆られるまで手は出さない。動けばいいな。程度。1週間やってもだめなら諦めますね。パズルと同じです。 | こういう作業をすることは勉強にはなりません。これを当たり前のようにこなしてから、どうすることが正しかったのかを考えることが大事です。でも今回は管理人には必要ない知識なので、ここではやりません。人が作ったものを使いこなすのは大変だということです。ユーザ数が少ない。文献がすくなければなおさら面倒です。必要に駆られるまで手は出さない。動けばいいな。程度。1週間やってもだめなら諦めますね。パズルと同じです。 | ||
− | + | ||
+ | === ''' サンプル5.公式サイトのRóbert Márkiさん作成 ''' === | ||
+ | Róbertが作成したQtプロジェクトでのサンプルですが、プロジェクトファイルが配布されているわけでもないので、再現するのにはどうすればいいのかが、よくわからなかったので、自分でイチカラQt Guiプロジェクト作りこみながら、再現してみました。qmakeファイル配布されてましたけど、何をどうしろというのかというような内容でして、ここまで来て思ったんですけど、FreeTypeのサンプル集はどれも冷たい。どうやってビルドするべきかを環境とツールごとに分けて記述しているプロジェクトもある昨今なのに、ソースファイルとよくわからない*.proファイルの配布。冷たい。 | ||
+ | |||
+ | |||
+ | 不満を並べてもしょうがないので、ビルド手順を簡単に。 | ||
+ | |||
+ | 1.VisualStudioでQt Wigets Applicatioの新規作成を始めます。 | ||
+ | |||
+ | 2.今回の場合Wizardがいろいろと分類してくれるのは、ありがたくないのですが、Wizardのいうとおりに作るので、BaseClassを指定するところだけQMainWindowではなく、QWidgetに変更します。あとは規定値でよいです。 | ||
+ | |||
+ | 3.したらばプログラムを書きます。分割プログラムの形式なのでやや複雑ですが、以下の通り記述します。 | ||
+ | |||
+ | まずmain.cpp | ||
+ | |||
+ | <Syntaxhighlight2 lang="cpp" line start="1"> | ||
+ | #include "QtSampleProject.h" | ||
+ | #include <QtWidgets/QApplication> | ||
+ | |||
+ | #include <QPainter> | ||
+ | #include <QFile> | ||
+ | |||
+ | #include <iostream> | ||
+ | |||
+ | #include <ft2build.h> | ||
+ | #include FT_FREETYPE_H | ||
+ | #include FT_OUTLINE_H | ||
+ | |||
+ | QString g_usageText = | ||
+ | "usage:\n" | ||
+ | "example4 FONT_PATH CHARACTER SIZE DIRECT_RENDERING_MODE(1|0)"; | ||
+ | |||
+ | int main(int argc, char *argv[]) | ||
+ | { | ||
+ | bool status = false; | ||
+ | bool isSizeOk = false; | ||
+ | QString path = "C:\\Windows\\Fonts\\BIZ-UDGothicR.ttc"; | ||
+ | QChar character = 'm'; | ||
+ | int size = QString("60").toInt(&isSizeOk); | ||
+ | bool directRender = QString("1").toInt(); | ||
+ | |||
+ | if (QFile::exists(path) && isSizeOk) { | ||
+ | status = true; | ||
+ | QApplication a(argc, argv); | ||
+ | QtSampleProject w(path, character, size, directRender); | ||
+ | w.show(); | ||
+ | return a.exec(); | ||
+ | } | ||
+ | if (!status) { | ||
+ | std::cout << qPrintable(g_usageText) << std::endl; | ||
+ | return 0; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | |||
+ | </Syntaxhighlight2> | ||
+ | |||
+ | |||
+ | プロジェクト名.cpp ここでは仮にQtSampleProjectとしておきます。 | ||
+ | |||
+ | <Syntaxhighlight2 lang="cpp" line start="1"> | ||
+ | #include "QtSampleProject.h" | ||
+ | |||
+ | QtSampleProject::QtSampleProject(QWidget *parent) | ||
+ | : QWidget(parent) | ||
+ | { | ||
+ | m_face = 0; | ||
+ | m_library = 0; | ||
+ | m_directRender = 0; | ||
+ | ui.setupUi(this); | ||
+ | } | ||
+ | QtSampleProject::QtSampleProject(const QString& fileName, QChar character, int pointSize, bool directRender, QWidget* parent) : QWidget(parent), m_directRender(directRender) | ||
+ | { | ||
+ | FT_Error error = FT_Err_Ok; | ||
+ | m_face = 0; | ||
+ | m_library = 0; | ||
+ | error = FT_Init_FreeType(&m_library); | ||
+ | if(!error){ | ||
+ | error = FT_New_Face(m_library, fileName.toLatin1().constData(), 0, &m_face); | ||
+ | |||
+ | if (!error) { | ||
+ | error = FT_Set_Char_Size(m_face, 0, pointSize * 64, physicalDpiX(), physicalDpiY()); | ||
+ | if (!error) { | ||
+ | FT_UInt glyph_index = 0; | ||
+ | glyph_index = FT_Get_Char_Index(m_face, character.unicode()); | ||
+ | error = FT_Load_Glyph(m_face, glyph_index, FT_LOAD_DEFAULT); | ||
+ | if (!error) { | ||
+ | FT_Pos left = m_face->glyph->metrics.horiBearingX; | ||
+ | FT_Pos right = left + m_face->glyph->metrics.width; | ||
+ | FT_Pos top = m_face->glyph->metrics.horiBearingY; | ||
+ | FT_Pos bottom = top - m_face->glyph->metrics.height; | ||
+ | |||
+ | m_glyphRect = QRect(QPoint(TRUNC(left), | ||
+ | -TRUNC(top) + 1), | ||
+ | QSize (TRUNC(right - left) + 1, | ||
+ | TRUNC(top - bottom) + 1) | ||
+ | ); | ||
+ | setFixedSize(m_glyphRect.width(), m_glyphRect.height()); | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | ui.setupUi(this); | ||
+ | } | ||
+ | QtSampleProject::~QtSampleProject() | ||
+ | { | ||
+ | if(m_face){ | ||
+ | FT_Done_Face(m_face); | ||
+ | } | ||
+ | if(m_library){ | ||
+ | FT_Done_FreeType(m_library); | ||
+ | } | ||
+ | |||
+ | } | ||
+ | |||
+ | void QtSampleProject::graySpans(int y, int count, const FT_Span_* spans, void* user) { | ||
+ | QPainter* painter = (QPainter*)user; | ||
+ | y = -y; | ||
+ | |||
+ | for (int i = 0; i < count; i++) { | ||
+ | const FT_Span span = spans[i]; | ||
+ | qreal opacity = qreal(span.coverage) / 255.0; | ||
+ | |||
+ | painter->setOpacity(opacity); | ||
+ | |||
+ | if (span.len > 1) { | ||
+ | painter->drawLine(span.x, y, span.x + span.len - 1, y); | ||
+ | } | ||
+ | else { | ||
+ | painter->drawPoint(span.x, y); | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | void QtSampleProject::paintEvent(QPaintEvent* event) { | ||
+ | QWidget::paintEvent(event); | ||
+ | |||
+ | if (m_library && m_face) { | ||
+ | FT_Error error = FT_Err_Ok; | ||
+ | QPainter painter(this); | ||
+ | painter.translate(-m_glyphRect.x(), -m_glyphRect.y()); | ||
+ | if (m_directRender) { | ||
+ | painter.setPen(Qt::black); | ||
+ | FT_Raster_Params params; | ||
+ | |||
+ | params.target = 0; | ||
+ | params.flags = FT_RASTER_FLAG_DIRECT | FT_RASTER_FLAG_AA; | ||
+ | params.user = &painter; | ||
+ | params.gray_spans = &QtSampleProject::graySpans; | ||
+ | params.black_spans = 0; | ||
+ | params.bit_set = 0; | ||
+ | params.bit_test = 0; | ||
+ | |||
+ | FT_Outline* outline = &m_face->glyph->outline; | ||
+ | FT_Outline_Render(m_library, outline, ¶ms); | ||
+ | } | ||
+ | else { | ||
+ | error = FT_Render_Glyph(m_face->glyph, FT_RENDER_MODE_NORMAL); | ||
+ | QImage glyphImage(m_face->glyph->bitmap.buffer, | ||
+ | m_face->glyph->bitmap.width, | ||
+ | m_face->glyph->bitmap.rows, | ||
+ | m_face->glyph->bitmap.pitch, | ||
+ | QImage::Format_Indexed8); | ||
+ | painter.translate(m_glyphRect.x(), m_glyphRect.y()); | ||
+ | |||
+ | QVector<QRgb> colorTable; | ||
+ | for (int i = 0; i < 256; ++i) { | ||
+ | colorTable << qRgba(0, 0, 0, i); | ||
+ | } | ||
+ | glyphImage.setColorTable(colorTable); | ||
+ | painter.drawImage(QPoint(0, 0), glyphImage); | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | </Syntaxhighlight2> | ||
+ | |||
+ | プロジェクト名.h | ||
+ | |||
+ | <Syntaxhighlight2 lang="cpp" line start="1"> | ||
+ | #pragma once | ||
+ | |||
+ | #include <QtWidgets/QWidget> | ||
+ | #include "ui_QtSampleProject.h" | ||
+ | |||
+ | #include <QPainter> | ||
+ | #include <QFile> | ||
+ | |||
+ | #include <iostream> | ||
+ | |||
+ | #include <ft2build.h> | ||
+ | #include FT_FREETYPE_H | ||
+ | #include FT_OUTLINE_H | ||
+ | |||
+ | #define TRUNC(x) ((x) >> 6) | ||
+ | |||
+ | class QtSampleProject : public QWidget | ||
+ | { | ||
+ | Q_OBJECT | ||
+ | |||
+ | public: | ||
+ | QtSampleProject(QWidget* parent = nullptr); | ||
+ | QtSampleProject(const QString& fileName, QChar character, int pointSize, bool directRender, QWidget* parent = 0); | ||
+ | ~QtSampleProject(); | ||
+ | |||
+ | private: | ||
+ | bool m_directRender = 0; | ||
+ | FT_Library m_library = 0; | ||
+ | FT_Face m_face = 0; | ||
+ | QRect m_glyphRect; | ||
+ | |||
+ | static void graySpans(int y, int count, const FT_Span_* spans, void* user); | ||
+ | Ui::QtSampleProjectClass ui; | ||
+ | |||
+ | protected: | ||
+ | void paintEvent(QPaintEvent* event); | ||
+ | }; | ||
+ | |||
+ | </Syntaxhighlight2> | ||
+ | |||
[[フォント TrueType 構造解析]]に戻る。 | [[フォント TrueType 構造解析]]に戻る。 |