絵文字をフォント自体に定義された色で描画する

絵文字を単純に System.Drawing.Graphics.DrawString メソッドで描画すると、このDrawStringで指定したBrushの色で描画されます。 絵文字自体に定義された色では描画されません。せっかくの絵文字がもったいない・・・
ここでは、DirectWriteを使って、絵文字をフォント自体に定義された色で描画するサンプルを示します。

■ 前準備
DirectXをC#から使えるようにする前準備が必要です。ここではラッパーの一つである SharpDX を使うことにします。
nugetのSharpDXのサイトを訪れ、以下のパッケージをインストールします。
 * SharpDX.Direct2D1
 * SharpDX.Mathmatics
 * SharpDX.Desktop
※ SharpDX.Direct2D1をインストールすると、依存関係から SharpDX (Core) と SharpDX.DXGI もインストールされます。

■ 実装
前準備が出来たら、以下のようなコードを実装します。
この中の DrawTextLayout で、DrawTextOptions.EnableColorFont を指定するのがミソになります。
このコードで、左のようなイメージが生成されます。


using System;
using SharpDX;
using SharpDX.Direct2D1;
using SharpDX.DirectWrite;
using System.Windows.Forms;
using D2DFactory = SharpDX.Direct2D1.Factory;
using DWriteFactory = SharpDX.DirectWrite.Factory;

namespace PopMaker
{
    public partial class EmojiForm : Form
    {
        private D2DFactory d2dFactory;
        private DWriteFactory dwFactory;

        public EmojiForm()
        {
            InitializeComponent();
            System.Drawing.Bitmap bitmap = CreateEmoji();
            pictureBox.Image = bitmap;
        }

        // 絵文字をフォント自体の色を用いて描画したイメージを作成する
        public System.Drawing.Bitmap CreateEmoji()
        {
            string text = "😄💌🐶";
            RenderTargetProperties renderTargetProperties = new RenderTargetProperties();
            renderTargetProperties.Type = RenderTargetType.Default;
            renderTargetProperties.PixelFormat = new PixelFormat(SharpDX.DXGI.Format.B8G8R8A8_UNorm, AlphaMode.Premultiplied);
            d2dFactory = new D2DFactory();
            DeviceContextRenderTarget renderTarget = new DeviceContextRenderTarget(d2dFactory, renderTargetProperties);

            dwFactory = new DWriteFactory(SharpDX.DirectWrite.FactoryType.Shared);
            SolidColorBrush pBrush = new SolidColorBrush(renderTarget, Color.Black);
            TextFormat textFormat = new TextFormat(dwFactory, "Arial", FontWeight.Regular, FontStyle.Normal, 32.0f);
            TextLayout textLayout = new TextLayout(dwFactory, text, textFormat, 300.0f, 200.0f);
            TextMetrics textMetrics = textLayout.Metrics;
            float overhangTop = textLayout.OverhangMetrics.Top;
            int W = (int)Math.Ceiling(textMetrics.Width);
            int H = (int)Math.Ceiling(textMetrics.Height + overhangTop);

            System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap(W, H);
            System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(bitmap);
            IntPtr hDC = g.GetHdc();
            Rectangle rect = new Rectangle(0, 0, W, H);
            renderTarget.BindDeviceContext(hDC, rect);
            renderTarget.BeginDraw();
            renderTarget.DrawTextLayout(new Vector2(0, overhangTop), textLayout, pBrush, DrawTextOptions.EnableColorFont);
            renderTarget.EndDraw();
            renderTarget.Dispose();

            g.ReleaseHdc();
            g.Dispose();
            return bitmap;
        }
    }
}