Compare commits

..

5 Commits

Author SHA1 Message Date
Marcin Ziąbek 6c80c59996 Fixed misspelling in release notes 2021-09-01 19:19:16 +02:00
Marcin Ziąbek 08a37666fe 2021.9.1 2021-09-01 19:14:52 +02:00
Marcin Ziąbek c2fb68562d 2021.9.0 2021-08-30 23:37:44 +02:00
Marcin Ziąbek 683ab362d8 Added support for registering font types based on the suggestion of brendonparker 2021-08-29 20:15:12 +02:00
Marcin Ziąbek 04af33fc31 Included examples for DSL and complex layouts 2021-08-23 23:51:42 +02:00
11 changed files with 223 additions and 22 deletions
+32
View File
@@ -0,0 +1,32 @@
using System.IO;
using NUnit.Framework;
using QuestPDF.Drawing;
using QuestPDF.Examples.Engine;
using QuestPDF.Fluent;
using QuestPDF.Helpers;
using QuestPDF.Infrastructure;
namespace QuestPDF.Examples
{
public class BarCode
{
[Test]
public void Example()
{
FontManager.RegisterFontType("LibreBarcode39", File.OpenRead("LibreBarcode39-Regular.ttf"));
RenderingTest
.Create()
.PageSize(400, 100)
.FileName()
.Render(container =>
{
container
.Background(Colors.White)
.AlignCenter()
.AlignMiddle()
.Text("*QuestPDF*", TextStyle.Default.FontType("LibreBarcode39").Size(64));
});
}
}
}
+46
View File
@@ -0,0 +1,46 @@
using System.Diagnostics;
using System.Linq;
using NUnit.Framework;
using QuestPDF.Drawing;
using QuestPDF.Examples.Engine;
using QuestPDF.Fluent;
using QuestPDF.Helpers;
using QuestPDF.Infrastructure;
namespace QuestPDF.Examples
{
public class ContinuousPageDocument : IDocument
{
public DocumentMetadata GetMetadata() => DocumentMetadata.Default;
public void Compose(IDocumentContainer container)
{
container.Page(page =>
{
page.Margin(20);
page.ContinuousSize(150);
page.Header().Text("Header");
page.Content().PaddingVertical(10).Border(1).Padding(10).Stack(stack =>
{
foreach (var index in Enumerable.Range(1, 100))
stack.Item().Text($"Line {index}", TextStyle.Default.Color(Placeholders.Color()));
});
page.Footer().Text("Footer");
});
}
}
public class ContinuousPageExamples
{
[Test]
public void ContinuousPage()
{
var path = "example.pdf";
new ContinuousPageDocument().GeneratePdf(path);
Process.Start("explorer", path);
}
}
}
+78
View File
@@ -755,5 +755,83 @@ namespace QuestPDF.Examples
});
});
}
[Test]
public void ComplexLayout()
{
RenderingTest
.Create()
.PageSize(500, 225)
.FileName()
.Render(container =>
{
container
.Padding(25)
.Stack(stack =>
{
stack.Item().Row(row =>
{
row.RelativeColumn().LabelCell("Label 1");
row.RelativeColumn(3).Grid(grid =>
{
grid.Columns(3);
grid.Item(2).LabelCell("Label 2");
grid.Item().LabelCell("Label 3");
grid.Item(2).ValueCell().Text("Value 2");
grid.Item().ValueCell().Text("Value 3");
});
});
stack.Item().Row(row =>
{
row.RelativeColumn().ValueCell().Text("Value 1");
row.RelativeColumn(3).Grid(grid =>
{
grid.Columns(3);
grid.Item().LabelCell("Label 4");
grid.Item(2).LabelCell("Label 5");
grid.Item().ValueCell().Text("Value 4");
grid.Item(2).ValueCell().Text("Value 5");
});
});
stack.Item().Row(row =>
{
row.RelativeColumn().LabelCell("Label 6");
row.RelativeColumn().ValueCell().Text("Value 6");
});
});
});
}
[Test]
public void DomainSpecificLanguage()
{
RenderingTest
.Create()
.PageSize(600, 310)
.FileName()
.Render(container =>
{
container
.Padding(25)
.Grid(grid =>
{
grid.Columns(10);
for(var i=1; i<=4; i++)
{
grid.Item(2).LabelCell(Placeholders.Label());
grid.Item(3).ValueCell().Image(Placeholders.Image(200, 150));
}
});
});
}
}
}
+3 -3
View File
@@ -12,11 +12,11 @@ namespace QuestPDF.Examples
{
return container
.Border(1)
.Background(dark ? "#EEE" : "#FFF")
.Background(dark ? Colors.Grey.Lighten2 : Colors.White)
.Padding(10);
}
public static IContainer LabelCell(this IContainer container) => container.Cell(true);
public static void LabelCell(this IContainer container, string text) => container.Cell(true).Text(text, TextStyle.Default.Medium());
public static IContainer ValueCell(this IContainer container) => container.Cell(false);
}
@@ -40,7 +40,7 @@ namespace QuestPDF.Examples
{
stack.Item().Row(row =>
{
row.RelativeColumn(2).LabelCell().Text(Placeholders.Label());
row.RelativeColumn(2).LabelCell(Placeholders.Label());
row.RelativeColumn(3).ValueCell().Text(Placeholders.Paragraph());
});
}
Binary file not shown.
@@ -16,4 +16,10 @@
<ProjectReference Include="..\QuestPDF\QuestPDF.csproj" />
</ItemGroup>
<ItemGroup>
<None Update="LibreBarcode39-Regular.ttf">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>
@@ -1,15 +1,23 @@
using System.Collections.Concurrent;
using System;
using System.Collections.Concurrent;
using System.IO;
using QuestPDF.Drawing.SpacePlan;
using QuestPDF.Infrastructure;
using SkiaSharp;
namespace QuestPDF.Drawing
{
internal static class CanvasCache
public static class FontManager
{
private static ConcurrentDictionary<string, SKTypeface> Typefaces = new ConcurrentDictionary<string, SKTypeface>();
private static ConcurrentDictionary<string, SKPaint> Paints = new ConcurrentDictionary<string, SKPaint>();
private static ConcurrentDictionary<string, SKPaint> ColorPaint = new ConcurrentDictionary<string, SKPaint>();
public static void RegisterFontType(string fontName, Stream stream)
{
Typefaces.TryAdd(fontName, SKTypeface.FromStream(stream));
}
internal static SKPaint ColorToPaint(this string color)
{
return ColorPaint.GetOrAdd(color, Convert);
@@ -29,12 +37,10 @@ namespace QuestPDF.Drawing
static SKPaint Convert(TextStyle style)
{
var slant = style.IsItalic ? SKFontStyleSlant.Italic : SKFontStyleSlant.Upright;
return new SKPaint
{
Color = SKColor.Parse(style.Color),
Typeface = SKTypeface.FromFamilyName(style.FontType, (int)style.FontWeight, (int)SKFontStyleWidth.Normal, slant),
Typeface = GetTypeface(style),
TextSize = style.Size,
TextEncoding = SKTextEncoding.Utf32,
@@ -47,6 +53,17 @@ namespace QuestPDF.Drawing
}
};
}
static SKTypeface GetTypeface(TextStyle style)
{
if (Typefaces.TryGetValue(style.FontType, out var result))
return result;
var slant = style.IsItalic ? SKFontStyleSlant.Italic : SKFontStyleSlant.Upright;
return SKTypeface.FromFamilyName(style.FontType, (int)style.FontWeight, (int)SKFontStyleWidth.Normal, slant)
?? throw new ArgumentException($"The typeface {style.FontType} could not be found.");
}
}
internal static TextMeasurement BreakText(this TextStyle style, string text, float availableWidth)
+13 -1
View File
@@ -1,3 +1,4 @@
using System;
using QuestPDF.Fluent;
using QuestPDF.Helpers;
using QuestPDF.Infrastructure;
@@ -36,9 +37,20 @@ namespace QuestPDF.Elements
.Decoration(decoration =>
{
decoration.Header().Element(Header);
decoration.Content().Extend().Element(Content);
decoration
.Content()
.Element(x => IsClose(MinSize.Width, MaxSize.Width) ? x.ExtendHorizontal() : x)
.Element(x => IsClose(MinSize.Height, MaxSize.Height) ? x.ExtendVertical() : x)
.Element(Content);
decoration.Footer().Element(Footer);
});
bool IsClose(float x, float y)
{
return Math.Abs(x - y) < Size.Epsilon;
}
}
}
}
+4 -4
View File
@@ -18,10 +18,10 @@ namespace QuestPDF.Fluent
{
if (element?.Child != null && element.Child is Empty == false)
{
var message = $"Container {element.GetType().Name} already contains an {element.Child.GetType().Name} child. " +
$"Tried to assign {child?.GetType()?.Name}." +
$"You should not assign multiple elements to single-child containers.";
var message = "You should not assign multiple child elements to a single-child container. " +
"This may happen when a container variable is used outside of its scope/closure OR the container is used in multiple fluent API chains OR the container is used incorrectly in a loop. " +
"This exception is thrown to help you detect that some part of the code is overriding fragments of the document layout with a new content - essentially destroying existing content.";
throw new DocumentComposeException(message);
}
+15 -5
View File
@@ -12,14 +12,24 @@ namespace QuestPDF.Fluent
public void Size(PageSize pageSize)
{
Page.MinSize = pageSize;
Page.MaxSize = pageSize;
MinSize(pageSize);
MaxSize(pageSize);
}
public void ContinuousSize(float width)
{
Page.MinSize = new PageSize(width, 0);
Page.MaxSize = new PageSize(width, Infrastructure.Size.Max.Height);
MinSize(new PageSize(width, 0));
MaxSize(new PageSize(width, Infrastructure.Size.Max.Height));
}
public void MinSize(PageSize pageSize)
{
Page.MinSize = pageSize;
}
public void MaxSize(PageSize pageSize)
{
Page.MaxSize = pageSize;
}
public void MarginLeft(float value)
+4 -4
View File
@@ -4,9 +4,9 @@
<Authors>MarcinZiabek</Authors>
<Company>CodeFlint</Company>
<PackageId>QuestPDF</PackageId>
<Version>2021.8</Version>
<Version>2021.9.2</Version>
<PackageDescription>QuestPDF is an open-source, modern and battle-tested library that can help you with generating PDF documents by offering friendly, discoverable and predictable C# fluent API.</PackageDescription>
<PackageReleaseNotes>New elements: Unconstrained, Scale, ScaleHorizontal, ScaleVertical, FlipOver, FlipHorizontal, FlipVertical, Rotate, RotateLeft, RotateRight, TranslateX, TranslateY. Added support for more placeholders in the PageNumber element (current page, total number of pages, page number of any predefined location). Added support for documents with various page sizes. Various API improvements.</PackageReleaseNotes>
<PackageReleaseNotes>Added support for registering custom fonts from a stream. Fixed continuous page setting. Improved exception messages.</PackageReleaseNotes>
<LangVersion>8</LangVersion>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<PackageIcon>Logo.png</PackageIcon>
@@ -14,8 +14,8 @@
<PackageProjectUrl>https://www.questpdf.com/</PackageProjectUrl>
<RepositoryUrl>https://github.com/QuestPDF/library.git</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<Copyright>QuestPDF contributors</Copyright>
<PackageTags>PDF file export generate create render portable document format quest free</PackageTags>
<Copyright>Marcin Ziąbek, QuestPDF contributors</Copyright>
<PackageTags>pdf file export generate generation tool create creation render portable document format quest html library converter free</PackageTags>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<Nullable>enable</Nullable>
<TargetFrameworks>net462;netstandard2.0;netcoreapp2.0;netcoreapp3.0</TargetFrameworks>