The indexToLoc table stores the offsets to the locations of the glyphs in the font, relative to the beginning of the glyphData table. In order to compute the length of the last glyph element, there is an extra entry after the last valid index.
Inheritance: TrueTypeFontTable
Esempio n. 1
0
        /// <summary>
        /// Gets the data of the specified glyph.
        /// </summary>
        public byte[] GetGlyphData(int glyph)
        {
            IndexToLocationTable loca = this.fontData.loca;
            int start = GetOffset(glyph);
            int next  = GetOffset(glyph + 1);
            int count = next - start;

            byte[] bytes = new byte[count];
            Buffer.BlockCopy(this.fontData.Data, start, bytes, 0, count);
            return(bytes);
        }
Esempio n. 2
0
    /// <summary>
    /// Creates a new font image that is a subset of this font image containing only the specified glyphs.
    /// </summary>
    public FontImage CreateFontSubSet(Dictionary<int, object> glyphs, bool cidFont)
    {
      // Create new font image
      FontImage fontImage = new FontImage(this);

      // Create new loca and glyf table
      IndexToLocationTable loca = new IndexToLocationTable();
      loca.ShortIndex = this.loca.ShortIndex;
      GlyphDataTable glyf = new GlyphDataTable();

      // Add all required tables
      //fontImage.AddTable(this.os2);
      if (!cidFont)
        fontImage.AddTable(this.cmap);
      if (this.cvt != null)
        fontImage.AddTable(this.cvt);
      if (this.fpgm != null)
        fontImage.AddTable(this.fpgm);
      fontImage.AddTable(glyf);
      fontImage.AddTable(this.head);
      fontImage.AddTable(this.hhea);
      fontImage.AddTable(this.hmtx);
      fontImage.AddTable(loca);
      if (this.maxp != null)
        fontImage.AddTable(this.maxp);
      //fontImage.AddTable(this.name);
      if (this.prep != null)
        fontImage.AddTable(this.prep);

      // Get closure of used glyphs
      this.glyf.CompleteGlyphClosure(glyphs);

      // Create a sorted array of all used glyphs
      int glyphCount = glyphs.Count;
      int[] glyphArray = new int[glyphCount];
      glyphs.Keys.CopyTo(glyphArray, 0);
      Array.Sort<int>(glyphArray);

      // Calculate new size of glyph table.
      int size = 0;
      for (int idx = 0; idx < glyphCount; idx++)
        size += this.glyf.GetGlyphSize(glyphArray[idx]);
      glyf.DirectoryEntry.Length = size;

      // Create new loca table
      int numGlyphs = this.maxp.numGlyphs;
      loca.locaTable = new int[numGlyphs + 1];

      // Create new glyf table
      glyf.glyphTable = new byte[glyf.DirectoryEntry.PaddedLength];

      // Fill new glyf and loca table
      int glyphOffset = 0;
      int glyphIndex = 0;
      for (int idx = 0; idx < numGlyphs; idx++)
      {
        loca.locaTable[idx] = glyphOffset;
        if (glyphIndex < glyphCount && glyphArray[glyphIndex] == idx)
        {
          glyphIndex++;
          byte[] bytes = this.glyf.GetGlyphData(idx);
          int length = bytes.Length;
          if (length > 0)
          {
            Buffer.BlockCopy(bytes, 0, glyf.glyphTable, glyphOffset, length);
            glyphOffset += length;
          }
        }
      }
      loca.locaTable[numGlyphs] = glyphOffset;

      // Compile font tables into byte array
      fontImage.Compile();

      return fontImage;
    }
Esempio n. 3
0
    /// <summary>
    /// Reads all required table from the font prgram.
    /// </summary>
    internal void Read()
    {
      try
      {
        // Read offset table
        this.offsetTable.Version = ReadULong();
        this.offsetTable.TableCount = ReadUShort();
        this.offsetTable.SearchRange = ReadUShort();
        this.offsetTable.EntrySelector = ReadUShort();
        this.offsetTable.RangeShift = ReadUShort();

        // Move to table dictionary at position 12
        Debug.Assert(this.pos == 12);
        //this.tableDictionary = (this.offsetTable.TableCount);
        for (int idx = 0; idx < this.offsetTable.TableCount; idx++)
        {
          TableDirectoryEntry entry = TableDirectoryEntry.ReadFrom(this);
          this.tableDictionary.Add(entry.Tag, entry);
#if VERBOSE
          Debug.WriteLine(String.Format("Font table: {0}", entry.Tag));
#endif
        }

        // PDFlib checks this, but it is not part of the OpenType spec anymore
        if (this.tableDictionary.ContainsKey("bhed"))
          throw new NotSupportedException("Bitmap fonts are not supported by PDFsharp.");

        // Read required tables
        if (Seek(CMapTable.Tag) != -1)
          this.cmap = new CMapTable(this);

        if (Seek(ControlValueTable.Tag) != -1)
          this.cvt = new ControlValueTable(this);

        if (Seek(FontProgram.Tag) != -1)
          this.fpgm = new FontProgram(this);

        if (Seek(MaximumProfileTable.Tag) != -1)
          this.maxp = new MaximumProfileTable(this);

        if (Seek(NameTable.Tag) != -1)
          this.name = new NameTable(this);

        if (Seek(FontHeaderTable.Tag) != -1)
          this.head = new FontHeaderTable(this);

        if (Seek(HorizontalHeaderTable.Tag) != -1)
          this.hhea = new HorizontalHeaderTable(this);

        if (Seek(HorizontalMetricsTable.Tag) != -1)
          this.hmtx = new HorizontalMetricsTable(this);

        if (Seek(OS2Table.Tag) != -1)
          this.os2 = new OS2Table(this);

        if (Seek(PostScriptTable.Tag) != -1)
          this.post = new PostScriptTable(this);

        if (Seek(GlyphDataTable.Tag) != -1)
          this.glyf = new GlyphDataTable(this);

        if (Seek(IndexToLocationTable.Tag) != -1)
          this.loca = new IndexToLocationTable(this);

        if (Seek(GlyphSubstitutionTable.Tag) != -1)
          this.gsub = new GlyphSubstitutionTable(this);

        if (Seek(ControlValueProgram.Tag) != -1)
          this.prep = new ControlValueProgram(this);
      }
      catch (Exception ex)
      {
        throw ex;
      }
    }
Esempio n. 4
0
    /// <summary>
    /// Adds the specified table to this font image.
    /// </summary>
    public void AddTable(TrueTypeFontTable fontTable)
    {
      if (!CanWrite)
        throw new InvalidOperationException("Font image cannot be modified.");

      if (fontTable == null)
        throw new ArgumentNullException("fontTable");

      if (fontTable.FontImage == null)
      {
        fontTable.fontImage = this;
      }
      else
      {
        Debug.Assert(fontTable.FontImage.CanRead);
        // Create a reference to this font table
        fontTable = new IRefFontTable(this, fontTable);
      }

      //Debug.Assert(fontTable.FontImage == null);
      //fontTable.fontImage = this;

      this.tableDictionary[fontTable.DirectoryEntry.Tag] = fontTable.DirectoryEntry;
      switch (fontTable.DirectoryEntry.Tag)
      {
        case TableTagNames.CMap:
          this.cmap = fontTable as CMapTable;
          break;

        case TableTagNames.Cvt:
          this.cvt = fontTable as ControlValueTable;
          break;

        case TableTagNames.Fpgm:
          this.fpgm = fontTable as FontProgram;
          break;

        case TableTagNames.MaxP:
          this.maxp = fontTable as MaximumProfileTable;
          break;

        case TableTagNames.Name:
          this.name = fontTable as NameTable;
          break;

        case TableTagNames.Head:
          this.head = fontTable as FontHeaderTable;
          break;

        case TableTagNames.HHea:
          this.hhea = fontTable as HorizontalHeaderTable;
          break;

        case TableTagNames.HMtx:
          this.hmtx = fontTable as HorizontalMetricsTable;
          break;

        case TableTagNames.OS2:
          this.os2 = fontTable as OS2Table;
          break;

        case TableTagNames.Post:
          this.post = fontTable as PostScriptTable;
          break;

        case TableTagNames.Glyf:
          this.glyf = fontTable as GlyphDataTable;
          break;

        case TableTagNames.Loca:
          this.loca = fontTable as IndexToLocationTable;
          break;

        case TableTagNames.GSUB:
          this.gsub = fontTable as GlyphSubstitutionTable;
          break;

        case TableTagNames.Prep:
          this.prep = fontTable as ControlValueProgram;
          break;
      }
    }
Esempio n. 5
0
        /// <summary>
        /// Creates a new font image that is a subset of this font image containing only the specified glyphs.
        /// </summary>
        public FontData CreateFontSubSet(Dictionary <int, object> glyphs, bool cidFont)
        {
            // Create new font image
            FontData fontData = new FontData(this);

            // Create new loca and glyf table
            IndexToLocationTable loca = new IndexToLocationTable();

            loca.ShortIndex = this.loca.ShortIndex;
            GlyphDataTable glyf = new GlyphDataTable();

            // Add all required tables
            //fontData.AddTable(this.os2);
            if (!cidFont)
            {
                fontData.AddTable(this.cmap);
            }
            if (this.cvt != null)
            {
                fontData.AddTable(this.cvt);
            }
            if (this.fpgm != null)
            {
                fontData.AddTable(this.fpgm);
            }
            fontData.AddTable(glyf);
            fontData.AddTable(this.head);
            fontData.AddTable(this.hhea);
            fontData.AddTable(this.hmtx);
            fontData.AddTable(loca);
            if (this.maxp != null)
            {
                fontData.AddTable(this.maxp);
            }
            //fontData.AddTable(this.name);
            if (this.prep != null)
            {
                fontData.AddTable(this.prep);
            }

            // Get closure of used glyphs
            this.glyf.CompleteGlyphClosure(glyphs);

            // Create a sorted array of all used glyphs
            int glyphCount = glyphs.Count;

            int[] glyphArray = new int[glyphCount];
            glyphs.Keys.CopyTo(glyphArray, 0);
            Array.Sort <int>(glyphArray);

            // Calculate new size of glyph table.
            int size = 0;

            for (int idx = 0; idx < glyphCount; idx++)
            {
                size += this.glyf.GetGlyphSize(glyphArray[idx]);
            }
            glyf.DirectoryEntry.Length = size;

            // Create new loca table
            int numGlyphs = this.maxp.numGlyphs;

            loca.locaTable = new int[numGlyphs + 1];

            // Create new glyf table
            glyf.glyphTable = new byte[glyf.DirectoryEntry.PaddedLength];

            // Fill new glyf and loca table
            int glyphOffset = 0;
            int glyphIndex  = 0;

            for (int idx = 0; idx < numGlyphs; idx++)
            {
                loca.locaTable[idx] = glyphOffset;
                if (glyphIndex < glyphCount && glyphArray[glyphIndex] == idx)
                {
                    glyphIndex++;
                    byte[] bytes  = this.glyf.GetGlyphData(idx);
                    int    length = bytes.Length;
                    if (length > 0)
                    {
                        Buffer.BlockCopy(bytes, 0, glyf.glyphTable, glyphOffset, length);
                        glyphOffset += length;
                    }
                }
            }
            loca.locaTable[numGlyphs] = glyphOffset;

            // Compile font tables into byte array
            fontData.Compile();

            return(fontData);
        }
Esempio n. 6
0
        /// <summary>
        /// Reads all required tables from the font data.
        /// </summary>
        internal void Read()
        {
            try
            {
                // Read offset table
                this.offsetTable.Version       = ReadULong();
                this.offsetTable.TableCount    = ReadUShort();
                this.offsetTable.SearchRange   = ReadUShort();
                this.offsetTable.EntrySelector = ReadUShort();
                this.offsetTable.RangeShift    = ReadUShort();

                // Move to table dictionary at position 12
                Debug.Assert(this.pos == 12);
                //this.tableDictionary = (this.offsetTable.TableCount);
                for (int idx = 0; idx < this.offsetTable.TableCount; idx++)
                {
                    TableDirectoryEntry entry = TableDirectoryEntry.ReadFrom(this);
                    this.tableDictionary.Add(entry.Tag, entry);
#if VERBOSE
                    Debug.WriteLine(String.Format("Font table: {0}", entry.Tag));
#endif
                }

                // PDFlib checks this, but it is not part of the OpenType spec anymore
                if (this.tableDictionary.ContainsKey("bhed"))
                {
                    throw new NotSupportedException("Bitmap fonts are not supported by PDFsharp.");
                }

                // Read required tables
                if (Seek(CMapTable.Tag) != -1)
                {
                    this.cmap = new CMapTable(this);
                }

                if (Seek(ControlValueTable.Tag) != -1)
                {
                    this.cvt = new ControlValueTable(this);
                }

                if (Seek(FontProgram.Tag) != -1)
                {
                    this.fpgm = new FontProgram(this);
                }

                if (Seek(MaximumProfileTable.Tag) != -1)
                {
                    this.maxp = new MaximumProfileTable(this);
                }

                if (Seek(NameTable.Tag) != -1)
                {
                    this.name = new NameTable(this);
                }

                if (Seek(FontHeaderTable.Tag) != -1)
                {
                    this.head = new FontHeaderTable(this);
                }

                if (Seek(HorizontalHeaderTable.Tag) != -1)
                {
                    this.hhea = new HorizontalHeaderTable(this);
                }

                if (Seek(HorizontalMetricsTable.Tag) != -1)
                {
                    this.hmtx = new HorizontalMetricsTable(this);
                }

                if (Seek(OS2Table.Tag) != -1)
                {
                    this.os2 = new OS2Table(this);
                }

                if (Seek(PostScriptTable.Tag) != -1)
                {
                    this.post = new PostScriptTable(this);
                }

                if (Seek(GlyphDataTable.Tag) != -1)
                {
                    this.glyf = new GlyphDataTable(this);
                }

                if (Seek(IndexToLocationTable.Tag) != -1)
                {
                    this.loca = new IndexToLocationTable(this);
                }

                if (Seek(GlyphSubstitutionTable.Tag) != -1)
                {
                    this.gsub = new GlyphSubstitutionTable(this);
                }

                if (Seek(ControlValueProgram.Tag) != -1)
                {
                    this.prep = new ControlValueProgram(this);
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
Esempio n. 7
0
        /// <summary>
        /// Adds the specified table to this font image.
        /// </summary>
        public void AddTable(TrueTypeFontTable fontTable)
        {
            if (!CanWrite)
            {
                throw new InvalidOperationException("Font image cannot be modified.");
            }

            if (fontTable == null)
            {
                throw new ArgumentNullException("fontTable");
            }

            if (fontTable.fontData == null)
            {
                fontTable.fontData = this;
            }
            else
            {
                Debug.Assert(fontTable.fontData.CanRead);
                // Create a reference to this font table
                fontTable = new IRefFontTable(this, fontTable);
            }

            //Debug.Assert(fontTable.FontData == null);
            //fontTable.fontData = this;

            this.tableDictionary[fontTable.DirectoryEntry.Tag] = fontTable.DirectoryEntry;
            switch (fontTable.DirectoryEntry.Tag)
            {
            case TableTagNames.CMap:
                this.cmap = fontTable as CMapTable;
                break;

            case TableTagNames.Cvt:
                this.cvt = fontTable as ControlValueTable;
                break;

            case TableTagNames.Fpgm:
                this.fpgm = fontTable as FontProgram;
                break;

            case TableTagNames.MaxP:
                this.maxp = fontTable as MaximumProfileTable;
                break;

            case TableTagNames.Name:
                this.name = fontTable as NameTable;
                break;

            case TableTagNames.Head:
                this.head = fontTable as FontHeaderTable;
                break;

            case TableTagNames.HHea:
                this.hhea = fontTable as HorizontalHeaderTable;
                break;

            case TableTagNames.HMtx:
                this.hmtx = fontTable as HorizontalMetricsTable;
                break;

            case TableTagNames.OS2:
                this.os2 = fontTable as OS2Table;
                break;

            case TableTagNames.Post:
                this.post = fontTable as PostScriptTable;
                break;

            case TableTagNames.Glyf:
                this.glyf = fontTable as GlyphDataTable;
                break;

            case TableTagNames.Loca:
                this.loca = fontTable as IndexToLocationTable;
                break;

            case TableTagNames.GSUB:
                this.gsub = fontTable as GlyphSubstitutionTable;
                break;

            case TableTagNames.Prep:
                this.prep = fontTable as ControlValueProgram;
                break;
            }
        }
Esempio n. 8
0
        /// <summary>
        /// Gets the size of the byte array that defines the glyph.
        /// </summary>
        public int GetGlyphSize(int glyph)
        {
            IndexToLocationTable loca = this.fontData.loca;

            return(GetOffset(glyph + 1) - GetOffset(glyph));
        }