public DocumentTtfSubsetFont(string FullPath) : base(FullPath)
        {
            IsEmbedded = true;
            isUnicode  = true;

            GlyphToChar firstChar = new GlyphToChar {
                character  = 0,
                oldGlyphId = 0,
                newGlyphId = 0
            };

            lstGlyphToChar.Add(firstChar);
            dctCharToGlyphOldNew.Add(0, firstChar);
            dctNewGlyphIdToGlyphOldNew.Add(0, firstChar);

            this.Flags = FontTypes.Symbolic;
            this.Name  = guid + "+" + Name;
        }
        public override string SetText(string text)
        {
            foreach (char ch in text)
            {
                // si ya existe este caracter, no hago nada
                if (hashChar.Contains(ch))
                {
                    continue;
                }

                // nuevo caracter
                int counter = dctNewGlyphIdToGlyphOldNew.Count;

                // este caracter, con este antiguo glyph, tendrá uno nuevo
                GlyphToChar glyphConversion = new GlyphToChar {
                    character  = ch,
                    oldGlyphId = dctCharCodeToGlyphID[ch],
                    newGlyphId = counter
                };

                lstGlyphToChar.Add(glyphConversion);

                dctCharToGlyphOldNew.Add(ch, glyphConversion);
                dctNewGlyphIdToGlyphOldNew.Add(counter, glyphConversion);

                AddNewChar(ch);
            }

            var sb = new StringBuilder();

            foreach (char c in text)
            {
                sb.Append((char)GetGlyphId(c));
            }

            return(sb.ToString());
        }
        private byte[] Subset(byte[] font)
        {
            // regular: 1 char is 1 glyph
            // composite: 1 char is 1 glyph that points to many glyphs
            int glyphToCharIndex = 0;

            while (glyphToCharIndex < lstGlyphToChar.Count)
            {
                GlyphToChar glyphChar = lstGlyphToChar[glyphToCharIndex];
                glyphToCharIndex++;

                // obtengo el glyph en sí
                glyphChar.bytes = new byte[Glypth[glyphChar.oldGlyphId].lengthFile];
                Array.Copy(font, Glypth[glyphChar.oldGlyphId].offsetFile,   // source
                           glyphChar.bytes, 0,                              // destination
                           Glypth[glyphChar.oldGlyphId].lengthFile);        // length

                int fontOffset       = Glypth[glyphChar.oldGlyphId].offsetFile;
                int endPtsOfContours = GetUInt16(font, ref fontOffset);
                if (endPtsOfContours >= 0)   // If numberOfContours is negative, a composite glyph description is used.
                {
                    continue;
                }
                fontOffset += 8;

                while (true)
                {
                    int flags = GetUInt16(font, ref fontOffset);        // component flag

                    int glyphIndexOffset = fontOffset;
                    int glyphIndex       = GetUInt16(font, ref fontOffset); // glyph index of component

                    // nuevo caracter
                    int counter = dctNewGlyphIdToGlyphOldNew.Count;

                    // este caracter, con este antiguo glyph, tendrá uno nuevo
                    GlyphToChar compositeGlyph = new GlyphToChar {
                        character  = null,
                        oldGlyphId = glyphIndex,
                        newGlyphId = counter
                    };

                    lstGlyphToChar.Add(compositeGlyph);
                    dctNewGlyphIdToGlyphOldNew.Add(counter, compositeGlyph);

                    // se escribe en este glyph, donde referencia a glyphIndex el newGlyph
                    SetUInt16(glyphChar.bytes, glyphIndexOffset - Glypth[glyphChar.oldGlyphId].offsetFile, counter);

                    if ((flags & MORE_COMPONENTS) == 0)
                    {
                        break;
                    }

                    if ((flags & ARG_1_AND_2_ARE_WORDS) == 0)
                    {
                        fontOffset += 2;
                    }
                    else
                    {
                        fontOffset += 4;
                    }

                    if ((flags & WE_HAVE_A_SCALE) == WE_HAVE_A_SCALE)
                    {
                        fontOffset += 2;
                    }
                    else if ((flags & WE_HAVE_AN_X_AND_Y_SCALE) == WE_HAVE_AN_X_AND_Y_SCALE)
                    {
                        fontOffset += 4;
                    }
                    else if ((flags & WE_HAVE_A_TWO_BY_TWO) == WE_HAVE_A_TWO_BY_TWO)
                    {
                        fontOffset += 8;
                    }
                }
            }

            Dictionary <string, TtfTable> dctTablesUsed = new Dictionary <string, TtfTable>();

            // de todas las tablas cargadas, sólo grabaremos las que PDF necesita
            foreach (string table in tablesNames)
            {
                if (dctTables.ContainsKey(table))
                {
                    dctTablesUsed.Add(table, dctTables[table]);
                }
            }

            int tableOffset = 16 * dctTablesUsed.Count + 12;

            byte[]     hhea = SetHhea(font, dctTablesUsed);
            byte[]     maxp = SetMaxp(font, dctTablesUsed);
            byte[]     hmtx = SetHmtx();
            byte[]     cmap = SetCmap();
            List <int> glyphOffset;

            byte[] glyph = SetGlyph(out glyphOffset);

            if (glyph.Length < 128000)
            {
                indexToLocFormat = 0;   // 0 for short offsets
            }
            else
            {
                indexToLocFormat = 1;   // 1 for long
            }

            byte[] head = SetHead(font);
            byte[] loca = SetLoca(glyphOffset, head);

            int fontSubsetSize = 0;

            fontSubsetSize += 12;                       // initial header
            fontSubsetSize += 16 * dctTablesUsed.Count; // initial header pointers
            // de las tablas que vamos a grabar
            foreach (KeyValuePair <string, TtfTable> kvp in dctTablesUsed)
            {
                switch (kvp.Key)
                {
                case "hhea":
                    fontSubsetSize += Get4bytePadding(hhea.Length);
                    break;

                case "maxp":
                    fontSubsetSize += Get4bytePadding(maxp.Length);
                    break;

                case "hmtx":
                    fontSubsetSize += Get4bytePadding(hmtx.Length);
                    break;

                case "cmap":
                    fontSubsetSize += Get4bytePadding(cmap.Length);
                    break;

                case "glyf":
                    fontSubsetSize += Get4bytePadding(glyph.Length);
                    break;

                case "loca":
                    fontSubsetSize += Get4bytePadding(loca.Length);
                    break;

                case "head":
                    fontSubsetSize += head.Length;
                    break;

                default:
                    fontSubsetSize += Get4bytePadding(dctTables[kvp.Key].length);
                    break;
                }
            }

            byte[] fontSubset    = new byte[Get4bytePadding(fontSubsetSize)];
            int    fontSubsetPos = 0;

            // -- Header --
            fontSubsetPos = SetUInt32(fontSubset, fontSubsetPos, 0x00010000);
            fontSubsetPos = SetUInt16(fontSubset, fontSubsetPos, dctTablesUsed.Count);

            CalculateBinarySearchRegisters(dctTablesUsed.Count, 16, 4, out int entrySelector, out int searchRange, out int rangeShift);

            fontSubsetPos = SetUInt16(fontSubset, fontSubsetPos, searchRange);
            fontSubsetPos = SetUInt16(fontSubset, fontSubsetPos, entrySelector);
            fontSubsetPos = SetUInt16(fontSubset, fontSubsetPos, rangeShift);

            foreach (KeyValuePair <string, TtfTable> kvp in dctTablesUsed)
            {
                fontSubsetPos = SetString(fontSubset, fontSubsetPos, kvp.Key);
                switch (kvp.Key)
                {
                case "hhea":
                    fontSubsetPos = WriteHeader(fontSubset, fontSubsetPos, hhea, ref tableOffset);
                    break;

                case "maxp":
                    fontSubsetPos = WriteHeader(fontSubset, fontSubsetPos, maxp, ref tableOffset);
                    break;

                case "hmtx":
                    fontSubsetPos = WriteHeader(fontSubset, fontSubsetPos, hmtx, ref tableOffset);
                    break;

                case "cmap":
                    fontSubsetPos = WriteHeader(fontSubset, fontSubsetPos, cmap, ref tableOffset);
                    break;

                case "glyf":
                    fontSubsetPos = WriteHeader(fontSubset, fontSubsetPos, glyph, ref tableOffset);
                    break;

                case "loca":
                    fontSubsetPos = WriteHeader(fontSubset, fontSubsetPos, loca, ref tableOffset);
                    break;

                case "head":
                    fontSubsetPos = WriteHeader(fontSubset, fontSubsetPos, head, ref tableOffset);
                    break;

                default:
                    fontSubsetPos = SetUInt32(fontSubset, fontSubsetPos, kvp.Value.checksum);
                    fontSubsetPos = SetUInt32(fontSubset, fontSubsetPos, tableOffset);
                    fontSubsetPos = SetUInt32(fontSubset, fontSubsetPos, kvp.Value.length);

                    tableOffset += Get4bytePadding(kvp.Value.length);
                    break;
                }
            }

            // -- Tables --
            int checkSumAdjustmentOffset = 0;

            foreach (KeyValuePair <string, TtfTable> kvp in dctTablesUsed)
            {
                switch (kvp.Key)
                {
                case "hhea":
                    Array.Copy(hhea, 0, fontSubset, fontSubsetPos, hhea.Length);
                    fontSubsetPos += Get4bytePadding(hhea.Length);
                    break;

                case "maxp":
                    Array.Copy(maxp, 0, fontSubset, fontSubsetPos, maxp.Length);
                    fontSubsetPos += Get4bytePadding(maxp.Length);
                    break;

                case "hmtx":
                    Array.Copy(hmtx, 0, fontSubset, fontSubsetPos, hmtx.Length);
                    fontSubsetPos += Get4bytePadding(hmtx.Length);
                    break;

                case "cmap":
                    Array.Copy(cmap, 0, fontSubset, fontSubsetPos, cmap.Length);
                    fontSubsetPos += Get4bytePadding(cmap.Length);
                    break;

                case "glyf":
                    Array.Copy(glyph, 0, fontSubset, fontSubsetPos, glyph.Length);
                    fontSubsetPos += Get4bytePadding(glyph.Length);
                    break;

                case "loca":
                    Array.Copy(loca, 0, fontSubset, fontSubsetPos, loca.Length);
                    fontSubsetPos += Get4bytePadding(loca.Length);
                    break;

                case "head":
                    checkSumAdjustmentOffset = fontSubsetPos + 8;
                    Array.Copy(head, 0, fontSubset, fontSubsetPos, head.Length);
                    fontSubsetPos += Get4bytePadding(head.Length);
                    break;

                default:
                    Array.Copy(font, kvp.Value.offset, fontSubset, fontSubsetPos, kvp.Value.length);
                    fontSubsetPos += Get4bytePadding(kvp.Value.length);
                    break;
                }
            }

            SetUInt32(fontSubset, checkSumAdjustmentOffset, (int)CalculateFileChecksum(fontSubset));  // checkSumAdjustment

            return(fontSubset);
        }