static char DecodeChar(FontHeader header, Dictionary <char, char> charMap, int charIndex) { int charValue = (header.FirstAscii + charIndex); char fontChar = (char)charValue; char actualChar; if (charValue > 0x100) { if (!charMap.ContainsKey(fontChar)) { //throw new Exception("Couldn't find char in charlist to decode!"); actualChar = fontChar; } else { actualChar = charMap[fontChar]; } } else { if (!charMap.ContainsKey(fontChar)) { actualChar = fontChar; } else { actualChar = charMap[fontChar]; } } return(actualChar); }
public static TTFStringMeasurer Create(TrueTypeFile forfont, CMapEncoding encoding, TypeMeasureOptions options) { HorizontalMetrics table = forfont.Directories["hmtx"].Table as HorizontalMetrics; CMAPTable cmap = forfont.Directories["cmap"].Table as CMAPTable; OS2Table os2 = forfont.Directories["OS/2"].Table as OS2Table; FontHeader head = forfont.Directories["head"].Table as FontHeader; HorizontalHeader hhead = forfont.Directories["hhea"].Table as HorizontalHeader; CMAPSubTable map = cmap.GetOffsetTable(encoding); if (map == null) { encoding = CMapEncoding.Unicode_20; map = cmap.GetOffsetTable(CMapEncoding.Unicode_20); } if (map == null) { encoding = CMapEncoding.MacRoman; map = cmap.GetOffsetTable(CMapEncoding.MacRoman); } return(new TTFStringMeasurer(head.UnitsPerEm, map, os2, hhead, table.HMetrics, forfont, encoding, options)); }
public static object Read(Stream stream) { // read the header FontHeader hdr = stream.ReadStruct <FontHeader>(); if (hdr.sig0 != 0x0500 || hdr.sig1 != 0x000E) { throw new Exception("Invalid font file"); } // allocate the buffers var nchars = 1 + hdr.nchars; var cofs = new ushort[nchars]; var glyphs = new byte[256][]; var gdata = new GlyphData[256]; // glyph offsets stream.Seek(hdr.cofs, SeekOrigin.Begin); stream.ReadStructs <ushort>(cofs, nchars); // widths stream.Seek(hdr.wpos, SeekOrigin.Begin); for (var i = 0; i < nchars; i++) { gdata[i].width = (byte)stream.ReadByte(); } // heights stream.Seek(hdr.hpos, SeekOrigin.Begin); for (var i = 0; i < nchars; i++) { gdata[i].yoffset = (byte)stream.ReadByte(); gdata[i].height = (byte)stream.ReadByte(); } // glyphs var glyphsz = hdr.wmax * hdr.hmax; var stride = hdr.wmax; for (var i = 0; i < nchars; i++) { stream.Seek(cofs[i], SeekOrigin.Begin); var w = gdata[i].width; var h = gdata[i].height; glyphs[i] = new byte[glyphsz]; DecodeGlyph4bpp(stream, w, h, glyphs[i], stride); } // fill up to 256 glyphs for (var i = nchars; i < 256; i++) { glyphs[i] = glyphs[0]; gdata[i] = gdata[0]; } return(new FntFile(glyphs, hdr.wmax, hdr.hmax, gdata)); }
private TrueTypeFontTable ReadFontHeader(uint length, TrueTypeTableEntryList list, BigEndianReader reader) { FontHeader fh = new FontHeader(reader.Position); fh.TableVersion = reader.ReadFixedVersion(); fh.FontRevision = reader.ReadFixedVersion(); fh.ChecksumAdjustment = reader.ReadUInt32(); fh.MagicNumber = reader.ReadUInt32(); fh.FontFlags = (FontHeaderFlags)reader.ReadUInt16(); fh.UnitsPerEm = reader.ReadUInt16(); fh.Created = reader.ReadDateTime(); fh.Modified = reader.ReadDateTime(); fh.XMin = reader.ReadInt16(); fh.YMin = reader.ReadInt16(); fh.XMax = reader.ReadInt16(); fh.YMax = reader.ReadInt16(); fh.MacStyle = (FontStyleFlags)reader.ReadUInt16(); fh.SmallestScreenFont = reader.ReadUInt16(); fh.DirectionHints = (FontDirectionFlags)reader.ReadInt16(); fh.IndexToLocationFormat = (FontIndexLocationFormat)reader.ReadInt16(); fh.GlyphDataFormat = (GlyphDataFormat)reader.ReadInt16(); return(fh); }
//------------------------------------------------------------------------------------------xx.02.2005 /// <summary>Reads the font data from the file.</summary> /// <param name="openTypeReader">Open Type Reader</param> private void ReadFontDataFromFile(OpenTypeReader openTypeReader) { #region TrueType Collection if (bTrueTypeCollection) { String sTTCTag = openTypeReader.sReadTag(); if (sTTCTag != "ttcf") { throw new ReportException("'" + sFontName + " is not a valid TTC font file."); } UInt32 uVersion = openTypeReader.uReadULONG(); Int32 iNumFonts = (Int32)openTypeReader.uReadULONG(); if (iTrueTypeCollectionIndex >= iNumFonts) { throw new ReportException("'" + sFontName + " has invalid TrueType collection index."); } openTypeReader.Skip(iTrueTypeCollectionIndex * 4); Int32 iOffset = (Int32)openTypeReader.uReadULONG(); openTypeReader.Seek(iOffset); } #endregion #region Offset Table UInt32 uSfntVersion = openTypeReader.uReadULONG(); if (uSfntVersion == 0x4F54544F /* 'OTTO' */) { fontDataType = FontDataType.CFFdata; } #if DEBUG else if (uSfntVersion == 0x00010000 /* Version 1.0 */) { fontDataType = FontDataType.TrueTypeOutlines; } else { throw new ReportException("'" + sFontName + " is not a valid TTF, OTF or TTC font file."); } #endif iNumTables = (Int32)openTypeReader.iReadUSHORT(); iSearchRange = (Int32)openTypeReader.iReadUSHORT(); iEntrySelector = (Int32)openTypeReader.iReadUSHORT(); iRangeShift = (Int32)openTypeReader.iReadUSHORT(); #endregion #region Table Directory for (Int32 iTable = 0; iTable < iNumTables; iTable++) { TableDirectory tableDirectory_New = new TableDirectory(); tableDirectory_New.sTag = openTypeReader.sReadTag(); tableDirectory_New.uCheckSum = openTypeReader.uReadULONG(); tableDirectory_New.iOffset = (Int32)openTypeReader.uReadULONG(); tableDirectory_New.iLength = (Int32)openTypeReader.uReadULONG(); dict_TableDirectory.Add(tableDirectory_New.sTag, tableDirectory_New); } Boolean bCFF = dict_TableDirectory.ContainsKey("CFF"); if ((bCFF && fontDataType == FontDataType.TrueTypeOutlines) || (!bCFF && fontDataType == FontDataType.CFFdata)) { throw new ReportException("'" + sFontName + " is not a valid TTC font file."); } #endregion #region Font Header TableDirectory tableDirectory = dict_TableDirectory["head"]; fontHeader = new FontHeader(); openTypeReader.Seek(tableDirectory.iOffset); fontHeader.uTableVersionNumber = openTypeReader.uReadULONG(); Debug.Assert(fontHeader.uTableVersionNumber == 0x00010000 /* Version 1.0 */); openTypeReader.Skip(12); fontHeader.iFlags = openTypeReader.iReadUSHORT(); fontHeader.iUnitsPerEm = openTypeReader.iReadUSHORT(); openTypeReader.Skip(16); fontHeader.iXMin = openTypeReader.int16_ReadSHORT(); fontHeader.iYMin = openTypeReader.int16_ReadSHORT(); fontHeader.iXMax = openTypeReader.int16_ReadSHORT(); fontHeader.iYMax = openTypeReader.int16_ReadSHORT(); fontHeader.iMacStyle = openTypeReader.iReadUSHORT(); fontHeader.iLowestRecPPEM = openTypeReader.iReadUSHORT(); fontHeader.iFontDirectionHint = openTypeReader.int16_ReadSHORT(); fontHeader.iIndexToLocFormat = openTypeReader.int16_ReadSHORT(); fontHeader.iGlyphDataFormat = openTypeReader.int16_ReadSHORT(); #endregion #region Horizontal Header tableDirectory = dict_TableDirectory["hhea"]; horizontalHeader = new HorizontalHeader(); openTypeReader.Seek(tableDirectory.iOffset); horizontalHeader.uTableVersionNumber = openTypeReader.uReadULONG(); Debug.Assert(horizontalHeader.uTableVersionNumber == 0x00010000 /* Version 1.0 */); horizontalHeader.iAscender = openTypeReader.int16_ReadFWORD(); horizontalHeader.iDescender = openTypeReader.int16_ReadFWORD(); horizontalHeader.iLineGap = openTypeReader.int16_ReadFWORD(); horizontalHeader.iAdvanceWidthMax = openTypeReader.iReadUFWORD(); horizontalHeader.iMinLeftSideBearing = openTypeReader.int16_ReadFWORD(); horizontalHeader.iMinRightSideBearing = openTypeReader.int16_ReadFWORD(); horizontalHeader.iXMaxExtent = openTypeReader.int16_ReadFWORD(); horizontalHeader.iCaretSlopeRise = openTypeReader.int16_ReadSHORT(); horizontalHeader.iCaretSlopeRun = openTypeReader.int16_ReadSHORT(); horizontalHeader.iCaretOffset = openTypeReader.int16_ReadSHORT(); openTypeReader.Skip(10); horizontalHeader.iNumberOfHMetrics = openTypeReader.iReadUSHORT(); #endregion #region Windows Metrics (OS/2) tableDirectory = dict_TableDirectory["OS/2"]; winMetrics = new WinMetrics(); openTypeReader.Seek(tableDirectory.iOffset); winMetrics.iVersion = openTypeReader.iReadUSHORT(); winMetrics.iXAvgCharWidth = openTypeReader.int16_ReadSHORT(); winMetrics.iUsWeightClass = openTypeReader.iReadUSHORT(); winMetrics.iUsWidthClass = openTypeReader.iReadUSHORT(); winMetrics.iFsType = openTypeReader.iReadUSHORT(); winMetrics.iYSubscriptXSize = openTypeReader.int16_ReadSHORT(); winMetrics.iYSubscriptYSize = openTypeReader.int16_ReadSHORT(); winMetrics.iYSubscriptXOffset = openTypeReader.int16_ReadSHORT(); winMetrics.iYSubscriptYOffset = openTypeReader.int16_ReadSHORT(); winMetrics.iYSuperscriptXSize = openTypeReader.int16_ReadSHORT(); winMetrics.iYSuperscriptYSize = openTypeReader.int16_ReadSHORT(); winMetrics.iYSuperscriptXOffset = openTypeReader.int16_ReadSHORT(); winMetrics.iYSuperscriptYOffset = openTypeReader.int16_ReadSHORT(); winMetrics.iYStrikeoutSize = openTypeReader.int16_ReadSHORT(); winMetrics.iYStrikeoutPosition = openTypeReader.int16_ReadSHORT(); winMetrics.iSFamilyClass = openTypeReader.int16_ReadSHORT(); winMetrics.aByte_Panose = openTypeReader.aByte_ReadBYTE(10); if (winMetrics.iVersion == 0) { openTypeReader.Skip(4); // skip ulCharRange } else { winMetrics.uUlUnicodeRange1 = openTypeReader.uReadULONG(); winMetrics.uUlUnicodeRange2 = openTypeReader.uReadULONG(); winMetrics.uUlUnicodeRange3 = openTypeReader.uReadULONG(); winMetrics.uUlUnicodeRange4 = openTypeReader.uReadULONG(); } winMetrics.sAchVendID = openTypeReader.sReadTag(); winMetrics.iFsSelection = openTypeReader.iReadUSHORT(); winMetrics.iUsFirstCharIndex = openTypeReader.iReadUSHORT(); winMetrics.iUsLastCharIndex = openTypeReader.iReadUSHORT(); winMetrics.iSTypoAscender = openTypeReader.int16_ReadSHORT(); winMetrics.iSTypoDescender = openTypeReader.int16_ReadSHORT(); winMetrics.iSTypoLineGap = openTypeReader.int16_ReadSHORT(); winMetrics.iUsWinAscent = openTypeReader.iReadUSHORT(); winMetrics.iUsWinDescent = openTypeReader.iReadUSHORT(); if (winMetrics.iVersion > 0) { winMetrics.iUlCodePageRange1 = openTypeReader.uReadULONG(); winMetrics.iUlCodePageRange2 = openTypeReader.uReadULONG(); if (winMetrics.iVersion > 1) { winMetrics.iSXHeight = openTypeReader.int16_ReadSHORT(); winMetrics.iSCapHeight = openTypeReader.int16_ReadSHORT(); winMetrics.uUsDefaultChar = openTypeReader.uReadULONG(); winMetrics.uUsBreakChar = openTypeReader.uReadULONG(); winMetrics.uUsMaxContext = openTypeReader.uReadULONG(); } } #endregion #region Post tableDirectory = dict_TableDirectory["post"]; openTypeReader.Seek(tableDirectory.iOffset + 4); Double r1 = openTypeReader.int16_ReadSHORT(); Double r0 = openTypeReader.iReadUSHORT(); rItalicAngle = r1 + r0 / 16384.0; iUnderlinePosition = openTypeReader.int16_ReadFWORD(); iUnderlineThickness = openTypeReader.int16_ReadFWORD(); bFixedPitch = (openTypeReader.uReadULONG() != 0); #endregion ReadTable_name(openTypeReader); ReadTable_hmtx(openTypeReader); }
protected double GetLineHeight(FontUnitType units, OS2Table os2, HorizontalHeader hhead, FontHeader header, double emsize) { double h; bool useTypo; if (units == FontUnitType.UseFontPreference) { useTypo = (os2.Version >= OS2TableVersion.OpenType15) && ((os2.Selection & FontSelection.UseTypographicSizes) > 0); } else if (units == FontUnitType.UseHeadMetrics) { useTypo = false; } else if (null == os2) { useTypo = false; } else { useTypo = true; } if (useTypo) { h = ((double)(os2.TypoAscender - os2.TypoDescender + os2.TypoLineGap) / ((double)header.UnitsPerEm) * emsize); } else { h = ((double)(hhead.Ascender - hhead.Descender + hhead.LineGap) / ((double)header.UnitsPerEm) * emsize); } return(h); }
public LineSize MeasureString(CMapEncoding encoding, string s, int startOffset, double emsize, double available, bool wordboundary, out int charsfitted, FontUnitType useUnits = FontUnitType.UseFontPreference) { HorizontalMetrics table = this.Directories["hmtx"].Table as HorizontalMetrics; CMAPTable cmap = this.Directories["cmap"].Table as CMAPTable; OS2Table os2 = this.Directories["OS/2"].Table as OS2Table; CMAPSubTable mac = cmap.GetOffsetTable(encoding); if (mac == null) { mac = cmap.GetOffsetTable(CMapEncoding.MacRoman); } HorizontalHeader hhead = this.Directories["hhea"].Table as HorizontalHeader; FontHeader head = this.Directories["head"].Table as FontHeader; available = (available * head.UnitsPerEm) / emsize; double len = 0.0; double lastwordlen = 0.0; int lastwordcount = 0; charsfitted = 0; for (int i = startOffset; i < s.Length; i++) { char c = s[i]; if (char.IsWhiteSpace(c)) { lastwordlen = len; lastwordcount = charsfitted; } int moffset = (int)mac.GetCharacterGlyphOffset(c); //System.Diagnostics.Debug.WriteLine("Character '" + chars[i].ToString() + "' (" + ((byte)chars[i]).ToString() + ") has offset '" + moffset.ToString() + "' in mac encoding and '" + woffset + "' in windows encoding"); if (moffset >= table.HMetrics.Count) { moffset = table.HMetrics.Count - 1; } Scryber.OpenType.SubTables.HMetric metric; metric = table.HMetrics[moffset]; if (i == 0) { len = -metric.LeftSideBearing; } len += metric.AdvanceWidth; //check if we can fit more if (len > available) { len -= metric.AdvanceWidth; break; } charsfitted++; } bool isboundary = false; if ((charsfitted + startOffset < s.Length) && wordboundary && lastwordlen > 0) { len = lastwordlen; charsfitted = lastwordcount; isboundary = true; } len = len / (double)head.UnitsPerEm; len = len * emsize; double h = GetLineHeight(useUnits, os2, hhead, head, emsize); return(new LineSize((float)len, (float)h, charsfitted, startOffset, isboundary)); }
/// <summary> /// Measures the size of the provided string at the specified font size (starting at a specific offset), /// stopping when the available space is full and returning the number of characters fitted. /// </summary> /// <param name="encoding">The encoding to use to map the characters</param> /// <param name="s">The string to measure the size of</param> /// <param name="startOffset">The starting (zero based) offset in that string to start measuring from</param> /// <param name="emsize">The M size in font units</param> /// <param name="availablePts">The max width allowed for this string</param> /// <param name="wordspace">The spacing between words in font units. Default 0</param> /// <param name="charspace">The spacing between characters in font units. Default 0</param> /// <param name="hscale">The horizontal scaling of all characters. Default 100</param> /// <param name="vertical">If true then this is vertical writing</param> /// <param name="wordboundary">If True the measuring will stop at a boundary to a word rather than character.</param> /// <param name="charsfitted">Set to the number of characters that can be renered at this size within the width.</param> /// <returns></returns> public LineSize MeasureString(CMapEncoding encoding, string s, int startOffset, double emsize, double availablePts, double?wordspacePts, double charspacePts, double hscale, bool vertical, bool wordboundary, out int charsfitted, FontUnitType useUnits = FontUnitType.UseFontPreference) { HorizontalMetrics table = this.Directories["hmtx"].Table as HorizontalMetrics; CMAPTable cmap = this.Directories["cmap"].Table as CMAPTable; OS2Table os2 = this.Directories["OS/2"].Table as OS2Table; CMAPSubTable mac = cmap.GetOffsetTable(encoding); if (mac == null) { mac = cmap.GetOffsetTable(CMapEncoding.MacRoman); } HorizontalHeader hhead = this.Directories["hhea"].Table as HorizontalHeader; FontHeader head = this.Directories["head"].Table as FontHeader; double availableFU = availablePts * ((double)head.UnitsPerEm / emsize); double charspaceFU = NoCharacterSpace; if (charspacePts != NoCharacterSpace) { charspaceFU = charspacePts * ((double)head.UnitsPerEm / emsize); } double wordspaceFU = NoWordSpace; if (wordspacePts.HasValue) { wordspaceFU = (wordspacePts.Value * ((double)head.UnitsPerEm / emsize)); } else if (charspacePts != NoCharacterSpace) { //If we dont have explicit wordspacing then we use the character spacing wordspaceFU = charspaceFU; } double len = 0.0; double lastwordlen = 0.0; int lastwordcount = 0; charsfitted = 0; for (int i = startOffset; i < s.Length; i++) { char c = s[i]; if (char.IsWhiteSpace(c)) { lastwordlen = len; lastwordcount = charsfitted; } int moffset = (int)mac.GetCharacterGlyphOffset(c); if (moffset >= table.HMetrics.Count) { moffset = table.HMetrics.Count - 1; } Scryber.OpenType.SubTables.HMetric metric; metric = table.HMetrics[moffset]; double w = metric.AdvanceWidth; if (i == 0) { w -= metric.LeftSideBearing; } if (c == ' ') { if (wordspaceFU != NoWordSpace) { w += wordspaceFU; } } else if (charspaceFU != NoCharacterSpace) { w += charspaceFU; } if (hscale != NoHorizontalScale) { w *= hscale; } len += w; //check if we can fit more if (len > availableFU) { len -= w; break; } charsfitted++; } bool isboundary = false; if ((charsfitted + startOffset < s.Length) && wordboundary && lastwordlen > 0) { len = lastwordlen; charsfitted = lastwordcount; isboundary = true; } len = len * emsize; len = len / (double)head.UnitsPerEm; double h = GetLineHeight(useUnits, os2, hhead, head, emsize); return(new LineSize(len, h, charsfitted, startOffset, isboundary)); }