public static void Crop(Glyph glyph) { // Crop the top. while ((glyph.Subrect.Height > 1) && BitmapUtils.IsAlphaEntirely(0, glyph.Bitmap, new Rectangle(glyph.Subrect.X, glyph.Subrect.Y, glyph.Subrect.Width, 1))) { glyph.Subrect.Y++; glyph.Subrect.Height--; glyph.YOffset++; } // Crop the bottom. while ((glyph.Subrect.Height > 1) && BitmapUtils.IsAlphaEntirely(0, glyph.Bitmap, new Rectangle(glyph.Subrect.X, glyph.Subrect.Bottom - 1, glyph.Subrect.Width, 1))) { glyph.Subrect.Height--; } // Crop the left. while ((glyph.Subrect.Width > 1) && BitmapUtils.IsAlphaEntirely(0, glyph.Bitmap, new Rectangle(glyph.Subrect.X, glyph.Subrect.Y, 1, glyph.Subrect.Height))) { glyph.Subrect.X++; glyph.Subrect.Width--; glyph.XOffset++; } // Crop the right. while ((glyph.Subrect.Width > 1) && BitmapUtils.IsAlphaEntirely(0, glyph.Bitmap, new Rectangle(glyph.Subrect.Right - 1, glyph.Subrect.Y, 1, glyph.Subrect.Height))) { glyph.Subrect.Width--; } }
public static Bitmap ArrangeGlyphs(Glyph[] sourceGlyphs) { // Build up a list of all the glyphs needing to be arranged. List<ArrangedGlyph> glyphs = new List<ArrangedGlyph>(); for (int i = 0; i < sourceGlyphs.Length; i++) { ArrangedGlyph glyph = new ArrangedGlyph(); glyph.Source = sourceGlyphs[i]; // Leave a one pixel border around every glyph in the output bitmap. glyph.Width = sourceGlyphs[i].Subrect.Width + 2; glyph.Height = sourceGlyphs[i].Subrect.Height + 2; glyphs.Add(glyph); } // Sort so the largest glyphs get arranged first. glyphs.Sort(CompareGlyphSizes); // Work out how big the output bitmap should be. int outputWidth = GuessOutputWidth(sourceGlyphs); int outputHeight = 0; // Choose positions for each glyph, one at a time. for (int i = 0; i < glyphs.Count; i++) { PositionGlyph(glyphs, i, outputWidth); outputHeight = Math.Max(outputHeight, glyphs[i].Y + glyphs[i].Height); } // Create the merged output bitmap. outputHeight = MakeValidTextureSize(outputHeight, false); return CopyGlyphsToOutput(glyphs, outputWidth, outputHeight); }
// Heuristic guesses what might be a good output width for a list of glyphs. static int GuessOutputWidth(Glyph[] sourceGlyphs) { int maxWidth = 0; int totalSize = 0; foreach (Glyph glyph in sourceGlyphs) { maxWidth = Math.Max(maxWidth, glyph.Subrect.Width); totalSize += glyph.Subrect.Width * glyph.Subrect.Height; } int width = Math.Max((int)Math.Sqrt(totalSize), maxWidth); return MakeValidTextureSize(width, true); }
private Glyph ImportGlyph(Factory factory, FontFace fontFace, char character, FontMetrics fontMetrics, float fontSize, FontAntiAliasMode antiAliasMode) { var indices = fontFace.GetGlyphIndices(new int[] { character }); var metrics = fontFace.GetDesignGlyphMetrics(indices, false); var metric = metrics[0]; var width = (float)(metric.AdvanceWidth - metric.LeftSideBearing - metric.RightSideBearing) / fontMetrics.DesignUnitsPerEm * fontSize; var height = (float)(metric.AdvanceHeight - metric.TopSideBearing - metric.BottomSideBearing) / fontMetrics.DesignUnitsPerEm * fontSize; var xOffset = (float)metric.LeftSideBearing / fontMetrics.DesignUnitsPerEm * fontSize; var yOffset = (float)(metric.TopSideBearing - metric.VerticalOriginY) / fontMetrics.DesignUnitsPerEm * fontSize; var advanceWidth = (float)metric.AdvanceWidth / fontMetrics.DesignUnitsPerEm * fontSize; //var advanceHeight = (float)metric.AdvanceHeight / fontMetrics.DesignUnitsPerEm * fontSize; var pixelWidth = (int)Math.Ceiling(width + 4); var pixelHeight = (int)Math.Ceiling(height + 4); var matrix = Matrix.Identity; matrix.M41 = -(float)Math.Floor(xOffset) + 1; matrix.M42 = -(float)Math.Floor(yOffset) + 1; Bitmap bitmap; if (char.IsWhiteSpace(character)) { bitmap = new Bitmap(1, 1, PixelFormat.Format32bppArgb); } else { var glyphRun = new GlyphRun { FontFace = fontFace, Advances = new[] { (float)Math.Ceiling(advanceWidth) }, FontSize = fontSize, BidiLevel = 0, Indices = indices, IsSideways = false, Offsets = new[] { new GlyphOffset() } }; RenderingMode renderingMode; if (antiAliasMode != FontAntiAliasMode.Aliased) { var rtParams = new RenderingParams(factory); renderingMode = fontFace.GetRecommendedRenderingMode(fontSize, 1.0f, MeasuringMode.Natural, rtParams); rtParams.Dispose(); } else { renderingMode = RenderingMode.Aliased; } using (var runAnalysis = new GlyphRunAnalysis(factory, glyphRun, 1.0f, matrix, renderingMode, MeasuringMode.Natural, 0.0f, 0.0f)) { var bounds = new SharpDX.Rectangle(0, 0, pixelWidth, pixelHeight); bitmap = new Bitmap(bounds.Width, bounds.Height, PixelFormat.Format32bppArgb); if (renderingMode == RenderingMode.Aliased) { var texture = new byte[bounds.Width * bounds.Height]; runAnalysis.CreateAlphaTexture(TextureType.Aliased1x1, bounds, texture, texture.Length); for (int y = 0; y < bounds.Height; y++) { for (int x = 0; x < bounds.Width; x++) { int pixelX = y * bounds.Width + x; var grey = texture[pixelX]; var color = Color.FromArgb(grey, grey, grey); bitmap.SetPixel(x, y, color); } } } else { var texture = new byte[bounds.Width * bounds.Height * 3]; runAnalysis.CreateAlphaTexture(TextureType.Cleartype3x1, bounds, texture, texture.Length); for (int y = 0; y < bounds.Height; y++) { for (int x = 0; x < bounds.Width; x++) { int pixelX = (y * bounds.Width + x) * 3; var red = LinearToGamma(texture[pixelX]); var green = LinearToGamma(texture[pixelX + 1]); var blue = LinearToGamma(texture[pixelX + 2]); var color = Color.FromArgb(red, green, blue); bitmap.SetPixel(x, y, color); } } } } } var glyph = new Glyph(character, bitmap) { XOffset = -matrix.M41, XAdvance = advanceWidth, YOffset = -matrix.M42, }; return(glyph); }