public IAsset LoadAsset(StagedAsset stagedAsset) { IAsset asset = null; switch (stagedAsset.Type) { case (AssetType.AudioAsset): asset = new AudioAsset(stagedAsset.Id, new AudioFileReader(stagedAsset.FilePath)); break; case (AssetType.SpriteFontAsset): { SpriteFont sf; lock (stagedAsset.Content) sf = stagedAsset.Content.Load <SpriteFont>(stagedAsset.FilePath); asset = new SpriteFontAsset(stagedAsset.Id, sf); } break; case (AssetType.Texture2DAsset): { Texture2D td; lock (stagedAsset.Content) td = stagedAsset.Content.Load <Texture2D>(stagedAsset.FilePath); asset = new Texture2DAsset(stagedAsset.Id, td); } break; } return(asset); }
public static List <char> GetCharactersToImport(SpriteFontAsset asset) { var characters = new List <char>(); var fontTypeStatic = asset.FontType as OfflineRasterizedSpriteFontType; if (fontTypeStatic == null) { throw new ArgumentException("Tried to compile a dynamic sprite font with compiler for signed distance field fonts"); } // extract the list from the provided file if it exits if (File.Exists(fontTypeStatic.CharacterSet)) { string text; using (var streamReader = new StreamReader(fontTypeStatic.CharacterSet, Encoding.UTF8)) text = streamReader.ReadToEnd(); characters.AddRange(text); } // add character coming from character ranges characters.AddRange(CharacterRegion.Flatten(fontTypeStatic.CharacterRegions)); // remove duplicated characters characters = characters.Distinct().ToList(); return(characters); }
// Writes a block compressed monochromatic font texture. static unsafe Graphics.Image GetCompressedMono(Bitmap bitmap, SpriteFontAsset options) { if ((bitmap.Width & 3) != 0 || (bitmap.Height & 3) != 0) { throw new ArgumentException("Block compression requires texture size to be a multiple of 4."); } var image = Graphics.Image.New2D(bitmap.Width, bitmap.Height, 1, Graphics.PixelFormat.BC2_UNorm); var pixelBuffer = (BC2Pixel *)image.PixelBuffer[0].DataPointer; using (var bitmapData = new BitmapUtils.PixelAccessor(bitmap, ImageLockMode.ReadOnly)) { for (int y = 0; y < bitmap.Height; y += 4) { for (int x = 0; x < bitmap.Width; x += 4) { BC2Pixel bc2Pixel; CompressBlock(bitmapData, x, y, options, out bc2Pixel); *pixelBuffer = bc2Pixel; pixelBuffer++; } } } return(image); }
static Glyph[] ImportFont(SpriteFontAsset options, out float lineSpacing, out float baseLine) { // Which importer knows how to read this source font? IFontImporter importer; var sourceExtension = (Path.GetExtension(options.Source) ?? "").ToLowerInvariant(); var bitmapFileExtensions = new List<string> { ".bmp", ".png", ".gif" }; var importFromBitmap = bitmapFileExtensions.Contains(sourceExtension); importer = importFromBitmap ? (IFontImporter) new BitmapImporter() : new TrueTypeImporter(); // create the list of character to import var characters = GetCharactersToImport(options); // Import the source font data. importer.Import(options, characters); lineSpacing = importer.LineSpacing; baseLine = importer.BaseLine; // Get all glyphs var glyphs = new List<Glyph>(importer.Glyphs); // Validate. if (glyphs.Count == 0) { throw new Exception("Font does not contain any glyphs."); } if (!importFromBitmap && options.AntiAlias != FontAntiAliasMode.ClearType) { foreach (var glyph in importer.Glyphs) BitmapUtils.ConvertGreyToAlpha(glyph.Bitmap, glyph.Subrect); } // Sort the glyphs glyphs.Sort((left, right) => left.Character.CompareTo(right.Character)); // Check that the default character is part of the glyphs if (options.DefaultCharacter != 0) { bool defaultCharacterFound = false; foreach (var glyph in glyphs) { if (glyph.Character == options.DefaultCharacter) { defaultCharacterFound = true; break; } } if (!defaultCharacterFound) { throw new InvalidOperationException("The specified DefaultCharacter is not part of this font."); } } return glyphs.ToArray(); }
/// <inheritdoc/> public void Import(SpriteFontAsset options, List <char> characters) { fontSource = options.FontSource.GetFontPath(); if (string.IsNullOrEmpty(fontSource)) { return; } // Get the msdfgen.exe location var msdfgen = ToolLocator.LocateTool("msdfgen.exe") ?? throw new AssetException("Failed to compile a font asset, msdfgen was not found."); msdfgenExe = msdfgen.FullPath; tempDir = $"{Environment.GetEnvironmentVariable("TEMP")}\\"; var factory = new Factory(); FontFace fontFace = options.FontSource.GetFontFace(); var fontMetrics = fontFace.Metrics; // Create a bunch of GDI+ objects. var fontSize = options.FontType.Size; var glyphList = new List <Glyph>(); // Remap the LineMap coming from the font with a user defined remapping // Note: // We are remapping the lineMap to allow to shrink the LineGap and to reposition it at the top and/or bottom of the // font instead of using only the top // According to http://stackoverflow.com/questions/13939264/how-to-determine-baseline-position-using-directwrite#comment27947684_14061348 // (The response is from a MSFT employee), the BaseLine should be = LineGap + Ascent but this is not what // we are experiencing when comparing with MSWord (LineGap + Ascent seems to offset too much.) // // So we are first applying a factor to the line gap: // NewLineGap = LineGap * LineGapFactor var lineGap = fontMetrics.LineGap * options.LineGapFactor; // Store the font height. LineSpacing = (float)(lineGap + fontMetrics.Ascent + fontMetrics.Descent) / fontMetrics.DesignUnitsPerEm * fontSize; // And then the baseline is also changed in order to allow the linegap to be distributed between the top and the // bottom of the font: // BaseLine = NewLineGap * LineGapBaseLineFactor BaseLine = (float)(lineGap * options.LineGapBaseLineFactor + fontMetrics.Ascent) / fontMetrics.DesignUnitsPerEm * fontSize; // Generate SDF bitmaps for each character in turn. foreach (var character in characters) { glyphList.Add(ImportGlyph(fontFace, character, fontMetrics, fontSize)); } Glyphs = glyphList; factory.Dispose(); }
static Graphics.Image GetImage(SpriteFontAsset options, Bitmap bitmap) { switch (options.Format) { case FontTextureFormat.Rgba32: return(GetImageRgba32(bitmap)); default: throw new NotSupportedException(); } }
public void Import(SpriteFontAsset options, List <char> characters) { // Load the source bitmap. Bitmap bitmap; try { // TODO Check if source can be used as is from here bitmap = new Bitmap(options.FontSource.GetFontPath()); } catch { throw new FontNotFoundException(options.FontSource.GetFontPath()); } // Convert to our desired pixel format. bitmap = BitmapUtils.ChangePixelFormat(bitmap, PixelFormat.Format32bppArgb); // What characters are included in this font? int characterIndex = 0; char currentCharacter = '\0'; // Split the source image into a list of individual glyphs. var glyphList = new List <Glyph>(); Glyphs = glyphList; LineSpacing = 0; foreach (Rectangle rectangle in FindGlyphs(bitmap)) { if (characterIndex < characters.Count) { currentCharacter = characters[characterIndex++]; } else { currentCharacter++; } glyphList.Add(new Glyph(currentCharacter, bitmap, rectangle) { XAdvance = rectangle.Width }); LineSpacing = Math.Max(LineSpacing, rectangle.Height); } // If the bitmap doesn't already have an alpha channel, create one now. if (BitmapUtils.IsAlphaEntirely(255, bitmap)) { BitmapUtils.ConvertGreyToAlpha(bitmap, new Rectangle(0, 0, bitmap.Width, bitmap.Height)); } }
static Graphics.Image GetImage(SpriteFontAsset options, Bitmap bitmap) { switch (options.Format) { //case FontTextureFormat.Auto: case FontTextureFormat.Rgba32: return(GetImageRgba32(bitmap)); //case FontTextureFormat.CompressedMono: // return GetCompressedMono(bitmap, options); default: throw new NotSupportedException(); } }
/// <summary> /// Compiles the specified font description into a <see cref="SignedDistanceFieldSpriteFont" /> object. /// </summary> /// <param name="fontFactory">The font factory used to create the fonts</param> /// <param name="fontAsset">The font description.</param> /// <returns>A SpriteFontData object.</returns> public static Graphics.SpriteFont Compile(IFontFactory fontFactory, SpriteFontAsset fontAsset) { if (fontAsset.FontType != SpriteFontType.SDF) { throw new ArgumentException("Tried to compile an incompatible sprite font with compiler for scalable fonts"); } float lineSpacing; float baseLine; var glyphs = ImportFont(fontAsset, out lineSpacing, out baseLine); Bitmap bitmap = GlyphPacker.ArrangeGlyphs(glyphs); return(SignedDistanceFieldFontWriter.CreateSpriteFontData(fontFactory, fontAsset, glyphs, lineSpacing, baseLine, bitmap)); }
static Glyph[] ImportFont(SpriteFontAsset options, out float lineSpacing, out float baseLine) { // Which importer knows how to read this source font? IFontImporter importer; var sourceExtension = (Path.GetExtension(options.FontSource.GetFontPath()) ?? "").ToLowerInvariant(); var bitmapFileExtensions = new List <string> { ".bmp", ".png", ".gif" }; var importFromBitmap = bitmapFileExtensions.Contains(sourceExtension); if (importFromBitmap) { throw new Exception("SDF Font from image is not supported!"); } importer = new SignedDistanceFieldFontImporter(); // create the list of character to import var characters = GetCharactersToImport(options); // Import the source font data. importer.Import(options, characters); lineSpacing = importer.LineSpacing; baseLine = importer.BaseLine; // Get all glyphs var glyphs = new List <Glyph>(importer.Glyphs); // Validate. if (glyphs.Count == 0) { throw new Exception("Font does not contain any glyphs."); } // Sort the glyphs glyphs.Sort((left, right) => left.Character.CompareTo(right.Character)); // Check that the default character is part of the glyphs if (!DefaultCharacterExists(options.DefaultCharacter, glyphs)) { throw new InvalidOperationException("The specified DefaultCharacter is not part of this font."); } return(glyphs.ToArray()); }
/// <summary> /// Compiles the specified font description into a <see cref="OfflineRasterizedSpriteFont" /> object. /// </summary> /// <param name="fontFactory">The font factory used to create the fonts</param> /// <param name="fontAsset">The font description.</param> /// <param name="srgb"></param> /// <returns>A SpriteFontData object.</returns> public static Graphics.SpriteFont Compile(IFontFactory fontFactory, SpriteFontAsset fontAsset, bool srgb) { var fontTypeStatic = fontAsset.FontType as OfflineRasterizedSpriteFontType; if (fontTypeStatic == null) { throw new ArgumentException("Tried to compile a dynamic sprite font with compiler for static fonts"); } float lineSpacing; float baseLine; var glyphs = ImportFont(fontAsset, out lineSpacing, out baseLine); // Optimize. foreach (Glyph glyph in glyphs) { GlyphCropper.Crop(glyph); } Bitmap bitmap = GlyphPacker.ArrangeGlyphs(glyphs); // Automatically detect whether this is a monochromatic or color font? //if (fontAsset.Format == FontTextureFormat.Auto) //{ // bool isMono = BitmapUtils.IsRgbEntirely(Color.White, bitmap); // // fontAsset.Format = isMono ? FontTextureFormat.CompressedMono : // FontTextureFormat.Rgba32; //} // Convert to pre-multiplied alpha format. if (fontAsset.FontType.IsPremultiplied) { if (fontAsset.FontType.AntiAlias == FontAntiAliasMode.ClearType) { BitmapUtils.PremultiplyAlphaClearType(bitmap, srgb); } else { BitmapUtils.PremultiplyAlpha(bitmap, srgb); } } return(OfflineRasterizedSpriteFontWriter.CreateSpriteFontData(fontFactory, fontAsset, glyphs, lineSpacing, baseLine, bitmap, srgb)); }
/// <summary> /// Gets the hdd path for the specified font so it can be passed to msdfgen.exe /// </summary> /// <param name="options">Font asset options</param> /// <returns>Absolute path to the font file</returns> private string GetFontSource(SpriteFontAsset options) { if (!string.IsNullOrEmpty(options.Source)) { return(options.Source); } // Note! If fonts are added at runtime the dictionary will not get updated after it has been initialized BuildFontsDictionary(); // TODO Check if msdfgen supports Bold/Italic font generation string outSource; if (options.Style.IsBold() && options.Style.IsItalic()) { if (foundFonts.TryGetValue(options.FontName + " Bold Italic", out outSource)) { return(outSource); } } if (options.Style.IsBold()) { if (foundFonts.TryGetValue(options.FontName + " Bold", out outSource)) { return(outSource); } } if (options.Style.IsItalic()) { if (foundFonts.TryGetValue(options.FontName + " Italic", out outSource)) { return(outSource); } } if (foundFonts.TryGetValue(options.FontName, out outSource)) { return(outSource); } return(null); }
/// <summary> /// Compiles the specified font description into a <see cref="SignedDistanceFieldSpriteFont" /> object. /// </summary> /// <param name="fontFactory">The font factory used to create the fonts</param> /// <param name="fontAsset">The font description.</param> /// <returns>A SpriteFontData object.</returns> public static Graphics.SpriteFont Compile(IFontFactory fontFactory, SpriteFontAsset fontAsset) { var fontTypeSDF = fontAsset.FontType as SignedDistanceFieldSpriteFontType; if (fontTypeSDF == null) { throw new ArgumentException("Tried to compile a dynamic sprite font with compiler for signed distance field fonts"); } float lineSpacing; float baseLine; var glyphs = ImportFont(fontAsset, out lineSpacing, out baseLine); Bitmap bitmap = GlyphPacker.ArrangeGlyphs(glyphs); return(SignedDistanceFieldFontWriter.CreateSpriteFontData(fontFactory, fontAsset, glyphs, lineSpacing, baseLine, bitmap)); }
public void Import(SpriteFontAsset options, List <char> characters) { var factory = new Factory(); // try to get the font face from the source file if not null FontFace fontFace = !string.IsNullOrEmpty(options.Source) ? GetFontFaceFromSource(factory, options) : GetFontFaceFromSystemFonts(factory, options); var fontMetrics = fontFace.Metrics; // Create a bunch of GDI+ objects. var fontSize = FontHelper.PointsToPixels(options.Size); var glyphList = new List <Glyph>(); // Remap the LineMap coming from the font with a user defined remapping // Note: // We are remapping the lineMap to allow to shrink the LineGap and to reposition it at the top and/or bottom of the // font instead of using only the top // According to http://stackoverflow.com/questions/13939264/how-to-determine-baseline-position-using-directwrite#comment27947684_14061348 // (The response is from a MSFT employee), the BaseLine should be = LineGap + Ascent but this is not what // we are experiencing when comparing with MSWord (LineGap + Ascent seems to offset too much.) // // So we are first applying a factor to the line gap: // NewLineGap = LineGap * LineGapFactor var lineGap = fontMetrics.LineGap * options.LineGapFactor; // Store the font height. LineSpacing = (float)(lineGap + fontMetrics.Ascent + fontMetrics.Descent) / fontMetrics.DesignUnitsPerEm * fontSize; // And then the baseline is also changed in order to allow the linegap to be distributed between the top and the // bottom of the font: // BaseLine = NewLineGap * LineGapBaseLineFactor BaseLine = (float)(lineGap * options.LineGapBaseLineFactor + fontMetrics.Ascent) / fontMetrics.DesignUnitsPerEm * fontSize; // Rasterize each character in turn. foreach (var character in characters) { glyphList.Add(ImportGlyph(factory, fontFace, character, fontMetrics, fontSize, options.AntiAlias)); } Glyphs = glyphList; factory.Dispose(); }
public void Import(SpriteFontAsset options, List<char> characters) { var factory = new Factory(); // try to get the font face from the source file if not null FontFace fontFace = !string.IsNullOrEmpty(options.Source) ? GetFontFaceFromSource(factory, options) : GetFontFaceFromSystemFonts(factory, options); var fontMetrics = fontFace.Metrics; // Create a bunch of GDI+ objects. var fontSize = FontHelper.PointsToPixels(options.Size); var glyphList = new List<Glyph>(); // Remap the LineMap coming from the font with a user defined remapping // Note: // We are remapping the lineMap to allow to shrink the LineGap and to reposition it at the top and/or bottom of the // font instead of using only the top // According to http://stackoverflow.com/questions/13939264/how-to-determine-baseline-position-using-directwrite#comment27947684_14061348 // (The response is from a MSFT employee), the BaseLine should be = LineGap + Ascent but this is not what // we are experiencing when comparing with MSWord (LineGap + Ascent seems to offset too much.) // // So we are first applying a factor to the line gap: // NewLineGap = LineGap * LineGapFactor var lineGap = fontMetrics.LineGap * options.LineGapFactor; // Store the font height. LineSpacing = (float)(lineGap + fontMetrics.Ascent + fontMetrics.Descent) / fontMetrics.DesignUnitsPerEm * fontSize; // And then the baseline is also changed in order to allow the linegap to be distributed between the top and the // bottom of the font: // BaseLine = NewLineGap * LineGapBaseLineFactor BaseLine = (float)(lineGap * options.LineGapBaseLineFactor + fontMetrics.Ascent) / fontMetrics.DesignUnitsPerEm * fontSize; // Rasterize each character in turn. foreach (var character in characters) glyphList.Add(ImportGlyph(factory, fontFace, character, fontMetrics, fontSize, options.AntiAlias)); Glyphs = glyphList; factory.Dispose(); }
public static List <char> GetCharactersToImport(SpriteFontAsset asset) { var characters = new List <char>(); // extract the list from the provided file if it exits if (File.Exists(asset.CharacterSet)) { string text; using (var streamReader = new StreamReader(asset.CharacterSet, Encoding.UTF8)) text = streamReader.ReadToEnd(); characters.AddRange(text); } // add character coming from character ranges characters.AddRange(CharacterRegion.Flatten(asset.CharacterRegions)); // remove duplicated characters characters = characters.Distinct().ToList(); return(characters); }
/// <summary> /// Compiles the specified font description into a <see cref="SpriteFontData" /> object. /// </summary> /// <param name="fontAsset">The font description.</param> /// <returns>A SpriteFontData object.</returns> public static StaticSpriteFontData Compile(SpriteFontAsset fontAsset) { float lineSpacing; float baseLine; Glyph[] glyphs = ImportFont(fontAsset, out lineSpacing, out baseLine); // Optimize. foreach (Glyph glyph in glyphs) { GlyphCropper.Crop(glyph); } Bitmap bitmap = GlyphPacker.ArrangeGlyphs(glyphs); // Automatically detect whether this is a monochromatic or color font? //if (fontAsset.Format == FontTextureFormat.Auto) //{ // bool isMono = BitmapUtils.IsRgbEntirely(Color.White, bitmap); // // fontAsset.Format = isMono ? FontTextureFormat.CompressedMono : // FontTextureFormat.Rgba32; //} // Convert to premultiplied alpha format. if (!fontAsset.NoPremultiply) { if (fontAsset.AntiAlias == FontAntiAliasMode.ClearType) { BitmapUtils.PremultiplyAlphaClearType(bitmap); } else { BitmapUtils.PremultiplyAlpha(bitmap); } } return(SpriteFontWriter.CreateSpriteFontData(fontAsset, glyphs, lineSpacing, baseLine, bitmap)); }
private FontFace GetFontFaceFromSource(Factory factory, SpriteFontAsset options) { if (!File.Exists(options.Source)) { // Font does not exist throw new FontNotFoundException(options.Source); } using (var fontFile = new FontFile(factory, options.Source)) { FontSimulations fontSimulations; switch (options.Style) { case Paradox.Graphics.Font.FontStyle.Regular: fontSimulations = FontSimulations.None; break; case Paradox.Graphics.Font.FontStyle.Bold: fontSimulations = FontSimulations.Bold; break; case Paradox.Graphics.Font.FontStyle.Italic: fontSimulations = FontSimulations.Oblique; break; default: throw new ArgumentOutOfRangeException(); } RawBool isSupported; FontFileType fontType; FontFaceType faceType; int numberFaces; fontFile.Analyze(out isSupported, out fontType, out faceType, out numberFaces); return(new FontFace(factory, faceType, new[] { fontFile }, 0, fontSimulations)); } }
private FontFace GetFontFaceFromSystemFonts(Factory factory, SpriteFontAsset options) { SharpDX.DirectWrite.Font font; using (var fontCollection = factory.GetSystemFontCollection(false)) { int index; if (!fontCollection.FindFamilyName(options.FontName, out index)) { // Lets try to import System.Drawing for old system bitmap fonts (like MS Sans Serif) throw new FontNotFoundException(options.FontName); } using (var fontFamily = fontCollection.GetFontFamily(index)) { var weight = options.Style.IsBold()? FontWeight.Bold: FontWeight.Regular; var style = options.Style.IsItalic() ? SharpDX.DirectWrite.FontStyle.Italic : SharpDX.DirectWrite.FontStyle.Normal; font = fontFamily.GetFirstMatchingFont(weight, FontStretch.Normal, style); } } return(new FontFace(font)); }
public static StaticSpriteFontData CreateSpriteFontData(SpriteFontAsset options, Glyph[] glyphs, float lineSpacing, float baseLine, Bitmap bitmap) { var spriteFontData = new StaticSpriteFontData { Size = FontHelper.PointsToPixels(options.Size), BaseOffset = baseLine, FontDefaultLineSpacing = lineSpacing, ExtraLineSpacing = options.LineSpacing, ExtraSpacing = options.Spacing, DefaultCharacter = options.DefaultCharacter }; WriteGlyphs(spriteFontData, glyphs); spriteFontData.Bitmaps = new ContentReference <Graphics.Image> [1]; var image = GetImage(options, bitmap); spriteFontData.Bitmaps[0] = new ContentReference <Graphics.Image> { Value = image }; return(spriteFontData); }
static Glyph[] ImportFont(SpriteFontAsset options, out float lineSpacing, out float baseLine) { // Which importer knows how to read this source font? IFontImporter importer; var sourceExtension = (Path.GetExtension(options.FontSource.GetFontPath()) ?? "").ToLowerInvariant(); var bitmapFileExtensions = new List<string> { ".bmp", ".png", ".gif" }; var importFromBitmap = bitmapFileExtensions.Contains(sourceExtension); if (importFromBitmap) { throw new Exception("SDF Font from image is not supported!"); } importer = new SignedDistanceFieldFontImporter(); // create the list of character to import var characters = GetCharactersToImport(options); // Import the source font data. importer.Import(options, characters); lineSpacing = importer.LineSpacing; baseLine = importer.BaseLine; // Get all glyphs var glyphs = new List<Glyph>(importer.Glyphs); // Validate. if (glyphs.Count == 0) { throw new Exception("Font does not contain any glyphs."); } // Sort the glyphs glyphs.Sort((left, right) => left.Character.CompareTo(right.Character)); // Check that the default character is part of the glyphs if (!DefaultCharacterExists(options.DefaultCharacter, glyphs)) { throw new InvalidOperationException("The specified DefaultCharacter is not part of this font."); } return glyphs.ToArray(); }
public static Graphics.SpriteFont CreateSpriteFontData(IFontFactory fontFactory, SpriteFontAsset options, Glyph[] glyphs, float lineSpacing, float baseLine, Bitmap bitmap, bool srgb) { var fontGlyphs = ConvertGlyphs(glyphs); var images = new[] { GetImage(options, bitmap, srgb) }; var sizeInPixels = FontHelper.PointsToPixels(options.Size); return(fontFactory.NewStatic(sizeInPixels, fontGlyphs, images, baseLine, lineSpacing, null, options.Spacing, options.LineSpacing, options.DefaultCharacter)); }
static Graphics.Image GetImage(SpriteFontAsset options, Bitmap bitmap) { switch (options.Format) { //case FontTextureFormat.Auto: case FontTextureFormat.Rgba32: return GetImageRgba32(bitmap); //case FontTextureFormat.CompressedMono: // return GetCompressedMono(bitmap, options); default: throw new NotSupportedException(); } }
private FontFace GetFontFaceFromSource(Factory factory, SpriteFontAsset options) { if (!File.Exists(options.Source)) { // Font does not exist throw new FontNotFoundException(options.Source); } using (var fontFile = new FontFile(factory, options.Source)) { FontSimulations fontSimulations; switch (options.Style) { case Paradox.Graphics.Font.FontStyle.Regular: fontSimulations = FontSimulations.None; break; case Paradox.Graphics.Font.FontStyle.Bold: fontSimulations = FontSimulations.Bold; break; case Paradox.Graphics.Font.FontStyle.Italic: fontSimulations = FontSimulations.Oblique; break; default: throw new ArgumentOutOfRangeException(); } RawBool isSupported; FontFileType fontType; FontFaceType faceType; int numberFaces; fontFile.Analyze(out isSupported, out fontType, out faceType, out numberFaces); return new FontFace(factory, faceType, new[] { fontFile }, 0, fontSimulations); } }
public static Graphics.SpriteFont CreateSpriteFontData(IFontFactory fontFactory, SpriteFontAsset options, Glyph[] glyphs, float lineSpacing, float baseLine, Bitmap bitmap, bool srgb) { var fontGlyphs = ConvertGlyphs(glyphs); var images = new[] { GetImage(options, bitmap, srgb) }; var sizeInPixels = FontHelper.PointsToPixels(options.Size); return fontFactory.NewStatic(sizeInPixels, fontGlyphs, images, baseLine, lineSpacing, null, options.Spacing, options.LineSpacing, options.DefaultCharacter); }
// We want to compress our font textures, because, like, smaller is better, // right? But a standard DXT compressor doesn't do a great job with fonts that // are in premultiplied alpha format. Our font data is greyscale, so all of the // RGBA channels have the same value. If one channel is compressed differently // to another, this causes an ugly variation in brightness of the rendered text. // Also, fonts are mostly either black or white, with grey values only used for // antialiasing along their edges. It is very important that the black and white // areas be accurately represented, while the precise value of grey is less // important. // // Trouble is, your average DXT compressor knows nothing about these // requirements. It will optimize to minimize a generic error metric such as // RMS, but this will often sacrifice crisp black and white in exchange for // needless accuracy of the antialiasing pixels, or encode RGB differently to // alpha. UGLY! // // Fortunately, encoding monochrome fonts turns out to be trivial. Using DXT3, // we can fix the end colors as black and white, which gives guaranteed exact // encoding of the font inside and outside, plus two fractional values for edge // antialiasing. Also, these RGB values (0, 1/3, 2/3, 1) map exactly to four of // the possible 16 alpha values available in DXT3, so we can ensure the RGB and // alpha channels always exactly match. static void CompressBlock(BitmapUtils.PixelAccessor bitmapData, int blockX, int blockY, SpriteFontAsset options, out BC2Pixel bc2Pixel) { long alphaBits = 0; int rgbBits = 0; int pixelCount = 0; for (int y = 0; y < 4; y++) { for (int x = 0; x < 4; x++) { long alpha; int rgb; int value = bitmapData[blockX + x, blockY + y].A; if (options.NoPremultiply) { // If we are not pre-multiplied, RGB is always white and we have 4 bit alpha. alpha = value >> 4; rgb = 0; } else { // For pre-multiplied encoding, quantize the source value to 2 bit precision. if (value < 256 / 6) { alpha = 0; rgb = 1; } else if (value < 256 / 2) { alpha = 5; rgb = 3; } else if (value < 256 * 5 / 6) { alpha = 10; rgb = 2; } else { alpha = 15; rgb = 0; } } // Add this pixel to the alpha and RGB bit masks. alphaBits |= alpha << (pixelCount * 4); rgbBits |= rgb << (pixelCount * 2); pixelCount++; } } // Output the alpha bit mask. bc2Pixel.AlphaBits = alphaBits; // Output the two endpoint colors (black and white in 5.6.5 format). bc2Pixel.EndPoint = 0x0000FFFF; // Output the RGB bit mask. bc2Pixel.RgbBits = rgbBits; }
/// <inheritdoc/> public void Import(SpriteFontAsset options, List<char> characters) { fontSource = options.FontSource.GetFontPath(); if (string.IsNullOrEmpty(fontSource)) return; // Get the msdfgen.exe location var installationDir = DirectoryHelper.GetPackageDirectory("Xenko"); var binDir = UPath.Combine(installationDir, new UDirectory("Bin")); binDir = UPath.Combine(binDir, new UDirectory("Windows-Direct3D11")); var msdfgen = UPath.Combine(binDir, new UFile("msdfgen.exe")); if (!File.Exists(msdfgen)) { throw new AssetException("Failed to compile a font asset, msdfgen was not found."); } msdfgenExe = msdfgen.FullPath; tempDir = $"{Environment.GetEnvironmentVariable("TEMP")}\\"; var factory = new Factory(); FontFace fontFace = options.FontSource.GetFontFace(); var fontMetrics = fontFace.Metrics; // Create a bunch of GDI+ objects. var fontSize = options.FontType.Size; var glyphList = new List<Glyph>(); // Remap the LineMap coming from the font with a user defined remapping // Note: // We are remapping the lineMap to allow to shrink the LineGap and to reposition it at the top and/or bottom of the // font instead of using only the top // According to http://stackoverflow.com/questions/13939264/how-to-determine-baseline-position-using-directwrite#comment27947684_14061348 // (The response is from a MSFT employee), the BaseLine should be = LineGap + Ascent but this is not what // we are experiencing when comparing with MSWord (LineGap + Ascent seems to offset too much.) // // So we are first applying a factor to the line gap: // NewLineGap = LineGap * LineGapFactor var lineGap = fontMetrics.LineGap * options.LineGapFactor; // Store the font height. LineSpacing = (float)(lineGap + fontMetrics.Ascent + fontMetrics.Descent) / fontMetrics.DesignUnitsPerEm * fontSize; // And then the baseline is also changed in order to allow the linegap to be distributed between the top and the // bottom of the font: // BaseLine = NewLineGap * LineGapBaseLineFactor BaseLine = (float)(lineGap * options.LineGapBaseLineFactor + fontMetrics.Ascent) / fontMetrics.DesignUnitsPerEm * fontSize; // Generate SDF bitmaps for each character in turn. foreach (var character in characters) glyphList.Add(ImportGlyph(fontFace, character, fontMetrics, fontSize)); Glyphs = glyphList; factory.Dispose(); }
public static List<char> GetCharactersToImport(SpriteFontAsset asset) { var characters = new List<char>(); // extract the list from the provided file if it exits if (File.Exists(asset.CharacterSet)) { string text; using (var streamReader = new StreamReader(asset.CharacterSet, Encoding.UTF8)) text = streamReader.ReadToEnd(); characters.AddRange(text); } // add character coming from character ranges characters.AddRange(CharacterRegion.Flatten(asset.CharacterRegions)); // remove duplicated characters characters = characters.Distinct().ToList(); return characters; }
private FontFace GetFontFaceFromSystemFonts(Factory factory, SpriteFontAsset options) { SharpDX.DirectWrite.Font font; using (var fontCollection = factory.GetSystemFontCollection(false)) { int index; if (!fontCollection.FindFamilyName(options.FontName, out index)) { // Lets try to import System.Drawing for old system bitmap fonts (like MS Sans Serif) throw new FontNotFoundException(options.FontName); } using (var fontFamily = fontCollection.GetFontFamily(index)) { var weight = options.Style.IsBold()? FontWeight.Bold: FontWeight.Regular; var style = options.Style.IsItalic() ? SharpDX.DirectWrite.FontStyle.Italic : SharpDX.DirectWrite.FontStyle.Normal; font = fontFamily.GetFirstMatchingFont(weight, FontStretch.Normal, style); } } return new FontFace(font); }
static Graphics.Image GetImage(SpriteFontAsset options, Bitmap bitmap) { // TODO Currently we only support Rgba32 as an option. Grayscale might be added later return(GetImageRgba32(bitmap)); }
public void Import(SpriteFontAsset options, List<char> characters) { // Load the source bitmap. Bitmap bitmap; try { bitmap = new Bitmap(options.Source); } catch { throw new FontNotFoundException(options.Source); } // Convert to our desired pixel format. bitmap = BitmapUtils.ChangePixelFormat(bitmap, PixelFormat.Format32bppArgb); // What characters are included in this font? int characterIndex = 0; char currentCharacter = '\0'; // Split the source image into a list of individual glyphs. var glyphList = new List<Glyph>(); Glyphs = glyphList; LineSpacing = 0; foreach (Rectangle rectangle in FindGlyphs(bitmap)) { if (characterIndex < characters.Count) currentCharacter = characters[characterIndex++]; else currentCharacter++; glyphList.Add(new Glyph(currentCharacter, bitmap, rectangle) { XAdvance = rectangle.Width }); LineSpacing = Math.Max(LineSpacing, rectangle.Height); } // If the bitmap doesn't already have an alpha channel, create one now. if (BitmapUtils.IsAlphaEntirely(255, bitmap)) { BitmapUtils.ConvertGreyToAlpha(bitmap, new Rectangle(0,0,bitmap.Width, bitmap.Height)); } }
/// <summary> /// Compiles the specified font description into a <see cref="SignedDistanceFieldSpriteFont" /> object. /// </summary> /// <param name="fontFactory">The font factory used to create the fonts</param> /// <param name="fontAsset">The font description.</param> /// <returns>A SpriteFontData object.</returns> public static Graphics.SpriteFont Compile(IFontFactory fontFactory, SpriteFontAsset fontAsset) { var fontTypeSDF = fontAsset.FontType as SignedDistanceFieldSpriteFontType; if (fontTypeSDF == null) throw new ArgumentException("Tried to compile a dynamic sprite font with compiler for signed distance field fonts"); float lineSpacing; float baseLine; var glyphs = ImportFont(fontAsset, out lineSpacing, out baseLine); Bitmap bitmap = GlyphPacker.ArrangeGlyphs(glyphs); return SignedDistanceFieldFontWriter.CreateSpriteFontData(fontFactory, fontAsset, glyphs, lineSpacing, baseLine, bitmap); }
// Writes a block compressed monochromatic font texture. static unsafe Graphics.Image GetCompressedMono(Bitmap bitmap, SpriteFontAsset options) { if ((bitmap.Width & 3) != 0 || (bitmap.Height & 3) != 0) { throw new ArgumentException("Block compression requires texture size to be a multiple of 4."); } var image = Graphics.Image.New2D(bitmap.Width, bitmap.Height, 1, Graphics.PixelFormat.BC2_UNorm); var pixelBuffer = (BC2Pixel*)image.PixelBuffer[0].DataPointer; using (var bitmapData = new BitmapUtils.PixelAccessor(bitmap, ImageLockMode.ReadOnly)) { for (int y = 0; y < bitmap.Height; y += 4) { for (int x = 0; x < bitmap.Width; x += 4) { BC2Pixel bc2Pixel; CompressBlock( bitmapData, x, y, options, out bc2Pixel); *pixelBuffer = bc2Pixel; pixelBuffer++; } } } return image; }
static Graphics.Image GetImage(SpriteFontAsset options, Bitmap bitmap) { // TODO Currently we only support Rgba32 as an option. Grayscale might be added later return GetImageRgba32(bitmap); }
public static List<char> GetCharactersToImport(SpriteFontAsset asset) { var characters = new List<char>(); var fontTypeStatic = asset.FontType as OfflineRasterizedSpriteFontType; if (fontTypeStatic == null) throw new ArgumentException("Tried to compile a dynamic sprite font with compiler for signed distance field fonts"); // extract the list from the provided file if it exits if (File.Exists(fontTypeStatic.CharacterSet)) { string text; using (var streamReader = new StreamReader(fontTypeStatic.CharacterSet, Encoding.UTF8)) text = streamReader.ReadToEnd(); characters.AddRange(text); } // add character coming from character ranges characters.AddRange(CharacterRegion.Flatten(fontTypeStatic.CharacterRegions)); // remove duplicated characters characters = characters.Distinct().ToList(); return characters; }
public static Graphics.SpriteFont CreateSpriteFontData(IFontFactory fontFactory, SpriteFontAsset options, Glyph[] glyphs, float lineSpacing, float baseLine, Bitmap bitmap) { var fontGlyphs = ConvertGlyphs(glyphs); var images = new[] { GetImage(options, bitmap) }; var sizeInPixels = options.FontType.Size; return fontFactory.NewScalable(sizeInPixels, fontGlyphs, images, baseLine, lineSpacing, null, options.Spacing, options.LineSpacing, options.DefaultCharacter); }
public static Graphics.SpriteFont CreateSpriteFontData(IFontFactory fontFactory, SpriteFontAsset options, Glyph[] glyphs, float lineSpacing, float baseLine, Bitmap bitmap) { var fontGlyphs = ConvertGlyphs(glyphs); var images = new[] { GetImage(options, bitmap) }; var sizeInPixels = options.FontType.Size; return(fontFactory.NewScalable(sizeInPixels, fontGlyphs, images, baseLine, lineSpacing, null, options.Spacing, options.LineSpacing, options.DefaultCharacter)); }
/// <summary> /// Compiles the specified font description into a <see cref="StaticSpriteFont" /> object. /// </summary> /// <param name="fontFactory">The font factory used to create the fonts</param> /// <param name="fontAsset">The font description.</param> /// <param name="srgb"></param> /// <returns>A SpriteFontData object.</returns> public static Graphics.SpriteFont Compile(IFontFactory fontFactory, SpriteFontAsset fontAsset, bool srgb) { if(fontAsset.IsDynamic) throw new ArgumentException("Tried to compile a dynamic sprite font with compiler for static fonts"); float lineSpacing; float baseLine; var glyphs = ImportFont(fontAsset, out lineSpacing, out baseLine); // Optimize. foreach (Glyph glyph in glyphs) GlyphCropper.Crop(glyph); Bitmap bitmap = GlyphPacker.ArrangeGlyphs(glyphs); // Automatically detect whether this is a monochromatic or color font? //if (fontAsset.Format == FontTextureFormat.Auto) //{ // bool isMono = BitmapUtils.IsRgbEntirely(Color.White, bitmap); // // fontAsset.Format = isMono ? FontTextureFormat.CompressedMono : // FontTextureFormat.Rgba32; //} // Convert to pre-multiplied alpha format. if (fontAsset.IsPremultiplied) { if (fontAsset.AntiAlias == FontAntiAliasMode.ClearType) { BitmapUtils.PremultiplyAlphaClearType(bitmap, srgb); } else { BitmapUtils.PremultiplyAlpha(bitmap, srgb); } } return StaticSpriteFontWriter.CreateSpriteFontData(fontFactory, fontAsset, glyphs, lineSpacing, baseLine, bitmap, srgb); }