protected void Initialize() { if (charsDict != null) return; charsDict = new Dictionary<int, Character>(); kernHash = new Dictionary<int, Kerning[]>(); charsSize = new List<float>(16); foreach (Character c in characters) charsDict.Add(c.code, c); foreach (Kerning k in kernings) { int hash = k.code0 + k.code1; Kerning[] kernArray; if (kernHash.TryGetValue(hash, out kernArray)) { int len = kernArray.Length; Array.Resize<Kerning>(ref kernArray, len + 1); kernArray[len] = k; } else { kernArray = new Kerning[1]; kernArray[0] = k; kernHash.Add(hash, kernArray); } } }
/// <summary> /// Add a new kerning entry to the character (or adjust an existing one). /// </summary> public void SetKerning (int previousChar, int amount) { if (kerning == null) kerning = new List<Kerning>(); for (int i = 0; i < kerning.Count; ++i) { if (kerning[i].previousChar == previousChar) { Kerning k = kerning[i]; k.amount = amount; kerning[i] = k; return; } } Kerning ker = new Kerning(); ker.previousChar = previousChar; ker.amount = amount; kerning.Add(ker); }
private void textBoxInput_TextChanged(object sender, EventArgs e) { textBoxBreakdown.Clear(); panelOutput.Controls.Clear(); string regCol = String.Join("|", headersCol); string regRow = String.Join("|", headersRow); List <string> output = new List <string>(); foreach (string block in Regex.Matches(textBoxInput.Text, "[^|\\b].*?\\b|.").OfType <Match>().Where(x => x.Value != " ").Select(x => x.Value)) { if (Regex.Matches(block, "\\W").Count > 0) { if (block != " ") { output.Add(block); } } else { MatchCollection match = Regex.Matches(block, String.Format("([{0}]\\d?[{1}]\\d?)|([{1}]\\d?[{0}]\\d?)", regCol, regRow)); List <string> l = match.OfType <Match>().Select(x => x.Value).ToList(); output.Add("(" + String.Join("-", l) + ")"); ///This whole flowPanel thing might be better done with calculations and drawing straight to the canvas ///It would allow for glyph overlaps but more calcs will be needed for wrapping FlowLayoutPanel flowPanel = new FlowLayoutPanel(); //for not foreach because of importance of glyph position for (int i = 0; i < l.Count; i++) { object tag = FormType.Isolated; string fil = String.Format("{0}\\{1}.png", repository, l[i]); if (languageSettings[Property.CharacterForms].Equals(CharacterForms.Multiple)) { if (l.Count != 1) { if (i == 0) { if (File.Exists(String.Format("{0}\\{1}_initial.png", repository, l[i]))) { fil = String.Format("{0}\\{1}_initial.png", repository, l[i]); tag = FormType.Initial; } } else if (i == l.Count - 1) { if (File.Exists(String.Format("{0}\\{1}_final.png", repository, l[i]))) { fil = String.Format("{0}\\{1}_final.png", repository, l[i]); tag = FormType.Final; } } else { if (File.Exists(String.Format("{0}\\{1}_medial.png", repository, l[i]))) { fil = String.Format("{0}\\{1}_medial.png", repository, l[i]); tag = FormType.Medial; } } } } if (File.Exists(fil) || (bool)languageSettings[Property.FillBlanks]) { Size s = (Size)languageSettings[Property.Sizing]; Bitmap im; if (File.Exists(fil)) { using (Image image = Image.FromFile(fil)) { im = (Bitmap)image.GetThumbnailImage(500, 500, null, IntPtr.Zero); } } else { im = nullimage; } Size characterSize = (Size)languageSettings[Property.Sizing]; //get crop data Kerning k = (Kerning)languageSettings[Property.Kerning]; string extender = tag.Equals(FormType.Isolated) ? "" : "_" + tag.ToString().ToLower(); string glyph = l[i] + extender; string line = languageInfo.Where(x => x.StartsWith("‡" + glyph + ";")).FirstOrDefault(); if (line != null && k != Kerning.Monospace) { Rectangle r = GetLetterCropping(line, languageSettings); Bitmap cropped = new Bitmap(r.Width, r.Height); using (Graphics g = Graphics.FromImage(cropped)) { g.DrawImage(im, new Rectangle(0, 0, r.Width, r.Height), r, GraphicsUnit.Pixel); } im = cropped; } im.MakeTransparent(Color.White); Panel p = new Panel() { BackgroundImage = im, BackgroundImageLayout = ImageLayout.Zoom, Size = characterSize, Tag = tag }; /// future feature - on hover, highlight original in text box /// if (k != Kerning.Monospace) { FlowDirection f = (FlowDirection)languageSettings[Property.WordDirection]; if (f == FlowDirection.LeftToRight || f == FlowDirection.RightToLeft) { p.Margin = new Padding((int)k / 2, 3, (int)k / 2, 3); } else { p.Margin = new Padding(3, (int)k / 2, 3, (int)k / 2); } CropAspect aspect = (CropAspect)languageSettings[Property.CropAspect]; if (aspect != CropAspect.None) { //v,b, or ttb if (aspect == CropAspect.Vertical || aspect == CropAspect.Both || (aspect == CropAspect.MatchedToWord && p.Margin.Left == 3)) { p.Height = (int)(p.Height * p.BackgroundImage.Height / 500f); } if (aspect == CropAspect.Horizontal || aspect == CropAspect.Both || (aspect == CropAspect.MatchedToWord && p.Margin.Left != 3)) { p.Width = (int)(p.Width * p.BackgroundImage.Width / 500f); } } } flowPanel.Controls.Add(p); } } FlowPanelDirection((FlowDirection)languageSettings[Property.WordDirection], flowPanel); panelOutput.Controls.Add(flowPanel); } } textBoxBreakdown.Text = String.Join(" ", output); }
/// <summary> /// This method for loading/saving a font file generated from AngelCode BMFont. /// </summary> /// <param name="serializer">The binaryserializer to use.</param> private void SerializeBMFFont(BinarySerializer serializer) { // ---------------------------------------------------------- // Read block Info (1) // ---------------------------------------------------------- byte blockType = 1; serializer.Serialize(ref blockType); if (blockType != 1) return; // Skip Info block int expectedBlockSize = 0; serializer.Serialize(ref expectedBlockSize); serializer.Stream.Seek(expectedBlockSize, SeekOrigin.Current); // ---------------------------------------------------------- // Read block Common (2) // ---------------------------------------------------------- serializer.Serialize(ref blockType); if (blockType != 2) return; var common = new BMFCommon(); common.Serialize(serializer); // Copy the base offset. BaseOffset = common.Base; LineSpacing = common.LineHeight; // ---------------------------------------------------------- // Read block page names (3) // ---------------------------------------------------------- serializer.Serialize(ref blockType); if (blockType != 3) return; serializer.Serialize(ref expectedBlockSize); // Create bitmap array. Bitmaps = new Bitmap[common.PageCount]; for (int i = 0; i < Bitmaps.Length; i++) { string name = null; serializer.Serialize(ref name, true); // Store the name in data Bitmaps[i] = new Bitmap { Data = name }; } // ---------------------------------------------------------- // Read block glyphs (4) // ---------------------------------------------------------- serializer.Serialize(ref blockType); if (blockType != 4) return; serializer.Serialize(ref expectedBlockSize); int countChars = expectedBlockSize/20; var bmfGlyph = new BMFGlyph(); Glyphs = new Glyph[countChars]; for (int i = 0; i < Glyphs.Length; i++) { bmfGlyph.Serialize(serializer); Glyphs[i] = new Glyph { Character = bmfGlyph.Id, Subrect = new Rectangle(bmfGlyph.X, bmfGlyph.Y, bmfGlyph.Width, bmfGlyph.Height), Offset = {X = bmfGlyph.OffsetX, Y = bmfGlyph.OffsetY}, XAdvance = bmfGlyph.AdvanceX, BitmapIndex = bmfGlyph.PageIndex }; } // ---------------------------------------------------------- // Read block kernings (5) optional // ---------------------------------------------------------- if (serializer.Stream.Position < serializer.Stream.Length) { // If there is still some data to read, there is probably some kernings serializer.Serialize(ref blockType); if (blockType != 5) return; serializer.Serialize(ref expectedBlockSize); int kernelCount = expectedBlockSize/10; Kernings = new Kerning[kernelCount]; for (int i = 0; i < Kernings.Length; i++) { serializer.Serialize(ref Kernings[i].First); serializer.Serialize(ref Kernings[i].Second); short offset = 0; serializer.Serialize(ref offset); Kernings[i].Offset = offset; } } }
private void Load(IFileStore store) { using (var stream = store.OpenFile(m_path)) { var reader = new StreamReader(stream, Encoding.UTF8); string line; string type = null; var options = new KeyValuePairs(); while ((line = reader.ReadLine()) != null) { // Parse each line string[] parts = line.Split(' '); if (parts.Length < 1) { continue; } // Extract type and options type = parts[0]; options.Clear(); for (int i = 1; i < parts.Length; ++i) { string part = parts[i]; int equalsIndex = part.IndexOf('='); if (equalsIndex >= 0) { string key = part.Substring(0, equalsIndex); string value = part.Substring(equalsIndex + 1); int intValue; if (value.StartsWith("\"")) { if (value.EndsWith("\"") && value.Length >= 2) { value = value.Substring(1, value.Length - 2); } else { value = value.Substring(1) + " "; i++; while (!parts[i].EndsWith("\"")) { value += parts[i] + " "; i++; } value += parts[i].Substring(0, parts[i].Length - 1); } options.Set(key, value); } else if (int.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out intValue)) { options.Set(key, intValue); } } } // Interpret switch (type) { case "common": { m_lineHeight = options.GetInteger("lineHeight"); m_base = options.GetInteger("base"); m_scaleW = options.GetInteger("scaleW"); m_scaleH = options.GetInteger("scaleH"); m_pages = new Page[options.GetInteger("pages")]; break; } case "page": { int id = options.GetInteger("id"); if (id >= PageCount) { Array.Resize(ref m_pages, id + 1); } m_pages[id] = new Page(); m_pages[id].Path = AssetPath.Combine(AssetPath.GetDirectoryName(m_path), options.GetString("file")); break; } case "chars": { m_chars = new Dictionary <int, Char>(options.GetInteger("count")); break; } case "char": { var id = options.GetInteger("id"); m_chars[id] = new Char(); m_chars[id].X = options.GetInteger("x"); m_chars[id].Y = options.GetInteger("y"); m_chars[id].Width = options.GetInteger("width"); m_chars[id].Height = options.GetInteger("height"); m_chars[id].XOffset = options.GetInteger("xoffset"); m_chars[id].YOffset = options.GetInteger("yoffset"); m_chars[id].XAdvance = options.GetInteger("xadvance"); m_chars[id].Page = options.GetInteger("page"); if (m_chars[id].Page < 0 || m_chars[id].Page >= PageCount) { m_chars[id].Page = 0; //throw new IOException( "Page count out of range" ); } break; } case "kernings": { m_kernings = new Dictionary <KerningPair, Kerning>(options.GetInteger("count")); break; } case "kerning": { var first = options.GetInteger("first"); var second = options.GetInteger("second"); var pair = new KerningPair(first, second); m_kernings[pair] = new Kerning(); m_kernings[pair].Amount = options.GetInteger("amount"); break; } } } } }
public void DoXMLPase(ref string content) { XmlDocument xml = new XmlDocument(); xml.LoadXml(content); XmlNode info = xml.GetElementsByTagName("info")[0]; XmlNode common = xml.GetElementsByTagName("common")[0]; XmlNodeList pages = xml.GetElementsByTagName("pages")[0].ChildNodes; XmlNodeList chars = xml.GetElementsByTagName("chars")[0].ChildNodes; fontName = info.Attributes.GetNamedItem("face").InnerText; fontSize = ToInt(info, "size"); lineHeight = ToInt(common, "lineHeight"); lineBaseHeight = ToInt(common, "base"); textureWidth = ToInt(common, "scaleW"); textureHeight = ToInt(common, "scaleH"); int pageNum = ToInt(common, "pages"); textureNames = new string[pageNum]; for (int i = 0; i < pageNum; i++) { XmlNode page = pages[i]; int pageId = ToInt(page, "id"); textureNames[pageId] = page.Attributes.GetNamedItem("file").InnerText; } charInfos = new CharacterInfo[chars.Count]; for (int i = 0; i < chars.Count; i++) { XmlNode charNode = chars[i]; charInfos[i] = CreateCharInfo( ToInt(charNode, "id"), ToInt(charNode, "x"), ToInt(charNode, "y"), ToInt(charNode, "width"), ToInt(charNode, "height"), ToInt(charNode, "xoffset"), ToInt(charNode, "yoffset"), ToInt(charNode, "xadvance"), ToInt(charNode, "page")); } // kernings XmlNode kerningsNode = xml.GetElementsByTagName("kernings")[0]; if (kerningsNode != null && kerningsNode.HasChildNodes) { XmlNodeList kerns = kerningsNode.ChildNodes; kernings = new Kerning[kerns.Count]; for (int i = 0; i < kerns.Count; i++) { XmlNode kerningNode = kerns[i]; kernings[i] = new Kerning(); kernings[i].first = ToInt(kerningNode, "first"); kernings[i].second = ToInt(kerningNode, "second"); kernings[i].amount = ToInt(kerningNode, "amount"); } } }
public override void Read(BinaryReader file, uint size) { base.Read(file, size); var cnt = file.ReadVLQInt32(); for (int i = 0; i < cnt; i++) { //This is actually a byte-byte pair but no idea why or how anyone would edit this var mapping = new CUInt16(cr2w, Unicodemapping, ""); mapping.Read(file, size); Unicodemapping.AddVariable(mapping); } Linedist.Read(file, size); Maxglyphheight.Read(file, size); Kerning.Read(file, size); var num = file.ReadVLQInt32(); for (int i = 0; i < num; i++) { var glyph = new CArray <CFloat>(cr2w, Glyphs, "Glyph - " + i) { Elementtype = "Float" }; // UVs CFloat uv00 = new CFloat(cr2w, glyph, "UV[0][0]"); uv00.Read(file, size); glyph.AddVariable(uv00); CFloat uv01 = new CFloat(cr2w, glyph, "UV[0][1]"); uv01.Read(file, size); glyph.AddVariable(uv01); CFloat uv10 = new CFloat(cr2w, glyph, "UV[1][0]"); uv10.Read(file, size); glyph.AddVariable(uv10); CFloat uv11 = new CFloat(cr2w, glyph, "UV[1][1]"); uv11.Read(file, size); glyph.AddVariable(uv11); CInt32 textureindex = new CInt32(cr2w, glyph, "Texture index"); textureindex.Read(file, size); glyph.AddVariable(textureindex); CInt32 width = new CInt32(cr2w, glyph, "Width"); width.Read(file, size); glyph.AddVariable(width); CInt32 height = new CInt32(cr2w, glyph, "Height"); height.Read(file, size); glyph.AddVariable(height); CInt32 advance_x = new CInt32(cr2w, glyph, "Advance X"); advance_x.Read(file, size); glyph.AddVariable(advance_x); CInt32 bearing_x = new CInt32(cr2w, glyph, "Bearing X"); bearing_x.Read(file, size); glyph.AddVariable(bearing_x); CInt32 bearing_y = new CInt32(cr2w, glyph, "Bearing Y"); bearing_y.Read(file, size); glyph.AddVariable(bearing_y); Glyphs.AddVariable(glyph); } }
public Bitmap test_draw(ObservableCollection <System.Windows.UIElement> list, ObservableCollection <FontModel> fontList, MaxRectsBinPack binPack, string alphabet, FontSettings fontSettings) { alphabet = alphabet.Replace("\n", ""); alphabet = alphabet.Replace("\r", ""); Library library = new Library(); Face face = library.NewFace(fontSettings.FontName, 0); // Find the largest glyph bounding rectangle // Rect glyphRect = getGlyphRect(face, alphabet); //int glyphWidth = (int)Math.Ceiling(glyphRect.Width) + 4 * fontSettings.OutlineWidth; //int glyphHeight = (int)Math.Ceiling(glyphRect.Height) + 4 * fontSettings.OutlineWidth; int glyphWidth = 18 + 4 * fontSettings.OutlineWidth; int glyphHeight = 18 + 4 * fontSettings.OutlineWidth; //add new font FontModel newFont = new FontModel() { Id = (ushort)fontSettings.FontSize, size = fontSettings.FontSize, lineheight = glyphHeight, // 22, spacelength = (int)(glyphWidth * 0.6f), //todo ? baseline = 0, kerning = -0.5f, monowidth = fontSettings.FontSize + 1, letterspacing = 0, rangeFrom = alphabet[0], rangeTo = alphabet[alphabet.Length - 1] }; fontList.Add(newFont); Bitmap bmp = new Bitmap((int)Math.Ceiling((double)fontSettings.ImageWidth), (int)Math.Ceiling((double)fontSettings.ImageHeight)); Graphics g = Graphics.FromImage(bmp); g.Clear(fontSettings.BgColor); //g.Clear(Color.Black);q int x = 0, y = 0; for (int i = 0; i < alphabet.ToCharArray().Length; i++) { string currentChar0 = alphabet.ToCharArray()[i].ToString(); uint glyphIndex = face.GetCharIndex(uchar2code(currentChar0)); if (fontSettings.FontSize <= 14) { face.SetPixelSizes((uint)0, (uint)fontSettings.FontSize); face.LoadGlyph(glyphIndex, LoadFlags.Default, LoadTarget.Normal); face.Glyph.RenderGlyph(RenderMode.Normal); } else { face.SetCharSize(0, fontSettings.FontSize, 0, 72); face.LoadGlyph(glyphIndex, LoadFlags.ForceAutohint, LoadTarget.Lcd); face.Glyph.RenderGlyph(RenderMode.Lcd); } //Get character alignment float left = (float)face.Glyph.Metrics.HorizontalBearingX; float right = (float)face.Glyph.Metrics.HorizontalBearingX + (float)face.Glyph.Metrics.Width; float top = (float)face.Glyph.Metrics.HorizontalBearingY; float bottom = (float)face.Glyph.Metrics.HorizontalBearingY + (float)face.Glyph.Metrics.Height; float FHT = fontSettings.FontSize; int FHD = (int)Math.Ceiling(FHT); int kx = x + face.Glyph.BitmapLeft; int ky = (int)Math.Round((float)y + (FHD - face.Glyph.BitmapTop)); ////Select render mode (1 times or 2 times) //if (this.grender_mode == "freetype_nearestneighbor") //{ // face.SetCharSize(0, this.fontHeight * 2, 0, 72); // face.LoadGlyph(glyphIndex, LoadFlags.ForceAutohint, LoadTarget.Lcd); // face.Glyph.RenderGlyph(RenderMode.Lcd); // FTBitmap ftbmp = face.Glyph.Bitmap; // if (ftbmp.Width == 0) // { // x += this.tile_width; // if (x + this.tile_width > this.image_width) // { // x = 0; // y += this.tile_height; // } // continue; // } // Bitmap tmpBmp = ftbmp.ToGdipBitmap(this.penColor); // tmpBmp = kPasteImage(tmpBmp, tile_width * 2, tile_height * 2, (int)face.Glyph.BitmapLeft, // (int)Math.Round(((float)this.fontHeight * 2 - face.Glyph.BitmapTop))); // Bitmap cBmp = kResizeImage(tmpBmp, tmpBmp.Width / 2, tmpBmp.Height / 2, System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor); // Bitmap nBmp = gray2alpha(cBmp); // cBmp.Dispose(); // g.DrawImageUnscaled(nBmp, x + FontSettings.relativePositionX, y + FontSettings.relativePositionY); // nBmp.Dispose(); //} //else if (this.grender_mode == "freetype_HighQualityBicubic") //{ // face.SetCharSize(0, this.fontHeight * 2, 0, 72); // face.LoadGlyph(glyphIndex, LoadFlags.ForceAutohint, LoadTarget.Lcd); // face.Glyph.RenderGlyph(RenderMode.Lcd); // FTBitmap ftbmp = face.Glyph.Bitmap; // if (ftbmp.Width == 0) // { // x += this.tile_width; // if (x + this.tile_width > this.image_width) // { // x = 0; // y += this.tile_height; // } // continue; // } // Bitmap tmpBmp = ftbmp.ToGdipBitmap(this.penColor); // tmpBmp = kPasteImage(tmpBmp, tile_width * 2, tile_height * 2, (int)face.Glyph.BitmapLeft, // (int)Math.Round(((float)this.fontHeight * 2 - face.Glyph.BitmapTop))); // Bitmap cBmp = kResizeImage(tmpBmp, tmpBmp.Width / 2, tmpBmp.Height / 2, System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic); // Bitmap nBmp = gray2alpha(cBmp); // cBmp.Dispose(); // g.DrawImageUnscaled(nBmp, x + FontSettings.relativePositionX, y + FontSettings.relativePositionY); // nBmp.Dispose(); //} //else if (this.grender_mode == "freetype_drawtwice") //{ // face.LoadGlyph(glyphIndex, LoadFlags.Default, LoadTarget.Normal); // face.Glyph.RenderGlyph(RenderMode.Normal); // FTBitmap ftbmp = face.Glyph.Bitmap; // if (ftbmp.Width == 0) // { // x += this.tile_width; // if (x + this.tile_width > this.image_width) // { // x = 0; // y += this.tile_height; // } // continue; // } // Bitmap cBmp = ftbmp.ToGdipBitmap(this.penColor); // Bitmap sBmp = ftbmp.ToGdipBitmap(this.shadowColor); // Bitmap nBmp = gray2alpha(cBmp); // cBmp.Dispose(); // g.DrawImageUnscaled(sBmp, kx + FontSettings.relativePositionX + 1, ky + FontSettings.relativePositionY + 1);//draw twice // g.DrawImageUnscaled(nBmp, kx + FontSettings.relativePositionX, ky + FontSettings.relativePositionY); // cBmp.Dispose(); // nBmp.Dispose(); //} //else if (this.grender_mode == "freeyype_nosmoothing") //{ // face.SetPixelSizes((uint)0, (uint)this.fontHeight); // face.LoadGlyph(glyphIndex, LoadFlags.Monochrome, LoadTarget.Mono); // face.Glyph.RenderGlyph(RenderMode.Mono); // FTBitmap ftbmp = face.Glyph.Bitmap; // if (ftbmp.Width == 0) // { // x += this.tile_width; // if (x + this.tile_width > this.image_width) // { // x = 0; // y += this.tile_height; // } // continue; // } // Bitmap cBmp = ftbmp.ToGdipBitmap(this.penColor); // g.DrawImageUnscaled(cBmp, kx + FontSettings.relativePositionX, ky + FontSettings.relativePositionY); // cBmp.Dispose(); //} // int tile_width = 24; //int tile_height = FontSettings.iFontHeight;//24; ////else ////{ FTBitmap ftbmp = face.Glyph.Bitmap; // if (ftbmp.Width == 0) // { // x += tile_width; // if (x + tile_width > this.image_width) // { // x = 0; // y += tile_height; // } // continue; // } Bitmap cBmp = ftbmp.ToGdipBitmap(fontSettings.PenColor); Bitmap nBmp = gray2alpha(cBmp); Rect newPos = binPack.Insert(cBmp.Width, cBmp.Height, MaxRectsBinPack.FreeRectChoiceHeuristic.RectBottomLeftRule); //DebugRectangle System.Windows.Shapes.Rectangle testRect = new System.Windows.Shapes.Rectangle { Stroke = System.Windows.Media.Brushes.LightGreen, StrokeThickness = 0 }; ImageBrush ib = new ImageBrush(); // cBmp.MakeTransparent(); cBmp.Dispose(); var source = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(nBmp.GetHbitmap(), IntPtr.Zero, Int32Rect.Empty, System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions()); nBmp.Dispose(); ib.ImageSource = source; testRect.Fill = ib; testRect.Width = newPos.Width; testRect.Height = newPos.Height; Canvas.SetLeft(testRect, newPos.Left); Canvas.SetTop(testRect, newPos.Top); list.Add(testRect); Glyph newGlyph = new Glyph() { X = (int)Math.Ceiling(newPos.Left), Y = (int)Math.Ceiling(newPos.Top), width = (int)Math.Ceiling(newPos.Width), height = (int)Math.Ceiling(newPos.Height) }; newFont.SetGlyph(currentChar0, newGlyph); //if(glyphIndex == 33) //{ //} // Construct KerningData for (int j = 0; j < alphabet.ToCharArray().Length; j++) { string left_Char0 = alphabet.ToCharArray()[j].ToString(); uint left_glyphIndex = face.GetCharIndex(uchar2code(left_Char0)); //if (left_glyphIndex == 45) //{ //} //char c1 = mAlphabet[i]; //FT_UInt c1Index = FT_Get_Char_Index(face, c1); var delta = face.GetKerning(left_glyphIndex, glyphIndex, KerningMode.Default); // KerningData kd = new KerningData(kern_currentChar0, currentChar0, delta.X.ToInt32() >> 6, 0, delta.Y.ToInt32() >> 6, 0); if (left_glyphIndex == 0 || delta.X == 0) //no kerning { continue; } Kerning newKerning = new Kerning(); newKerning.RightGlyphID = left_glyphIndex; newKerning.KerningValue = delta.X.ToInt32() >> 6; newFont.SetKerning(left_Char0, newKerning); } newFont.SetVerticalOffset(currentChar0, ky); //cBmp.Dispose(); //g.DrawImageUnscaled(nBmp, (int)Math.Ceiling(newPos.X) + fontSettings.relativePositionX, (int)Math.Ceiling(newPos.Y) + fontSettings.relativePositionY); //// g.DrawImageUnscaled(nBmp, kx + FontSettings.relativePositionX, ky + FontSettings.relativePositionY); //nBmp.Dispose(); } g.Dispose(); library.Dispose(); return(bmp); }
/// <summary> /// Create a font from a file. /// Return null if an error. /// </summary> /// <param name="filename"></param> /// <returns></returns> public static BitmapFont ReadFile(string filename) { var font = new BitmapFont(); var bytes = File.ReadAllBytes(filename); // start with ASCII "BMF" if (bytes.Length < 3 || bytes[0] != 66 || bytes[1] != 77 || bytes[2] != 70) { return(null); // wrong header } var version = bytes[3]; if (version > 3) { return(null); // unsupported version } var index = 4; // start here Func <int, int> Read = n => { var val = 0; for (var i = 0; i < n; ++i) { val = bytes[index++]; } return(val); }; Func <int, uint> ReadU = n => (uint)Read(n); int pages = 0; while (index < bytes.Length) { var type = bytes[index++]; var size = Read(4); // block size, not including type and 4 byte size field var next = size + index; // should end here switch (type) { case 1: // general info - how font was generated { var fontSize = Read(2); // size of TT font var bits = Read(1); // bit 0: smooth, bit 1: unicode, bit 2: italic, bit 3: bold, bit 4: fixedHeight, bits 5-7: reserved var smooth = (bits & 1) != 0; // smoothing was on var unicode = (bits & 2) != 0; // a unicode charset var italic = (bits & 4) != 0; // font is italic var bold = (bits & 8) != 0; // font is bold var fixedHeight = (bits & 16) != 0; var charSet = Read(1); // name of OEM charset, when not Unicode var stretchH = Read(2); // 100% means no stretch var aa = Read(1); // supersampling level used var paddingUp = Read(1); var paddingRight = Read(1); var paddingDown = Read(1); var paddingLeft = Read(1); var spacingH = Read(1); var spacingV = Read(1); // character spacing var outline = Read(1); // outline thickness var sb = new StringBuilder(); while (bytes[index] != 0) { sb.Append((char)bytes[index++]); } var name = sb.ToString(); // name of true type font used index++; // skip 0 } break; case 2: // common { font.LineHeight = Read(2); // uint 0 font.Base = Read(2); // uint 2 var scaleW = Read(2); // uint 4 var scaleH = Read(2); // uint 6 pages = Read(2); // uint 8 number of texture pages var bitField = Read(1); // bits 10 bits 0-6: reserved, bit 7: packed var packed = (bitField & 128) != 0; // if packed, each color channel has monochrome characters and alpha channel describes what's in channels // each channel: Set to 0 if the channel holds the glyph data, 1 if it holds the outline, 2 if it holds the glyph and the outline, 3 if its set to zero, and 4 if its set to one. var alphaChnl = Read(1); // uint 11 var redChnl = Read(1); //uint 12 var greenChnl = Read(1); //uint 13 var blueChnl = Read(1); //uint 14 } break; case 3: // page names for textures { for (var i = 0; i < pages; ++i) { var sb = new StringBuilder(); while (bytes[index] != 0) { sb.Append((char)bytes[index++]); } var name = sb.ToString(); index++; // skip 0 } } break; case 4: // chars { // The number of characters in the file can be computed by taking the size of // the block and dividing with the size of the charInfo structure, i.e.: numChars = charsBlock.blockSize/20. if ((size % 20) != 0) { return(null); // wrong size } var num = size / 20; for (var i = 0; i < num; ++i) { var c = new BitmapCharacter(); var id = Read(4); // character ID (unicode?) //uint 0+c*20 These fields are repeated until all characters have been described c.X = Read(2); // uint 4+c*20 texture X position c.Y = Read(2); //uint 6+c*20 texture Y position c.Width = Read(2); //uint 8+c*20 texture width c.Height = Read(2); //uint 10+c*20 texture height c.XOffset = Read(2); // int 12+c*20 offset when copying to screen c.YOffset = Read(2); // int 14+c*20 c.XAdvance = Read(2); //int 16+c*20 advance after drawing character var page = Read(1); // uint 18+c*20 // texture page where character is found var chnl = Read(1); // uint 19+c*20 // texture where found (1=blue,2-green,4-red,8=alpha,15=all channels) font.Characters[id] = c; } } break; case 5: // kerning pairs { if ((size % 10) != 0) { return(null); // wrong size } var num = size / 10; for (var i = 0; i < num; ++i) { // This block is only in the file if there are any kerning pairs with amount differing from 0. var k = new Kerning(); // uint 0+c*10 These fields are repeated until all kerning pairs have been described k.First = Read(4); // first character id k.Second = Read(4); // uint 4+c*10 second character id k.Amount = Read(2); // int 8+c*6 amount to adjust x position font.KerningList.Add(k); } } break; default: return(null); // unknown block type } if (next != index) { return(null); // wrong block size } } return(font); }
void ParseKerning() { var k = new Kerning(); k.first = (char) GetInt("first"); k.second = (char) GetInt("second"); k.amount = GetInt("amount"); Dictionary<char, Kerning> valueDict; if (kerningTable.ContainsKey(k.first)) { valueDict = kerningTable[k.first]; } else { valueDict = new Dictionary<char, Kerning>(); kerningTable[k.first] = valueDict; } valueDict.Add(k.second, k); }
/// <summary> /// This method for loading/saving a font file generated from AngelCode BMFont. /// </summary> /// <param name="serializer">The binaryserializer to use.</param> private void SerializeBMFFont(BinarySerializer serializer) { // ---------------------------------------------------------- // Read block Info (1) // ---------------------------------------------------------- byte blockType = 1; serializer.Serialize(ref blockType); if (blockType != 1) { return; } // Skip Info block int expectedBlockSize = 0; serializer.Serialize(ref expectedBlockSize); serializer.Stream.Seek(expectedBlockSize, SeekOrigin.Current); // ---------------------------------------------------------- // Read block Common (2) // ---------------------------------------------------------- serializer.Serialize(ref blockType); if (blockType != 2) { return; } var common = new BMFCommon(); common.Serialize(serializer); // Copy the base offset. BaseOffset = common.Base; LineSpacing = common.LineHeight; // ---------------------------------------------------------- // Read block page names (3) // ---------------------------------------------------------- serializer.Serialize(ref blockType); if (blockType != 3) { return; } serializer.Serialize(ref expectedBlockSize); // Create bitmap array. Bitmaps = new Bitmap[common.PageCount]; for (int i = 0; i < Bitmaps.Length; i++) { string name = null; serializer.Serialize(ref name, true); // Store the name in data Bitmaps[i] = new Bitmap { Data = name }; } // ---------------------------------------------------------- // Read block glyphs (4) // ---------------------------------------------------------- serializer.Serialize(ref blockType); if (blockType != 4) { return; } serializer.Serialize(ref expectedBlockSize); int countChars = expectedBlockSize / 20; var bmfGlyph = new BMFGlyph(); Glyphs = new Glyph[countChars]; for (int i = 0; i < Glyphs.Length; i++) { bmfGlyph.Serialize(serializer); Glyphs[i] = new Glyph { Character = bmfGlyph.Id, Subrect = new Rectangle(bmfGlyph.X, bmfGlyph.Y, bmfGlyph.Width, bmfGlyph.Height), Offset = { X = bmfGlyph.OffsetX, Y = bmfGlyph.OffsetY }, XAdvance = bmfGlyph.AdvanceX, BitmapIndex = bmfGlyph.PageIndex }; } // ---------------------------------------------------------- // Read block kernings (5) optional // ---------------------------------------------------------- if (serializer.Stream.Position < serializer.Stream.Length) { // If there is still some data to read, there is probably some kernings serializer.Serialize(ref blockType); if (blockType != 5) { return; } serializer.Serialize(ref expectedBlockSize); int kernelCount = expectedBlockSize / 10; Kernings = new Kerning[kernelCount]; for (int i = 0; i < Kernings.Length; i++) { serializer.Serialize(ref Kernings[i].First); serializer.Serialize(ref Kernings[i].Second); short offset = 0; serializer.Serialize(ref offset); Kernings[i].Offset = offset; } } }
/// <summary>Parses the FNT file.</summary> private void ParseFNTFile() { string fntFile = m_fntFile; StreamReader stream = new StreamReader( fntFile ); string line; char[] separators = new char[] { ' ', '=' }; while ( ( line = stream.ReadLine() ) != null ) { string[] tokens = line.Split( separators ); if ( tokens[0] == "info" ) { // Get rendered size for ( int i = 1; i < tokens.Length; i++ ) { if ( tokens[i] == "size" ) { m_charSet.RenderedSize = int.Parse( tokens[i + 1] ); } } } else if ( tokens[0] == "common" ) { // Fill out BitmapCharacterSet fields for ( int i = 1; i < tokens.Length; i++ ) { if ( tokens[i] == "lineHeight" ) { m_charSet.LineHeight = int.Parse( tokens[i + 1] ); } else if ( tokens[i] == "base" ) { m_charSet.Base = int.Parse( tokens[i + 1] ); } else if ( tokens[i] == "scaleW" ) { m_charSet.Width = int.Parse( tokens[i + 1] ); } else if ( tokens[i] == "scaleH" ) { m_charSet.Height = int.Parse( tokens[i + 1] ); } } } else if ( tokens[0] == "char" ) { // New BitmapCharacter int index = 0; for ( int i = 1; i < tokens.Length; i++ ) { if ( tokens[i] == "id" ) { index = int.Parse( tokens[i + 1] ); } else if ( tokens[i] == "x" ) { m_charSet.Characters[index].X = int.Parse( tokens[i + 1] ); } else if ( tokens[i] == "y" ) { m_charSet.Characters[index].Y = int.Parse( tokens[i + 1] ); } else if ( tokens[i] == "width" ) { m_charSet.Characters[index].Width = int.Parse( tokens[i + 1] ); } else if ( tokens[i] == "height" ) { m_charSet.Characters[index].Height = int.Parse( tokens[i + 1] ); } else if ( tokens[i] == "xoffset" ) { m_charSet.Characters[index].XOffset = int.Parse( tokens[i + 1] ); } else if ( tokens[i] == "yoffset" ) { m_charSet.Characters[index].YOffset = int.Parse( tokens[i + 1] ); } else if ( tokens[i] == "xadvance" ) { m_charSet.Characters[index].XAdvance = int.Parse( tokens[i + 1] ); } } } else if ( tokens[0] == "kerning" ) { // Build kerning list int index = 0; Kerning k = new Kerning(); for ( int i = 1; i < tokens.Length; i++ ) { if ( tokens[i] == "first" ) { index = int.Parse( tokens[i + 1] ); } else if ( tokens[i] == "second" ) { k.Second = int.Parse( tokens[i + 1] ); } else if ( tokens[i] == "amount" ) { k.Amount = int.Parse( tokens[i + 1] ); } } m_charSet.Characters[index].KerningList.Add( k ); } } stream.Close(); }