OSDN Git Service

046f402e7d7e702c278ac32228810c8af42f93d1
[dtxmania/dtxmania.git] / DTXManiaプロジェクト / コード / 全体 / CPrivateFont.cs
1 using System;\r
2 using System.Collections.Generic;\r
3 using System.Text;\r
4 using System.IO;\r
5 using System.Runtime.InteropServices;\r
6 using System.Drawing;\r
7 using System.Drawing.Drawing2D;\r
8 using System.Diagnostics;\r
9 using SlimDX;\r
10 using FDK;\r
11 \r
12 namespace DTXMania\r
13 {\r
14         /// <summary>\r
15         /// プライベートフォントでの描画を扱うクラス。\r
16         /// </summary>\r
17         /// <exception cref="FileNotFoundException">フォントファイルが見つからない時に例外発生</exception>\r
18         /// <exception cref="ArgumentException">スタイル指定不正時に例外発生</exception>\r
19         /// <remarks>\r
20         /// 簡単な使い方\r
21         /// CPrivateFont prvFont = new CPrivateFont( CSkin.Path( @"Graphics\fonts\mplus-1p-bold.ttf" ), 36 );   // プライベートフォント\r
22         /// とか\r
23         /// CPrivateFont prvFont = new CPrivateFont( new FontFamily("MS UI Gothic"), 36, FontStyle.Bold );              // システムフォント\r
24         /// とかした上で、\r
25         /// Bitmap bmp = prvFont.DrawPrivateFont( "ABCDE", Color.White, Color.Black );                                                  // フォント色=白、縁の色=黒の例。縁の色は省略可能\r
26         /// とか\r
27         /// Bitmap bmp = prvFont.DrawPrivateFont( "ABCDE", Color.White, Color.Black, Color.Yellow, Color.OrangeRed ); // 上下グラデーション(Yellow→OrangeRed)\r
28         /// とかして、\r
29         /// CTexture ctBmp = TextureFactory.tテクスチャの生成( bmp, false );\r
30         /// ctBMP.t2D描画( ~~~ );\r
31         /// で表示してください。\r
32         /// \r
33         /// 注意点\r
34         /// 任意のフォントでのレンダリングは結構負荷が大きいので、なるべkなら描画フレーム毎にフォントを再レンダリングするようなことはせず、\r
35         /// 一旦レンダリングしたものを描画に使い回すようにしてください。\r
36         /// また、長い文字列を与えると、返されるBitmapも横長になります。この横長画像をそのままテクスチャとして使うと、\r
37         /// 古いPCで問題を発生させやすいです。これを回避するには、一旦Bitmapとして取得したのち、256pixや512pixで分割して\r
38         /// テクスチャに定義するようにしてください。\r
39         /// </remarks>\r
40         public class CPrivateFont : IDisposable\r
41         {\r
42                 #region [ コンストラクタ ]\r
43                 public CPrivateFont(FontFamily fontfamily, int pt, FontStyle style)\r
44                 {\r
45                         Initialize(null, fontfamily, pt, style);\r
46                 }\r
47                 public CPrivateFont(FontFamily fontfamily, int pt)\r
48                 {\r
49                         Initialize(null, fontfamily, pt, FontStyle.Regular);\r
50                 }\r
51                 public CPrivateFont(string fontpath, int pt, FontStyle style)\r
52                 {\r
53                         Initialize(fontpath, null, pt, style);\r
54                 }\r
55                 public CPrivateFont(string fontpath, int pt)\r
56                 {\r
57                         Initialize(fontpath, null, pt, FontStyle.Regular);\r
58                 }\r
59                 public CPrivateFont()\r
60                 {\r
61                         //throw new ArgumentException("CPrivateFont: 引数があるコンストラクタを使用してください。");\r
62                 }\r
63                 #endregion\r
64 \r
65                 protected void Initialize(string fontpath, FontFamily fontfamily, int pt, FontStyle style)\r
66                 {\r
67                         this._pfc = null;\r
68                         this._fontfamily = null;\r
69                         this._font = null;\r
70                         this._pt = pt;\r
71                         this._rectStrings = new Rectangle(0, 0, 0, 0);\r
72                         this._ptOrigin = new Point(0, 0);\r
73                         this.bDispose完了済み = false;\r
74 \r
75                         if (fontfamily != null)\r
76                         {\r
77                                 this._fontfamily = fontfamily;\r
78                         }\r
79                         else\r
80                         {\r
81                                 try\r
82                                 {\r
83                                         this._pfc = new System.Drawing.Text.PrivateFontCollection();    //PrivateFontCollectionオブジェクトを作成する\r
84                                         this._pfc.AddFontFile(fontpath);                                                                //PrivateFontCollectionにフォントを追加する\r
85                                         _fontfamily = _pfc.Families[0];\r
86                                 }\r
87                                 catch (System.IO.FileNotFoundException)\r
88                                 {\r
89                                         Trace.TraceWarning("プライベートフォントの追加に失敗しました({0})。代わりにMS PGothicの使用を試みます。", fontpath);\r
90                                         //throw new FileNotFoundException( "プライベートフォントの追加に失敗しました。({0})", Path.GetFileName( fontpath ) );\r
91                                         //return;\r
92                                         _fontfamily = null;\r
93                                 }\r
94 \r
95                                 //foreach ( FontFamily ff in _pfc.Families )\r
96                                 //{\r
97                                 //      Debug.WriteLine( "fontname=" + ff.Name );\r
98                                 //      if ( ff.Name == Path.GetFileNameWithoutExtension( fontpath ) )\r
99                                 //      {\r
100                                 //              _fontfamily = ff;\r
101                                 //              break;\r
102                                 //      }\r
103                                 //}\r
104                                 //if ( _fontfamily == null )\r
105                                 //{\r
106                                 //      Trace.TraceError( "プライベートフォントの追加後、検索に失敗しました。({0})", fontpath );\r
107                                 //      return;\r
108                                 //}\r
109                         }\r
110 \r
111                         // 指定されたフォントスタイルが適用できない場合は、フォント内で定義されているスタイルから候補を選んで使用する\r
112                         // 何もスタイルが使えないようなフォントなら、例外を出す。\r
113                         if (_fontfamily != null)\r
114                         {\r
115                                 if (!_fontfamily.IsStyleAvailable(style))\r
116                                 {\r
117                                         FontStyle[] FS = { FontStyle.Regular, FontStyle.Bold, FontStyle.Italic, FontStyle.Underline, FontStyle.Strikeout };\r
118                                         style = FontStyle.Regular | FontStyle.Bold | FontStyle.Italic | FontStyle.Underline | FontStyle.Strikeout;      // null非許容型なので、代わりに全盛をNGワードに設定\r
119                                         foreach (FontStyle ff in FS)\r
120                                         {\r
121                                                 if (this._fontfamily.IsStyleAvailable(ff))\r
122                                                 {\r
123                                                         style = ff;\r
124                                                         Trace.TraceWarning("フォント{0}へのスタイル指定を、{1}に変更しました。", Path.GetFileName(fontpath), style.ToString());\r
125                                                         break;\r
126                                                 }\r
127                                         }\r
128                                         if (style == (FontStyle.Regular | FontStyle.Bold | FontStyle.Italic | FontStyle.Underline | FontStyle.Strikeout))\r
129                                         {\r
130                                                 Trace.TraceWarning("フォント{0}は適切なスタイル{1}を選択できませんでした。", Path.GetFileName(fontpath), style.ToString());\r
131                                         }\r
132                                 }\r
133                                 //this._font = new Font(this._fontfamily, pt, style);                   //PrivateFontCollectionの先頭のフォントのFontオブジェクトを作成する\r
134                                 float emSize = pt * 96.0f / 72.0f;\r
135                                 this._font = new Font(this._fontfamily, emSize, style, GraphicsUnit.Pixel);     //PrivateFontCollectionの先頭のフォントのFontオブジェクトを作成する\r
136                                 //HighDPI対応のため、pxサイズで指定\r
137                         }\r
138                         else\r
139                         // フォントファイルが見つからなかった場合 (MS PGothicを代わりに指定する)\r
140                         {\r
141                                 float emSize = pt * 96.0f / 72.0f;\r
142                                 this._font = new Font("MS PGothic", emSize, style, GraphicsUnit.Pixel); //MS PGothicのFontオブジェクトを作成する\r
143                                 FontFamily[] ffs = new System.Drawing.Text.InstalledFontCollection().Families;\r
144                                 int lcid = System.Globalization.CultureInfo.GetCultureInfo("en-us").LCID;\r
145                                 foreach (FontFamily ff in ffs)\r
146                                 {\r
147                                         // Trace.WriteLine( lcid ) );\r
148                                         if (ff.GetName(lcid) == "MS PGothic")\r
149                                         {\r
150                                                 this._fontfamily = ff;\r
151                                                 Trace.TraceInformation("MS PGothicを代わりに指定しました。");\r
152                                                 return;\r
153                                         }\r
154                                 }\r
155                                 throw new FileNotFoundException("プライベートフォントの追加に失敗し、MS PGothicでの代替処理にも失敗しました。({0})", Path.GetFileName(fontpath));\r
156                         }\r
157                 }\r
158 \r
159                 [Flags]\r
160                 protected enum DrawMode\r
161                 {\r
162                         Normal,\r
163                         Edge,\r
164                         Gradation\r
165                 }\r
166 \r
167                 #region [ DrawPrivateFontのオーバーロード群 ]\r
168                 /// <summary>\r
169                 /// 文字列を描画したテクスチャを返す\r
170                 /// </summary>\r
171                 /// <param name="drawstr">描画文字列</param>\r
172                 /// <param name="fontColor">描画色</param>\r
173                 /// <returns>描画済テクスチャ</returns>\r
174                 public Bitmap DrawPrivateFont(string drawstr, Color fontColor)\r
175                 {\r
176                         return DrawPrivateFont(drawstr, DrawMode.Normal, fontColor, Color.White, Color.White, Color.White);\r
177                 }\r
178 \r
179                 /// <summary>\r
180                 /// 文字列を描画したテクスチャを返す\r
181                 /// </summary>\r
182                 /// <param name="drawstr">描画文字列</param>\r
183                 /// <param name="fontColor">描画色</param>\r
184                 /// <param name="edgeColor">縁取色</param>\r
185                 /// <returns>描画済テクスチャ</returns>\r
186                 public Bitmap DrawPrivateFont(string drawstr, Color fontColor, Color edgeColor)\r
187                 {\r
188                         return DrawPrivateFont(drawstr, DrawMode.Edge, fontColor, edgeColor, Color.White, Color.White);\r
189                 }\r
190 \r
191                 /// <summary>\r
192                 /// 文字列を描画したテクスチャを返す\r
193                 /// </summary>\r
194                 /// <param name="drawstr">描画文字列</param>\r
195                 /// <param name="fontColor">描画色</param>\r
196                 /// <param name="gradationTopColor">グラデーション 上側の色</param>\r
197                 /// <param name="gradationBottomColor">グラデーション 下側の色</param>\r
198                 /// <returns>描画済テクスチャ</returns>\r
199                 //public Bitmap DrawPrivateFont( string drawstr, Color fontColor, Color gradationTopColor, Color gradataionBottomColor )\r
200                 //{\r
201                 //    return DrawPrivateFont( drawstr, DrawMode.Gradation, fontColor, Color.White, gradationTopColor, gradataionBottomColor );\r
202                 //}\r
203 \r
204                 /// <summary>\r
205                 /// 文字列を描画したテクスチャを返す\r
206                 /// </summary>\r
207                 /// <param name="drawstr">描画文字列</param>\r
208                 /// <param name="fontColor">描画色</param>\r
209                 /// <param name="edgeColor">縁取色</param>\r
210                 /// <param name="gradationTopColor">グラデーション 上側の色</param>\r
211                 /// <param name="gradationBottomColor">グラデーション 下側の色</param>\r
212                 /// <returns>描画済テクスチャ</returns>\r
213                 public Bitmap DrawPrivateFont(string drawstr, Color fontColor, Color edgeColor, Color gradationTopColor, Color gradataionBottomColor)\r
214                 {\r
215                         return DrawPrivateFont(drawstr, DrawMode.Edge | DrawMode.Gradation, fontColor, edgeColor, gradationTopColor, gradataionBottomColor);\r
216                 }\r
217 \r
218 #if こちらは使わない // (Bitmapではなく、CTextureを返す版)\r
219                 /// <summary>\r
220                 /// 文字列を描画したテクスチャを返す\r
221                 /// </summary>\r
222                 /// <param name="drawstr">描画文字列</param>\r
223                 /// <param name="fontColor">描画色</param>\r
224                 /// <returns>描画済テクスチャ</returns>\r
225                 public CTexture DrawPrivateFont( string drawstr, Color fontColor )\r
226                 {\r
227                         Bitmap bmp = DrawPrivateFont( drawstr, DrawMode.Normal, fontColor, Color.White, Color.White, Color.White );\r
228                         return TextureFactory.tテクスチャの生成( bmp, false );\r
229                 }\r
230 \r
231                 /// <summary>\r
232                 /// 文字列を描画したテクスチャを返す\r
233                 /// </summary>\r
234                 /// <param name="drawstr">描画文字列</param>\r
235                 /// <param name="fontColor">描画色</param>\r
236                 /// <param name="edgeColor">縁取色</param>\r
237                 /// <returns>描画済テクスチャ</returns>\r
238                 public CTexture DrawPrivateFont( string drawstr, Color fontColor, Color edgeColor )\r
239                 {\r
240                         Bitmap bmp = DrawPrivateFont( drawstr, DrawMode.Edge, fontColor, edgeColor, Color.White, Color.White );\r
241                         return TextureFactory.tテクスチャの生成( bmp, false );\r
242                 }\r
243 \r
244                 /// <summary>\r
245                 /// 文字列を描画したテクスチャを返す\r
246                 /// </summary>\r
247                 /// <param name="drawstr">描画文字列</param>\r
248                 /// <param name="fontColor">描画色</param>\r
249                 /// <param name="gradationTopColor">グラデーション 上側の色</param>\r
250                 /// <param name="gradationBottomColor">グラデーション 下側の色</param>\r
251                 /// <returns>描画済テクスチャ</returns>\r
252                 //public CTexture DrawPrivateFont( string drawstr, Color fontColor, Color gradationTopColor, Color gradataionBottomColor )\r
253                 //{\r
254                 //    Bitmap bmp = DrawPrivateFont( drawstr, DrawMode.Gradation, fontColor, Color.White, gradationTopColor, gradataionBottomColor );\r
255                 //        return TextureFactory.tテクスチャの生成( bmp, false );\r
256                 //}\r
257 \r
258                 /// <summary>\r
259                 /// 文字列を描画したテクスチャを返す\r
260                 /// </summary>\r
261                 /// <param name="drawstr">描画文字列</param>\r
262                 /// <param name="fontColor">描画色</param>\r
263                 /// <param name="edgeColor">縁取色</param>\r
264                 /// <param name="gradationTopColor">グラデーション 上側の色</param>\r
265                 /// <param name="gradationBottomColor">グラデーション 下側の色</param>\r
266                 /// <returns>描画済テクスチャ</returns>\r
267                 public CTexture DrawPrivateFont( string drawstr, Color fontColor, Color edgeColor,  Color gradationTopColor, Color gradataionBottomColor )\r
268                 {\r
269                         Bitmap bmp = DrawPrivateFont( drawstr, DrawMode.Edge | DrawMode.Gradation, fontColor, edgeColor, gradationTopColor, gradataionBottomColor );\r
270                         return TextureFactory.tテクスチャの生成( bmp, false );\r
271                 }\r
272 #endif\r
273                 #endregion\r
274 \r
275                 /// <summary>\r
276                 /// 文字列を描画したテクスチャを返す(メイン処理)\r
277                 /// </summary>\r
278                 /// <param name="rectDrawn">描画された領域</param>\r
279                 /// <param name="ptOrigin">描画文字列</param>\r
280                 /// <param name="drawstr">描画文字列</param>\r
281                 /// <param name="drawmode">描画モード</param>\r
282                 /// <param name="fontColor">描画色</param>\r
283                 /// <param name="edgeColor">縁取色</param>\r
284                 /// <param name="gradationTopColor">グラデーション 上側の色</param>\r
285                 /// <param name="gradationBottomColor">グラデーション 下側の色</param>\r
286                 /// <returns>描画済テクスチャ</returns>\r
287                 protected Bitmap DrawPrivateFont(string drawstr, DrawMode drawmode, Color fontColor, Color edgeColor, Color gradationTopColor, Color gradationBottomColor)\r
288                 {\r
289                         if (this._fontfamily == null || drawstr == null || drawstr == "")\r
290                         {\r
291                                 // nullを返すと、その後bmp→texture処理や、textureのサイズを見て・・の処理で全部例外が発生することになる。\r
292                                 // それは非常に面倒なので、最小限のbitmapを返してしまう。\r
293                                 // まずはこの仕様で進めますが、問題有れば(上位側からエラー検出が必要であれば)例外を出したりエラー状態であるプロパティを定義するなり検討します。\r
294                                 if (drawstr != "")\r
295                                 {\r
296                                         Trace.TraceWarning("DrawPrivateFont()の入力不正。最小値のbitmapを返します。");\r
297                                 }\r
298                                 _rectStrings = new Rectangle(0, 0, 0, 0);\r
299                                 _ptOrigin = new Point(0, 0);\r
300                                 return new Bitmap(1, 1);\r
301                         }\r
302                         bool bEdge = ((drawmode & DrawMode.Edge) == DrawMode.Edge);\r
303                         bool bGradation = ((drawmode & DrawMode.Gradation) == DrawMode.Gradation);\r
304 \r
305                         // 縁取りの縁のサイズは、とりあえずフォントの大きさの1/4とする\r
306                         int nEdgePt = (bEdge) ? _pt / 4 : 0;\r
307 \r
308                         // 描画サイズを測定する\r
309                         Size stringSize = System.Windows.Forms.TextRenderer.MeasureText(drawstr, this._font, new Size(int.MaxValue, int.MaxValue),\r
310                                 System.Windows.Forms.TextFormatFlags.NoPrefix |\r
311                                 System.Windows.Forms.TextFormatFlags.NoPadding\r
312                         );\r
313 \r
314                         //取得した描画サイズを基に、描画先のbitmapを作成する\r
315                         Bitmap bmp = new Bitmap(stringSize.Width + nEdgePt * 2, stringSize.Height + nEdgePt * 2);\r
316                         bmp.MakeTransparent();\r
317 \r
318                         using (Graphics g = Graphics.FromImage(bmp))\r
319                         {\r
320                                 g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;\r
321 \r
322                                 using (StringFormat sf = new StringFormat())\r
323                                 {\r
324                                         // 画面下部(垂直方向位置)\r
325                                         sf.LineAlignment = StringAlignment.Far;\r
326                                         // 画面中央(水平方向位置)\r
327                                         sf.Alignment = StringAlignment.Center;\r
328 \r
329                                         // レイアウト枠\r
330                                         Rectangle r = new Rectangle(0, 0, stringSize.Width + nEdgePt * 2, stringSize.Height + nEdgePt * 2);\r
331 \r
332                                         // 縁取り有りの描画\r
333                                         if (bEdge)\r
334                                         {\r
335                                                 // DrawPathで、ポイントサイズを使って描画するために、DPIを使って単位変換する\r
336                                                 // (これをしないと、単位が違うために、小さめに描画されてしまう)\r
337                                                 float sizeInPixels = _font.SizeInPoints * g.DpiY / 72;  // 1 inch = 72 points\r
338 \r
339                                                 using (System.Drawing.Drawing2D.GraphicsPath gp = new System.Drawing.Drawing2D.GraphicsPath())\r
340                                                 {\r
341                                                         gp.AddString(drawstr, this._fontfamily, (int)this._font.Style, sizeInPixels, r, sf);\r
342 \r
343                                                         // 縁取りを描画する\r
344                                                         using (Pen p = new Pen(edgeColor, nEdgePt))\r
345                                                         {\r
346                                                                 p.LineJoin = System.Drawing.Drawing2D.LineJoin.Round;\r
347                                                                 g.DrawPath(p, gp);\r
348 \r
349                                                                 // 塗りつぶす\r
350                                                                 using (Brush br = bGradation ?\r
351                                                                         new LinearGradientBrush(r, gradationTopColor, gradationBottomColor, LinearGradientMode.Vertical) as Brush :\r
352                                                                         new SolidBrush(fontColor) as Brush)\r
353                                                                 {\r
354                                                                         g.FillPath(br, gp);\r
355                                                                 }\r
356                                                         }\r
357                                                 }\r
358                                         }\r
359                                         else\r
360                                         {\r
361                                                 // 縁取りなしの描画\r
362                                                 using (Brush br = new SolidBrush(fontColor))\r
363                                                 {\r
364                                                         g.DrawString(drawstr, _font, br, 0f, 0f);\r
365                                                 }\r
366                                                 // System.Windows.Forms.TextRenderer.DrawText(g, drawstr, _font, new Point(0, 0), fontColor);\r
367                                         }\r
368 #if debug表示\r
369                         g.DrawRectangle( new Pen( Color.White, 1 ), new Rectangle( 1, 1, stringSize.Width-1, stringSize.Height-1 ) );\r
370                         g.DrawRectangle( new Pen( Color.Green, 1 ), new Rectangle( 0, 0, bmp.Width - 1, bmp.Height - 1 ) );\r
371 #endif\r
372                                         _rectStrings = new Rectangle(0, 0, stringSize.Width, stringSize.Height);\r
373                                         _ptOrigin = new Point(nEdgePt * 2, nEdgePt * 2);\r
374                                 }\r
375                         }\r
376 \r
377                         return bmp;\r
378                 }\r
379 \r
380                 /// <summary>\r
381                 /// 最後にDrawPrivateFont()した文字列の描画領域を取得します。\r
382                 /// </summary>\r
383                 public Rectangle RectStrings\r
384                 {\r
385                         get\r
386                         {\r
387                                 return _rectStrings;\r
388                         }\r
389                         protected set\r
390                         {\r
391                                 _rectStrings = value;\r
392                         }\r
393                 }\r
394                 public Point PtOrigin\r
395                 {\r
396                         get\r
397                         {\r
398                                 return _ptOrigin;\r
399                         }\r
400                         protected set\r
401                         {\r
402                                 _ptOrigin = value;\r
403                         }\r
404                 }\r
405 \r
406                 #region [ IDisposable 実装 ]\r
407                 //-----------------\r
408                 public void Dispose()\r
409                 {\r
410                         if (!this.bDispose完了済み)\r
411                         {\r
412                                 if (this._font != null)\r
413                                 {\r
414                                         this._font.Dispose();\r
415                                         this._font = null;\r
416                                 }\r
417                                 if (this._pfc != null)\r
418                                 {\r
419                                         this._pfc.Dispose();\r
420                                         this._pfc = null;\r
421                                 }\r
422 \r
423                                 this.bDispose完了済み = true;\r
424                         }\r
425                 }\r
426                 //-----------------\r
427                 #endregion\r
428 \r
429                 #region [ private ]\r
430                 //-----------------\r
431                 protected bool bDispose完了済み;\r
432                 protected Font _font;\r
433 \r
434                 private System.Drawing.Text.PrivateFontCollection _pfc;\r
435                 private FontFamily _fontfamily;\r
436                 private int _pt;\r
437                 private Rectangle _rectStrings;\r
438                 private Point _ptOrigin;\r
439                 //-----------------\r
440                 #endregion\r
441         }\r
442 }\r