25 using System.Collections.Generic;
28 using SharpDX.Direct2D1;
29 using SharpDX.DirectWrite;
35 namespace SiliconStudio.Paradox.Assets.SpriteFont.Compiler
38 using System.Drawing.Imaging;
42 internal class TrueTypeImporter : IFontImporter
47 public float LineSpacing {
get;
private set; }
49 public float BaseLine {
get;
private set; }
51 public void Import(SpriteFontAsset options,
List<char> characters)
56 FontFace fontFace = options.Source != null ? GetFontFaceFromSource(factory, options) : GetFontFaceFromSystemFonts(factory, options);
58 var fontMetrics = fontFace.Metrics;
61 var fontSize = FontHelper.PointsToPixels(options.Size);
63 var glyphList =
new List<Glyph>();
75 var lineGap = fontMetrics.LineGap * options.LineGapFactor;
78 LineSpacing = (float)(lineGap + fontMetrics.Ascent + fontMetrics.Descent) / fontMetrics.DesignUnitsPerEm * fontSize;
83 BaseLine = (float)(lineGap * options.LineGapBaseLineFactor + fontMetrics.Ascent) / fontMetrics.DesignUnitsPerEm * fontSize;
86 foreach (var character
in characters)
87 glyphList.Add(ImportGlyph(factory, fontFace, character, fontMetrics, fontSize, options.AntiAlias));
94 private FontFace GetFontFaceFromSource(
Factory factory, SpriteFontAsset options)
96 if (!
File.Exists(options.Source))
99 throw new FontNotFoundException(options.Source);
102 using (var fontFile =
new FontFile(factory, options.Source))
104 FontSimulations fontSimulations;
105 switch (options.Style)
107 case Paradox.Graphics.Font.FontStyle.Regular:
108 fontSimulations = FontSimulations.None;
110 case Paradox.Graphics.Font.FontStyle.Bold:
111 fontSimulations = FontSimulations.Bold;
113 case Paradox.Graphics.Font.FontStyle.Italic:
114 fontSimulations = FontSimulations.Oblique;
117 throw new ArgumentOutOfRangeException();
121 FontFileType fontType;
122 FontFaceType faceType;
125 fontFile.Analyze(out isSupported, out fontType, out faceType, out numberFaces);
127 return new FontFace(factory, faceType,
new[] { fontFile }, 0, fontSimulations);
131 private FontFace GetFontFaceFromSystemFonts(
Factory factory, SpriteFontAsset options)
133 SharpDX.DirectWrite.Font font;
134 using (var fontCollection = factory.GetSystemFontCollection(
false))
137 if (!fontCollection.FindFamilyName(options.FontName, out index))
140 throw new FontNotFoundException(options.FontName);
143 using (var fontFamily = fontCollection.GetFontFamily(index))
145 var weight = FontWeight.Regular;
146 var style = SharpDX.DirectWrite.FontStyle.Normal;
147 switch (options.Style)
149 case Paradox.Graphics.Font.FontStyle.Bold:
150 weight = FontWeight.Bold;
152 case Paradox.Graphics.Font.FontStyle.Italic:
153 weight = FontWeight.Regular;
154 style = SharpDX.DirectWrite.FontStyle.Italic;
156 case Paradox.Graphics.Font.FontStyle.Regular:
157 weight = FontWeight.Regular;
160 font = fontFamily.GetFirstMatchingFont(weight, FontStretch.Normal, style);
164 return new FontFace(font);
167 private Glyph ImportGlyph(
Factory factory, FontFace fontFace,
char character, FontMetrics fontMetrics,
float fontSize,
FontAntiAliasMode antiAliasMode)
169 var indices = fontFace.GetGlyphIndices(
new int[] { character });
171 var metrics = fontFace.GetDesignGlyphMetrics(indices,
false);
172 var metric = metrics[0];
174 var width = (float)(metric.AdvanceWidth - metric.LeftSideBearing - metric.RightSideBearing) / fontMetrics.DesignUnitsPerEm * fontSize;
175 var height = (float)(metric.AdvanceHeight - metric.TopSideBearing - metric.BottomSideBearing) / fontMetrics.DesignUnitsPerEm * fontSize;
177 var xOffset = (float)metric.LeftSideBearing / fontMetrics.DesignUnitsPerEm * fontSize;
178 var yOffset = (
float)(metric.TopSideBearing - metric.VerticalOriginY) / fontMetrics.DesignUnitsPerEm * fontSize;
180 var advanceWidth = (
float)metric.AdvanceWidth / fontMetrics.DesignUnitsPerEm * fontSize;
183 var pixelWidth = (int)Math.Ceiling(width + 4);
184 var pixelHeight = (int)Math.Ceiling(height + 4);
186 var matrix = Matrix.Identity;
187 matrix.M41 = -(float)Math.Floor(xOffset) + 1;
188 matrix.M42 = -(float)Math.Floor(yOffset) + 1;
191 if (
char.IsWhiteSpace(character))
193 bitmap =
new Bitmap(1, 1,
PixelFormat.Format32bppArgb);
197 var glyphRun =
new GlyphRun
200 Advances =
new[] { (float)Math.Ceiling(advanceWidth) },
205 Offsets =
new[] {
new GlyphOffset() }
209 RenderingMode renderingMode;
212 var rtParams =
new RenderingParams(factory);
213 renderingMode = fontFace.GetRecommendedRenderingMode(fontSize, 1.0f, MeasuringMode.Natural, rtParams);
218 renderingMode = RenderingMode.Aliased;
221 using (var runAnalysis =
new GlyphRunAnalysis(factory,
226 MeasuringMode.Natural,
231 var bounds =
new SharpDX.Rectangle(0, 0, pixelWidth, pixelHeight);
232 bitmap =
new Bitmap(bounds.Width, bounds.Height,
PixelFormat.Format32bppArgb);
234 if (renderingMode == RenderingMode.Aliased)
237 var texture =
new byte[bounds.Width * bounds.Height];
238 runAnalysis.CreateAlphaTexture(TextureType.Aliased1x1, bounds, texture, texture.Length);
239 for (
int y = 0;
y < bounds.Height;
y++)
241 for (
int x = 0; x < bounds.Width; x++)
243 int pixelX =
y * bounds.Width + x;
244 var grey = texture[pixelX];
245 var color = Color.FromArgb(grey, grey, grey);
247 bitmap.SetPixel(x,
y, color);
253 var texture =
new byte[bounds.Width * bounds.Height * 3];
254 runAnalysis.CreateAlphaTexture(TextureType.Cleartype3x1, bounds, texture, texture.Length);
255 for (
int y = 0;
y < bounds.Height;
y++)
257 for (
int x = 0; x < bounds.Width; x++)
259 int pixelX = (
y * bounds.Width + x) * 3;
260 var red = LinearToGamma(texture[pixelX]);
261 var green = LinearToGamma(texture[pixelX + 1]);
262 var blue = LinearToGamma(texture[pixelX + 2]);
263 var color = Color.FromArgb(red, green, blue);
265 bitmap.SetPixel(x,
y, color);
272 var glyph =
new Glyph(character, bitmap)
274 XOffset = -matrix.M41,
275 XAdvance = advanceWidth,
276 YOffset = -matrix.M42,
281 private static byte LinearToGamma(byte color)
283 return (byte)(Math.Pow(color / 255.0f, 1 / 2.2f) * 255.0f);
SharpDX.DirectWrite.Factory Factory
_In_ size_t _In_ DXGI_FORMAT _In_ size_t _In_ float size_t y
SharpDX.DirectWrite.Font Font
Description of a glyph (a single character)
FontAntiAliasMode
Available antialias mode.
PixelFormat
Defines various types of pixel formats.