diff --git a/PdfSharpCore/Pdf.Advanced/PdfEmbeddedFile.cs b/PdfSharpCore/Pdf.Advanced/PdfEmbeddedFile.cs new file mode 100644 index 00000000..20dcb243 --- /dev/null +++ b/PdfSharpCore/Pdf.Advanced/PdfEmbeddedFile.cs @@ -0,0 +1,132 @@ +namespace PdfSharpCore.Pdf.Advanced +{ + /// + /// Represent a file stream embedded in the PDF document + /// + public class PdfEmbeddedFile : PdfDictionary + { + private readonly PdfDictionary paramsDictionary; + + public PdfEmbeddedFile(PdfDocument document) + : base(document) + { + this.paramsDictionary = new PdfDictionary(); + + Elements.SetName(Keys.Type, "/EmbeddedFile"); + Elements.SetObject(Keys.Params, paramsDictionary); + } + + public PdfEmbeddedFile(PdfDocument document, byte[] bytes, string checksum = null) + : this(document) + { + this.CreateStreamAndSetProperties(bytes, checksum); + } + + public void CreateStreamAndSetProperties(byte[] bytes, string checksum = null) + { + this.CreateStream(bytes); + + this.paramsDictionary.Elements.SetInteger(Keys.Size, bytes.Length); + + if (string.IsNullOrEmpty(checksum)) + this.paramsDictionary.Elements.Remove(Keys.CheckSum); + else + this.paramsDictionary.Elements.SetString(Keys.CheckSum, checksum); + } + + public string MimeType + { + get { return Elements.GetName(Keys.Subtype); } + set { Elements.SetName(Keys.Subtype, value); } + } + + // TODO : Add properties for the subdictionnary Params and the subsubdictionnary Mac + + /// + /// Predefined keys of this embedded file. + /// + public class Keys : PdfDictionary.PdfStream.Keys + { + /// + /// (Optional) The type of PDF object that this dictionary describes; if present, + /// must be EmbeddedFile for an embedded file stream. + /// + [KeyInfo(KeyType.Name | KeyType.Optional, FixedValue = "EmbeddedFile")] + public const string Type = "/Type"; + + /// + /// (Optional) The subtype of the embedded file. The value of this entry must be a + /// first-class name, as defined in Appendix E. Names without a registered prefix + /// must conform to the MIME media type names defined in Internet RFC 2046, + /// Multipurpose Internet Mail Extensions (MIME), Part Two: Media Types(see the + /// Bibliography), with the provision that characters not allowed in names must + /// use the 2-character hexadecimal code format described in Section 3.2.4, + /// “Name Objects.” + /// + [KeyInfo(KeyType.Name | KeyType.Optional)] + public const string Subtype = "/Subtype"; + + /// + /// (Optional) An embedded file parameter dictionary containing additional, + /// file-specific information (see Table 3.43). + /// + [KeyInfo(KeyType.Dictionary | KeyType.Optional)] + public const string Params = "/Params"; + + /// + /// (Optional) The size of the embedded file, in bytes. + /// + [KeyInfo(KeyType.Integer | KeyType.Optional)] + public const string Size = "/Size"; + + /// + /// (Optional) The date and time when the embedded file was created. + /// + [KeyInfo(KeyType.Date | KeyType.Optional)] + public const string CreationDate = "/CreationDate"; + + /// + /// (Optional) The date and time when the embedded file was last modified. + /// + [KeyInfo(KeyType.Date | KeyType.Optional)] + public const string ModDate = "/ModDate"; + + /// + /// (Optional) A subdictionary containing additional information specific to Mac OS files (see Table 3.44). + /// + [KeyInfo(KeyType.Dictionary | KeyType.Optional)] + public const string Mac = "/Mac"; + + /// + /// (Optional) A 16-byte string that is the checksum of the bytes of the uncompressed + /// embedded file. The checksum is calculated by applying the standard MD5 message-digest + /// algorithm (described in Internet RFC 1321, The MD5 Message-Digest Algorithm; see the + /// Bibliography) to the bytes of the embedded file stream. + /// + [KeyInfo(KeyType.Dictionary | KeyType.Optional)] + public const string CheckSum = "/CheckSum"; + + /// + /// Gets the KeysMeta for these keys. + /// + internal static DictionaryMeta Meta + { + get + { + if (Keys.meta == null) + Keys.meta = CreateMeta(typeof(Keys)); + return Keys.meta; + } + } + static DictionaryMeta meta; + } + + /// + /// Gets the KeysMeta of this dictionary type. + /// + internal override DictionaryMeta Meta + { + get { return Keys.Meta; } + } + } +} diff --git a/PdfSharpCore/Pdf.Advanced/PdfFileSpecification.cs b/PdfSharpCore/Pdf.Advanced/PdfFileSpecification.cs new file mode 100644 index 00000000..056aa399 --- /dev/null +++ b/PdfSharpCore/Pdf.Advanced/PdfFileSpecification.cs @@ -0,0 +1,120 @@ +namespace PdfSharpCore.Pdf.Advanced +{ + /// + /// Represent a file stream embedded in the PDF document + /// + public class PdfFileSpecification : PdfDictionary + { + private readonly PdfDictionary embeddedFileDictionary; + + public PdfFileSpecification(PdfDocument document) + : base(document) + { + this.embeddedFileDictionary = new PdfDictionary(); + + Elements.SetName(Keys.Type, "/Filespec"); + Elements.SetObject(Keys.EF, embeddedFileDictionary); + } + + public PdfFileSpecification(PdfDocument document, string fileName, PdfEmbeddedFile embeddedFile) + : this(document) + { + this.FileName = fileName; + this.EmbeddedFile = embeddedFile; + } + + public string FileName + { + get { return Elements.GetString(Keys.F); } + set { Elements.SetString(Keys.F, value); } + } + + public PdfEmbeddedFile EmbeddedFile + { + get + { + var reference = embeddedFileDictionary.Elements.GetReference(Keys.F); + + return reference?.Value as PdfEmbeddedFile; + } + set + { + if (value == null) + { + embeddedFileDictionary.Elements.Remove(Keys.F); + } + else + { + if (!value.IsIndirect) + Owner._irefTable.Add(value); + + embeddedFileDictionary.Elements.SetReference(Keys.F, value); + } + } + } + + /// + /// Predefined keys of this embedded file. + /// + public class Keys : KeysBase + { + /// + /// (Required if an EF or RF entry is present; recommended always) + /// The type of PDF object that this dictionary describes; must be Filespec + /// for a file specification dictionary (see implementation note 45 in Appendix H). + /// + [KeyInfo(KeyType.Name | KeyType.Optional, FixedValue = "Filespec")] + public const string Type = "/Type"; + + /// + /// (Required if the DOS, Mac, and Unix entries are all absent; amended with the UF + /// entry for PDF 1.7) A file specification string of the form described in Section + /// 3.10.1, “File Specification Strings,” or (if the file system is URL) a uniform + /// resource locator, as described in Section 3.10.4, “URL Specifications.” + /// + /// Note: It is recommended that the UF entry be used in addition to the F entry. + /// The UF entry provides cross-platform and cross-language compatibility and the F + /// entry provides backwards compatibility + /// + [KeyInfo(KeyType.Dictionary | KeyType.Optional)] + public const string F = "/F"; + + /// + /// (Required if RF is present; PDF 1.3; amended to include the UF key in PDF 1.7) + /// A dictionary containing a subset of the keys F, UF, DOS, Mac, and Unix, + /// corresponding to the entries by those names in the file specification dictionary. + /// The value of each such key is an embedded file stream (see Section 3.10.3, + /// “Embedded File Streams”) containing the corresponding file. If this entry is + /// present, the Type entry is required and the file specification dictionary must + /// be indirectly referenced. (See implementation note 46in Appendix H.) + /// + /// Note: It is recommended that the F and UF entries be used in place of the DOS, + /// Mac, or Unix entries. + /// + [KeyInfo(KeyType.Dictionary | KeyType.Optional)] + public const string EF = "/EF"; + + /// + /// Gets the KeysMeta for these keys. + /// + internal static DictionaryMeta Meta + { + get + { + if (Keys.meta == null) + Keys.meta = CreateMeta(typeof(Keys)); + return Keys.meta; + } + } + static DictionaryMeta meta; + } + + /// + /// Gets the KeysMeta of this dictionary type. + /// + internal override DictionaryMeta Meta + { + get { return Keys.Meta; } + } + } +} diff --git a/PdfSharpCore/Pdf.Annotations/PdfFileAttachmentAnnotation.cs b/PdfSharpCore/Pdf.Annotations/PdfFileAttachmentAnnotation.cs new file mode 100644 index 00000000..34c995e2 --- /dev/null +++ b/PdfSharpCore/Pdf.Annotations/PdfFileAttachmentAnnotation.cs @@ -0,0 +1,129 @@ +using PdfSharpCore.Pdf.Advanced; +using System; + +namespace PdfSharpCore.Pdf.Annotations +{ + /// + /// Represent a file that is attached to the PDF + /// + public class PdfFileAttachmentAnnotation : PdfAnnotation + { + /// + /// Name of icons used in displaying the annotation. + /// + public enum IconType + { + Graph, + PushPin, + Paperclip, + Tag + } + + /// + /// Initializes a new instance of the class. + /// + public PdfFileAttachmentAnnotation() + { + Elements.SetName(Keys.Subtype, "/FileAttachment"); + } + + /// + /// Initializes a new instance of the class. + /// + public PdfFileAttachmentAnnotation(PdfDocument document) + : base(document) + { + Elements.SetName(Keys.Subtype, "/FileAttachment"); + Flags = PdfAnnotationFlags.Locked; + } + + public IconType Icon + { + get + { + var iconName = Elements.GetName(Keys.Name); + + if (iconName == null) + return IconType.PushPin; + + return (IconType)(Enum.Parse(typeof(IconType), iconName)); + } + set { Elements.SetName(Keys.Name, value.ToString()); } + } + + public PdfFileSpecification File + { + get + { + var reference = Elements.GetReference(Keys.FS); + + return reference?.Value as PdfFileSpecification; + } + set + { + if (value == null) + { + Elements.Remove(Keys.FS); + } + else + { + if (!value.IsIndirect) + Owner._irefTable.Add(value); + + Elements.SetReference(Keys.FS, value); + } + } + } + + /// + /// Predefined keys of this dictionary. + /// + internal new class Keys : PdfAnnotation.Keys + { + /// + /// (Required) The file associated with this annotation. + /// + [KeyInfo(KeyType.Dictionary | KeyType.Required)] + public const string FS = "/FS"; + + /// + /// (Optional) The name of an icon to be used in displaying the annotation. + /// Viewer applications should provide predefined icon appearances for at least + /// the following standard names: + /// + /// Graph + /// PushPin + /// Paperclip + /// Tag + /// + /// Additional names may be supported as well. Default value: PushPin. + /// Note: The annotation dictionary’s AP entry, if present, takes precedence over + /// the Name entry; see Table 8.15 on page 606 and Section 8.4.4, “Appearance Streams.” + /// + [KeyInfo(KeyType.Name | KeyType.Optional)] + public const string Name = "/Name"; + + /// + /// Gets the KeysMeta for these keys. + /// + public static DictionaryMeta Meta + { + get + { + if (Keys.meta == null) + Keys.meta = CreateMeta(typeof(Keys)); + return Keys.meta; + } + } + static DictionaryMeta meta; + } + + /// + /// Gets the KeysMeta of this dictionary type. + /// + internal override DictionaryMeta Meta + { + get { return Keys.Meta; } + } + } +}