From a2f00eb15652e9a19facd938d479630f0a31e980 Mon Sep 17 00:00:00 2001 From: special946 Date: Fri, 13 Jul 2018 13:45:10 +0300 Subject: [PATCH] Add Free Text Annotation --- .../Fonts/enums/StandartType1Fonts.cs | 110 ++++++++ .../DA/AnnotationDefaultAppearance.cs | 95 +++++++ .../Pdf.Annotations/PdfBorderEffect.cs | 98 +++++++ .../Pdf.Annotations/PdfBorderStyle.cs | 257 ++++++++++++++++++ .../Pdf.Annotations/PdfFreeTextAnnotation.cs | 160 +++++++++++ src/PdfSharp/PdfSharp.csproj | 5 + 6 files changed, 725 insertions(+) create mode 100644 src/PdfSharp/Fonts/enums/StandartType1Fonts.cs create mode 100644 src/PdfSharp/Pdf.Annotations/DA/AnnotationDefaultAppearance.cs create mode 100644 src/PdfSharp/Pdf.Annotations/PdfBorderEffect.cs create mode 100644 src/PdfSharp/Pdf.Annotations/PdfBorderStyle.cs create mode 100644 src/PdfSharp/Pdf.Annotations/PdfFreeTextAnnotation.cs diff --git a/src/PdfSharp/Fonts/enums/StandartType1Fonts.cs b/src/PdfSharp/Fonts/enums/StandartType1Fonts.cs new file mode 100644 index 00000000..f3508338 --- /dev/null +++ b/src/PdfSharp/Fonts/enums/StandartType1Fonts.cs @@ -0,0 +1,110 @@ +#region PDFsharp - A .NET library for processing PDF +// +// Authors: +// Andrey Ryzhkov +// +#endregion + +using System; +using System.Collections.Generic; + +namespace PdfSharp.Fonts +{ + public sealed class StandardType1Fonts + { + + //private StandardType1Fonts() + //{ + //} + + private static readonly ICollection _FONTS = new List(); + + static StandardType1Fonts() + { + _FONTS.Add(PdfSharp.Fonts.StandardType1Fonts.COURIER); + _FONTS.Add(PdfSharp.Fonts.StandardType1Fonts.COURIER_BOLD); + _FONTS.Add(PdfSharp.Fonts.StandardType1Fonts.COURIER_BOLDOBLIQUE); + _FONTS.Add(PdfSharp.Fonts.StandardType1Fonts.COURIER_OBLIQUE); + _FONTS.Add(PdfSharp.Fonts.StandardType1Fonts.HELVETICA); + _FONTS.Add(PdfSharp.Fonts.StandardType1Fonts.HELVETICA_BOLD); + _FONTS.Add(PdfSharp.Fonts.StandardType1Fonts.HELVETICA_BOLDOBLIQUE); + _FONTS.Add(PdfSharp.Fonts.StandardType1Fonts.HELVETICA_OBLIQUE); + _FONTS.Add(PdfSharp.Fonts.StandardType1Fonts.SYMBOL); + _FONTS.Add(PdfSharp.Fonts.StandardType1Fonts.TIMES_ROMAN); + _FONTS.Add(PdfSharp.Fonts.StandardType1Fonts.TIMES_BOLD); + _FONTS.Add(PdfSharp.Fonts.StandardType1Fonts.TIMES_BOLDITALIC); + _FONTS.Add(PdfSharp.Fonts.StandardType1Fonts.TIMES_ITALIC); + _FONTS.Add(PdfSharp.Fonts.StandardType1Fonts.ZAPFDINGBATS); + } + + public static bool IsStandardFont(String fontName) + { + return _FONTS.Contains(fontName); + } + + /// This is a possible value of a base 14 type 1 font + public const string COURIER = "Courier"; + + /// This is a possible value of a base 14 type 1 font + public const string COURIER_BOLD = "Courier-Bold"; + + /// This is a possible value of a base 14 type 1 font + public const string COURIER_OBLIQUE = "Courier-Oblique"; + + /// This is a possible value of a base 14 type 1 font + public const string COURIER_BOLDOBLIQUE = "Courier-BoldOblique"; + + /// This is a possible value of a base 14 type 1 font + public const string HELVETICA = "Helvetica"; + + /// This is a possible value of a base 14 type 1 font + public const string HELVETICA_BOLD = "Helvetica-Bold"; + + /// This is a possible value of a base 14 type 1 font + public const string HELVETICA_OBLIQUE = "Helvetica-Oblique"; + + /// This is a possible value of a base 14 type 1 font + public const string HELVETICA_BOLDOBLIQUE = "Helvetica-BoldOblique"; + + /// This is a possible value of a base 14 type 1 font + public const string SYMBOL = "Symbol"; + + /// This is a possible value of a base 14 type 1 font + public const string TIMES_ROMAN = "Times-Roman"; + + /// This is a possible value of a base 14 type 1 font + public const string TIMES_BOLD = "Times-Bold"; + + /// This is a possible value of a base 14 type 1 font + public const string TIMES_ITALIC = "Times-Italic"; + + /// This is a possible value of a base 14 type 1 font + public const string TIMES_BOLDITALIC = "Times-BoldItalic"; + + /// This is a possible value of a base 14 type 1 font + public const string ZAPFDINGBATS = "ZapfDingbats"; + } + + /// + /// The PostScript names of 14 Type 1 fonts, known as the standard fonts. + /// These fonts, or their font metrics and suitable substitution fonts, are guaranteed + /// to be available to the viewer application. + /// + public enum StandardType1Font + { + TimesRoman, + TimesBold, + TimesItalic, + TimesBoldItalic, + Helvetica, + HelveticaBold, + HelveticaOblique, + HelveticaBoldOblique, + Courier, + CourierBold, + CourierOblique, + CourierBoldOblique, + Symbol, + ZapfDingbats + } +} \ No newline at end of file diff --git a/src/PdfSharp/Pdf.Annotations/DA/AnnotationDefaultAppearance.cs b/src/PdfSharp/Pdf.Annotations/DA/AnnotationDefaultAppearance.cs new file mode 100644 index 00000000..83a7c77f --- /dev/null +++ b/src/PdfSharp/Pdf.Annotations/DA/AnnotationDefaultAppearance.cs @@ -0,0 +1,95 @@ +#region PDFsharp - A .NET library for processing PDF +// +// Authors: +// Andrey Ryzhkov +// +#endregion + +using System.Collections.Generic; +using System.Globalization; + +using PdfSharp.Drawing; +using PdfSharp.Fonts; + +namespace PdfSharp.Pdf.Annotations.DA +{ + class AnnotationDefaultAppearance + { + private static readonly IDictionary stdAnnotFontNames = + new Dictionary(); + + private string color = "1 g"; + + private string fontName = "/Helvetica"; + + private float fontSize = 0f; + + static AnnotationDefaultAppearance() + { + stdAnnotFontNames.Add(StandardType1Font.Courier, "/" + StandardType1Fonts.COURIER); + stdAnnotFontNames.Add(StandardType1Font.CourierBold, "/" + StandardType1Fonts.COURIER_BOLD); + stdAnnotFontNames.Add(StandardType1Font.CourierOblique, "/" + StandardType1Fonts.COURIER_OBLIQUE); + stdAnnotFontNames.Add(StandardType1Font.CourierBoldOblique, "/" + StandardType1Fonts.COURIER_BOLDOBLIQUE); + + stdAnnotFontNames.Add(StandardType1Font.Helvetica, "/" + StandardType1Fonts.HELVETICA); + stdAnnotFontNames.Add(StandardType1Font.HelveticaBold, "/" + StandardType1Fonts.HELVETICA_BOLD); + stdAnnotFontNames.Add(StandardType1Font.HelveticaOblique, "/" + StandardType1Fonts.HELVETICA_OBLIQUE); + stdAnnotFontNames.Add(StandardType1Font.HelveticaBoldOblique, "/" + StandardType1Fonts.HELVETICA_BOLDOBLIQUE); + + stdAnnotFontNames.Add(StandardType1Font.TimesRoman, "/" + StandardType1Fonts.TIMES_ROMAN); + stdAnnotFontNames.Add(StandardType1Font.TimesBold, "/" + StandardType1Fonts.TIMES_BOLD); + stdAnnotFontNames.Add(StandardType1Font.TimesItalic, "/" + StandardType1Fonts.TIMES_ITALIC); + stdAnnotFontNames.Add(StandardType1Font.TimesBoldItalic, "/" + StandardType1Fonts.TIMES_BOLDITALIC); + + stdAnnotFontNames.Add(StandardType1Font.Symbol, "/" + StandardType1Fonts.SYMBOL); + + stdAnnotFontNames.Add(StandardType1Font.ZapfDingbats, "/" + StandardType1Fonts.ZAPFDINGBATS); + } + + public AnnotationDefaultAppearance() + { + SetFont(StandardType1Font.Helvetica); + SetFontSize(10f); + SetColor(XColor.FromGrayScale(1.0)); + } + + public void SetFont(StandardType1Font font) + { + fontName = stdAnnotFontNames[font]; + } + + public void SetFontSize(float size) + { + fontSize = size; + } + + public void SetColor(XColor color) + { + if (color.ColorSpace.Equals(XColorSpace.GrayScale)) + { + this.color = color.GS.ToString("0.0#####", CultureInfo.InvariantCulture) + " g"; + } + else if (color.ColorSpace.Equals(XColorSpace.Rgb)) + { + this.color = color.R.ToString("0.0#####", CultureInfo.InvariantCulture) + " " + + color.G.ToString("0.0#####", CultureInfo.InvariantCulture) + " " + + color.B.ToString("0.0#####", CultureInfo.InvariantCulture) + " rg"; + } + else if (color.ColorSpace.Equals(XColorSpace.Cmyk)) + { + this.color = color.C.ToString("0.0#####", CultureInfo.InvariantCulture) + " " + + color.M.ToString("0.0#####", CultureInfo.InvariantCulture) + " " + + color.Y.ToString("0.0#####", CultureInfo.InvariantCulture) + " " + + color.K.ToString("0.0#####", CultureInfo.InvariantCulture) + " k"; + } + } + + /// + /// Get string value from AnnotationDefaultAppearance + /// + public override string ToString() + { + return fontName + " " + fontSize.ToString() + " Tf " + color; + } + } +} diff --git a/src/PdfSharp/Pdf.Annotations/PdfBorderEffect.cs b/src/PdfSharp/Pdf.Annotations/PdfBorderEffect.cs new file mode 100644 index 00000000..0158bf9d --- /dev/null +++ b/src/PdfSharp/Pdf.Annotations/PdfBorderEffect.cs @@ -0,0 +1,98 @@ +#region PDFsharp - A .NET library for processing PDF +// +// Begining with PDF 1.5, some annotations(square, circle and polygon) may have +// a BE entry, which is a border effect dictionary that specifies an effect to be applied +// to the border of the annotations. +// +// Authors: +// Andrey Ryzhkov +// +#endregion + +using System; + +namespace PdfSharp.Pdf.Annotations +{ + public class PdfBorderEffect : PdfDictionary + { + /// + /// Initializes a new instance of the class. + /// + public PdfBorderEffect() + { + Elements.SetName(Keys.S, "/S"); + Elements.SetInteger(Keys.I, 0); + } + + /// + /// Initializes a new instance of the class. + /// + /// Border effect + public PdfBorderEffect(pdfBorderEffect effect) + { + Effect = effect; + } + + /// + /// Get or set border effect. + /// + public pdfBorderEffect Effect + { + get + { + return (pdfBorderEffect)Enum.Parse(typeof(pdfBorderEffect), Enum.GetName(typeof(pdfBorderEffect), Elements.GetInteger(Keys.I))); + } + set + { + if (Enum.IsDefined(typeof(pdfBorderEffect), value)) + { + if (value == pdfBorderEffect.None) + { + Elements.SetName(Keys.S, "/S"); + } + else if (value == pdfBorderEffect.Cloud1 || value == pdfBorderEffect.Cloud2) + { + Elements.SetName(Keys.S, "/C"); + } + Elements.SetInteger(Keys.I, (int)value); + } + + } + } + + /// + /// Predefined keys of this dictionary. + /// + public class Keys : KeysBase + { + /// + /// (Optional) A name representing the border effect to apply. Possible values are: + /// S - No effect: the border is as described by the annotation dictionary's BS entry. + /// C - The border should appear "cloudly". The width and dash array specified by BS are honored. + /// Default value: S. + /// + [KeyInfo("1.5", KeyType.Name | KeyType.Optional)] + public const string S = "/S"; + + /// + /// (Optional; valid only if the value of S is C) A number describing the intensity of the + /// effect. Suggest values range from 0 to 2. + /// Default value: 0. + /// + [KeyInfo("1.5", KeyType.Integer | KeyType.Optional)] + public const string I = "/I"; + } + } + + /// + /// Border effect types. + /// + public enum pdfBorderEffect + { + None = 0, + Cloud1 = 1, + Cloud2 = 2 + } + + +} diff --git a/src/PdfSharp/Pdf.Annotations/PdfBorderStyle.cs b/src/PdfSharp/Pdf.Annotations/PdfBorderStyle.cs new file mode 100644 index 00000000..7e46e1ec --- /dev/null +++ b/src/PdfSharp/Pdf.Annotations/PdfBorderStyle.cs @@ -0,0 +1,257 @@ +#region PDFsharp - A .NET library for processing PDF +// +// An annotation may optionally be surrounded by a border when displayed or +// printed.If present, the border is drawn completely inside the annotation rectangle. +// In PDF 1.1, the characteristics of the border are specified by the Border +// entry in the annotation dictionary. Beginning with +// PDF 1.2, some types of annotation may instead specify their border characteristics +// in a border style dictionary designated by the annotation’s BS entry.Such dictionaries +// are also used to specify the width and dash pattern for the lines drawn +// by line, square, circle, and ink annotations.Table 8.12 summarizes the contents +// of the border style dictionary.If neither the Border nor the BS entry is present, +// the border is drawn as a solid line with a width of 1 point. +// +// +// +// Authors: +// Andrey Ryzhkov +// +#endregion + +using System; +using System.Collections.Generic; + +namespace PdfSharp.Pdf.Annotations +{ + public class PdfBorderStyle : PdfDictionary + { + public const int DASH_3 = 1; + public const int DASH_6_3 = 2; + + + private PdfArray _dashArray; + + /// + /// Initializes a new instance of the class. + /// + public PdfBorderStyle() + { + Initialize(); + } + + void Initialize() + { + Elements.SetName(Keys.Type, "/Border"); + Elements.SetReal(Keys.W, 1.0); + Elements.SetName(Keys.S, "/S"); + + _dashArray = new PdfArray(); + _dashArray.Elements.Add(new PdfInteger(3)); + } + + /// + /// Get or set border width in points. If this value is 0, no border is drawn. + /// + public double BorderWidth + { + get + { + return Elements.GetReal(Keys.W); + } + set + { + if (value <= 0) + { + Elements.SetReal(Keys.W, 0); + Elements.Remove(Keys.S); + Elements.Remove(Keys.D); + } + else + { + Elements.SetReal(Keys.W, value); + } + } + } + + /// + /// Get or set border style. + /// + public StyleBorder BorderStyle + { + get + { + string value = Elements.GetName(Keys.S); + value = value.Substring(1); + switch (value) + { + case "S": + return StyleBorder.Solid; + case "D": + return StyleBorder.Dashed; + case "B": + return StyleBorder.Beveled; + case "I": + return StyleBorder.Inset; + case "U": + return StyleBorder.Underline; + } + return StyleBorder.ERROR; + } + set + { + if (Enum.IsDefined(typeof(StyleBorder), value) + && value != StyleBorder.ERROR) + { + char v = value.ToString("G")[0]; + Elements.SetName(Keys.S, "/" + v); + if (value == StyleBorder.Dashed) + { + Elements["/D"] = _dashArray; + } + else if (value == StyleBorder.Solid) + { + Elements.Remove(Keys.D); + + } + } + } + } + + /// + /// Get or set dash array. A dash array defining a pattern of dashes + /// an gaps to be used in drawing a dashed border. + /// + public PdfArray DashArray + { + get + { + return _dashArray; + } + set + { + _dashArray = value; + Elements["/D"] = _dashArray; + } + } + + /// + /// Predefined keys of this dictionary. + /// + public class Keys : KeysBase + { + /// + /// (Optional) The type of PDF object that this dictionary describes; if present, must be + /// Border for a border style dictionary + /// + [KeyInfo(KeyType.Name | KeyType.Optional, FixedValue = "Border")] + public const string Type = "/Type"; + + /// + /// (Optional) The border width in points. If this value is 0, no border is drawn. + /// Default value: 1. + /// + [KeyInfo(KeyType.Real | KeyType.Optional)] + public const string W = "/W"; + + /// + /// (Optional) The border style: + /// S(Solid) A solid rectangle surrounding the annotation. + /// D(Dashed) A dashed rectangle surrounding the annotation.The dash pattern + /// is specified by the D entry (see below). + /// B(Beveled) A simulated embossed rectangle that appears to be raised above the + /// surface of the page. + /// I(Inset) A simulated engraved rectangle that appears to be recessed below the + /// surface of the page. + /// U(Underline) A single line along the bottom of the annotation rectangle. + /// Other border styles may be defined in the future. (See implementation note 64 in + /// Appendix H.) Default value: S. + /// + [KeyInfo(KeyType.Name | KeyType.Optional)] + public const string S = "/S"; + + /// + /// (Optional) A dash array defining a pattern of dashes and gaps to be used in drawing a + /// dashed border(border style D above). The dash array is specified in the same format + /// as in the line dash pattern parameter of the graphics state(see “Line Dash Pattern” on + /// page 155). The dash phase is not specified and is assumed to be 0. For example, a D + /// entry of[3 2] specifies a border drawn with 3-point dashes alternating with 2-point + /// gaps.Default value: [3]. + /// + [KeyInfo(KeyType.Array | KeyType.Optional)] + public const string D = "/D"; + } + } + + /// + /// The border style + /// + public enum StyleBorder + { + ERROR, + Solid, + Dashed, + Beveled, + Inset, + Underline + } + + /// + /// Pre-define border style array + /// + public class DashArray + { + public static readonly Dictionary Standard = new Dictionary(); + + static DashArray() + { + PdfArray arr_2_2 = new PdfArray(); + arr_2_2.Elements.Add(new PdfInteger(2)); + arr_2_2.Elements.Add(new PdfInteger(2)); + Standard[dashArray.Dash_2_2] = arr_2_2; + + PdfArray arr_3_3 = new PdfArray(); + arr_3_3.Elements.Add(new PdfInteger(3)); + arr_3_3.Elements.Add(new PdfInteger(3)); + Standard[dashArray.Dash_3_3] = arr_3_3; + + PdfArray arr_4_4 = new PdfArray(); + arr_4_4.Elements.Add(new PdfInteger(4)); + arr_4_4.Elements.Add(new PdfInteger(4)); + Standard[dashArray.Dash_4_4] = arr_4_4; + + PdfArray arr_4_3_2_3 = new PdfArray(); + arr_4_3_2_3.Elements.Add(new PdfInteger(4)); + arr_4_3_2_3.Elements.Add(new PdfInteger(3)); + arr_4_3_2_3.Elements.Add(new PdfInteger(2)); + arr_4_3_2_3.Elements.Add(new PdfInteger(3)); + Standard[dashArray.Dash_4_3_2_3] = arr_4_3_2_3; + + PdfArray arr_4_3_16_3 = new PdfArray(); + arr_4_3_16_3.Elements.Add(new PdfInteger(4)); + arr_4_3_16_3.Elements.Add(new PdfInteger(3)); + arr_4_3_16_3.Elements.Add(new PdfInteger(16)); + arr_4_3_16_3.Elements.Add(new PdfInteger(3)); + Standard[dashArray.Dash_4_3_16_3] = arr_4_3_16_3; + + PdfArray arr_8_4_4_4 = new PdfArray(); + arr_8_4_4_4.Elements.Add(new PdfInteger(8)); + arr_8_4_4_4.Elements.Add(new PdfInteger(4)); + arr_8_4_4_4.Elements.Add(new PdfInteger(4)); + arr_8_4_4_4.Elements.Add(new PdfInteger(4)); + Standard[dashArray.Dash_8_4_4_4] = arr_8_4_4_4; + } + + /// + /// Dash array's types for dased border style + /// + public enum dashArray + { + Dash_2_2, + Dash_3_3, + Dash_4_4, + Dash_4_3_2_3, + Dash_4_3_16_3, + Dash_8_4_4_4 + } + } +} diff --git a/src/PdfSharp/Pdf.Annotations/PdfFreeTextAnnotation.cs b/src/PdfSharp/Pdf.Annotations/PdfFreeTextAnnotation.cs new file mode 100644 index 00000000..c0f8cf97 --- /dev/null +++ b/src/PdfSharp/Pdf.Annotations/PdfFreeTextAnnotation.cs @@ -0,0 +1,160 @@ +#region PDFsharp - A .NET library for processing PDF +// +// Authors: +// Andrey Ryzhkov +// +#endregion + +using PdfSharp.Drawing; +using PdfSharp.Fonts; +using PdfSharp.Pdf.Annotations.DA; + +namespace PdfSharp.Pdf.Annotations +{ + /// + /// Represents a free text annotation (PDF 1.3). + /// + public sealed class PdfFreeTextAnnotation : PdfAnnotation + { + private AnnotationDefaultAppearance _da; + private PdfBorderStyle _borderStyle; + private PdfBorderEffect _borderEffect; + + /// + /// Initializes a new instance of the class. + /// + public PdfFreeTextAnnotation() + { + Initialize(); + } + + /// + /// Initializes a new instance of the class. + /// + /// + public PdfFreeTextAnnotation(PdfDocument document) + : base(document) + { + Initialize(); + } + + void Initialize() + { + Elements.SetName(Keys.Subtype, "/FreeText"); + Elements.SetInteger(Keys.Q, 0); + _da = new AnnotationDefaultAppearance(); + Elements.SetString(Keys.DA, _da.ToString()); + _borderStyle = new PdfBorderStyle(); + _borderEffect = new PdfBorderEffect(); + } + + /// + /// Gets or sets justification to be used in displaying the annotation’s text: + /// 0 Left-justified + /// 1 Centered + /// 2 Right-justified + /// + public int Justification + { + get { return Elements.GetInteger(Keys.Q); } + set + { + if (value >= 0 && value <= 2) + { + Elements.SetInteger(Keys.Q, value); + } + } + } + + /// + /// Set annotation's font from . + /// + public void SetFont(StandardType1Font font) + { + _da.SetFont(font); + Elements.SetString(Keys.DA, _da.ToString()); + } + + /// + /// Set font size. + /// + /// Font size in points. + public void SetFontSize(float size) + { + _da.SetFontSize(size); + Elements.SetString(Keys.DA, _da.ToString()); + } + + /// + /// Set font color. + /// + public void SetFontColor(XColor color) + { + _da.SetColor(color); + Elements.SetString(Keys.DA, _da.ToString()); + } + + /// + /// Get or set border style. + /// + public PdfBorderStyle BorderStyle + { + get + { + return _borderStyle; + } + set + { + _borderStyle = value; + Elements[Keys.BS] = _borderStyle; + } + } + + /// + /// Get or set border effect. + /// + public PdfBorderEffect BorderEffect + { + get + { + return _borderEffect; + } + set + { + _borderEffect = value; + Elements[Keys.BE] = _borderEffect; + } + } + + /// + /// Predefined keys of this dictionary. + /// + internal new class Keys : PdfAnnotation.Keys + { + /// + /// (Required) The default appearance string to be used in formatting the text. + /// + [KeyInfo(KeyType.String | KeyType.Required)] + public const string DA = "/DA"; + + /// + /// (Optional; PDF 1.4) A code specifying the form of quadding (justification) to be + /// used in displaying the annotation’s text: + /// 0 Left-justified + /// 1 Centered + /// 2 Right-justified + /// Default value: 0 (left-justified). + /// + [KeyInfo(KeyType.Integer | KeyType.Optional)] + public const string Q = "/Q"; + + /// + /// (Optional; PDF 1.5) Begining with PDF 1.5, some annotations (square, circle and polygon) may have + /// a BE entry, which is a border effect dictionary that specifies an effect to be applied + /// to the border of the annotations. + /// + [KeyInfo("1.5", KeyType.Dictionary | KeyType.Optional)] + public const string BE = "/BE"; + } + } +} diff --git a/src/PdfSharp/PdfSharp.csproj b/src/PdfSharp/PdfSharp.csproj index 6b370019..e99a35d8 100644 --- a/src/PdfSharp/PdfSharp.csproj +++ b/src/PdfSharp/PdfSharp.csproj @@ -173,6 +173,7 @@ + @@ -246,11 +247,15 @@ + + + +