Delphi Programming / Object Pascal
[掲載 2018年07月29日] [更新 2018年08月15日] Delphi 一般・その他
Emoji ( 絵文字 ) の描画
動作確認等
Windows 10.0.17134 Pro-32 bit + Delphi 10.2.3 Tokyo Community
Windows 7 U64(SP1) + Delphi 10.2.3 Tokyo Community
Windows 8.1 でカラーの絵文字が使用可能になりました.本ページは主にこのカラーの絵文字の描画に関するテストの記事です.
Windows では文字を表示するフォント (フォント名あるいはフォントファミリー)
に,記号や絵文字が格納されているフォントがあります.それらのフォントを使用すると下図のように記号や絵文字等を表示することができます.
図1
一般的な文字用と記号や絵文字用フォント
上が一般的な文字フォントによる描画
フォント名は Meiryo
下が記号や絵文字用フォントによる描画
フォント名は Wingdings
リスト1
一般的な文字用と記号や絵文字用フォントよる TEdit への描画
copy code
// =============================================================================
// フォーム生成時の処理
// Edit1, Edit2 とのフォント名を異なるものにする
// =============================================================================
procedure TForm1.FormCreate(Sender: TObject);
begin
Edit1.Font.Size := 20 ;
Edit2.Font.Size := 20 ;
Edit1.Font.Name := 'Meiryo' ;
Edit2.Font.Name := 'Wingdings' ;
end ;
// =============================================================================
// TEdit の OnChange イベント処理
// Edit1, Edit2 の文字(コードポイント)を同じにする
// =============================================================================
procedure TForm1.Edit1Change(Sender: TObject);
begin
if Sender = Edit1 then begin
Edit2.Text := Edit1.Text;
end else begin
Edit1.Text := Edit2.Text;
end ;
end ;
本ページで扱っているのはこの記号フォントによる文字ではなく,Unicode の Emoji (エモジ) という規格の文字です.
絵文字は日本独特の文化として携帯電話等のモバイル端末で使用されてきましたが,現在は世界中で日常的に使用されています.Unicode でも Emoji という日本語の読み名の規格にもなっています.
Unicode では例えば以下のコードポイントが絵文字として登録されています.
U + 2600 ~ U + 27BF
U + 1F300 ~ U + 1F5FF
U + 1F600 ~ U + 1F64F
U + 1F680 ~ U + 1F6FF
Emoji については以下のリンクの記事等を参考にしてください.
Emoji の中でカラー表示可能な絵文字のことを Color Emoji, あるいはカラー絵文字と書くことがありますが,マイクロソフトでは Color Font という用語を使用しています.
Windows では Windows 8 で絵文字フォントが提供され,Windows 8.1 でカラーの絵文字の表示が可能になりました.
01_ TEdit にカラーの絵文字を表示してもモノクロの絵文字になる
EmojiSurrogatePair.zip [866 KB] 2020年12月24日版 (EXEのみ)
TEdit に絵文字を表示するテストです.
下の 3 つ文字はカラーの絵文字です (ブラウザの種類とバージョンによってはモノクロ表示).その右側がそれらの文字のコードポイントです.U + 10000 以降の値となっています.U
+ 10000 以降はサロゲートペアな文字です.
🚺 🚫 🔯 #$1F6BA#$1F6AB#$1F52F
TEdit の Text プロパティにコードポイントの値を直接代入すればこれらの文字を表示できますが,ここではコードポイントの値を変数として扱えるようにして,コードポイントの値をサロゲートペアに分解して表示するようにしています.また,コンボボックスで表示に使用するフォントを変更できるようにしてみました.
下図は上の 3 つの絵文字を表示した結果ですが,モノクロの絵文字になっています.
Delphi の TEdit や TMemo は Windows の Edit コントロールをカプセル化したテキストの入力編集用コントロールです.つまり,文字等のテキストの実際の描画は Windows の Edit コントロールが行っています.Windoows の Edit コントロールはカラー絵文字をカラーで描画する機能を実装していません.したがって,Delphi の TEdit や TMemo ではカラーの絵文字であってもモノクロの絵文字として表示されることになります.
[備考]
Windows 7 にインストールされているフォントには,Segoe UI Symbol フォントも含めてカラー情報はありません.Windows 7 にはフォントのカラー情報を処理する機能も実装されていません.
図2
コードポイントの値を指定して TEdit にカラーの絵文字を描画
Windows 10 での実行結果
フォントはメイリオ
フォームに以下を配置している
一番上は TButton と TComboBox
その下に TEdit を 3 つ.順番に
Edit1, Edit2, Edit3
図3
コードポイントの値を指定して TEdit にカラーの絵文字を描画
Windows 10 での実行結果
フォントは Segoe UI Emoji
下図は Windows 7 での実行結果です.フォントは Windows 10 と同じメイリオを使用していますが四角形が表示されいます.Windows 7 でもフォントを Segoe UI Symbol (シーゴー・ユーアイ・シンボル) にすれば絵文字が表示できます.
絵文字の描画機能は Windows 8 で実装されました.Windows 8.1 ではカラーの絵文字の描画にも対応になっています.Segoe UI Symbol フォントは,Windows 7 でも絵文字の描画ができるように Windows の更新プログラム KB2729094 でインストールされています.もし KB2729094 をインストールしていない場合は,以下のマイクロソフトのサイトからダウンロードしてインストールできます.
図4
コードポイントの値を指定して TEdit にカラーの絵文字を描画
Windows 7 では使用するフォントによっては絵文字にならない
フォントがメイリオの場合
図5
コードポイントの値を指定して TEdit にカラーの絵文字を描画
Windows 7 で Segoe UI Symbol フォントにした場合
リスト2
コードポイントを指定して TEdit に絵文字を表示,コードポイントをサロゲートペアに分解
uses に MECSUtils が必要
copy code
implementation
uses
MECSUtils;
{$R *.dfm}
// -----------------------------------------------------------------------------
// EnumFontFamiliesのコールバック関数
// -----------------------------------------------------------------------------
function EnumFontFamProc(lpelf: PEnumLogFont; lpntm: PNewTextMetric;
nFontType: Integer; lParam: TStrings): Integer; stdcall ;
var
LFontName : String ;
begin
Result := 1 ;
LFontName := lpelf.elfLogFont.lfFaceName;
// 縦書き用フォントは除外
if Pos('@' , LFontName) = 0 then begin
lParam.Add(LFontName);
end ;
end ;
// =============================================================================
// フォーム生成時の処理
// コンボボックスにフォント名のリストをセット
// =============================================================================
procedure TForm1.FormCreate(Sender: TObject);
var
LDC : HDC;
LIndex : Integer;
begin
// フォント名リストの作成
// 全フォントのリストを取得する関数はEnumFontFamiliesEx
ComboBox1.Clear;
ComboBox1.Sorted := True;
LDC := GetDC(Handle);
try
EnumFontFamilies(LDC, nil , @EnumFontFamProc, LPARAM(ComboBox1.Items));
LIndex := ComboBox1.Items.IndexOf(Self.Font.Name);
ComboBox1.ItemIndex := LIndex;
finally
ReleaseDC(Handle, LDC);
end ;
Edit2.Font.Name := ComboBox1.Text;
Edit1.Text := '#$1F6BA#$1F6AB#$1F52F' ;
end ;
// =============================================================================
// Edit1に入力したコードポイントの値を実際の文字にして表示
// サロゲートペアな文字の場合はサロゲートペアに分解してそのコードを表示
// =============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
LStrList : TStringList;
LText : string ;
LText16 : string ;
LoopCnt : Integer;
begin
Edit2.Text := '' ;
LStrList := TStringList.Create;
try
// デリミタの設定して文字列をセット
LStrList.Delimiter := '#' ;
LStrList.StrictDelimiter := True;
LStrList.DelimitedText := Edit1.Text;
// 1文字分のコードポイントの値を取り出して順番に文字列に追加
LText := '' ;
for LoopCnt := 0 to LStrList.Count - 1 do begin
if Trim(LStrList[LoopCnt]) <> '' then begin
LText := LText + CodePointToUTF16(StrToUInt(LStrList[LoopCnt]));
end ;
end ;
finally
FreeAndNil(LStrList);
end ;
Edit2.Text := LText;
// 対象の文字列
LText := Edit2.Text;
LText16 := '' ;
for LoopCnt := 1 to Length(LText) do begin
LText16 := LText16 + '#' + Format('$%.4x' , [Ord(LText[LoopCnt]), 4 ]);
end ;
Edit3.Text := LText16;
end ;
// =============================================================================
// ComboBox1のOnClickイベント
// コンボボックスでフォント名を選択したらそのフォントで文字を再表示
// =============================================================================
procedure TForm1.ComboBox1Click(Sender: TObject);
begin
Edit2.Font.Name := ComboBox1.Items[ComboBox1.ItemIndex];
end ;
02_ Direct2D を使用してカラーの絵文字を TCanvas に描画
マイクロソフトでは,カラー絵文字の描画に関して,Direct2D を使用する方法,XAML (ザムル)
アプリケーションではその設定方法について説明しています.
下のリンクの記事に Direct2D を使用するサンプルが掲載されています.このコードは,コピペすればそのまま動作しますが,ここでは元のコードを少し変更しています.
下図が実行結果です.絵文字は参考にしたサンプルコードと全く同じ絵文字を使用しています.
Windows 7 では D2D1_DRAW_TEXT_OPTIONS_ENABLE_COLOR_FONT
フラグを指定しても無効です.このフラグを指定すると何も描画しません.Windows 7 にインストールされているフォントはカラー情報を待っていません.Windows 7 にはフォントのカラー情報を処理する機能も実装されていません.
フォントのカラー情報を処理する機能が実装されたのは Windows 8.1 からです.
図6
Direct2D によるカラーの絵文字描画
図7
Direct2D によるカラーの絵文字描画
Windows 7 の場合はモノクロの絵文字となる
正しく表示できない絵文字がある
[備考 1]
本サンプルでは Windows のバージョン判定に CheckWin32Version 関数を使用しています.
Delphi 10 Seattle より前のジージョンでは,アプリケーションマニフェストの確認が必要です.
リスト3
Direct2D を使用したカラーの絵文字の描画
copy code
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes,
Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls;
type
TForm1 = class (TForm)
procedure FormPaint(Sender: TObject);
private
{ Private 宣言 }
public
{ Public 宣言 }
end ;
var
Form1: TForm1;
implementation
uses
Winapi.D2D1,
System.Win.ComObj,
Vcl.Direct2D;
{$R *.dfm}
type
TMyCanvas = class (TDirect2DCanvas)
public
procedure TextOut(X, Y: Integer; const Text: string ); override ;
end ;
procedure TForm1.FormPaint(Sender: TObject);
var
FD2DCanvas: TDirect2DCanvas;
begin
FD2DCanvas := TMyCanvas.Create(Canvas.Handle, ClientRect);
try
FD2DCanvas.BeginDraw;
FD2DCanvas.TextOut(10 , 10 , '絵文字テスト ' + sLineBreak
+ '😍😀😊😜😐😅😎💖😘😂😃💋💖😋😭😇🙄💩🙈🙉🙊🔞' );
FD2DCanvas.EndDraw;
finally
FD2DCanvas.Free;
end ;
end ;
{ TMyCanvas }
procedure TMyCanvas.TextOut(X, Y: Integer; const Text: string );
const
D2D1_DRAW_TEXT_OPTIONS_ENABLE_COLOR_FONT = $00000004 ;
var
TextRange: TDwriteTextRange;
TextLayout: IDWriteTextLayout;
begin
OleCheck(DWriteFactory.CreateTextLayout(PWideChar(Text),
Length(Text),
Font.Handle,
0 ,
0 ,
TextLayout));
TextRange.startPosition := 0 ;
TextRange.length := Length(Text);
TextLayout.SetWordWrapping(DWRITE_WORD_WRAPPING_NO_WRAP);
RequiredState([csHandleValid, csFontValid, csBrushValid]);
if CheckWin32Version(6 , 3 ) then begin
TextLayout.SetFontFamilyName('Segoe UI Emoji' , TextRange);
TextLayout.SetFontSize(11.5 , TextRange);
RenderTarget.DrawTextLayout(D2D1PointF(x - 0.5 , y - 0.5 ),
TextLayout,
Font.Brush.Handle,
D2D1_DRAW_TEXT_OPTIONS_ENABLE_COLOR_FONT);
end else begin
TextLayout.SetFontFamilyName('Segoe UI Symbol' , TextRange);
TextLayout.SetFontSize(15.5 , TextRange);
RenderTarget.DrawTextLayout(D2D1PointF(x - 0.5 , y - 0.5 ),
TextLayout,
Font.Brush.Handle,
D2D1_DRAW_TEXT_OPTIONS_NONE);
end ;
end ;
end .
上のコード中の絵文字はカラーで表示されていますが (ブラウザの種類とバージョンによってはモノクロ表示),それらの絵文字は,Delphi 10.2.3 Tokyo Community の IDE のコードエディタでは,下図のように表示されます.
図8
Delphi の IDE のコードエディタでの表示
下図は Direct2D を使用して,前項のテストで使用したカラー絵文字を TLabel に描画した結果です.モノクロではなくカラーの絵文字として表示されています.TEdit や TMemo はテキストの入力用コントロールです.一方,TLabel や TPanel はテキストの表示専用のコントロールですから,この方法よる描画でも十分実用になります.
絵文字のデザインあるいは色がウェブブラウザでの表示と違いますが,筆者にはこの現象に関する知識はありません.
[備考 2]
このようなテストでは,フォームに配置した TLabel のサイズを十分な大きさにして AutoSize プロパティの値を False にしておきます.TLabel.Caption プロパティの値を設定するわけではないので,描画する内容に応じて TLabel のサイズが自動的に変わることはありません.
図9
Direct2D によるカラーの絵文字の描画
コードポイントの値を指定して描画
Windows 7 ではモノクロでの描画になる
図10
同じコードポイントの文字をブラウザで表示した結果
Windows 7(SP1) のFireFox 61.0.1 における表示
リスト4
Direct2D で TLabel の Canvas にカラーの絵文字を描画
copy code
procedure TForm1.Button1Click(Sender: TObject);
var
FD2DCanvas: TDirect2DCanvas;
begin
FD2DCanvas := TMyCanvas.Create(Label1.Canvas.Handle, ClientRect);
try
FD2DCanvas.BeginDraw;
FD2DCanvas.RenderTarget.Clear (D2D1ColorF(clWhite));
FD2DCanvas.TextOut(0 , 0 , #$1F6BA #$1F6AB #$1F52F );
FD2DCanvas.EndDraw;
finally
FD2DCanvas.Free;
end ;
end ;
03_ ブラウザコントロールを使用したカラー絵文字の表示と編集
ウェブブラウザコントロールに絵文字を描画するテストです.使用したのは Chrome ブラウザコントロール CEF4Delphi ですが,以下のリンクのサンプルをそのまま使用してテストしてみました.
ただし,表示している HTML コードは,結果の図の下のコードです.HTML コードを表示した後にページを編集モードにして文字を入力しています.
下図で表示している絵文字は,下の絵文字をコピーして貼り付けています.これは前項のテストで使用したものと全く同じです.
😍😀😊😜😐😅😎💖😘😂😃💋💖😋😭😇🙄💩🙈🙉🙊🔞
このブラウザコントロール自身には独自のフォントのレンダリング機能はありません.フォントのレンダリングは Windows のフォントレンダリングの機能が使われます.したがって,文字の表示デザインは,前項の Direct2D による描画と同じになります.当然 Windows 7 ではモノクロ表示です.
図11
ブラウザコントロールを編集モードにしてカラー絵文字を表示
文字の挿入,削除,選択,コピーや貼り付けの操作が可能
Windows 7 の環境ではモノクロの絵文字となる
リスト5
テストに使用した test.html ファイルの HTML コード
copy code
<!doctype HTML PUBLIC "-// W3C//DTD HTML 4.01 Transitional//EN" >
<html >
<head >
<html lang="ja" >
<meta http -equiv ="Content-Type" content ="text/html; charset=EUC-JP" >
</head >
<body >
</body >
</html >
TWebBrowser コンポーネントでも以下のようにすれば編集モードの切り換えができます.
ただし,TWebBrowser の場合,レンダリングモードを IE 11 にしても,Windows 10 でもカラーの絵文字はモノクロ表示となります.
リスト6
TWebBrowser で編集モードを切り換える方法
copy code
implementation
uses
MSHTML;
{$R *.dfm}
// =============================================================================
// フォーム生成時の処理
// =============================================================================
procedure TForm1.FormCreate(Sender: TObject);
begin
Edit1.Text := ExpandFileName('test.html' );
WebBrowser1.Navigate(Edit1.Text);
end ;
// =============================================================================
// designMode開始
// =============================================================================
procedure TForm1.Button1Click(Sender: TObject);
begin
(WebBrowser1.Document as IHTMLDocument2).designMode := 'on' ;
end ;
// =============================================================================
// designMode終了
// =============================================================================
procedure TForm1.Button2Click(Sender: TObject);
begin
(WebBrowser1.Document as IHTMLDocument2).designMode := 'off' ;
end ;
04_ ワードパッドを使用して文字のコードポイントを調べる
Windows 10 に付属のワードパッドで文字を入力すると,その文字のコードポイントの値を容易に調べることができます.Windows 10.0.1713 のワードパッドはカラー絵文字には対応していません.カラーの絵文字はモノクロで表示されます.
Windows 7 に付属のワードパッドは,絵文字を表示できませんが,同じ操作で入力した文字のコードポイントを調べることが可能です.
Microsoft word 2010 でも同じ手順でコードポイントを調べることができます.
コードポイントの値を変更すれば,文字を変更することができます.
図12
ワードパッドを使用して文字のコードポイントを知る
[Alt] + [X] でキャレットの左側の文字がコードポイントの値に変る
再度 [Alt] + [X] で文字の表示に戻る
Windows 7 のワードパッドは絵文字が表示できないので□となる
05_ Windows 10 のタッチキーボードを使用して Emoji を入力
Windows 10.0.17134
で使用可能な絵文字は,日本語 IME の変換候補のリストから選択できますが,下図のようなタッチキーボードからもマウス操作で入力できます.
クリックした絵文字は,現在アクティブな入力コントロールに貼り付けされます.
タスクバーにタッチキーボードのアイコンがない場合は,タスクバーのポップアップメニューから [タッチキーボードボタンを表示] をクリックします.
図13
タッチキーボードのアイコンをクリック
図14
左下の赤枠位置のキーをクック
06_ カラー絵文字の描画にはフォントのレンダリングが必要
本ページのテストでも確認しましたが,Windows 8 以前の Windows ではカラーの絵文字をカラーでは描画できません.Windows 8 以前でカラー絵文字をカラーで描画するには,フォントに格納されている情報を解析して,人が理解可能な「文字」という画像にして出力するフォントのレンダリングを行わなけれなりません.
カラー絵文字フォントには以下のような種類があります.フォントのデータからこれらの種類を判定して処理を分けることになります.本ページのテストで使用した Segoe UI Emoji は (3) の方式のフォントです.
(1) フォントに SVG 画像データとして格納する方式
(2) フォントに PNG 画像データとして格納する方式
(3) 色数分のレイヤー画像の情報をフォントに格納する方式
下図は,そのようなフォントの描画エンジンを実装したテキストエディタの例です.上の参考リンクの最後のリンクの記事は,このテキストエディタ TATEditor の作者が書いた記事です.
下図は Windows 7 での実行結果です.Windows 7 にインストールされているフォントにはカラー絵文字としての情報はありません.Windows 10 の Segoe UI Emoji フォントを Windows 7 にインストールして,そのフォントで表示しています.
図15
カラーの絵文字が描画できるテキストエディタの例
07_ フォントレンダリング用のライブラリ FreeType
plFreeType_Test.zip [44.1 MB] 2018年08月15日版 (EXE 同梱.説明なし)
マイクロソフトの COLR / CPAL 仕様のカラー絵文字の描画テスト
前項で紹介したテキストエディタ TATEditor の作者が書いた記事の中の FreeType は,フォントのレンダリング用のライブラリです.このライブラリは以下のサイトが提供しています.
このライブラリの Windows 用のソースコードは C++ 用です.Delphi で使用するためには以下のリンクから DLL をダウンロードしてその DLL 内の関数を使用します.32 ビットの EXE で使用する時は [Win32] フォルダ内の
freetype.dll を使用します.64 ビットの EXE で使用する時は [Win64] フォルダ内の freetype.dll を使用します.この DLL はシステム的にパスが通った場所に置きます.今回は EXE があるフォンダ内に置いてテストしています.
その下のリンクはソースコードのダウンロードのページへのリンクです.どちらも FreeType のサイトからのリンクです.2018年08月12日現在の FreeType のバージョンは 2.9.1 です.
図16
FreeType ライブラリの DLL
ダウンロードしたバージョン 2.9.1 の DLL を使用するには Visual C++ 2017 のランタイムライブラリが必要です.マイクロソフトの以下のページからダウンロードできます.
32 ビットの EXE で使用する時は [x86] を選択してダウンロードしてインストールします.64 ビットの EXE で使用する時は [x64] を選択してからダウンロードしてインストールします.
このリンクは,正確には,最新の Visula Studio のバージョンの再配布可能パッケージのダウンロード用リンクです.2018年08月12日現在は Visuala Studio 2017 用となっています.
図17
Visual C++ のランタイムライブラリ
FreeType ライブラリを Delphi で利用するためのユニット類が以下のページにあります.
[ctypes] と [freetype] をダウンロードします.[ctypes] 内の ctypes.pas と [freetype] 内の [Demo] フォルダ以外のファイルを,ライブラリのパスが通った場所に置き,uses に FreeType を追加して利用します.
この Delphi 用のライブラリは少し古い FreeType 用です.必要に応じて FreeType.dll 内の関数等の定義コードを追加して利用します.
図18
[ctypes] と [freetype] をダウンロード
クリックすれば各々のダウンロードのページに移動できる
図19
ライブラリのパスの通った場所に置く
FreeType ライブラリを使用した簡単なテストコードとのその実行結果です.
Windows 10 から Segoe UI Emoji フォント (ファイル名は seguiemj.ttf) をコピーして,EXE
が生成されるフォルダ内に置いてテストしています.
白い矩形領域がビットマップの領域です.絵文字のフォントはフォントの領域全体に描画されます.そのため,一般の文字と同時に描画する際はバランスを考慮する必要があるかも知れません.
図20
下のコードを Windows 7 で実行した結果
リスト7
FreeType を使用してカラー絵文字のフォントを TLabel の Canvas に描画
uses に FreeType が必要
copy code
// =============================================================================
// FreeTypeライブラリを使用した文字のグリフ(字形)データの取得例
// 1文字だけの簡単な例
// =============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
LFTLibrary : FT_Library;
LError : FT_Error;
LByteStream : TBytesStream;
LFontFilePath : string ;
LLineHeight : Integer;
LCodePoint : FT_ULong;
LFTFace : FT_Face;
LGlyphIndex : FT_UInt;
LGlyphSlot : FT_GlyphSlot;
LDrawLeft : Integer;
LDrawTop : Integer;
begin
// 文字を描画する背景を塗り潰す
Label1.Canvas.Brush.Style := bsClear;
Label1.Canvas.Brush.Color := clSilver;
Label1.Canvas.FillRect(Label1.Canvas.ClipRect);
// 文字の高さ(ピクセル数)
LLineHeight := 80 ;
// FreeTypeライブラリの初期化
LError := FT_Init_FreeType(LFTLibrary);
if LError <> 0 then Exit;
LByteStream := TBytesStream.Create;
try
// フォントファイルのデータをメモリストリームに読み込む
LFontFilePath := ExpandFileName('.\seguiemj.ttf' );
LByteStream.LoadFromFile(LFontFilePath);
// そのフォントデータからFT_Fac3オブジェクトを取得
FT_New_Memory_Face(LFTLibrary,
@LByteStream.Bytes[0 ],
LByteStream.Size,
0 ,
LFTFace );
// 描画するピクセルのサイズを設定
FT_Set_Pixel_Sizes(LFTFace, 0 , LLineHeight);
// グリフデータを取得する文字のコードポイント
LCodePoint := $1F61C ;
// コードポイントの値から文字のグリフ(字形)のインデックスを取得
LGlyphIndex := FT_Get_Char_Index(LFTFace, LCodePoint);
// FT_Face.GlyphSlotとしてグリフのデータのポインタを取得
FT_Load_Glyph(LFTFace, LGlyphIndex, FT_LOAD_DEFAULT);
// グリフのビットマップデータを取得
LGlyphSlot := LFTFace.glyph;
FT_Render_Glyph(LGlyphSlot, FT_RENDER_MODE_NORMAL);
// 描画開始位置を指定
LDrawLeft := 10 ;
LDrawTop := LLineHeight - LFTFace.glyph.bitmap_top;
// 取得したビットデータをTBitmapにして描画
DrawFreeTypeBitmap(LGlyphSlot.bitmap, LDrawLeft, LDrawTop);
finally
FreeAndNil(LByteStream);
end ;
// 終了処理
FT_Done_Face(LFTFace);
FT_Done_FreeType(LFTLibrary) ;
end ;
// -----------------------------------------------------------------------------
// FreeTypeで取得したビットマップデータをTBitmapのデータにして描画
// AFTBitmap : パレット情報なしの256色のビットマップのバイトデータ
// データはボトムアップ
// X : 描画会開始X座標値
// Y : 描画開始Y座標値
//
// ここでは32ビットのアルファチャンネル付きのビットマプに変換してから描画
// -----------------------------------------------------------------------------
procedure TForm1.DrawFreeTypeBitmap(AFTBitmap: FT_Bitmap; X, Y: Integer);
type
TRGBQArray = array [0 ..High(Integer) div 4 - 1 ] of RGBQUAD;
PRGBQArray = ^TRGBQArray;
var
LBitmap : TBitmap;
LBytePos : Integer;
LPosX : Integer;
LPosY : Integer;
LScanArray : PRGBQArray;
LColorQuad : RGBQUAD;
LByte : Byte;
begin
LBitmap := TBitmap.Create;
try
LBitmap.SetSize(AFTBitmap.width, AFTBitmap.rows);
LBitmap.PixelFormat := pf32bit;
LBitmap.AlphaFormat := afDefined;
LBytePos := 0 ;
for LPosY := 0 to LBitmap.Height - 1 do begin
LScanArray := LBitmap.ScanLine[LPosY];
for LPosX :=0 to LBitmap.Width - 1 do begin
LByte := AFTBitmap.buffer[LBytePos];
if LByte <> $00 then begin
LByte := $00 ;
end else begin
LByte := $FF ;
end ;
LColorQuad.rgbRed := LByte;
LColorQuad.rgbGreen := LByte;
LColorQuad.rgbBlue := LByte;
LColorQuad.rgbReserved := $FF ;
LScanArray[LPosX] := LColorQuad;
inc(LBytePos);
end ;
end ;
Label1.Canvas.Draw(X, y, LBitmap);
finally
FreeAndNil(LBitmap);
end ;
end ;
上のサンプルでは,マイクロソフトの COLR / CPAL 仕様の Color Emoji フォント (マイクロソフトの用語では Color Font) を使用していますが,FT_LOAD_COLOR にしてもカラーにはなりません.
FreeType 2.9.1 はこの仕様のフォントには対応していません.以下のリンクの記事で,この仕様に対応した FreeType を提供している方がいます.少し分かりにくいのですが「Rebased the patch here」と書かれている部分です.以下の 2 番目のリンクが実際のダウンロードの URL です.
ダウンロードしたファイルは FreeType 2.9 相当ですが,DLL は含まれていません.Visual C++ でコンパイルして DLL を作成してテストしました.Visual Studio Express 2013 for Windows Desktop を使用しました.
Visual C++ 2013 で作成した DLL なので,Visual C++ 2013 のランタイムライブラリが必要です.マイクロソフトの以下のページからダウンロードできます.
32 ビットの EXE を実行する時は x86 のファイルをダウンロードしてインストールします.64 ビットの EXE を実行する時は x64 のファイルをダウンロードしてインストールします.
図21
[builds] [windows] [vc2010] フォルダ
freetype.vcxproj を Visual Studio の IDE で開く
[ビルド] [構成マネージャ] で [Release] を選択して [Win32] または [x64] を選択
[ビルド] [ソリューションのビルド]
図22
[objs] 直下に DLL が作成される
作成した DLL を使用した簡単なテストコードとその実行結果です.Windows 7 の環境でも,カラーの絵文字であればカラーで描画できることが確認できました.
上の手順でビルドした DLL と,Windows 10 からコピーした
Segoe UI Emoji フォント (ファイル名は seguiemj.ttf) を,EXE と同じフォルダ内に置いてテストしています.
本項の先頭から plFreeType_Test.zip をダウンロードすると,その中に EXE の作成と実行に必要なファイル類があります.ただしフォントファイルは同梱していません.
図23
下のコードを Windows 7 で実行した結果
Windows 7 でも,カラーの絵文字フォントであればカラーで描画できる
TBitmap の描画なのでいろいろな加工が可能
リスト8
COLR / CPAL 仕様に対応した FreeType を使用してカラー絵文字のフォントを描画
uses に FreeType が必要
copy code
implementation
{$R *.dfm}
const
FT_LOAD_COLOR = 1 shl 20 ;
// =============================================================================
// FreeTypeライブラリを使用してカラー絵文字を描画
// MicrosoftのEmoji(Color Font)のCOLR/CPAL対応のFreeTypeライブラリを使用
//
// Windows 10 のSegoe UI Emojiフォントをコピーしてテスト
// 1文字だけの簡単な例
// =============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
LFTLibrary : FT_Library;
LError : FT_Error;
LByteStream : TBytesStream;
LFontFilePath : string ;
LLineHeight : Integer;
LCodePoint : FT_ULong;
LFTFace : FT_Face;
LGlyphIndex : FT_UInt;
LGlyphSlot : FT_GlyphSlot;
LDrawLeft : Integer;
LDrawTop : Integer;
begin
// 文字を描画する背景を塗り潰す
Label1.Canvas.Brush.Style := bsClear;
Label1.Canvas.Brush.Color := clSilver;
Label1.Canvas.FillRect(Label1.Canvas.ClipRect);
// 文字の高さ(ピクセル数)
LLineHeight := 80 ;
// FreeTypeライブラリの初期化
LError := FT_Init_FreeType(LFTLibrary);
if LError <> 0 then Exit;
LByteStream := TBytesStream.Create;
try
// フォントファイルのデータをメモリストリームに読み込む
LFontFilePath := ExpandFileName('.\seguiemj.ttf' );
LByteStream.LoadFromFile(LFontFilePath);
// そのフォントデータからFT_Fac3オブジェクトを取得
FT_New_Memory_Face(LFTLibrary,
@LByteStream.Bytes[0 ],
LByteStream.Size,
0 ,
LFTFace );
// 描画するピクセルのサイズを設定
FT_Set_Pixel_Sizes(LFTFace, 0 , LLineHeight);
// グリフデータを取得する文字のコードポイント
LCodePoint := $1F61C ;
// コードポイントの値から文字のグリフ(字形)のインデックスを取得
LGlyphIndex := FT_Get_Char_Index(LFTFace, LCodePoint);
// FT_Face.GlyphSlotとしてグリフのデータのポインタを取得
FT_Load_Glyph(LFTFace, LGlyphIndex, FT_LOAD_COLOR);
// グリフのビットマップデータを取得
LGlyphSlot := LFTFace.glyph;
FT_Render_Glyph(LGlyphSlot, FT_RENDER_MODE_NORMAL);
// 描画開始位置を指定
LDrawLeft := 10 ;
LDrawTop := LLineHeight - LFTFace.glyph.bitmap_top;
// 取得したビットデータをTBitmapにして描画
DrawFreeTypeBitmap(LGlyphSlot.bitmap, LDrawLeft, LDrawTop);
finally
FreeAndNil(LByteStream);
end ;
// 終了処理
FT_Done_Face(LFTFace);
FT_Done_FreeType(LFTLibrary) ;
end ;
// -----------------------------------------------------------------------------
// FreeTypeで取得したビットマップデータをTBitmapのデータにして描画
// AFTBitmap : ビットマップのバイトデータ
// データはボトムアップ
// X : 描画会開始X座標値
// Y : 描画開始Y座標値
//
// 32ビットのアルファチャンネル付きのビットマプとして描画
// -----------------------------------------------------------------------------
procedure TForm1.DrawFreeTypeBitmap(AFTBitmap: FT_Bitmap; X, Y: Integer);
type
TRGBQArray = array [0 ..High(Integer) div 4 - 1 ] of RGBQUAD;
PRGBQArray = ^TRGBQArray;
var
LIsColor : Boolean;
LIncValue : Integer;
LBitmap : TBitmap;
LBytePos : Integer;
LPosX : Integer;
LPosY : Integer;
LScanArray : PRGBQArray;
LColorQuad : RGBQUAD;
LByte : Byte;
LBValue : Byte;
LGValue : Byte;
LRValue : Byte;
LAValue : Byte;
begin
LBitmap := TBitmap.Create;
try
LBitmap.SetSize(AFTBitmap.width, AFTBitmap.rows);
LBitmap.PixelFormat := pf32bit;
LBitmap.AlphaFormat := afDefined;
LIncValue := 1 ;
LIsColor := AFTBitmap.width = AFTBitmap.pitch div 4 ;
if LIsColor then LIncValue := 4 ;
LBytePos := 0 ;
for LPosY := 0 to LBitmap.Height - 1 do begin
LScanArray := LBitmap.ScanLine[LPosY];
for LPosX :=0 to LBitmap.Width - 1 do begin
if LIsColor then begin
LRValue := AFTBitmap.buffer[LBytePos + 0 ];
LGValue := AFTBitmap.buffer[LBytePos + 1 ];
LBValue := AFTBitmap.buffer[LBytePos + 2 ];
LAValue := AFTBitmap.buffer[LBytePos + 3 ];
end else begin
LByte := AFTBitmap.buffer[LBytePos];
if LByte <> $00 then begin
LRValue := $00 ;
LGValue := $00 ;
LBValue := $00 ;
LAValue := $FF ;
end else begin
LRValue := $FF ;
LGValue := $FF ;
LBValue := $FF ;
LAValue := $FF ;
end ;
end ;
LColorQuad.rgbRed := LRValue;
LColorQuad.rgbGreen := LGValue;
LColorQuad.rgbBlue := LBValue;
LColorQuad.rgbReserved := LAValue;
LScanArray[LPosX] := LColorQuad;
inc(LBytePos, LIncValue);
end ;
end ;
Label1.Canvas.Draw(X, y, LBitmap);
finally
FreeAndNil(LBitmap);
end ;
end ;