move path class and add doc comments to document creation api

This commit is contained in:
Eliot Jones
2018-12-25 10:37:00 +00:00
parent ed3792c950
commit 9a1879829d
6 changed files with 129 additions and 39 deletions

View File

@@ -4,6 +4,7 @@
using System.Collections.Generic;
using System.Linq;
using Dictionaries;
using Geometry;
using Util;
using Util.JetBrains.Annotations;

View File

@@ -4,6 +4,7 @@
using System.Collections.Generic;
using System.Linq;
using Commands;
using Geometry;
using Util;
internal class Type1CharStrings

View File

@@ -1,7 +0,0 @@
namespace UglyToad.PdfPig.Geometry.Paths
{
internal class GeneralPath
{
// TODO: provide an implementation
}
}

View File

@@ -1,11 +1,10 @@
// ReSharper disable ArrangeRedundantParentheses
namespace UglyToad.PdfPig.Fonts
namespace UglyToad.PdfPig.Geometry
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Geometry;
internal class PdfPath
{

View File

@@ -15,6 +15,9 @@
using Util;
using Util.JetBrains.Annotations;
/// <summary>
/// Provides methods to construct new PDF documents.
/// </summary>
internal class PdfDocumentBuilder
{
private const byte Break = (byte)'\n';
@@ -23,12 +26,31 @@
private readonly Dictionary<int, PdfPageBuilder> pages = new Dictionary<int, PdfPageBuilder>();
private readonly Dictionary<Guid, FontStored> fonts = new Dictionary<Guid, FontStored>();
/// <summary>
/// Whether to include the document information dictionary in the produced document.
/// </summary>
public bool IncludeDocumentInformation { get; set; } = true;
/// <summary>
/// The values of the fields to include in the document information dictionary.
/// </summary>
public DocumentInformationBuilder DocumentInformation { get; } = new DocumentInformationBuilder();
/// <summary>
/// The current page builders in the document and the corresponding 1 indexed page numbers. Use <see cref="AddPage"/> to add a new page.
/// </summary>
public IReadOnlyDictionary<int, PdfPageBuilder> Pages => pages;
/// <summary>
/// The fonts currently available in the document builder added via <see cref="AddTrueTypeFont"/> or <see cref="AddStandard14Font"/>. Keyed by id for internal purposes.
/// </summary>
public IReadOnlyDictionary<Guid, IWritingFont> Fonts => fonts.ToDictionary(x => x.Key, x => x.Value.FontProgram);
/// <summary>
/// Determines whether the bytes of the TrueType font file provided can be used in a PDF document.
/// </summary>
/// <param name="fontFileBytes">The bytes of a TrueType font file.</param>
/// <param name="reasons">Any reason messages explaining why the file can't be used, if applicable.</param>
/// <returns><see langword="true"/> if the file can be used, <see langword="false"/> otherwise.</returns>
public bool CanUseTrueTypeFont(IReadOnlyList<byte> fontFileBytes, out IReadOnlyList<string> reasons)
{
var reasonsMutable = new List<string>();
@@ -76,6 +98,11 @@
}
}
/// <summary>
/// Adds a TrueType font to the builder so that pages in this document can use it.
/// </summary>
/// <param name="fontFileBytes">The bytes of a TrueType font.</param>
/// <returns>An identifier which can be passed to <see cref="PdfPageBuilder.AddText"/>.</returns>
public AddedFont AddTrueTypeFont(IReadOnlyList<byte> fontFileBytes)
{
try
@@ -94,6 +121,11 @@
}
}
/// <summary>
/// Adds one of the Standard 14 fonts which are included by default in PDF programs so that pages in this document can use it. These Standard 14 fonts are old and possibly obsolete.
/// </summary>
/// <param name="type">The type of the Standard 14 font to use.</param>
/// <returns>An identifier which can be passed to <see cref="PdfPageBuilder.AddText"/>.</returns>
public AddedFont AddStandard14Font(Standard14Font type)
{
var id = Guid.NewGuid();
@@ -104,6 +136,12 @@
return added;
}
/// <summary>
/// Add a new page with the specified size, this page will be included in the output when <see cref="Build"/> is called.
/// </summary>
/// <param name="size">The size of the page to add.</param>
/// <param name="isPortrait">Whether the page is in portait or landscape orientation.</param>
/// <returns>A builder for editing the new page.</returns>
public PdfPageBuilder AddPage(PageSize size, bool isPortrait = true)
{
if (!size.TryGetPdfRectangle(out var rectangle))
@@ -137,16 +175,10 @@
return builder;
}
public void Generate(Stream stream)
{
}
public void Generate(string fileName)
{
}
/// <summary>
/// Builds a PDF document from the current content of this builder and its pages.
/// </summary>
/// <returns>The bytes of the resulting PDF document.</returns>
public byte[] Build()
{
var context = new BuilderContext();

View File

@@ -13,23 +13,37 @@
using Graphics.Operations.TextShowing;
using Graphics.Operations.TextState;
/// <summary>
/// A builder used to add construct a page in a PDF document.
/// </summary>
internal class PdfPageBuilder
{
private readonly PdfDocumentBuilder documentBuilder;
private readonly List<IGraphicsStateOperation> operations = new List<IGraphicsStateOperation>();
private BeginText lastBeginText;
internal IReadOnlyList<IGraphicsStateOperation> Operations => operations;
/// <summary>
/// The number of this page, 1-indexed.
/// </summary>
public int PageNumber { get; }
public IReadOnlyList<IGraphicsStateOperation> Operations => operations;
/// <summary>
/// The current size of the page.
/// </summary>
public PdfRectangle PageSize { get; set; }
public PdfPageBuilder(int number, PdfDocumentBuilder documentBuilder)
internal PdfPageBuilder(int number, PdfDocumentBuilder documentBuilder)
{
this.documentBuilder = documentBuilder ?? throw new ArgumentNullException(nameof(documentBuilder));
PageNumber = number;
}
/// <summary>
/// Draws a line on the current page between two points with the specified line width.
/// </summary>
/// <param name="from">The first point on the line.</param>
/// <param name="to">The last point on the line.</param>
/// <param name="lineWidth">The width of the line in user space units.</param>
public void DrawLine(PdfPoint from, PdfPoint to, decimal lineWidth = 1)
{
if (lineWidth != 1)
@@ -47,6 +61,13 @@
}
}
/// <summary>
/// Draws a rectangle on the current page starting at the specified point with the given width, height and line width.
/// </summary>
/// <param name="position">The position of the rectangle, for positive width and height this is the top-left corner.</param>
/// <param name="width">The width of the rectangle.</param>
/// <param name="height">The height of the rectangle.</param>
/// <param name="lineWidth">The width of the line border of the rectangle.</param>
public void DrawRectangle(PdfPoint position, decimal width, decimal height, decimal lineWidth = 1)
{
if (lineWidth != 1)
@@ -63,7 +84,18 @@
}
}
public List<Letter> AddText(string text, decimal fontSize, PdfPoint position, PdfDocumentBuilder.AddedFont font)
/// <summary>
/// Calculates the size and position of each letter in a given string in the provided font without changing the state of the page.
/// </summary>
/// <param name="text">The text to measure each letter of.</param>
/// <param name="fontSize">The size of the font in user space units.</param>
/// <param name="position">The position of the baseline (lower-left corner) to start drawing the text from.</param>
/// <param name="font">
/// A font added to the document using <see cref="PdfDocumentBuilder.AddTrueTypeFont"/>
/// or <see cref="PdfDocumentBuilder.AddStandard14Font"/> methods.
/// </param>
/// <returns>The letters from the input text with their corresponding size and position.</returns>
public IReadOnlyList<Letter> MeasureText(string text, decimal fontSize, PdfPoint position, PdfDocumentBuilder.AddedFont font)
{
if (font == null)
{
@@ -91,24 +123,56 @@
var textMatrix = TransformationMatrix.FromValues(1, 0, 0, 1, position.X, position.Y);
var letters = DrawLetters(text, fontProgram, fm, fontSize, textMatrix);
try
{
var beginText = BeginText.Value;
operations.Add(beginText);
operations.Add(new SetFontAndSize(font.Name, fontSize));
operations.Add(new MoveToNextLineWithOffset(position.X, position.Y));
operations.Add(new ShowText(text));
operations.Add(EndText.Value);
return letters;
}
beginText = null;
}
catch (Exception ex)
/// <summary>
/// Draws the text in the provided font at the specified position and returns the letters which will be drawn.
/// </summary>
/// <param name="text">The text to draw to the page.</param>
/// <param name="fontSize">The size of the font in user space units.</param>
/// <param name="position">The position of the baseline (lower-left corner) to start drawing the text from.</param>
/// <param name="font">
/// A font added to the document using <see cref="PdfDocumentBuilder.AddTrueTypeFont"/>
/// or <see cref="PdfDocumentBuilder.AddStandard14Font"/> methods.
/// </param>
/// <returns>The letters from the input text with their corresponding size and position.</returns>
public IReadOnlyList<Letter> AddText(string text, decimal fontSize, PdfPoint position, PdfDocumentBuilder.AddedFont font)
{
if (font == null)
{
throw;
throw new ArgumentNullException(nameof(font));
}
if (text == null)
{
throw new ArgumentNullException(nameof(text));
}
if (!documentBuilder.Fonts.TryGetValue(font.Id, out var fontProgram))
{
throw new ArgumentException($"No font has been added to the PdfDocumentBuilder with Id: {font.Id}. " +
$"Use {nameof(documentBuilder.AddTrueTypeFont)} to register a font.", nameof(font));
}
if (fontSize <= 0)
{
throw new ArgumentOutOfRangeException(nameof(fontSize), "Font size must be greater than 0");
}
var fm = fontProgram.GetFontMatrix();
var textMatrix = TransformationMatrix.FromValues(1, 0, 0, 1, position.X, position.Y);
var letters = DrawLetters(text, fontProgram, fm, fontSize, textMatrix);
operations.Add(BeginText.Value);
operations.Add(new SetFontAndSize(font.Name, fontSize));
operations.Add(new MoveToNextLineWithOffset(position.X, position.Y));
operations.Add(new ShowText(text));
operations.Add(EndText.Value);
return letters;
}
@@ -127,7 +191,7 @@
{
var c = text[i];
if(!font.TryGetBoundingBox(c, out var rect))
if (!font.TryGetBoundingBox(c, out var rect))
{
throw new InvalidOperationException($"The font does not contain a character: {c}.");
}
@@ -144,7 +208,7 @@
var letter = new Letter(c.ToString(), documentSpace, advanceRect.BottomLeft, width, fontSize, font.Name, fontSize);
letters.Add(letter);
var tx = advanceRect.Width * horizontalScaling;
var ty = 0;