From d9052e138872aa9f636bc9201b5d3e956ea35f80 Mon Sep 17 00:00:00 2001 From: Eliot Jones Date: Fri, 28 Dec 2018 16:55:46 +0000 Subject: [PATCH] update readme and document public api for document creation --- README.md | 58 +++++++++++++++++ .../PublicApiScannerTests.cs | 4 ++ .../Writer/PdfDocumentBuilderTests.cs | 4 +- .../Content/DocumentInformation.cs | 2 +- src/UglyToad.PdfPig/Fonts/Standard14.cs | 18 ----- src/UglyToad.PdfPig/Fonts/Standard14Font.cs | 65 +++++++++++++++++++ .../Fonts/TrueType/Tables/KerningTable.cs | 2 + .../Writer/PdfDocumentBuilder.cs | 49 ++++++++++++-- src/UglyToad.PdfPig/Writer/PdfPageBuilder.cs | 2 +- src/UglyToad.PdfPig/Writer/TokenWriter.cs | 33 +++++++--- 10 files changed, 202 insertions(+), 35 deletions(-) create mode 100644 src/UglyToad.PdfPig/Fonts/Standard14Font.cs diff --git a/README.md b/README.md index 0eef0692..efdc59fa 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,23 @@ The simplest usage at this stage is to open a document, reading the words from e } } +New in v0.0.5 - To create documents use the class ```PdfDocumentBuilder```. Though they are deprecated within the PDF specification the Standard 14 fonts provide a quick way to get started: + + PdfDocumentBuilder builder = new PdfDocumentBuilder(); + + PdfPageBuilder page = builder.AddPage(PageSize.A4); + + // Fonts must be registered with the document builder prior to use to prevent duplication. + PdfDocumentBuilder.AddedFont font = builder.AddStandard14Font(Standard14Font.Helvetica); + + page.AddText("Hello World!", 12, new PdfPoint(25, 520), font); + + byte[] documentBytes = builder.Build(); + + File.WriteAllBytes(@"C:\\git\newPdf.pdf"); + +Each font must be registered with the PdfDocumentBuilder prior to use enable pages to share the font resources. Currently only Standard 14 fonts and TrueType fonts (.ttf) are supported. + ## Installation ## The package is available via the releases tab or from Nuget: @@ -71,6 +88,47 @@ The document contains the version of the PDF specification it complies with, acc decimal version = document.Version; +### Document Creation ### + +New in v0.0.5 - The ```PdfDocumentBuilder``` creates a new document with no pages or content. First, for text content, a font must be registered with the builder. Currently this supports Standard 14 fonts provided by Adobe by default and TrueType format fonts. + +To add a Standard 14 font use: + + public AddedFont AddStandard14Font(Standard14Font type) + +Or for a TrueType font use: + + AddedFont AddTrueTypeFont(IReadOnlyList fontFileBytes) + +Passing in the bytes of a TrueType file (.ttf). You can check the suitability of a TrueType file for embedding in a PDF document using: + + bool CanUseTrueTypeFont(IReadOnlyList fontFileBytes, out IReadOnlyList reasons) + +Which provides a list of reasons why the font cannot be used if the check fails. You should check the license for a TrueType font prior to use, since the compressed font file is embedded in, and distributed with, the resultant document. + +The ```AddedFont``` class represents a key to the font stored on the document builder. This must be provided when adding text content to pages. To add a page to a document use: + + PdfPageBuilder AddPage(PageSize size, bool isPortrait = true) + +This creates a new ```PdfPageBuilder``` with the specified size. The first added page is page number 1, then 2, then 3, etc. The page builder supports adding text, drawing lines and rectangles and measuring the size of text prior to drawing. + +To draw lines and rectangles in black (different colors are not currently supported) use the methods: + + void DrawLine(PdfPoint from, PdfPoint to, decimal lineWidth = 1) + void DrawRectangle(PdfPoint position, decimal width, decimal height, decimal lineWidth = 1) + +The line width can be varied and defaults to 1. + +To write text to the page you must have a reference to an ```AddedFont``` from the methods on ```PdfDocumentBuilder``` as described above. You can then draw the text to the page using: + + IReadOnlyList AddText(string text, decimal fontSize, PdfPoint position, PdfDocumentBuilder.AddedFont font) + +Where ```position``` is the baseline of the text to draw. Currently **only ASCII text is supported** and the text will be drawn in black and the color cannot be varied. You can also measure the resulting size of text prior to drawing using the method: + + IReadOnlyList MeasureText(string text, decimal fontSize, PdfPoint position, PdfDocumentBuilder.AddedFont font) + +Which does not change the state of the page, unlike ```AddText```. + ### Document Information ### The ```PdfDocument``` provides access to the document metadata as ```DocumentInformation``` defined in the PDF file. These tend not to be provided therefore most of these entries will be ```null```: diff --git a/src/UglyToad.PdfPig.Tests/PublicApiScannerTests.cs b/src/UglyToad.PdfPig.Tests/PublicApiScannerTests.cs index a1d47dfa..f57f535b 100644 --- a/src/UglyToad.PdfPig.Tests/PublicApiScannerTests.cs +++ b/src/UglyToad.PdfPig.Tests/PublicApiScannerTests.cs @@ -50,6 +50,7 @@ "UglyToad.PdfPig.Fonts.FontDescriptor", "UglyToad.PdfPig.Fonts.FontDescriptorFlags", "UglyToad.PdfPig.Fonts.FontStretch", + "UglyToad.PdfPig.Fonts.Standard14Font", "UglyToad.PdfPig.Tokens.ArrayToken", "UglyToad.PdfPig.Tokens.BooleanToken", "UglyToad.PdfPig.Tokens.CommentToken", @@ -65,6 +66,9 @@ "UglyToad.PdfPig.Tokens.StreamToken", "UglyToad.PdfPig.Tokens.StringToken", "UglyToad.PdfPig.Util.IWordExtractor", + "UglyToad.PdfPig.Writer.PdfDocumentBuilder", + "UglyToad.PdfPig.Writer.PdfPageBuilder", + "UglyToad.PdfPig.Writer.TokenWriter", "UglyToad.PdfPig.XObjects.XObjectImage" }; diff --git a/src/UglyToad.PdfPig.Tests/Writer/PdfDocumentBuilderTests.cs b/src/UglyToad.PdfPig.Tests/Writer/PdfDocumentBuilderTests.cs index 5746b1fa..db2c6096 100644 --- a/src/UglyToad.PdfPig.Tests/Writer/PdfDocumentBuilderTests.cs +++ b/src/UglyToad.PdfPig.Tests/Writer/PdfDocumentBuilderTests.cs @@ -68,9 +68,9 @@ { var builder = new PdfDocumentBuilder(); - var page = builder.AddPage(PageSize.A4); + PdfPageBuilder page = builder.AddPage(PageSize.A4); - var font = builder.AddStandard14Font(Standard14Font.Helvetica); + PdfDocumentBuilder.AddedFont font = builder.AddStandard14Font(Standard14Font.Helvetica); page.AddText("Hello World!", 12, new PdfPoint(25, 520), font); diff --git a/src/UglyToad.PdfPig/Content/DocumentInformation.cs b/src/UglyToad.PdfPig/Content/DocumentInformation.cs index 56beacfc..747fcb7c 100644 --- a/src/UglyToad.PdfPig/Content/DocumentInformation.cs +++ b/src/UglyToad.PdfPig/Content/DocumentInformation.cs @@ -38,7 +38,7 @@ public string Keywords { get; } /// - /// The name of the application which created the original document before it was converted to PDF. if applicable. + /// The name of the application which created the original document before it was converted to PDF if applicable. /// [CanBeNull] public string Creator { get; } diff --git a/src/UglyToad.PdfPig/Fonts/Standard14.cs b/src/UglyToad.PdfPig/Fonts/Standard14.cs index b9a6febb..05b33ade 100644 --- a/src/UglyToad.PdfPig/Fonts/Standard14.cs +++ b/src/UglyToad.PdfPig/Fonts/Standard14.cs @@ -167,22 +167,4 @@ return mappedName; } } - - internal enum Standard14Font - { - TimesRoman = 0, - TimesBold = 1, - TimesItalic=2, - TimesBoldItalic = 3, - Helvetica = 4, - HelveticaBold = 5, - HelveticaOblique = 6, - HelveticaBoldOblique = 7, - Courier = 8, - CourierBold = 9, - CourierOblique = 10, - CourierBoldOblique = 11, - Symbol = 12, - ZapfDingbats = 13 - } } diff --git a/src/UglyToad.PdfPig/Fonts/Standard14Font.cs b/src/UglyToad.PdfPig/Fonts/Standard14Font.cs new file mode 100644 index 00000000..f41843df --- /dev/null +++ b/src/UglyToad.PdfPig/Fonts/Standard14Font.cs @@ -0,0 +1,65 @@ +namespace UglyToad.PdfPig.Fonts +{ + /// + /// The Standard 14 fonts included by default in PDF readers. + /// + public enum Standard14Font + { + /// + /// Times New Roman. + /// + TimesRoman = 0, + /// + /// Times New Roman Bold. + /// + TimesBold = 1, + /// + /// Times New Roman Italic. + /// + TimesItalic = 2, + /// + /// Times New Roman Bold and Italic. + /// + TimesBoldItalic = 3, + /// + /// Helvetica. + /// + Helvetica = 4, + /// + /// Helvetica Bold. + /// + HelveticaBold = 5, + /// + /// Helvetica Oblique (Italic without different font shapes). + /// + HelveticaOblique = 6, + /// + /// Helvetica Bold and Oblique. + /// + HelveticaBoldOblique = 7, + /// + /// Courier. + /// + Courier = 8, + /// + /// Courier Bold. + /// + CourierBold = 9, + /// + /// Courier Oblique. + /// + CourierOblique = 10, + /// + /// Courier Bold and Oblique. + /// + CourierBoldOblique = 11, + /// + /// Symbol. + /// + Symbol = 12, + /// + /// Zapf Dingbats. + /// + ZapfDingbats = 13 + } +} \ No newline at end of file diff --git a/src/UglyToad.PdfPig/Fonts/TrueType/Tables/KerningTable.cs b/src/UglyToad.PdfPig/Fonts/TrueType/Tables/KerningTable.cs index ed5773a1..764be4f8 100644 --- a/src/UglyToad.PdfPig/Fonts/TrueType/Tables/KerningTable.cs +++ b/src/UglyToad.PdfPig/Fonts/TrueType/Tables/KerningTable.cs @@ -87,6 +87,7 @@ // TODO: Implement and test this; return null; +#pragma warning disable 162 var rowWidth = data.ReadUnsignedShort(); var leftClassTableOffset = data.ReadUnsignedShort(); @@ -135,6 +136,7 @@ } return new KerningSubTable(version, coverage, pairs); +#pragma warning restore 162 } } } diff --git a/src/UglyToad.PdfPig/Writer/PdfDocumentBuilder.cs b/src/UglyToad.PdfPig/Writer/PdfDocumentBuilder.cs index 55bf43bd..6303ac70 100644 --- a/src/UglyToad.PdfPig/Writer/PdfDocumentBuilder.cs +++ b/src/UglyToad.PdfPig/Writer/PdfDocumentBuilder.cs @@ -18,7 +18,7 @@ /// /// Provides methods to construct new PDF documents. /// - internal class PdfDocumentBuilder + public class PdfDocumentBuilder { private static readonly TrueTypeFontParser Parser = new TrueTypeFontParser(); @@ -29,6 +29,7 @@ /// Whether to include the document information dictionary in the produced document. /// public bool IncludeDocumentInformation { get; set; } = true; + /// /// The values of the fields to include in the document information dictionary. /// @@ -42,7 +43,7 @@ /// /// The fonts currently available in the document builder added via or . Keyed by id for internal purposes. /// - public IReadOnlyDictionary Fonts => fonts.ToDictionary(x => x.Key, x => x.Value.FontProgram); + internal IReadOnlyDictionary Fonts => fonts.ToDictionary(x => x.Key, x => x.Value.FontProgram); /// /// Determines whether the bytes of the TrueType font file provided can be used in a PDF document. @@ -340,12 +341,25 @@ } } + /// + /// A key representing a font available to use on the current document builder. Create by adding a font to a document using either + /// or . + /// public class AddedFont { - public Guid Id { get; } + /// + /// The Id uniquely identifying this font on the builder. + /// + internal Guid Id { get; } + /// + /// The name of this font. + /// public NameToken Name { get; } + /// + /// Create a new . + /// internal AddedFont(Guid id, NameToken name) { Id = id; @@ -353,13 +367,40 @@ } } - internal class DocumentInformationBuilder + /// + /// Sets the values of the dictionary for the document being created. + /// Control inclusion of the document information dictionary on the output with . + /// + public class DocumentInformationBuilder { + /// + /// . + /// public string Title { get; set; } + + /// + /// . + /// public string Author { get; set; } + + /// + /// . + /// public string Subject { get; set; } + + /// + /// . + /// public string Keywords { get; set; } + + /// + /// . + /// public string Creator { get; set; } + + /// + /// . + /// public string Producer { get; set; } = "PdfPig"; internal Dictionary ToDictionary() diff --git a/src/UglyToad.PdfPig/Writer/PdfPageBuilder.cs b/src/UglyToad.PdfPig/Writer/PdfPageBuilder.cs index aeb50f91..fd56af59 100644 --- a/src/UglyToad.PdfPig/Writer/PdfPageBuilder.cs +++ b/src/UglyToad.PdfPig/Writer/PdfPageBuilder.cs @@ -16,7 +16,7 @@ /// /// A builder used to add construct a page in a PDF document. /// - internal class PdfPageBuilder + public class PdfPageBuilder { private readonly PdfDocumentBuilder documentBuilder; private readonly List operations = new List(); diff --git a/src/UglyToad.PdfPig/Writer/TokenWriter.cs b/src/UglyToad.PdfPig/Writer/TokenWriter.cs index 237a35bc..3694efa0 100644 --- a/src/UglyToad.PdfPig/Writer/TokenWriter.cs +++ b/src/UglyToad.PdfPig/Writer/TokenWriter.cs @@ -8,7 +8,10 @@ using Tokens; using Util; - internal class TokenWriter + /// + /// Writes any type of to the corresponding PDF document format output. + /// + public class TokenWriter { private static readonly byte ArrayStart = GetByte("["); private static readonly byte ArrayEnd = GetByte("]"); @@ -52,6 +55,11 @@ private static readonly byte[] Xref = OtherEncodings.StringAsLatin1Bytes("xref"); + /// + /// Writes the given input token to the output stream with the correct PDF format and encoding including whitespace and line breaks as applicable. + /// + /// The token to write to the stream. + /// The stream to write the token to. public static void WriteToken(IToken token, Stream outputStream) { switch (token) @@ -96,14 +104,14 @@ } } - private static void WriteHex(HexToken hex, Stream stream) - { - stream.WriteByte(HexStart); - stream.WriteText(hex.GetHexString()); - stream.WriteByte(HexEnd); - } - - public static void WriteCrossReferenceTable(IReadOnlyDictionary objectOffsets, + /// + /// Writes a valid single section cross-reference (xref) table plus trailer dictionary to the output for the set of object offsets. + /// + /// The byte offset from the start of the document for each object in the document. + /// The object representing the catalog dictionary which is referenced from the trailer dictionary. + /// The output stream to write to. + /// The object reference for the document information dictionary if present. + internal static void WriteCrossReferenceTable(IReadOnlyDictionary objectOffsets, ObjectToken catalogToken, Stream outputStream, IndirectReference? documentInformationReference) @@ -198,6 +206,13 @@ outputStream.Write(Eof, 0, Eof.Length); } + private static void WriteHex(HexToken hex, Stream stream) + { + stream.WriteByte(HexStart); + stream.WriteText(hex.GetHexString()); + stream.WriteByte(HexEnd); + } + private static void WriteArray(ArrayToken array, Stream outputStream) { outputStream.WriteByte(ArrayStart);