/**
         * <summary>Gets the object equivalent to the given value.</summary>
         */
        public static PdfDirectObject Get(
            object value
            )
        {
            if (value == null)
            {
                return(null);
            }

            if (value is int)
            {
                return(PdfInteger.Get((int)value));
            }
            if (value is double || value is float)
            {
                return(PdfReal.Get(value));
            }
            if (value is string)
            {
                return(PdfTextString.Get((string)value));
            }
            if (value is DateTime)
            {
                return(PdfDate.Get((DateTime)value));
            }
            if (value is bool)
            {
                return(PdfBoolean.Get((bool)value));
            }
            throw new NotImplementedException();
        }
예제 #2
0
        public Field this[
            string key
        ]
        {
            get
            {
                /*
                 * TODO: It is possible for different field dictionaries to have the SAME fully qualified field
                 * name if they are descendants of a common ancestor with that name and have no
                 * partial field names (T entries) of their own. Such field dictionaries are different
                 * representations of the same underlying field; they should differ only in properties
                 * that specify their visual appearance. In particular, field dictionaries with the same
                 * fully qualified field name must have the same field type (FT), value (V), and default
                 * value (DV).
                 */
                PdfReference valueFieldReference = null;
                {
                    IEnumerator partialNamesIterator = key.Split('.').GetEnumerator();
                    IEnumerator <PdfDirectObject> fieldObjectsIterator = BaseDataObject.GetEnumerator();
                    while (partialNamesIterator.MoveNext())
                    {
                        string partialName = (string)partialNamesIterator.Current;
                        valueFieldReference = null;
                        while (fieldObjectsIterator != null &&
                               fieldObjectsIterator.MoveNext())
                        {
                            PdfReference  fieldReference  = (PdfReference)fieldObjectsIterator.Current;
                            PdfDictionary fieldDictionary = (PdfDictionary)fieldReference.DataObject;
                            PdfTextString fieldName       = (PdfTextString)fieldDictionary[PdfName.T];
                            if (fieldName != null && fieldName.Value.Equals(partialName))
                            {
                                valueFieldReference = fieldReference;
                                PdfArray kidFieldObjects = (PdfArray)fieldDictionary.Resolve(PdfName.Kids);
                                fieldObjectsIterator = (kidFieldObjects == null ? null : kidFieldObjects.GetEnumerator());
                                break;
                            }
                        }
                        if (valueFieldReference == null)
                        {
                            break;
                        }
                    }
                }
                return(Field.Wrap(valueFieldReference));
            }
            set
            {
                throw new NotImplementedException();

                /*
                 * TODO:put the field into the correct position, based on the full name (key)!!!
                 */
            }
        }
예제 #3
0
        /**
         * <summary>Sets the Javascript script into the specified base data object.</summary>
         */
        internal static void SetScript(PdfDictionary baseDataObject, PdfName key, string value)
        {
            PdfDataObject scriptObject = baseDataObject.Resolve(key);

            if (!(scriptObject is PdfStream) && value.Length > 256)
            {
                baseDataObject[key] = baseDataObject.File.Register(scriptObject = new PdfStream());
            }
            // Insert the script!
            if (scriptObject is PdfStream)
            {
                bytes::IBuffer scriptBuffer = ((PdfStream)scriptObject).Body;
                scriptBuffer.Clear();
                scriptBuffer.Append(value);
            }
            else
            {
                baseDataObject[key] = new PdfTextString(value);
            }
        }
        /**
         * <summary>Creates the character code mapping for composite fonts.</summary>
         */
        private void Load_CreateEncoding(
            PdfDictionary font,
            PdfDictionary cidFont
            )
        {
            /*
             * NOTE: Composite fonts map text shown by content stream strings through a 2-level encoding
             * scheme:
             *  character code -> CID (character index) -> GID (glyph index)
             * This works for rendering purposes, but if we want our text data to be intrinsically meaningful,
             * we need a further mapping towards some standard character identification scheme (Unicode):
             *  Unicode <- character code -> CID -> GID
             * Such mapping may be provided by a known CID collection or (in case of custom encodings like
             * Identity-H) by an explicit ToUnicode CMap.
             * CID -> GID mapping is typically identity, that is CIDS correspond to GIDS, so we don't bother
             * about that. Our base encoding is Identity-H, that is character codes correspond to CIDs;
             * however, sometimes a font maps multiple Unicode codepoints to the same GID (for example, the
             * hyphen glyph may be associated to the hyphen (\u2010) and minus (\u002D) symbols), breaking
             * the possibility to recover their original Unicode values once represented as character codes
             * in content stream strings. In this case, we are forced to remap the exceeding codes and
             * generate an explicit CMap (TODO: I tried to emit a differential CMap using the usecmap
             * operator in order to import Identity-H as base encoding, but it failed in several engines
             * (including Acrobat, Ghostscript, Poppler, whilst it surprisingly worked with pdf.js), so we
             * have temporarily to stick with full CMaps).
             */

            // Encoding [PDF:1.7:5.6.1,5.6.4].
            PdfDirectObject encodingObject = PdfName.IdentityH;
            SortedDictionary <ByteArray, int> sortedCodes;

            {
                codes = new BiDictionary <ByteArray, int>(glyphIndexes.Count);
                int         lastRemappedCharCodeValue = 0;
                IList <int> removedGlyphIndexKeys     = null;
                foreach (KeyValuePair <int, int> glyphIndexEntry in glyphIndexes.ToList())
                {
                    int       glyphIndex = glyphIndexEntry.Value;
                    ByteArray charCode   = new ByteArray(new byte[]
                    {
                        (byte)((glyphIndex >> 8) & 0xFF),
                        (byte)(glyphIndex & 0xFF)
                    });

                    // Checking for multiple Unicode codepoints which map to the same glyph index...

                    /*
                     * NOTE: In case the same glyph index maps to multiple Unicode codepoints, we are forced to
                     * alter the identity encoding creating distinct cmap entries for the exceeding codepoints.
                     */
                    if (codes.ContainsKey(charCode))
                    {
                        if (glyphIndex == 0) // .notdef glyph already mapped.
                        {
                            if (removedGlyphIndexKeys == null)
                            {
                                removedGlyphIndexKeys = new List <int>();
                            }
                            removedGlyphIndexKeys.Add(glyphIndexEntry.Key);
                            continue;
                        }

                        // Assigning the new character code...

                        /*
                         * NOTE: As our base encoding is identity, we have to look for a value that doesn't
                         * collide with existing glyph indices.
                         */
                        while (glyphIndexes.ContainsValue(++lastRemappedCharCodeValue))
                        {
                            ;
                        }
                        charCode.Data[0] = (byte)((lastRemappedCharCodeValue >> 8) & 0xFF);
                        charCode.Data[1] = (byte)(lastRemappedCharCodeValue & 0xFF);
                    }
                    else if (glyphIndex == 0) // .notdef glyph.
                    {
                        DefaultCode = glyphIndexEntry.Key;
                    }

                    codes[charCode] = glyphIndexEntry.Key;
                }
                if (removedGlyphIndexKeys != null)
                {
                    foreach (int removedGlyphIndexKey in removedGlyphIndexKeys)
                    {
                        glyphIndexes.Remove(removedGlyphIndexKey);
                    }
                }
                sortedCodes = new SortedDictionary <ByteArray, int>(codes);
                if (lastRemappedCharCodeValue > 0) // Custom encoding.
                {
                    string         cmapName   = "Custom";
                    bytes::IBuffer cmapBuffer = CMapBuilder.Build(
                        CMapBuilder.EntryTypeEnum.CID,
                        cmapName,
                        sortedCodes,
                        delegate(KeyValuePair <ByteArray, int> codeEntry)
                        { return(glyphIndexes[codeEntry.Value]); }
                        );
                    encodingObject = File.Register(
                        new PdfStream(
                            new PdfDictionary(
                                new PdfName[]
                    {
                        PdfName.Type,
                        PdfName.CMapName,
                        PdfName.CIDSystemInfo
                    },
                                new PdfDirectObject[]
                    {
                        PdfName.CMap,
                        new PdfName(cmapName),
                        new PdfDictionary(
                            new PdfName[]
                        {
                            PdfName.Registry,
                            PdfName.Ordering,
                            PdfName.Supplement
                        },
                            new PdfDirectObject[]
                        {
                            PdfTextString.Get("Adobe"),
                            PdfTextString.Get("Identity"),
                            PdfInteger.Get(0)
                        }
                            )
                    }
                                ),
                            cmapBuffer
                            )
                        );
                }
            }
            font[PdfName.Encoding]       = encodingObject;   // Character-code-to-CID mapping.
            cidFont[PdfName.CIDToGIDMap] = PdfName.Identity; // CID-to-glyph-index mapping.

            // ToUnicode [PDF:1.6:5.9.2].
            PdfDirectObject toUnicodeObject = null;

            {
                bytes::IBuffer toUnicodeBuffer = CMapBuilder.Build(
                    CMapBuilder.EntryTypeEnum.BaseFont,
                    null,
                    sortedCodes,
                    delegate(KeyValuePair <ByteArray, int> codeEntry)
                    { return(codeEntry.Value); }
                    );
                toUnicodeObject = File.Register(new PdfStream(toUnicodeBuffer));
            }
            font[PdfName.ToUnicode] = toUnicodeObject; // Character-code-to-Unicode mapping.

            // Glyph widths.
            PdfArray widthsObject = new PdfArray();

            {
                int      lastGlyphIndex            = -10;
                PdfArray lastGlyphWidthRangeObject = null;
                foreach (int glyphIndex in glyphIndexes.Values.OrderBy(x => x).ToList())
                {
                    int width;
                    if (!glyphWidths.TryGetValue(glyphIndex, out width))
                    {
                        width = 0;
                    }
                    if (glyphIndex - lastGlyphIndex != 1)
                    {
                        widthsObject.Add(PdfInteger.Get(glyphIndex));
                        widthsObject.Add(lastGlyphWidthRangeObject = new PdfArray());
                    }
                    lastGlyphWidthRangeObject.Add(PdfInteger.Get(width));
                    lastGlyphIndex = glyphIndex;
                }
            }
            cidFont[PdfName.W] = widthsObject; // Glyph widths.
        }