FreeTypeを使うのソースを表示
新しいページはコチラ
移動:
案内
,
検索
[[フォント TrueType 構造解析]]に戻る。 == '''概要''' == この記事はFreeTypeを使うであって、FreeTypeをまとめる記事ではないです。なので遊び場程度の記事になります。遊べるかは謎です。Font情報をどれくらい操作できるのか試してみるところです。目標はPDFを作るためのグリフ番号取得と、フォントプログラムの再構成。サブセットフォントを作るということです。 そこまですることなんか?とは思っています。フォントの構造を知ることに重きを置きながらがんばります。 まずはコンソールプログラムでチュートリアルっぽいことを。 ってチュートリアルのとおり、作り始めたらQt64bitコンソールアプリケーションを作ってるせいで、64bitのライブラリが必要になってしまった。開発時にダイナミックリンクを使うと勉強の質が低下してしまうので、64bit32bit混在で動かすわけにもいかず、似非64bitのfreetypeライブラリを作成するために、libpngで似非64bitプラットフォームを作成した。似非というのは、何もプログラムを変更しないで、ただ64bit宣言するだけのことです。bit演算が凄まじいアプリケーション群なので、これが原因でアドレスの使い方が変わってバグる可能性はあるが、莫大なコードを目の前に、全てを潰していくのはサハラ砂漠にダイアモンドを埋めたのを探すようなモノ。無謀な道とは知りつつ、しばらく、これで突き進む。 ちな 似非を作るには[[VC PlusPlus:似非64bitプラットフォームの追加|コチラ]]の手順として記載。 Qtコンソールプログラムの書き始めは以下のような状態。Qtについては、Qt導入の記事をみて下さい。なんでQtなん?って思う人いるとおもいますけど、さほどQtの要素は使わないので、安心して下さい。Qtやってるっていう見せかけですよ。 <Syntaxhighlight2 lang="cpp"> #include <QtCore/QCoreApplication> int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); return a.exec(); } </Syntaxhighlight2> 自分は64bit版ですが、64bit版を生成するのが面倒な人はQtの32bit版のLibraryを導入して新規作成するとよいね。Qtの64bit版を使ってるつもりで説明します。ところどころ32bit版の人向けのコメントも添えます。 まずはプロジェクトの設定を変えて、freetypeが使える状態にします。 インクルードファイルのありかを設定します。ライブラリを使うときはまずはヘッダファイルで関数の全ての情報が必要です。標準関数でさえ#include <stdio.h>って設定するもんね。同じこと。 ソリューション構成をDebug、ソリューションプラットフォームをx64<span>(</span>32bitに人はWin32<span>)</span>に設定します。ツールバーのリストを選ぶところですね。次に、メニューの[プロジェクト]-[プロパティ]を選択します。 [VC++ディレクトリ]の項目の中の[外部インクルードディレクトリ]に以下を追加します。 C:\…\…\…\…\freetype-2.9.1\include [VC++ディレクトリ]の項目の中の[ライブラリディレクトリ]に以下を追加します。 C:\…\…\…\…\freetype-2.9.1\objs\x64\Debug 絶対パスなので、…の部分はそれぞれの、freetypeの配置した場所に、freetype-2.9.1となっているところもそれぞれのバージョン番号だったり、名前を変えてfreetypeにしたりしてる場合も合わせて下さい。64bitの場合はx64ですが、32bitのQtアプリの場合はx64ではなくWin32です。 構成のRelease版も合わせて変更しておくとよいでしょう。インクルードディレクトリは同じで、ライブラリディレクトリはDebugがReleaseに代わります。 実際にデバッグでもなんでもテストでアプリを動かす時は、ダイナミックリンクライブラリを使うので、dllをがうごかせるように実行ファイルと同じディレクトリ置くとか、環境変数のPathの参照可能な範囲に配置する指定をしないと駄目です。プロジェクトごとにどの環境で動かすのかを見極めて環境変数の設定しないとだめです。プログラマなら実行ファイルが完成するまではDebug版のダイナミックリンクライブラリを使うはずなので、環境変数Pathにfreetype.libのx64 <span>(</span>Win32をQtアプリの人はWin32<span>)</span> のDebug版にPathを設定しましょう。 コンパネのシステムの右側の詳細設定から詳細。環境変数の中のPathに C:¥…\…\…\…\…\freetype-2.9.1\objs\x64\Debug を追加しましょう。コマンドプロンプトでwhere %path% freetype.dll とすると、フルパスが帰ってきたら、パスが通っていて、freetype.dllがどの実行ファイルからも参照できるようになっていることを意味します。フルパスが表示されず。また次のプロンプトだけが表示された場合は失敗しています。もう一度確認しましょう。デバッグ押しても、もちろんアプリを起動できません。 そうすると、うまく設定できたかを確かめるために、少しだけプログラムを記述してビルドして確かめてみます。 <Syntaxhighlight2 lang="cpp" line=1> #include <QtCore/QCoreApplication> int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); FT_Library library; int error; error = FT_Init_FreeType(&library); if (error) { fprintf(stderr, qPrintable("")); exit(1); } return a.exec(); } </Syntaxhighlight2> 6行目から14行目を追加しました。これで一度ビルド Ctrl+Shift+B します。ちゃんと動くか確かめるためです。もちろん管理人はスーパープログラマなので、うまく動かせました。え。なにがスーパーやねん。わかります。へっぽこでした。 うまくいくと例の安心の出力になります。この正常終了って文字。プログラマにとってはアドレナリン・ドーパミン?だっけがでますね。 <Syntaxhighlight2 lang="text"> ビルドを開始しました... 1>------ ビルド開始: プロジェクト: QtConsole###########, 構成: Debug x64 ------ 1>QtConsole###########.vcxproj -> C:\…\…\…\…\QtConsole###########\x64\Debug\QtConsole###########.exe ========== ビルド: 1 正常終了、0 失敗、0 更新不要、0 スキップ ========== </Syntaxhighlight2> === '''サンプル1.Qt ConsoleApplicationでテキスト出力 ''' === ここまできたらFreetypeを使える状態になったと言えます。いよいよ使っていきましょう。ところでfreetypeって、どういうことができるのか、 ひとことで言えば、フォントから文字を描画するのに必要な情報を取り出す作業ができる。どんな情報?っていうのが詳しい説明になるわけですが、 *フォントデータからプログラマが指定したフォントサイズ<span>(</span>ポイント<span>)</span>をもとに、指定したグリフ番号のビットマップモノトーン値をピクセル毎に取得できます。 :なかなかえぐい計算量ですが、まぁ最近のPCの早いこと。しゅっとフォントがビットマップになります。 *前項のような作業のために文字コード番号から標準のグリフを取得したり、文字コード+付帯情報でその関連グリフの番号を取得できる。 :つまり、PDFでやりたかった文字コードからグリフ番号を取得する作業ができるということです。このライブラリを使えば目的は一つ達成できる。 これが最初のチュートリアルで紹介するサンプルの機能です。公式サイトにはQtでのサンプルもありますので、管理人と同じくQtで頑張っている人と共に勉強していけるはずです。 <Syntaxhighlight2 lang="cpp" line=1> #include <QtCore/QCoreApplication> #include <QString> #include <QFile> #include <QTextStream> #include <QImage> #include <QColor> #include <QSize> #include <ft2build.h> #include FT_FREETYPE_H static unsigned int text[] = { 0x00003042, 0x00003044, 0x00003046, 0x00003048, //あ、い、う、え 0x0000304a, 0x0000304b, 0x0000304d, 0x0000304f, //お、か、き、く 0x00003051, 0x00003053, 0x00003055, 0x00003057, //け、こ、さ、し 0x00003059, 0x0000305b, 0x0000305d, 0x0000305f, //す、せ、そ、た 0x00003061, 0x00003064, 0x00003066, 0x00003068, //ち、つ、て、と 0x0000000a, //改行 0x00000061, 0x00000062, 0x00000063, 0x00000064, //a、b、c、d 0x00000065, 0x00000066, 0x00000067, 0x00000068, //e、f、g、h 0x00000069, 0x0000006a, 0x0000006b, 0x0000006c, //i、j、k、l 0x0000006d, 0x0000006e, 0x0000006f, 0x00000070, //m、n、o、p 0x00000071, 0x00000072, 0x00000073, 0x00000074, //q、r、s、t 0x00000075, 0x00000076, 0x00000077, 0x00000078, //u、v、w、x 0x00000079, 0x0000007a, //y, z 0x00000061, 0x00000062, 0x00000063, 0x00000064, //a、b、c、d 0x00000065, 0x00000066, 0x00000067, 0x00000068, //e、f、g、h 0x00000069, 0x0000006a, 0x0000006b, 0x0000006c, //i、j、k、l 0x0000006d, 0x0000006e, 0x0000006f, 0x00000070, //m、n、 0x0000000a, //改行 }; #define LEN (sizeof text / sizeof text[0]) #define WIDTH 1024 #define HEIGHT 256 #define LEFT 16 #define TOP 32 static unsigned char canvas[HEIGHT][WIDTH]; static void draw(FT_Bitmap* bitmap, int x, int y) { for (int j = 0; j < bitmap->rows; j++) { for (int i = 0; i < bitmap->width; i++) { unsigned char c = bitmap->buffer[j * bitmap->pitch + i]; if (c) { if (y + j >= 0 && y + j < HEIGHT) { if (x + i >= 0 && x + i < WIDTH) { canvas[y + j][x + i] = c; } } } } } } int main(int argc, char* argv[]) { QCoreApplication a(argc, argv); QString QString_FileName = "C:/FreeTypeStep01Test.txt"; QString QString_ImageFileName = "C:/FreeTypeStep01Test.bmp"; QFile QFile_Text(QString_FileName); QString QString_ImageRowMonoBuffer = ""; QSize QSize_xy(WIDTH, HEIGHT); QImage QImage_Canvas(QSize_xy, QImage::Format_ARGB32_Premultiplied);//空イメージ FT_Library library; int error; error = FT_Init_FreeType(&library); if (error) { fprintf(stderr, qPrintable("ft init error\n")); exit(1); } FT_Face face; error = FT_New_Face(library, qPrintable("C:\\Windows\\Fonts\\KozGoPr6N-Medium.otf"), 0, &face); if (error) { fprintf(stderr, qPrintable("new face error\n")); exit(1); } error = FT_Set_Char_Size(face, 0, 8 * 64, 300, 300); if (error) { fprintf(stderr, qPrintable("set size error\n")); exit(1); } #define LEFT64(x) ((x) << 6) // 1/64が1の 32 bit 26.6 ニィロク ロク固定小数。 #define RIGHT64(x) ((x) >> 6) FT_Vector pen; pen.x = LEFT64(LEFT); pen.y = RIGHT64(TOP); unsigned int idces[LEN]; for (int i = 0; i < LEN; i++) { if (text[i] == '\n') { fprintf(stderr, qPrintable("%ld\n"), pen.x); pen.x = LEFT64(LEFT); pen.y += LEFT64(48); continue; } idces[i] = FT_Get_Char_Index(face, text[i]); error = FT_Load_Glyph(face, idces[i], FT_LOAD_DEFAULT); if (error) { fprintf(stderr, qPrintable("no glyph error/\n")); exit(1); } error = FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL); if (error) { fprintf(stderr, qPrintable("glyph render error\n")); exit(1); } draw(&face->glyph->bitmap, RIGHT64(pen.x) + face->glyph->bitmap_left, RIGHT64(pen.y) + face->glyph->bitmap_top); pen.x += face->glyph->advance.x; } fprintf(stderr, qPrintable("\n")); for (int y = 0; y < HEIGHT; y++) { for (int x = 0; x < WIDTH; x++) { QImage_Canvas.setPixel(x, y, qRgb(canvas[y][x], canvas[y][x], canvas[y][x])); } } QImage_Canvas.save(QString_ImageFileName, "BMP"); printf(qPrintable("P3\n%d %d\n%d\n"), WIDTH, HEIGHT, 255); if (QFile_Text.open(QIODevice::WriteOnly)) { QTextStream out(&QFile_Text); for (int y = 0; y < HEIGHT; y++) { for (int x = 0; x < WIDTH; x++) { if (canvas[y][x]) { QString_ImageRowMonoBuffer = QString_ImageRowMonoBuffer + " 1"; //printf(qPrintable("%2d"), 1); } else { QString_ImageRowMonoBuffer = QString_ImageRowMonoBuffer + " 0"; //printf(qPrintable("%2d"), 0); } } QString_ImageRowMonoBuffer = QString_ImageRowMonoBuffer + "\n"; //printf(qPrintable("\n")); out << QString_ImageRowMonoBuffer; QString_ImageRowMonoBuffer = ""; } QFile_Text.close(); } else { QString QString_Error(qPrintable("No Open or Create Error\n")); QString_Error = QString_Error + QFile_Text.errorString(); fprintf(stderr, qPrintable(QString_Error)); } return a.exec(); } </Syntaxhighlight2> テキストファイルと画像を出力するQtアプリケーションfreetype連動プログラムになっています。 生成される画像 [[ファイル:FreeTypeStep01Test.bmp|400px|thumb|none|実行結果]] 文字列は白黒を1ビットづつ見やすいように出力したものです。画像の方はNormalRenderingの安置エイリアスがかかっていますので少し綺麗。文字が上にいったり下にいったりしてるのは、Adobe AcrobatReaderの小塚ゴシックを参照したため。この仕組みで、違反者をさがしてるのかな。それともだいたいのフォントがこんな風にずれるようになってるのか。気になる。そのまえに、FreeTypeの基本について説明していかないとな。 ついでにQtの勉強にもなるという。いいね。このSiteは、いいねボタンないけどね。 [[フォント TrueType 構造解析]]に戻る。
FreeTypeを使う
に戻る。
個人用ツール
ログイン
名前空間
ページ
議論
変種
表示
閲覧
ソースを表示
履歴表示
操作
検索
案内
メインページ
コミュニティ・ポータル
最近の出来事
最近の更新
おまかせ表示
ヘルプ
ツールボックス
リンク元
関連ページの更新状況
特別ページ