ttfFontReader.cs :  » PDF » SharpPDF » sharpPDF » Fonts » TTF » C# / CSharp Open Source

Home
C# / CSharp Open Source
1.2.6.4 mono .net core
2.2.6.4 mono core
3.Aspect Oriented Frameworks
4.Bloggers
5.Build Systems
6.Business Application
7.Charting Reporting Tools
8.Chat Servers
9.Code Coverage Tools
10.Content Management Systems CMS
11.CRM ERP
12.Database
13.Development
14.Email
15.Forum
16.Game
17.GIS
18.GUI
19.IDEs
20.Installers Generators
21.Inversion of Control Dependency Injection
22.Issue Tracking
23.Logging Tools
24.Message
25.Mobile
26.Network Clients
27.Network Servers
28.Office
29.PDF
30.Persistence Frameworks
31.Portals
32.Profilers
33.Project Management
34.RSS RDF
35.Rule Engines
36.Script
37.Search Engines
38.Sound Audio
39.Source Control
40.SQL Clients
41.Template Engines
42.Testing
43.UML
44.Web Frameworks
45.Web Service
46.Web Testing
47.Wiki Engines
48.Windows Presentation Foundation
49.Workflows
50.XML Parsers
C# / C Sharp
C# / C Sharp by API
C# / CSharp Tutorial
C# / CSharp Open Source » PDF » SharpPDF 
SharpPDF » sharpPDF » Fonts » TTF » ttfFontReader.cs
using System;
using System.Collections;
using System.IO;
using System.Text;

using sharpPDF;
using sharpPDF.Enumerators;
using sharpPDF.Exceptions;
using sharpPDF.Fonts;
using sharpPDF.Fonts.TTF.IO;

namespace sharpPDF.Fonts.TTF{
  /// <summary>
  /// Descrizione di riepilogo per ttfFontReader.
  /// </summary>
  internal class ttfFontReader : FontReader
  {
    private AdvancedFileStream _fontStream = null;    
    private OffsetTable _offsetTable = new OffsetTable();
    private Hashtable _directoryTables = new Hashtable();    
    private NamesTable _namesTable = new NamesTable();
    private FontHeaderTable _headTable = new FontHeaderTable();
    private HorizontalHeaderTable _hheaTable = new HorizontalHeaderTable();
    private OSTable _osTable = new OSTable();
    private PostScriptTable _postTable = new PostScriptTable();
    private int[] _GlyphWidths;
    private ArrayList _CMAPTable = new ArrayList();
    private bool _disposed = false;

    #region ~Ctor

    /// <summary>
    /// Class's Constructor
    /// </summary>
    /// <param name="fontReference">Name of the font file</param>
    public ttfFontReader(string fontReference):base(fontReference)
    {
      //Check if it is a really TTF file
      if (!(_fontReference.ToLower().EndsWith(".ttf"))) {
        throw new pdfBadFontFileException();
      }
      try {
        _fontStream = new AdvancedFileStream(_fontReference,FileMode.Open);        
      } catch (Exception ex) {
        throw new pdfGenericIOException(ex.Message, ex);
      }
    }

    /// <summary>
    /// Method that Dispose the object
    /// </summary>
    public override void Dispose() {
      if (!_disposed) {
        _directoryTables = null;
        _CMAPTable = null;
        if (_fontStream != null) {
          _fontStream.Close();
          _fontStream = null;
        }
        this._disposed = true;
      }
    }

    #endregion

    /// <summary>
    /// Method that reads the informations from the font file
    /// </summary>
    private void readFontFile()
    {
      DirectoryTable tempTable;      
      try {        
        readOffsetTable();
        _fontStream.Seek(12,SeekOrigin.Begin);
        for (int i = 0; i < _offsetTable.NumberOfTables; i++) {
          tempTable = readDirectoryTable();
          _directoryTables.Add(tempTable.Tag.ToLower(), tempTable);
        }
        readNamesTable();
        readFontHeaderTable();
        readHorizontalHeaderTable();
        readOsTable();
        readPostScriptTable();
        readGlyphWidths();
        readCMAP();
      } catch (Exception ex) {
        throw new pdfBadFontFileException();
      }
    }

    /// <summary>
    /// Method that returns the definition of the font
    /// </summary>
    /// <returns>Font Definition object</returns>
    public override pdfFontDefinition getFontDefinition()
    {
      pdfFontDefinition myDefinition = new pdfFontDefinition();      
      try {
        //Fill All Font's Table
        readFontFile();
        //Creation of FontDefinition
        myDefinition.fontName = "BBCDEE+" + _namesTable.FontName;
        myDefinition.fullFontName = _namesTable.FullName;
        myDefinition.familyName = _namesTable.FamilyName;
        myDefinition.ascender = (int)_osTable.sTypoAscender * 1000 / _headTable.unitsPerEm;
        myDefinition.descender = (int)_osTable.sTypoDescender * 1000 / _headTable.unitsPerEm;
        myDefinition.capHeight = (int)_osTable.sCapHeight * 1000 / _headTable.unitsPerEm;
        myDefinition.fontBBox = new int[4]{
          (int)(_headTable.xMin * 1000 / _headTable.unitsPerEm),
          (int)(_headTable.yMin * 1000 / _headTable.unitsPerEm),
          (int)(_headTable.xMax * 1000 / _headTable.unitsPerEm),
          (int)(_headTable.yMax * 1000 / _headTable.unitsPerEm)
        };
        myDefinition.fontHeight = Convert.ToInt32(Math.Round((((double)myDefinition.fontBBox[3] - (double)myDefinition.fontBBox[1]) / 1000)));        
        if (myDefinition.fontHeight == 0) {
          myDefinition.fontHeight = 1;
        }
        myDefinition.italicAngle = (int)_postTable.ItalicAngle * 1000 / _headTable.unitsPerEm;
        myDefinition.underlinePosition = _postTable.UnderlinePosition;
        myDefinition.underlineThickness = _postTable.UnderlineThickness;
        myDefinition.isFixedPitch = _postTable.IsFixedPitch;
        CMAPTable myCMAP = null;
        //Get CMAP Platform=3, Encoding=1 Windows - Unicode
        myCMAP = getCMAP(3,1);
        if (myCMAP == null) {
          //Get CMAP Platform=1, Endoding=0 Mac
          myCMAP = getCMAP(1,0);
        }
        if (myCMAP != null) {            
          for (int i = 0; i < 65535;i++)
          {  
            CharacterMetric myMetric = new CharacterMetric();
            if (myCMAP.Mapping.ContainsKey(i)) {
              myMetric.characterMapping = ((int[])myCMAP.Mapping[i])[0];
              myMetric.characterWidth = ((int[])myCMAP.Mapping[i])[1];            
            } else {
              myMetric.characterMapping = 0;
              myMetric.characterWidth = 0;
            }
            myDefinition.fontMetrics[i] = myMetric;          
          }
        } else {
          throw new pdfCMAPNotSupportedException();
        }
        myCMAP = null;
      } catch (pdfCMAPNotSupportedException ex) {
        throw new pdfCMAPNotSupportedException();
      } catch (Exception ex) {
        throw new pdfBadFontFileException();
      } finally {
        if (_fontStream != null) {
          _fontStream.Close();
        }
      }
      return myDefinition;
    }

    /// <summary>
    /// Method that returns the a stream of the font file
    /// </summary>
    /// <returns>Byte aray with the stream of the font file</returns>
    public byte[] getFontStream()
    {
      byte[] returnBytes;
      _fontStream.SetPosition(0);
      returnBytes = new byte[_fontStream.Length];
            _fontStream.Read(returnBytes,0,returnBytes.Length);
      return returnBytes;
    }

    /// <summary>
    /// Method that reads the Offset Table
    /// </summary>
    private void readOffsetTable()
    {  
      /*---<Temporary>---*/
      _fontStream.SetPosition(0);      
      _fontStream.SkipBytes(4); //Font Version
      _offsetTable.Version = 1.0f;
      /*---</Temporary>---*/
      _offsetTable.NumberOfTables = _fontStream.readUShort_BE();      
      _offsetTable.SearchRange = _fontStream.readUShort_BE();      
      _offsetTable.EntrySelector = _fontStream.readUShort_BE();      
      _offsetTable.RangeShift = _fontStream.readUShort_BE();
    }

    /// <summary>
    /// Method that reads the Names Table
    /// </summary>
    private void readNamesTable()
    {
      if (_directoryTables.ContainsKey("name")) {
        _fontStream.SetPosition(((DirectoryTable)_directoryTables["name"]).Offset); //Set the offset
                _fontStream.SkipBytes(2);
        int platformID;
        int platformEncodingID;
        int languageID;
        int nameID;
        int length;
        int offset;
        int numTables = _fontStream.readUShort_BE();
        int startOffset = _fontStream.readUShort_BE();
        long currentStreamPosition;
        int i = 0;
        bool founded = false;
        while (i<numTables && !(founded))
        {
          platformID = _fontStream.readUShort_BE();
          platformEncodingID = _fontStream.readUShort_BE();
          languageID = _fontStream.readUShort_BE();
          nameID = _fontStream.readUShort_BE();
          length = _fontStream.readUShort_BE();
          offset = _fontStream.readUShort_BE();
          currentStreamPosition = _fontStream.Position;
          _fontStream.SetPosition(((DirectoryTable)_directoryTables["name"]).Offset + startOffset + offset);
          switch (nameID) {
            case 1: //FamilyName
              if ((platformID == 0 || platformID == 3 || (platformID == 2 && platformEncodingID == 1))){
                _namesTable.FamilyName = _fontStream.readUnicodeString(length);
              }
              else {
                _namesTable.FamilyName = _fontStream.readString(length);
              }
              break;
            case 4: //FullName
              if ((platformID == 0 || platformID == 3 || (platformID == 2 && platformEncodingID == 1))){
                _namesTable.FullName = _fontStream.readUnicodeString(length);
              }
              else {
                _namesTable.FullName = _fontStream.readString(length);
              }
              break;
            case 6:  //FontName            
              if ((platformID == 0 || platformID == 3 || (platformID == 2 && platformEncodingID == 1))) {
                _namesTable.FontName = _fontStream.readUnicodeString(length).Replace(" ","");
              } else {
                _namesTable.FontName = _fontStream.readString(length).Replace(" ","");
              }              
              break;            
          }
          if (_namesTable.FontName != null && _namesTable.FamilyName != null && _namesTable.FullName != null) {
            founded = true;
          } else {
            _fontStream.SetPosition(currentStreamPosition);
            i++;
          }          
        }
        //Check the names
        if (!founded) {
          throw new pdfBadFontFileException();
        }
      } else {
        throw new pdfBadFontFileException();
      }      
    }

    /// <summary>
    /// Method that reads a Directory Table
    /// </summary>
    /// <returns>Structure that represents the Directory Table</returns>
    private DirectoryTable readDirectoryTable()
    {
      DirectoryTable myTable = new DirectoryTable();
      myTable.Tag = _fontStream.readString(4);
      myTable.Checksum = _fontStream.readULong_BE();
      myTable.Offset = _fontStream.readULong_BE();
      myTable.Length = _fontStream.readULong_BE();
      return myTable;
    }

    /// <summary>
    /// Method that reads the FontHeader Table
    /// </summary>
    private void readFontHeaderTable()
    {      
      if (_directoryTables.ContainsKey("head")) {                
        _fontStream.SetPosition(((DirectoryTable)_directoryTables["head"]).Offset); //Set the offset
        _fontStream.SkipBytes(16); //Table Version
        _headTable.flags = _fontStream.readUShort_BE();
        _headTable.unitsPerEm = _fontStream.readUShort_BE();
        _fontStream.SkipBytes(16);
        _headTable.xMin = _fontStream.readShort_BE();
        _headTable.yMin = _fontStream.readShort_BE();
        _headTable.xMax = _fontStream.readShort_BE();
        _headTable.yMax = _fontStream.readShort_BE();
        _headTable.macStyle = _fontStream.readUShort_BE();
      } else {
        throw new pdfBadFontFileException();
      }
    }

    /// <summary>
    /// Method that reads the HorizontalHeader Table
    /// </summary>
    private void readHorizontalHeaderTable()
    {
      if (_directoryTables.ContainsKey("hhea")) {
        _fontStream.SetPosition(((DirectoryTable)_directoryTables["hhea"]).Offset); //Set the offset
        _fontStream.SkipBytes(4); //Table Version
        _hheaTable.Ascender =_fontStream.readShort_BE();
        _hheaTable.Descender = _fontStream.readShort_BE();
        _hheaTable.LineGap = _fontStream.readShort_BE();
        _hheaTable.advanceWidthMax = _fontStream.readUShort_BE();
        _hheaTable.minLeftSideBearing = _fontStream.readShort_BE();
        _hheaTable.minRightSideBearing = _fontStream.readShort_BE();
        _hheaTable.xMaxExtent = _fontStream.readShort_BE();
        _hheaTable.caretSlopeRise = _fontStream.readShort_BE();
        _hheaTable.caretSlopeRun = _fontStream.readShort_BE();
        _fontStream.SkipBytes(12);
        _hheaTable.numberOfHMetrics = _fontStream.readUShort_BE();        
      } else {
        throw new pdfBadFontFileException();
      }
    }

    /// <summary>
    /// Method that reads the OS Table
    /// </summary>
    private void readOsTable()
    {
      if (_directoryTables.ContainsKey("os/2")) {
        _fontStream.SetPosition(((DirectoryTable)_directoryTables["os/2"]).Offset); //Set the offset
        int osVersion = _fontStream.readShort_BE();        
        _osTable.xAvgCharWidth = _fontStream.readShort_BE();
        _osTable.usWeightClass = _fontStream.readUShort_BE();
        _osTable.usWidthClass = _fontStream.readUShort_BE();
        _osTable.fsType = _fontStream.readShort_BE();
        _osTable.ySubscriptXSize = _fontStream.readShort_BE();
        _osTable.ySubscriptYSize = _fontStream.readShort_BE();
        _osTable.ySubscriptXOffset = _fontStream.readShort_BE();
        _osTable.ySubscriptYOffset = _fontStream.readShort_BE();
        _osTable.ySuperscriptXSize = _fontStream.readShort_BE();
        _osTable.ySuperscriptYSize = _fontStream.readShort_BE();
        _osTable.ySuperscriptXOffset = _fontStream.readShort_BE();
        _osTable.ySuperscriptYOffset = _fontStream.readShort_BE();
        _osTable.yStrikeoutSize = _fontStream.readShort_BE();
        _osTable.yStrikeoutPosition = _fontStream.readShort_BE();
        _osTable.sFamilyClass = _fontStream.readShort_BE();
        _osTable.panose = _fontStream.readByteArray(10);
        _fontStream.SkipBytes(16);        
        _osTable.achVendID = _fontStream.readString(4);
        _osTable.fsSelection = _fontStream.readUShort_BE();
        _osTable.usFirstCharIndex = _fontStream.readUShort_BE();
        _osTable.usLastCharIndex = _fontStream.readUShort_BE();
        _osTable.sTypoAscender = _fontStream.readShort_BE();
        _osTable.sTypoDescender = _fontStream.readShort_BE();
        _osTable.sTypoLineGap = _fontStream.readShort_BE();
        _osTable.usWinAscent = _fontStream.readUShort_BE();
        _osTable.usWinDescent = _fontStream.readUShort_BE();
        _osTable.ulCodePageRange1 = 0;
        _osTable.ulCodePageRange2 = 0;
        if (osVersion > 0) {
          _osTable.ulCodePageRange1 = _fontStream.readInt_BE();
          _osTable.ulCodePageRange2 = _fontStream.readInt_BE();
        }
        if (osVersion > 1) {
          _fontStream.SkipBytes(2);
          _osTable.sCapHeight = _fontStream.readShort_BE();
        } else {
          _osTable.sCapHeight = (int)(0.7 * _headTable.unitsPerEm);
        }
      } else {
        throw new pdfBadFontFileException();
      }
    }

    /// <summary>
    /// Method that reads the PostScript Table
    /// </summary>
    private void readPostScriptTable()
    {
      if (_directoryTables.ContainsKey("post")) {
        _fontStream.SetPosition(((DirectoryTable)_directoryTables["post"]).Offset); //Set the offset
        _fontStream.SkipBytes(4); //Table Version
        short mantissa = _fontStream.readShort_BE();
        int fraction = _fontStream.readUShort_BE();
        _postTable.ItalicAngle = (double)mantissa + (double)fraction / 16384.0;
        _postTable.UnderlinePosition = _fontStream.readInt_BE();
        _postTable.UnderlineThickness = _fontStream.readInt_BE();        
        _postTable.IsFixedPitch = (_fontStream.readInt_BE() != 0);
      } else {
        throw new pdfBadFontFileException();
      }
    }

    /// <summary>
    /// Method that reads the Glyph's Widths
    /// </summary>
    private void readGlyphWidths()
    {
      if (_directoryTables.ContainsKey("hmtx")) {
        _GlyphWidths = new int[_hheaTable.numberOfHMetrics];
        _fontStream.SetPosition(((DirectoryTable)_directoryTables["hmtx"]).Offset);
        for(int i = 0; i < _hheaTable.numberOfHMetrics; i++)
        {
          _GlyphWidths[i] = (int)((_fontStream.readUShort_BE() * 1000) / _headTable.unitsPerEm);
          _fontStream.SkipBytes(2);
        }
      } else {
        throw new pdfBadFontFileException();
            }
    }

    /// <summary>
    /// Method that reads the CMAP
    /// </summary>
    private void readCMAP()
    {
      if (_directoryTables.ContainsKey("cmap")) {
        _fontStream.SetPosition(((DirectoryTable)_directoryTables["cmap"]).Offset);
        _fontStream.SkipBytes(2); //Table Version
        int tblNumber = _fontStream.readUShort_BE();
        int platformID;
        int encodingID;
        int offset;
        int format;
        for (int i = 0; i < tblNumber; i++)
        {
          platformID = _fontStream.readUShort_BE();
          encodingID = _fontStream.readUShort_BE();
          offset = _fontStream.readULong_BE();
          _CMAPTable.Add(new CMAPTable(platformID,encodingID,offset));
        }
        foreach(CMAPTable CMAP in _CMAPTable)
        {
          _fontStream.SetPosition(((DirectoryTable)_directoryTables["cmap"]).Offset + CMAP.Offset);
          format = _fontStream.readUShort_BE();
          switch (CMAP.PlatformID) {
            case 1: //Apple
              switch (format) {
                case 0:
                  CMAP.Mapping = readFormat0();
                  break;
                case 4:
                  CMAP.Mapping = readFormat4();
                  break;
                case 6:
                  CMAP.Mapping = readFormat6();
                  break;
              }
              break;
            case 3: //Microsoft
              if (format == 4) {
                CMAP.Mapping = readFormat4();
              }
              break;
          }
        }
      } else {
        throw new pdfBadFontFileException();
      }
    }

    /// <summary>
    /// Method that read the TTF Format 0
    /// </summary>
    /// <returns>Hashtable with glyph's informations</returns>
    private Hashtable readFormat0()
    {
      int[] glyphInfo;
      Hashtable returnTable = new Hashtable();
      _fontStream.SkipBytes(2); //Skip Version
      _fontStream.SkipBytes(2); //Skip Length
      for (int i = 0; i < 256; i++)
      {
        glyphInfo = new int[2];
        glyphInfo[0] = _fontStream.readByte();
        glyphInfo[1] = _GlyphWidths[glyphInfo[0]];
        returnTable.Add(i,glyphInfo);
        glyphInfo = null;
      }
      return returnTable;
    }

    /// <summary>
    /// Method that read the TTF Format 4
    /// </summary>
    /// <returns>Hashtable with glyph's informations</returns>
    private Hashtable readFormat4()
    {
      int i,j,glyph,idx;
      Hashtable returnTable = new Hashtable();
      int[] glyphInfo;
      int table_lenght = _fontStream.readUShort_BE();
      _fontStream.SkipBytes(2);
      int seg =  _fontStream.readUShort_BE() / 2;
      _fontStream.SkipBytes(6);
      int[] end = new int[seg];
      for (i = 0; i < seg; i++) {
        end[i] = _fontStream.readUShort_BE();
      }
      _fontStream.SkipBytes(2);
      int[] start = new int[seg];
      for (i = 0; i < seg; i++) {
        start[i] = _fontStream.readUShort_BE();
      }
      int[] delta = new int[seg];
      for (i = 0; i < seg; i++) {
        delta[i] = _fontStream.readUShort_BE();
      }
      int[] ro = new int[seg];
      for (i = 0; i < seg; i++) {
        ro[i] = _fontStream.readUShort_BE();
      }
      int[] glyphId = new int[table_lenght / 2 - 8 - seg * 4];
      for (i = 0; i < glyphId.Length; i++) {
        glyphId[i] = _fontStream.readUShort_BE();
      }
      for (i = 0; i < seg; i++) {
        for (j = start[i]; j <= end[i] && j != 0xFFFF; j++) {
          if (ro[i] == 0) {
            glyph = (j + delta[i]) & 0xFFFF;
          }
          else {
            idx = i + ro[i] / 2 - seg + j - start[i];
            glyph = (glyphId[idx] + delta[i]) & 0xFFFF;
          }
          glyphInfo = new int[2];
          glyphInfo[0] = glyph;
          glyphInfo[1] = _GlyphWidths[glyphInfo[0]];
          returnTable.Add(j, glyphInfo);
        }
      }
      return returnTable;
    }

    /// <summary>
    /// Method that read the TTF Format 6
    /// </summary>
    /// <returns>Hashtable with glyph's informations</returns>
    private Hashtable readFormat6()
    {
      int[] glyphInfo;
      Hashtable returnTable = new Hashtable();
      _fontStream.SkipBytes(2); //Skip Version
      _fontStream.SkipBytes(2); //Skip Length
      int start = _fontStream.readUShort_BE();
      int count = _fontStream.readUShort_BE();
      for (int i = 0; i < count; i++)
      {
        glyphInfo = new int[2];
        glyphInfo[0] = _fontStream.readByte();
        glyphInfo[1] = _GlyphWidths[glyphInfo[0]];
        returnTable.Add(i + start,glyphInfo);
        glyphInfo = null;
      }
      return returnTable;
    }

    /// <summary>
    /// Method that returns the CMAP table
    /// </summary>
    /// <param name="platformID">ID of the platform</param>
    /// <param name="encodingID">ID of the encoding</param>
    /// <returns>CMAP object</returns>
    private CMAPTable getCMAP(int platformID, int encodingID)
    {
      CMAPTable returnCMAP = null;
      int i = 0;
      while (i<_CMAPTable.Count && returnCMAP == null)
      {
        if (((CMAPTable)_CMAPTable[i]).PlatformID == platformID && ((CMAPTable)_CMAPTable[i]).EncodingID == encodingID) {
          returnCMAP = (CMAPTable)_CMAPTable[i];
        }
        i++;
      }
      return returnCMAP;
    }    

  }
}
www.java2v.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.