Delphi の ImageCollection へ Unicode絵文字をカラーで追加

Delphi の VirtualImageList(TVirtualImageList) を利用して、絵文字をアイコンとして、ImageCollection(TImageCollection) へ Unicode絵文字をカラーで動的に追加したい

通常の Canvas で TextOut するとモノクロになるので、Direct2D を使うんだとか
また、生成する画像サイズに収まるようにするため、フォントサイズを変化させながら収まるサイズを探しています

で、出来た関数
※投入後、VirtualImageList.AutoFill := False → True で反映されます
VirtualImageList が高DPIへサイズ調整するので、利用サイズより大きめで作成しておきましょう

uses Vcl.Graphics, Vcl.BaseImageCollection, Vcl.ImageCollection, System.ImageList, Vcl.ImgList, Vcl.VirtualImageList, Vcl.ComCtrls,
     Vcl.Direct2D, Winapi.D2D1

function AddImageCollectionItemFromEmoji(AImageCollection: TImageCollection; AEmoji: string; AWidth: Integer = 32; AHeight: Integer = 32; AItemName: string = ''; AMaxFontSize: Integer = 32): Integer;
var
    Bitmap: TBitmap;
    CollectionItem: TImageCollectionItem;
    SourceItem: TImageCollectionSourceItem;
    D2DCanvas: TDirect2DCanvas;
    Size: Integer;
begin
    Bitmap := TBitmap.Create;
    try
        Bitmap.SetSize(AWidth, AHeight);
        Bitmap.PixelFormat := pf32bit;
        Bitmap.AlphaFormat := afPremultiplied;

        D2DCanvas := TDirect2DCanvas.Create(Bitmap.Canvas, Rect(0, 0, AWidth, AHeight));
        try
            D2DCanvas.BeginDraw;
            
            
            // 背景を透過
            D2DCanvas.RenderTarget.Clear(D2D1ColorF(0, 0, 0, 0));
            

            // キャンバスに収まるフォントサイズを探す
            D2DCanvas.Font.Name := 'Segoe UI Emoji';
            for Size := AMaxFontSize downto 8 do begin
                D2DCanvas.Font.Size := Size;
                if (D2DCanvas.TextWidth(AEmoji) <= (Bitmap.Width)) and (D2DCanvas.TextHeight(AEmoji) <= (Bitmap.Height)) then begin
                    Break;
                end;
            end;

            // 中央寄せ
            D2DCanvas.Font.Handle.SetTextAlignment(DWRITE_TEXT_ALIGNMENT_CENTER);
            D2DCanvas.Font.Handle.SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_CENTER);

            // Direct2Dで描画
            D2DCanvas.RenderTarget.DrawText( //
              PWideChar(AEmoji), //
              Length(AEmoji), //
              D2DCanvas.Font.Handle, //
              D2D1RectF(0, 0, AWidth, AHeight), //
              D2DCanvas.Brush.Handle, //
              D2D1_DRAW_TEXT_OPTIONS_ENABLE_COLOR_FONT);

            D2DCanvas.EndDraw;
        finally
            D2DCanvas.Free;
        end;

        CollectionItem := AImageCollection.Images.Add;
        CollectionItem.Name := AItemName;
        Result := CollectionItem.Index;

        SourceItem := CollectionItem.SourceImages.Add;
        SourceItem.Image.Assign(Bitmap);
    finally
        Bitmap.Free;
    end;
end;

コメント