Example #1
0
        private InlineImage ParseInlineImage(
            )
        {
            /*
             * NOTE: Inline images use a peculiar syntax that's an exception to the usual rule
             * that the data in a content stream is interpreted according to the standard PDF syntax
             * for objects.
             */
            InlineImageHeader header;
            {
                List <PdfDirectObject> operands = new List <PdfDirectObject>();
                // Parsing the image entries...
                while (MoveNext() &&
                       tokenType != TokenTypeEnum.Keyword) // Not keyword (i.e. end at image data beginning (ID operator)).
                {
                    operands.Add(ParsePdfObject());
                }
                header = new InlineImageHeader(operands);
            }

            InlineImageBody body;

            {
                MoveNext();
                bytes::Buffer data = new bytes::Buffer();
                byte          c1 = 0, c2 = 0;
                do
                {
                    try
                    {
                        while (true)
                        {
                            c1 = (byte)stream.ReadByte();
                            c2 = (byte)stream.ReadByte();
                            if (c1 == 'E' && c2 == 'I')
                            {
                                break;
                            }

                            data.Append(c1);
                            data.Append(c2);
                        }
                        break;
                    }
                    catch
                    {
                        /* NOTE: Current stream has finished. */
                        // Move to the next stream!
                        MoveNextStream();
                    }
                } while(stream != null);
                body = new InlineImageBody(data);
            }

            return(new InlineImage(
                       header,
                       body
                       ));
        }
Example #2
0
        private InlineImage ParseInlineImage()
        {
            /*
             * NOTE: Inline images use a peculiar syntax that's an exception to the usual rule
             * that the data in a content stream is interpreted according to the standard PDF syntax
             * for objects.
             */
            InlineImageHeader header;
            {
                List <PdfDirectObject> operands = new List <PdfDirectObject>();
                // Parsing the image entries...
                while (MoveNext() && TokenType != TokenTypeEnum.Keyword) // Not keyword (i.e. end at image data beginning (ID operator)).
                {
                    operands.Add((PdfDirectObject)ParsePdfObject());
                }
                header = new InlineImageHeader(operands);
            }

            InlineImageBody body;

            {
                // [FIX:51,74] Wrong 'EI' token handling on inline image parsing.
                bytes::IInputStream stream = Stream;
                stream.ReadByte(); // Should be the whitespace following the 'ID' token.
                bytes::Buffer data = new bytes::Buffer();
                while (true)
                {
                    int curByte1 = stream.ReadByte();
                    if (curByte1 == -1)
                    {
                        break;
                    }
                    int curByte2 = stream.ReadByte();
                    if (curByte2 == -1)
                    {
                        break;
                    }

                    if (((char)curByte1 == 'E' && (char)curByte2 == 'I'))
                    {
                        break;
                    }
                    if (((char)curByte1 == ' ' && (char)curByte2 == 'E'))
                    {
                        break;
                    }
                    data.Append((byte)curByte1);
                    data.Append((byte)curByte2);
                }
                body = new InlineImageBody(data);
            }

            return(new InlineImage(header, body));
        }
Example #3
0
        private InlineImage ParseInlineImage(
            )
        {
            /*
             * NOTE: Inline images use a peculiar syntax that's an exception to the usual rule
             * that the data in a content stream is interpreted according to the standard PDF syntax
             * for objects.
             */
            InlineImageHeader header;
            {
                List <PdfDirectObject> operands = new List <PdfDirectObject>();
                // Parsing the image entries...
                while (MoveNext() &&
                       TokenType != TokenTypeEnum.Keyword) // Not keyword (i.e. end at image data beginning (ID operator)).
                {
                    operands.Add((PdfDirectObject)ParsePdfObject());
                }
                header = new InlineImageHeader(operands);
            }

            InlineImageBody body;

            {
                bytes::IInputStream stream = Stream;
                MoveNext();
                bytes::Buffer data     = new bytes::Buffer();
                byte          prevByte = 0;
                while (true)
                {
                    byte curByte = (byte)stream.ReadByte();
                    if (prevByte == 'E' && curByte == 'I')
                    {
                        break;
                    }

                    data.Append(prevByte = curByte);
                }
                body = new InlineImageBody(data);
            }

            return(new InlineImage(
                       header,
                       body
                       ));
        }
Example #4
0
        private InlineImage ParseInlineImage(
      )
        {
            /*
            NOTE: Inline images use a peculiar syntax that's an exception to the usual rule
            that the data in a content stream is interpreted according to the standard PDF syntax
            for objects.
              */
              InlineImageHeader header;
              {
            List<PdfDirectObject> operands = new List<PdfDirectObject>();
            // Parsing the image entries...
            while(MoveNext()
              && TokenType != TokenTypeEnum.Keyword) // Not keyword (i.e. end at image data beginning (ID operator)).
            {operands.Add((PdfDirectObject)ParsePdfObject());}
            header = new InlineImageHeader(operands);
              }

              InlineImageBody body;
              {
            bytes::IInputStream stream = Stream;
            MoveNext();
            bytes::Buffer data = new bytes::Buffer();
            while(true)
            {
              byte c1 = (byte)stream.ReadByte();
              byte c2 = (byte)stream.ReadByte();
              if(c1 == 'E' && c2 == 'I')
            break;

              data.Append(c1);
              data.Append(c2);
            }
            body = new InlineImageBody(data);
              }

              return new InlineImage(
            header,
            body
            );
        }
Example #5
0
        private void RefreshAppearance(
      )
        {
            Widget widget = Widgets[0];
              FormXObject normalAppearance;
              {
            AppearanceStates normalAppearances = widget.Appearance.Normal;
            normalAppearance = normalAppearances[null];
            if(normalAppearance == null)
            {normalAppearances[null] = normalAppearance = new FormXObject(Document, widget.Box.Size);}
              }
              PdfName fontName = null;
              double fontSize = 0;
              {
            PdfString defaultAppearanceState = DefaultAppearanceState;
            if(defaultAppearanceState == null)
            {
              // Retrieving the font to define the default appearance...
              fonts::Font defaultFont = null;
              PdfName defaultFontName = null;
              {
            // Field fonts.
            FontResources normalAppearanceFonts = normalAppearance.Resources.Fonts;
            foreach(KeyValuePair<PdfName,fonts::Font> entry in normalAppearanceFonts)
            {
              if(!entry.Value.Symbolic)
              {
                defaultFont = entry.Value;
                defaultFontName = entry.Key;
                break;
              }
            }
            if(defaultFontName == null)
            {
              // Common fonts.
              FontResources formFonts = Document.Form.Resources.Fonts;
              foreach(KeyValuePair<PdfName,fonts::Font> entry in formFonts)
              {
                if(!entry.Value.Symbolic)
                {
                  defaultFont = entry.Value;
                  defaultFontName = entry.Key;
                  break;
                }
              }
              if(defaultFontName == null)
              {
                //TODO:manage name collision!
                formFonts[
                  defaultFontName = new PdfName("default")
                  ] = defaultFont = new fonts::StandardType1Font(
                    Document,
                    fonts::StandardType1Font.FamilyEnum.Helvetica,
                    false,
                    false
                    );
              }
              normalAppearanceFonts[defaultFontName] = defaultFont;
            }
              }
              bytes::Buffer buffer = new bytes::Buffer();
              new SetFont(defaultFontName, IsMultiline ? 10 : 0).WriteTo(buffer, Document);
              widget.BaseDataObject[PdfName.DA] = defaultAppearanceState = new PdfString(buffer.ToByteArray());
            }

            // Retrieving the font to use...
            ContentParser parser = new ContentParser(defaultAppearanceState.ToByteArray());
            foreach(ContentObject content in parser.ParseContentObjects())
            {
              if(content is SetFont)
              {
            SetFont setFontOperation = (SetFont)content;
            fontName = setFontOperation.Name;
            fontSize = setFontOperation.Size;
            break;
              }
            }
            normalAppearance.Resources.Fonts[fontName] = Document.Form.Resources.Fonts[fontName];
              }

              // Refreshing the field appearance...
              /*
               * TODO: resources MUST be resolved both through the apperance stream resource dictionary and
               * from the DR-entry acroform resource dictionary
               */
              PrimitiveComposer baseComposer = new PrimitiveComposer(normalAppearance);
              BlockComposer composer = new BlockComposer(baseComposer);
              ContentScanner currentLevel = composer.Scanner;
              bool textShown = false;
              while(currentLevel != null)
              {
            if(!currentLevel.MoveNext())
            {
              currentLevel = currentLevel.ParentLevel;
              continue;
            }

            ContentObject content = currentLevel.Current;
            if(content is MarkedContent)
            {
              MarkedContent markedContent = (MarkedContent)content;
              if(PdfName.Tx.Equals(((BeginMarkedContent)markedContent.Header).Tag))
              {
            // Remove old text representation!
            markedContent.Objects.Clear();
            // Add new text representation!
            baseComposer.Scanner = currentLevel.ChildLevel; // Ensures the composer places new contents within the marked content block.
            ShowText(composer, fontName, fontSize);
            textShown = true;
              }
            }
            else if(content is Text)
            {currentLevel.Remove();}
            else if(currentLevel.ChildLevel != null)
            {currentLevel = currentLevel.ChildLevel;}
              }
              if(!textShown)
              {
            baseComposer.BeginMarkedContent(PdfName.Tx);
            ShowText(composer, fontName, fontSize);
            baseComposer.End();
              }
              baseComposer.Flush();
        }
Example #6
0
        private InlineImage ParseInlineImage(
            )
        {
            /*
             * NOTE: Inline images use a peculiar syntax that's an exception to the usual rule
             * that the data in a content stream is interpreted according to the standard PDF syntax
             * for objects.
             */
            InlineImageHeader header;
            {
                List <PdfDirectObject> operands = new List <PdfDirectObject>();
                // Parsing the image entries...
                while (MoveNext() &&
                       TokenType != TokenTypeEnum.Keyword) // Not keyword (i.e. end at image data beginning (ID operator)).
                {
                    operands.Add((PdfDirectObject)ParsePdfObject());
                }
                header = new InlineImageHeader(operands);
            }

            InlineImageBody body;

            {
                // [FIX:51,74] Wrong 'EI' token handling on inline image parsing.
                bytes::IInputStream stream = Stream;
                stream.ReadByte(); // Should be the whitespace following the 'ID' token.
                bytes::Buffer data           = new bytes::Buffer();
                var           endChunkBuffer = new sysIO::MemoryStream(3);
                int           endChunkIndex  = -1;
                while (true)
                {
                    int curByte = stream.ReadByte();
                    if (curByte == -1)
                    {
                        throw new PostScriptParseException("No 'EI' token found to close inline image data stream.");
                    }

                    if (endChunkIndex == -1)
                    {
                        if (IsWhitespace(curByte))
                        {
                            /*
                             * NOTE: Whitespace characters may announce the beginning of the end image operator.
                             */
                            endChunkBuffer.WriteByte((byte)curByte);
                            endChunkIndex++;
                        }
                        else
                        {
                            data.Append((byte)curByte);
                        }
                    }
                    else if (endChunkIndex == 0 && IsWhitespace(curByte))
                    {
                        /*
                         * NOTE: Only the last whitespace character may announce the beginning of the end image
                         * operator.
                         */
                        data.Append(endChunkBuffer.ToArray());
                        endChunkBuffer.SetLength(0);
                        endChunkBuffer.WriteByte((byte)curByte);
                    }
                    else if ((endChunkIndex == 0 && curByte == 'E') ||
                             (endChunkIndex == 1 && curByte == 'I'))
                    {
                        /*
                         * NOTE: End image operator characters.
                         */
                        endChunkBuffer.WriteByte((byte)curByte);
                        endChunkIndex++;
                    }
                    else if (endChunkIndex == 2 && IsWhitespace(curByte))
                    {
                        /*
                         * NOTE: The whitespace character after the end image operator completes the pattern.
                         */
                        break;
                    }
                    else
                    {
                        if (endChunkIndex > -1)
                        {
                            data.Append(endChunkBuffer.ToArray());
                            endChunkBuffer.SetLength(0);
                            endChunkIndex = -1;
                        }
                        data.Append((byte)curByte);
                    }
                }
                body = new InlineImageBody(data);
            }

            return(new InlineImage(
                       header,
                       body
                       ));
        }
        private void RefreshAppearance(
            )
        {
            Widget      widget = Widgets[0];
            FormXObject normalAppearance;
            {
                AppearanceStates normalAppearances = widget.Appearance.Normal;
                normalAppearance = normalAppearances[null];
                if (normalAppearance == null)
                {
                    normalAppearances[null] = normalAppearance = new FormXObject(Document, widget.Box.Size);
                }
            }
            PdfName fontName = null;
            double  fontSize = 0;
            {
                PdfString defaultAppearanceState = DefaultAppearanceState;
                if (defaultAppearanceState == null)
                {
                    // Retrieving the font to define the default appearance...
                    fonts::Font defaultFont     = null;
                    PdfName     defaultFontName = null;
                    {
                        // Field fonts.
                        FontResources normalAppearanceFonts = normalAppearance.Resources.Fonts;
                        foreach (KeyValuePair <PdfName, fonts::Font> entry in normalAppearanceFonts)
                        {
                            if (!entry.Value.Symbolic)
                            {
                                defaultFont     = entry.Value;
                                defaultFontName = entry.Key;
                                break;
                            }
                        }
                        if (defaultFontName == null)
                        {
                            // Common fonts.
                            FontResources formFonts = Document.Form.Resources.Fonts;
                            foreach (KeyValuePair <PdfName, fonts::Font> entry in formFonts)
                            {
                                if (!entry.Value.Symbolic)
                                {
                                    defaultFont     = entry.Value;
                                    defaultFontName = entry.Key;
                                    break;
                                }
                            }
                            if (defaultFontName == null)
                            {
                                //TODO:manage name collision!
                                formFonts[
                                    defaultFontName = new PdfName("default")
                                ] = defaultFont = new fonts::StandardType1Font(
                                    Document,
                                    fonts::StandardType1Font.FamilyEnum.Helvetica,
                                    false,
                                    false
                                    );
                            }
                            normalAppearanceFonts[defaultFontName] = defaultFont;
                        }
                    }
                    bytes::Buffer buffer = new bytes::Buffer();
                    new SetFont(defaultFontName, IsMultiline ? 10 : 0).WriteTo(buffer, Document);
                    widget.BaseDataObject[PdfName.DA] = defaultAppearanceState = new PdfString(buffer.ToByteArray());
                }

                // Retrieving the font to use...
                ContentParser parser = new ContentParser(defaultAppearanceState.ToByteArray());
                foreach (ContentObject content in parser.ParseContentObjects())
                {
                    if (content is SetFont)
                    {
                        SetFont setFontOperation = (SetFont)content;
                        fontName = setFontOperation.Name;
                        fontSize = setFontOperation.Size;
                        break;
                    }
                }
                normalAppearance.Resources.Fonts[fontName] = Document.Form.Resources.Fonts[fontName];
            }

            // Refreshing the field appearance...

            /*
             * TODO: resources MUST be resolved both through the apperance stream resource dictionary and
             * from the DR-entry acroform resource dictionary
             */
            PrimitiveComposer baseComposer = new PrimitiveComposer(normalAppearance);
            BlockComposer     composer     = new BlockComposer(baseComposer);
            ContentScanner    currentLevel = composer.Scanner;
            bool textShown = false;

            while (currentLevel != null)
            {
                if (!currentLevel.MoveNext())
                {
                    currentLevel = currentLevel.ParentLevel;
                    continue;
                }

                ContentObject content = currentLevel.Current;
                if (content is MarkedContent)
                {
                    MarkedContent markedContent = (MarkedContent)content;
                    if (PdfName.Tx.Equals(((BeginMarkedContent)markedContent.Header).Tag))
                    {
                        // Remove old text representation!
                        markedContent.Objects.Clear();
                        // Add new text representation!
                        baseComposer.Scanner = currentLevel.ChildLevel; // Ensures the composer places new contents within the marked content block.
                        ShowText(composer, fontName, fontSize);
                        textShown = true;
                    }
                }
                else if (content is Text)
                {
                    currentLevel.Remove();
                }
                else if (currentLevel.ChildLevel != null)
                {
                    currentLevel = currentLevel.ChildLevel;
                }
            }
            if (!textShown)
            {
                baseComposer.BeginMarkedContent(PdfName.Tx);
                ShowText(composer, fontName, fontSize);
                baseComposer.End();
            }
            baseComposer.Flush();
        }
Example #8
0
        /**
         * <summary>Builds a CMap according to the specified arguments.</summary>
         * <param name="entryType"></param>
         * <param name="cmapName">CMap name (<code>null</code> in case no custom name is needed).</param>
         * <param name="codes"></param>
         * <param name="outCodeFunction"></param>
         * <returns>Buffer containing the serialized CMap.</returns>
         */
        public static bytes::IBuffer Build(
            EntryTypeEnum entryType,
            string cmapName,
            SortedDictionary <ByteArray, int> codes,
            GetOutCodeDelegate outCodeFunction
            )
        {
            bytes::IBuffer buffer = new bytes::Buffer();

            // Header.
            string outCodeFormat;

            switch (entryType)
            {
            case EntryTypeEnum.BaseFont:
            {
                if (cmapName == null)
                {
                    cmapName = "Adobe-Identity-UCS";
                }
                buffer.Append(
                    "/CIDInit /ProcSet findresource begin\n"
                    + "12 dict begin\n"
                    + "begincmap\n"
                    + "/CIDSystemInfo\n"
                    + "<< /Registry (Adobe)\n"
                    + "/Ordering (UCS)\n"
                    + "/Supplement 0\n"
                    + ">> def\n"
                    + "/CMapName /").Append(cmapName).Append(" def\n"
                                                             + "/CMapVersion 10.001 def\n"
                                                             + "/CMapType 2 def\n"
                                                             + "1 begincodespacerange\n"
                                                             + "<0000> <FFFF>\n"
                                                             + "endcodespacerange\n"
                                                             );
                outCodeFormat = "<{0:X4}>";
                break;
            }

            case EntryTypeEnum.CID:
            {
                if (cmapName == null)
                {
                    cmapName = "Custom";
                }
                buffer.Append(
                    "%!PS-Adobe-3.0 Resource-CMap\n"
                    + "%%DocumentNeededResources: ProcSet (CIDInit)\n"
                    + "%%IncludeResource: ProcSet (CIDInit)\n"
                    + "%%BeginResource: CMap (").Append(cmapName).Append(")\n"
                                                                         + "%%Title: (").Append(cmapName).Append(" Adobe Identity 0)\n"
                                                                                                                 + "%%Version: 1\n"
                                                                                                                 + "%%EndComments\n"
                                                                                                                 + "/CIDInit /ProcSet findresource begin\n"
                                                                                                                 + "12 dict begin\n"
                                                                                                                 + "begincmap\n"
                                                                                                                 + "/CIDSystemInfo 3 dict dup begin\n"
                                                                                                                 + "/Registry (Adobe) def\n"
                                                                                                                 + "/Ordering (Identity) def\n"
                                                                                                                 + "/Supplement 0 def\n"
                                                                                                                 + "end def\n"
                                                                                                                 + "/CMapVersion 1 def\n"
                                                                                                                 + "/CMapType 1 def\n"
                                                                                                                 + "/CMapName /").Append(cmapName).Append(" def\n"
                                                                                                                                                          + "/WMode 0 def\n"
                                                                                                                                                          + "1 begincodespacerange\n"
                                                                                                                                                          + "<0000> <FFFF>\n"
                                                                                                                                                          + "endcodespacerange\n"
                                                                                                                                                          );
                outCodeFormat = "{0}";
                break;
            }

            default:
                throw new NotImplementedException();
            }

            // Entries.
            {
                IList <KeyValuePair <ByteArray, int> >  cidChars  = new List <KeyValuePair <ByteArray, int> >();
                IList <KeyValuePair <ByteArray, int>[]> cidRanges = new List <KeyValuePair <ByteArray, int>[]>();
                {
                    KeyValuePair <ByteArray, int>?  lastCodeEntry = null;
                    KeyValuePair <ByteArray, int>[] lastCodeRange = null;
                    foreach (KeyValuePair <ByteArray, int> codeEntry in codes)
                    {
                        if (lastCodeEntry.HasValue)
                        {
                            int codeLength = codeEntry.Key.Data.Length;
                            if (codeLength == lastCodeEntry.Value.Key.Data.Length &&
                                codeEntry.Key.Data[codeLength - 1] - lastCodeEntry.Value.Key.Data[codeLength - 1] == 1 &&
                                outCodeFunction(codeEntry) - outCodeFunction(lastCodeEntry.Value) == 1) // Contiguous codes.
                            {
                                if (lastCodeRange == null)
                                {
                                    lastCodeRange = new KeyValuePair <ByteArray, int>[] { lastCodeEntry.Value, default(KeyValuePair <ByteArray, int>) };
                                }
                            }
                            else // Separated codes.
                            {
                                AddEntry(cidRanges, cidChars, lastCodeEntry.Value, lastCodeRange);
                                lastCodeRange = null;
                            }
                        }
                        lastCodeEntry = codeEntry;
                    }
                    AddEntry(cidRanges, cidChars, lastCodeEntry.Value, lastCodeRange);
                }
                // Ranges section.
                BuildEntriesSection(buffer, entryType, cidRanges, BuildRangeEntry, "range", outCodeFunction, outCodeFormat);
                // Chars section.
                BuildEntriesSection(buffer, entryType, cidChars, BuildCharEntry, "char", outCodeFunction, outCodeFormat);
            }

            // Trailer.
            switch (entryType)
            {
            case EntryTypeEnum.BaseFont:
                buffer.Append(
                    "endcmap\n"
                    + "CMapName currentdict /CMap defineresource pop\n"
                    + "end\n"
                    + "end\n"
                    );
                break;

            case EntryTypeEnum.CID:
                buffer.Append(
                    "endcmap\n"
                    + "CMapName currentdict /CMap defineresource pop\n"
                    + "end\n"
                    + "end\n"
                    + "%%EndResource\n"
                    + "%%EOF"
                    );
                break;

            default:
                throw new NotImplementedException();
            }

            return(buffer);
        }
Example #9
0
        /**
          <summary>Creates the character code mapping for composite fonts.</summary>
        */
        private void Load_CreateEncoding(
            PdfDictionary font,
            PdfDictionary cidFont
            )
        {
            // CMap [PDF:1.6:5.6.4].
              bytes::Buffer cmapBuffer = new bytes::Buffer();
              cmapBuffer.Append(
            "%!PS-Adobe-3.0 Resource-CMap\n"
              + "%%DocumentNeededResources: ProcSet (CIDInit)\n"
              + "%%IncludeResource: ProcSet (CIDInit)\n"
              + "%%BeginResource: CMap (Adobe-Identity-UCS)\n"
              + "%%Title: (Adobe-Identity-UCS Adobe Identity 0)\n"
              + "%%Version: 1\n"
              + "%%EndComments\n"
              + "/CIDInit /ProcSet findresource begin\n"
              + "12 dict begin\n"
              + "begincmap\n"
              + "/CIDSystemInfo\n"
              + "3 dict dup begin\n"
              + "/Registry (Adobe) def\n"
              + "/Ordering (Identity) def\n"
              + "/Supplement 0 def\n"
              + "end def\n"
              + "/CMapName /Adobe-Identity-UCS def\n"
              + "/CMapVersion 1 def\n"
              + "/CMapType 0 def\n"
              + "/WMode 0 def\n"
              + "2 begincodespacerange\n"
              + "<20> <20>\n"
              + "<0000> <19FF>\n"
              + "endcodespacerange\n"
              + glyphIndexes.Count + " begincidchar\n"
            );
              // ToUnicode [PDF:1.6:5.9.2].
              bytes::Buffer toUnicodeBuffer = new bytes::Buffer();
              toUnicodeBuffer.Append(
            "/CIDInit /ProcSet findresource begin\n"
              + "12 dict begin\n"
              + "begincmap\n"
              + "/CIDSystemInfo\n"
              + "<< /Registry (Adobe)\n"
              + "/Ordering (UCS)\n"
              + "/Supplement 0\n"
              + ">> def\n"
              + "/CMapName /Adobe-Identity-UCS def\n"
              + "/CMapVersion 10.001 def\n"
              + "/CMapType 2 def\n"
              + "2 begincodespacerange\n"
              + "<20> <20>\n"
              + "<0000> <19FF>\n"
              + "endcodespacerange\n"
              + glyphIndexes.Count + " beginbfchar\n"
            );
              // CIDToGIDMap [PDF:1.6:5.6.3].
              bytes::Buffer gIdBuffer = new bytes::Buffer();
              gIdBuffer.Append((byte)0);
              gIdBuffer.Append((byte)0);
              int code = 0;
              codes = new BiDictionary<ByteArray,int>(glyphIndexes.Count);
              PdfArray widthsObject = new PdfArray(glyphWidths.Count);
              foreach(KeyValuePair<int,int> glyphIndexEntry in glyphIndexes)
              {
            // Character code (unicode to codepoint) entry.
            code++;
            byte[] charCode = (glyphIndexEntry.Key == 32
              ? new byte[]{32}
              : new byte[]
            {
              (byte)((code >> 8) & 0xFF),
              (byte)(code & 0xFF)
            });
            codes[new ByteArray(charCode)] = glyphIndexEntry.Key;

            // CMap entry.
            cmapBuffer.Append("<");
            toUnicodeBuffer.Append("<");
            for(int charCodeBytesIndex = 0,
            charCodeBytesLength = charCode.Length;
              charCodeBytesIndex < charCodeBytesLength;
              charCodeBytesIndex++
              )
            {
              string hex = ((int)charCode[charCodeBytesIndex]).ToString("X2");
              cmapBuffer.Append(hex);
              toUnicodeBuffer.Append(hex);
            }
            cmapBuffer.Append("> " + code + "\n");
            toUnicodeBuffer.Append("> <" + glyphIndexEntry.Key.ToString("X4") + ">\n");

            // CID-to-GID entry.
            int glyphIndex = glyphIndexEntry.Value;
            gIdBuffer.Append((byte)((glyphIndex >> 8) & 0xFF));
            gIdBuffer.Append((byte)(glyphIndex & 0xFF));

            // Width.
            int width;
            if(!glyphWidths.TryGetValue(glyphIndex, out width))
            {width = 0;}
            else if(width > 1000)
            {width = 1000;}
            widthsObject.Add(PdfInteger.Get(width));
              }
              cmapBuffer.Append(
            "endcidchar\n"
              + "endcmap\n"
              + "CMapName currentdict /CMap defineresource pop\n"
              + "end\n"
              + "end\n"
              + "%%EndResource\n"
              + "%%EOF"
            );
              PdfStream cmapStream = new PdfStream(cmapBuffer);
              PdfDictionary cmapHead = cmapStream.Header;
              cmapHead[PdfName.Type] = PdfName.CMap;
              cmapHead[PdfName.CMapName] = new PdfName("Adobe-Identity-UCS");
              cmapHead[PdfName.CIDSystemInfo] = new PdfDictionary(
            new PdfName[]
            {
              PdfName.Registry,
              PdfName.Ordering,
              PdfName.Supplement
            },
            new PdfDirectObject[]
            {
              new PdfTextString("Adobe"),
              new PdfTextString("Identity"),
              PdfInteger.Get(0)
            }
            ); // Generic predefined CMap (Identity-H/V (Adobe-Identity-0)) [PDF:1.6:5.6.4].
              font[PdfName.Encoding] = File.Register(cmapStream);

              PdfStream gIdStream = new PdfStream(gIdBuffer);
              cidFont[PdfName.CIDToGIDMap] = File.Register(gIdStream);

              cidFont[PdfName.W] = new PdfArray(new PdfDirectObject[]{PdfInteger.Get(1),widthsObject});

              toUnicodeBuffer.Append(
            "endbfchar\n"
              + "endcmap\n"
              + "CMapName currentdict /CMap defineresource pop\n"
              + "end\n"
              + "end\n"
            );
              PdfStream toUnicodeStream = new PdfStream(toUnicodeBuffer);
              font[PdfName.ToUnicode] = File.Register(toUnicodeStream);
        }
        /**
         * <summary>Creates the character code mapping for composite fonts.</summary>
         */
        private void Load_CreateEncoding(
            PdfDictionary font,
            PdfDictionary cidFont
            )
        {
            // CMap [PDF:1.6:5.6.4].
            bytes::Buffer cmapBuffer = new bytes::Buffer();

            cmapBuffer.Append(
                "%!PS-Adobe-3.0 Resource-CMap\n"
                + "%%DocumentNeededResources: ProcSet (CIDInit)\n"
                + "%%IncludeResource: ProcSet (CIDInit)\n"
                + "%%BeginResource: CMap (Adobe-Identity-UCS)\n"
                + "%%Title: (Adobe-Identity-UCS Adobe Identity 0)\n"
                + "%%Version: 1\n"
                + "%%EndComments\n"
                + "/CIDInit /ProcSet findresource begin\n"
                + "12 dict begin\n"
                + "begincmap\n"
                + "/CIDSystemInfo\n"
                + "3 dict dup begin\n"
                + "/Registry (Adobe) def\n"
                + "/Ordering (Identity) def\n"
                + "/Supplement 0 def\n"
                + "end def\n"
                + "/CMapName /Adobe-Identity-UCS def\n"
                + "/CMapVersion 1 def\n"
                + "/CMapType 0 def\n"
                + "/WMode 0 def\n"
                + "2 begincodespacerange\n"
                + "<20> <20>\n"
                + "<0000> <19FF>\n"
                + "endcodespacerange\n"
                + glyphIndexes.Count + " begincidchar\n"
                );
            // ToUnicode [PDF:1.6:5.9.2].
            bytes::Buffer toUnicodeBuffer = new bytes::Buffer();

            toUnicodeBuffer.Append(
                "/CIDInit /ProcSet findresource begin\n"
                + "12 dict begin\n"
                + "begincmap\n"
                + "/CIDSystemInfo\n"
                + "<< /Registry (Adobe)\n"
                + "/Ordering (UCS)\n"
                + "/Supplement 0\n"
                + ">> def\n"
                + "/CMapName /Adobe-Identity-UCS def\n"
                + "/CMapVersion 10.001 def\n"
                + "/CMapType 2 def\n"
                + "2 begincodespacerange\n"
                + "<20> <20>\n"
                + "<0000> <19FF>\n"
                + "endcodespacerange\n"
                + glyphIndexes.Count + " beginbfchar\n"
                );
            // CIDToGIDMap [PDF:1.6:5.6.3].
            bytes::Buffer gIdBuffer = new bytes::Buffer();

            gIdBuffer.Append((byte)0);
            gIdBuffer.Append((byte)0);
            int code = 0;

            codes = new BiDictionary <ByteArray, int>(glyphIndexes.Count);
            PdfArray widthsObject = new PdfArray(glyphWidths.Count);

            foreach (KeyValuePair <int, int> glyphIndexEntry in glyphIndexes)
            {
                // Character code (unicode to codepoint) entry.
                code++;
                byte[] charCode = (glyphIndexEntry.Key == 32
          ? new byte[] { 32 }
          : new byte[]
                {
                    (byte)((code >> 8) & 0xFF),
                    (byte)(code & 0xFF)
                });
                codes[new ByteArray(charCode)] = glyphIndexEntry.Key;

                // CMap entry.
                cmapBuffer.Append("<");
                toUnicodeBuffer.Append("<");
                for (int charCodeBytesIndex = 0,
                     charCodeBytesLength = charCode.Length;
                     charCodeBytesIndex < charCodeBytesLength;
                     charCodeBytesIndex++
                     )
                {
                    string hex = ((int)charCode[charCodeBytesIndex]).ToString("X2");
                    cmapBuffer.Append(hex);
                    toUnicodeBuffer.Append(hex);
                }
                cmapBuffer.Append("> " + code + "\n");
                toUnicodeBuffer.Append("> <" + glyphIndexEntry.Key.ToString("X4") + ">\n");

                // CID-to-GID entry.
                int glyphIndex = glyphIndexEntry.Value;
                gIdBuffer.Append((byte)((glyphIndex >> 8) & 0xFF));
                gIdBuffer.Append((byte)(glyphIndex & 0xFF));

                // Width.
                int width;
                if (!glyphWidths.TryGetValue(glyphIndex, out width))
                {
                    width = 0;
                }
                else if (width > 1000)
                {
                    width = 1000;
                }
                widthsObject.Add(PdfInteger.Get(width));
            }
            cmapBuffer.Append(
                "endcidchar\n"
                + "endcmap\n"
                + "CMapName currentdict /CMap defineresource pop\n"
                + "end\n"
                + "end\n"
                + "%%EndResource\n"
                + "%%EOF"
                );
            PdfStream     cmapStream = new PdfStream(cmapBuffer);
            PdfDictionary cmapHead   = cmapStream.Header;

            cmapHead[PdfName.Type]          = PdfName.CMap;
            cmapHead[PdfName.CMapName]      = new PdfName("Adobe-Identity-UCS");
            cmapHead[PdfName.CIDSystemInfo] = new PdfDictionary(
                new PdfName[]
            {
                PdfName.Registry,
                PdfName.Ordering,
                PdfName.Supplement
            },
                new PdfDirectObject[]
            {
                new PdfTextString("Adobe"),
                new PdfTextString("Identity"),
                PdfInteger.Get(0)
            }
                ); // Generic predefined CMap (Identity-H/V (Adobe-Identity-0)) [PDF:1.6:5.6.4].
            font[PdfName.Encoding] = File.Register(cmapStream);

            PdfStream gIdStream = new PdfStream(gIdBuffer);

            cidFont[PdfName.CIDToGIDMap] = File.Register(gIdStream);

            cidFont[PdfName.W] = new PdfArray(new PdfDirectObject[] { PdfInteger.Get(1), widthsObject });

            toUnicodeBuffer.Append(
                "endbfchar\n"
                + "endcmap\n"
                + "CMapName currentdict /CMap defineresource pop\n"
                + "end\n"
                + "end\n"
                );
            PdfStream toUnicodeStream = new PdfStream(toUnicodeBuffer);

            font[PdfName.ToUnicode] = File.Register(toUnicodeStream);
        }