/** * <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(); }
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)!!! */ } }
/** * <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. }