なお、この記事で紹介している対処コードを利用しても、Yu Gothic UIフォントで描画処理を実行すると、
文字列をまとめて描画した場合と、1文字ずつ描画した場合の文字間隔が異なる結果になります。
これは、フォントの「プロポーショナル メトリクス」機能による影響です。
「プロポーショナル メトリクス」に対応して一文字ずつ出力する方法については
こちらの記事を参照して下さい。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Data;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Text;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace KerningDemo
{
public partial class FormTextDraw1 : Form
{
public FormTextDraw1()
{
InitializeComponent();
}
private void panel1_Paint(object sender, PaintEventArgs e)
{
string DrawText = "ぺんぎんクッキー";
Font f = new Font("メイリオ",28);
Brush b = new SolidBrush(Color.Black);
e.Graphics.TextRenderingHint = TextRenderingHint.AntiAlias;
e.Graphics.DrawString(DrawText, f,b,0,10);
int xpos = 0;
for (int i = 0; i < DrawText.Length; i++)
{
e.Graphics.DrawString(DrawText.Substring(i,1), f, b, xpos, 70);
xpos = xpos + (int)e.Graphics.MeasureString(DrawText.Substring(i, 1),f).Width;
}
xpos = 0;
for (int i = 0; i < DrawText.Length; i++)
{
e.Graphics.DrawString(DrawText.Substring(i, 1), f, b, xpos, 130);
xpos = xpos + (int)TextRenderer.MeasureText(e.Graphics, DrawText.Substring(i, 1), f).Width;
}
xpos = 0;
for (int i = 0; i < DrawText.Length; i++)
{
e.Graphics.DrawString(DrawText.Substring(i, 1), f, b, xpos, 190);
Rectangle rect = new Rectangle(xpos, 130, 200, 200);
StringFormat sf = new StringFormat();
CharacterRange[] characterRanges = { new CharacterRange(0, 1) };
sf.SetMeasurableCharacterRanges(characterRanges);
Region[] r = e.Graphics.MeasureCharacterRanges(DrawText.Substring(i, 1), f, rect, sf);
xpos = xpos + (int)r[0].GetBounds(e.Graphics).Width;
}
}
}
}
string DrawText = "ぺんぎんクッキー";
Font f = new Font("メイリオ",28);
Brush b = new SolidBrush(Color.Black);
e.Graphics.DrawString(DrawText, f,b,0,10);
int xpos = 0;
for (int i = 0; i < DrawText.Length; i++)
{
e.Graphics.DrawString(DrawText.Substring(i,1), f, b, xpos, 70);
xpos = xpos + (int)e.Graphics.MeasureString(DrawText.Substring(i, 1),f).Width;
}
xpos = 0;
for (int i = 0; i < DrawText.Length; i++)
{
e.Graphics.DrawString(DrawText.Substring(i, 1), f, b, xpos, 130);
xpos = xpos + (int)TextRenderer.MeasureText(e.Graphics, DrawText.Substring(i, 1), f).Width;
}
xpos = 0;
for (int i = 0; i < DrawText.Length; i++)
{
e.Graphics.DrawString(DrawText.Substring(i, 1), f, b, xpos, 190);
Rectangle rect = new Rectangle(xpos, 130, 200, 200);
StringFormat sf = new StringFormat();
CharacterRange[] characterRanges = { new CharacterRange(0, 1) };
sf.SetMeasurableCharacterRanges(characterRanges);
Region[] r = e.Graphics.MeasureCharacterRanges(DrawText.Substring(i, 1), f, rect, sf);
xpos = xpos + (int)r[0].GetBounds(e.Graphics).Width;
}
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Text;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace KerningDemo
{
[StructLayout(LayoutKind.Sequential)]
public struct LPSIZE
{
public int cx;
public int cy;
}
public partial class FormTextDraw2 : Form
{
[DllImport("gdi32.dll", CharSet = CharSet.Unicode)]
public static extern bool GetTextExtentPoint32(IntPtr hdc, string lpString, int cbString, out LPSIZE lpSize);
[DllImport("gdi32.dll", EntryPoint = "DeleteObject")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool DeleteObject([In] IntPtr hObject);
[DllImport("gdi32.dll", EntryPoint = "SelectObject")]
public static extern IntPtr SelectObject([In] IntPtr hdc, [In] IntPtr hgdiobj);
public FormTextDraw2()
{
InitializeComponent();
}
private void panel1_Paint(object sender, PaintEventArgs e)
{
string DrawText = "ぺんぎんクッキー";
Font f = new Font("メイリオ", 28);
Brush b = new SolidBrush(Color.Black);
e.Graphics.TextRenderingHint = TextRenderingHint.AntiAlias;
e.Graphics.DrawString(DrawText, f, b, 0, 10);
int xpos = 0;
for (int i = 0; i < DrawText.Length; i++)
{
e.Graphics.DrawString(DrawText.Substring(i, 1), f, b, xpos, 70);
Rectangle rect = new Rectangle(xpos, 70, 200, 200);
StringFormat sf = new StringFormat();
CharacterRange[] characterRanges = { new CharacterRange(0, 1) };
sf.SetMeasurableCharacterRanges(characterRanges);
Region[] r = e.Graphics.MeasureCharacterRanges(DrawText.Substring(i, 1), f, rect, sf);
xpos = xpos + (int)r[0].GetBounds(e.Graphics).Width;
}
xpos = 0;
for (int i = 0; i < DrawText.Length; i++)
{
e.Graphics.DrawString(DrawText.Substring(i, 1), f, b, xpos, 130);
IntPtr hDC = e.Graphics.GetHdc();
xpos = xpos + GetTextWidth(DrawText.Substring(i, 1), 1, hDC, f);
e.Graphics.ReleaseHdc(hDC);
}
}
private int GetTextWidth(string text, int SourceLength, IntPtr hdc, Font f)
{
LPSIZE textSize;
IntPtr oldfnt = SelectObject(hdc, f.ToHfont());
GetTextExtentPoint32(hdc, text, SourceLength, out textSize);
DeleteObject(SelectObject(hdc, oldfnt));
return textSize.cx;
}
}
}
private int GetTextWidth(string text, int SourceLength, IntPtr hdc, Font f)
{
LPSIZE textSize;
IntPtr oldfnt = SelectObject(hdc, f.ToHfont());
GetTextExtentPoint32(hdc, text, SourceLength, out textSize);
DeleteObject(SelectObject(hdc, oldfnt));
return textSize.cx;
}
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Text;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace KerningDemo
{
public partial class FormTextDraw3 : Form
{
public FormTextDraw3()
{
InitializeComponent();
}
private void panel1_Paint(object sender, PaintEventArgs e)
{
string DrawText = "ぺんぎんクッキー";
Font f = new Font("メイリオ", 28);
Brush b = new SolidBrush(Color.Black);
e.Graphics.TextRenderingHint = TextRenderingHint.AntiAlias;
TextRenderer.DrawText(e.Graphics, DrawText, f,new Point(0, 10), Color.Black);
int xpos = 0;
for (int i = 0; i < DrawText.Length; i++)
{
TextRenderer.DrawText(e.Graphics, DrawText.Substring(i,1), f, new Point(xpos, 70), Color.Black);
xpos += TextRenderer.MeasureText(e.Graphics, DrawText.Substring(i, 1), f).Width;
}
xpos = 0;
for (int i = 0; i < DrawText.Length; i++)
{
TextRenderer.DrawText(e.Graphics, DrawText.Substring(i, 1), f, new Point(xpos, 130), Color.Black);
xpos += TextRenderer.MeasureText(e.Graphics, DrawText.Substring(i, 1), f, new Size(100,100),TextFormatFlags.NoPadding).Width;
}
}
}
}
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Net.Sockets;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace KerningDemo
{
public partial class FormTextDraw4 : Form
{
[DllImport("gdi32.dll", EntryPoint = "SelectObject")]
public static extern IntPtr SelectObject([In] IntPtr hdc, [In] IntPtr hgdiobj);
[DllImport("gdi32.dll", EntryPoint = "DeleteObject")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool DeleteObject([In] IntPtr hObject);
[DllImport("gdi32.dll")]
public static extern int SetBkMode(IntPtr hdc, int iBkMode);
public enum BkMode
{
TRANSPARENT = 1,
OPAQUE = 2
}
[DllImport("gdi32.dll")]
public static extern uint SetTextColor(IntPtr hdc, int crColor);
[Flags]
public enum ETOOptions : uint
{
ETO_CLIPPED = 0x4,
ETO_GLYPH_INDEX = 0x10,
ETO_IGNORELANGUAGE = 0x1000,
ETO_NUMERICSLATIN = 0x800,
ETO_NUMERICSLOCAL = 0x400,
ETO_OPAQUE = 0x2,
ETO_PDY = 0x2000,
ETO_RTLREADING = 0x800,
}
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int _Left;
public int _Top;
public int _Right;
public int _Bottom;
}
[DllImport("gdi32.dll", EntryPoint = "ExtTextOutW")]
public static extern bool ExtTextOut(IntPtr hdc, int X, int Y, uint fuOptions,
[In] ref RECT lprc, [MarshalAs(UnmanagedType.LPWStr)] string lpString, uint cbCount, [In] IntPtr lpDx);
[DllImport("gdi32.dll", CharSet = CharSet.Unicode)]
public static extern bool GetTextExtentPoint32(IntPtr hdc, string lpString, int cbString, out LPSIZE lpSize);
public FormTextDraw4()
{
InitializeComponent();
}
private void panel1_Paint(object sender, PaintEventArgs e)
{
string DrawText = "ぺんぎんクッキー";
Font f = new Font("メイリオ", 28);
RECT rect;
rect._Top = 0;
rect._Left = 0;
rect._Bottom = 1000;
rect._Right = 1000;
IntPtr hDC = e.Graphics.GetHdc();
SetBkMode(hDC, (int)BkMode.TRANSPARENT);
SetTextColor(hDC, ColorTranslator.ToWin32(Color.Black));
IntPtr oldfnt = SelectObject(hDC, f.ToHfont());
ExtTextOut(hDC, 0, 10, (uint)ETOOptions.ETO_CLIPPED, ref rect, DrawText, (uint)DrawText.Length, IntPtr.Zero);
DeleteObject(SelectObject(hDC, oldfnt));
e.Graphics.ReleaseHdc(hDC);
//
hDC = e.Graphics.GetHdc();
SetBkMode(hDC, (int)BkMode.TRANSPARENT);
SetTextColor(hDC, ColorTranslator.ToWin32(Color.Black));
oldfnt = SelectObject(hDC, f.ToHfont());
int xpos = 0;
for (int i = 0; i < DrawText.Length; i++)
{
ExtTextOut(hDC, xpos, 70, (uint)ETOOptions.ETO_CLIPPED, ref rect, DrawText.Substring(i,1), 1, IntPtr.Zero);
xpos += GetTextWidth(DrawText.Substring(i, 1), 1, hDC, f);
}
DeleteObject(SelectObject(hDC, oldfnt));
e.Graphics.ReleaseHdc(hDC);
}
private int GetTextWidth(string text, int SourceLength, IntPtr hdc, Font f)
{
LPSIZE textSize;
IntPtr oldfnt = SelectObject(hdc, f.ToHfont());
GetTextExtentPoint32(hdc, text, SourceLength, out textSize);
DeleteObject(SelectObject(hdc, oldfnt));
return textSize.cx;
}
}
}