Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6c80c59996 | |||
| 08a37666fe | |||
| c2fb68562d | |||
| 683ab362d8 | |||
| 04af33fc31 | |||
| 7f94ae589a | |||
| adfce6204e | |||
| 6d3c8d0708 | |||
| 3b8c300126 | |||
| 20fe49dd01 | |||
| 7cdc1fcee2 | |||
| c05c5e1597 |
@@ -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));
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,7 @@ namespace QuestPDF.Examples
|
||||
RenderingTest
|
||||
.Create()
|
||||
.PageSize(200, 150)
|
||||
.FileName()
|
||||
.Render(container =>
|
||||
{
|
||||
container
|
||||
@@ -33,6 +34,7 @@ namespace QuestPDF.Examples
|
||||
RenderingTest
|
||||
.Create()
|
||||
.PageSize(300, 300)
|
||||
.FileName()
|
||||
.Render(container =>
|
||||
{
|
||||
container
|
||||
@@ -55,49 +57,14 @@ namespace QuestPDF.Examples
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// [Test]
|
||||
// public void Page()
|
||||
// {
|
||||
// RenderingTest
|
||||
// .Create()
|
||||
// .PageSize(298, 421)
|
||||
// .Render(container =>
|
||||
// {
|
||||
// container
|
||||
// .Background("#FFF")
|
||||
// .Padding(15)
|
||||
// .Page(page =>
|
||||
// {
|
||||
// page.Header()
|
||||
// .Height(60)
|
||||
// .Background(Colors.Grey.Lighten1)
|
||||
// .AlignCenter()
|
||||
// .AlignMiddle()
|
||||
// .Text("Header");
|
||||
//
|
||||
// page.Content()
|
||||
// .Background(Colors.Grey.Lighten2)
|
||||
// .AlignCenter()
|
||||
// .AlignMiddle()
|
||||
// .Text("Content");
|
||||
//
|
||||
// page.Footer()
|
||||
// .Height(30)
|
||||
// .Background(Colors.Grey.Lighten1)
|
||||
// .AlignCenter()
|
||||
// .AlignMiddle()
|
||||
// .Text("Footer");
|
||||
// });
|
||||
// });
|
||||
// }
|
||||
|
||||
|
||||
[Test]
|
||||
public void Row()
|
||||
{
|
||||
RenderingTest
|
||||
.Create()
|
||||
.PageSize(740, 200)
|
||||
.FileName()
|
||||
.Render(container =>
|
||||
{
|
||||
container
|
||||
@@ -138,6 +105,7 @@ namespace QuestPDF.Examples
|
||||
RenderingTest
|
||||
.Create()
|
||||
.PageSize(740, 200)
|
||||
.FileName()
|
||||
.Render(container =>
|
||||
{
|
||||
container
|
||||
@@ -159,6 +127,7 @@ namespace QuestPDF.Examples
|
||||
RenderingTest
|
||||
.Create()
|
||||
.PageSize(500, 360)
|
||||
.FileName()
|
||||
.Render(container =>
|
||||
{
|
||||
container
|
||||
@@ -181,6 +150,7 @@ namespace QuestPDF.Examples
|
||||
RenderingTest
|
||||
.Create()
|
||||
.PageSize(210, 210)
|
||||
.FileName()
|
||||
.Render(container =>
|
||||
{
|
||||
container
|
||||
@@ -203,6 +173,7 @@ namespace QuestPDF.Examples
|
||||
RenderingTest
|
||||
.Create()
|
||||
.PageSize(300, 200)
|
||||
.FileName()
|
||||
.Render(container =>
|
||||
{
|
||||
var text = "";
|
||||
@@ -225,6 +196,7 @@ namespace QuestPDF.Examples
|
||||
RenderingTest
|
||||
.Create()
|
||||
.PageSize(400, 230)
|
||||
.FileName()
|
||||
.Render(container =>
|
||||
{
|
||||
var textStyle = TextStyle.Default.Size(14);
|
||||
@@ -259,6 +231,7 @@ namespace QuestPDF.Examples
|
||||
RenderingTest
|
||||
.Create()
|
||||
.PageSize(300, 200)
|
||||
.FileName()
|
||||
.Render(container =>
|
||||
{
|
||||
container
|
||||
@@ -288,6 +261,7 @@ namespace QuestPDF.Examples
|
||||
RenderingTest
|
||||
.Create()
|
||||
.PageSize(400, 250)
|
||||
.FileName()
|
||||
.Render(container =>
|
||||
{
|
||||
container
|
||||
@@ -363,6 +337,7 @@ namespace QuestPDF.Examples
|
||||
RenderingTest
|
||||
.Create()
|
||||
.PageSize(300, 300)
|
||||
.FileName()
|
||||
.Render(container =>
|
||||
{
|
||||
container
|
||||
@@ -407,6 +382,7 @@ namespace QuestPDF.Examples
|
||||
RenderingTest
|
||||
.Create()
|
||||
.PageSize(450, 150)
|
||||
.FileName()
|
||||
.Render(container =>
|
||||
{
|
||||
container
|
||||
@@ -439,6 +415,7 @@ namespace QuestPDF.Examples
|
||||
RenderingTest
|
||||
.Create()
|
||||
.PageSize(500, 175)
|
||||
.FileName()
|
||||
.Render(container =>
|
||||
{
|
||||
container
|
||||
@@ -465,6 +442,7 @@ namespace QuestPDF.Examples
|
||||
RenderingTest
|
||||
.Create()
|
||||
.PageSize(300, 300)
|
||||
.FileName()
|
||||
.Render(container =>
|
||||
{
|
||||
container
|
||||
@@ -504,6 +482,7 @@ namespace QuestPDF.Examples
|
||||
RenderingTest
|
||||
.Create()
|
||||
.PageSize(300, 150)
|
||||
.FileName()
|
||||
.Render(container =>
|
||||
{
|
||||
container
|
||||
@@ -523,21 +502,25 @@ namespace QuestPDF.Examples
|
||||
{
|
||||
RenderingTest
|
||||
.Create()
|
||||
.PageSize(400, 400)
|
||||
.PageSize(400, 250)
|
||||
.FileName()
|
||||
.Render(container =>
|
||||
{
|
||||
var style = TextStyle.Default.Size(20);
|
||||
|
||||
container
|
||||
.Background("#FFF")
|
||||
.Padding(25)
|
||||
.Stack(stack =>
|
||||
{
|
||||
stack.Spacing(5);
|
||||
stack.Item().Background(Placeholders.BackgroundColor()).Scale(0.5f).Text("Smaller text", style);
|
||||
stack.Item().Background(Placeholders.BackgroundColor()).Text("Normal text", style);
|
||||
stack.Item().Background(Placeholders.BackgroundColor()).Scale(2f).Text("Bigger text", style);
|
||||
stack.Item().Background(Placeholders.BackgroundColor()).Scale(-1.5f).Text("Flipped text", style);
|
||||
var scales = new[] { 0.75f, 1f, 1.25f, 1.5f };
|
||||
|
||||
foreach (var scale in scales)
|
||||
{
|
||||
stack
|
||||
.Item()
|
||||
.Border(1)
|
||||
.Scale(scale)
|
||||
.Padding(10)
|
||||
.Text($"Content with {scale} scale.", TextStyle.Default.Size(20));
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -547,31 +530,39 @@ namespace QuestPDF.Examples
|
||||
{
|
||||
RenderingTest
|
||||
.Create()
|
||||
.PageSize(500, 300)
|
||||
.PageSize(300, 200)
|
||||
.FileName()
|
||||
.Render(container =>
|
||||
{
|
||||
container
|
||||
.Background("#FFF")
|
||||
.Padding(25)
|
||||
.Box()
|
||||
.Background(Colors.Green.Lighten4)
|
||||
.Padding(5)
|
||||
|
||||
.Padding(25)
|
||||
|
||||
.Background(Colors.Green.Lighten3)
|
||||
|
||||
.TranslateX(15)
|
||||
.TranslateY(15)
|
||||
.Text("Text outside of bounds");
|
||||
|
||||
.Border(2)
|
||||
.BorderColor(Colors.Green.Darken1)
|
||||
|
||||
.Padding(50)
|
||||
.Text("Moved text", TextStyle.Default.Size(25));
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Rotate()
|
||||
public void ConstrainedRotate()
|
||||
{
|
||||
RenderingTest
|
||||
.Create()
|
||||
.PageSize(450, 450)
|
||||
.PageSize(350, 350)
|
||||
.FileName()
|
||||
.Render(container =>
|
||||
{
|
||||
container
|
||||
.Background("#FFF")
|
||||
.Padding(20)
|
||||
.Grid(grid =>
|
||||
{
|
||||
@@ -581,11 +572,10 @@ namespace QuestPDF.Examples
|
||||
foreach (var turns in Enumerable.Range(0, 4))
|
||||
{
|
||||
grid.Item()
|
||||
.Width(200)
|
||||
.Height(200)
|
||||
.Background(Colors.Grey.Lighten3)
|
||||
.Width(150)
|
||||
.Height(150)
|
||||
.Background(Colors.Grey.Lighten2)
|
||||
.Padding(10)
|
||||
//.Box()
|
||||
.Element(element =>
|
||||
{
|
||||
foreach (var x in Enumerable.Range(0, turns))
|
||||
@@ -594,23 +584,83 @@ namespace QuestPDF.Examples
|
||||
return element;
|
||||
})
|
||||
.Box()
|
||||
.Background(Colors.Grey.Lighten1)
|
||||
.Text($"Rotated {turns * 90} degrees.", TextStyle.Default.Size(14));
|
||||
.Background(Colors.White)
|
||||
.Padding(10)
|
||||
.Text($"Rotated {turns * 90}°", TextStyle.Default.Size(16));
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void FreeRotate()
|
||||
{
|
||||
RenderingTest
|
||||
.Create()
|
||||
.PageSize(300, 300)
|
||||
.FileName()
|
||||
.Render(container =>
|
||||
{
|
||||
container
|
||||
.Padding(25)
|
||||
.Background(Colors.Grey.Lighten2)
|
||||
|
||||
.AlignCenter()
|
||||
.AlignMiddle()
|
||||
|
||||
|
||||
.Background(Colors.White)
|
||||
|
||||
.Rotate(30)
|
||||
|
||||
.Width(100)
|
||||
.Height(100)
|
||||
.Background(Colors.Blue.Medium);
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void FreeRotateCenter()
|
||||
{
|
||||
RenderingTest
|
||||
.Create()
|
||||
.PageSize(300, 300)
|
||||
.FileName()
|
||||
.Render(container =>
|
||||
{
|
||||
container
|
||||
.Padding(25)
|
||||
.Background(Colors.Grey.Lighten2)
|
||||
|
||||
.AlignCenter()
|
||||
.AlignMiddle()
|
||||
|
||||
.Background(Colors.White)
|
||||
|
||||
.TranslateX(50)
|
||||
.TranslateY(50)
|
||||
|
||||
.Rotate(30)
|
||||
|
||||
.TranslateX(-50)
|
||||
.TranslateY(-50)
|
||||
|
||||
.Width(100)
|
||||
.Height(100)
|
||||
.Background(Colors.Blue.Medium);
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Flip()
|
||||
{
|
||||
RenderingTest
|
||||
.Create()
|
||||
.PageSize(450, 450)
|
||||
.PageSize(350, 350)
|
||||
.FileName()
|
||||
.Render(container =>
|
||||
{
|
||||
container
|
||||
.Background("#FFF")
|
||||
.Padding(20)
|
||||
.Grid(grid =>
|
||||
{
|
||||
@@ -620,21 +670,24 @@ namespace QuestPDF.Examples
|
||||
foreach (var turns in Enumerable.Range(0, 4))
|
||||
{
|
||||
grid.Item()
|
||||
.Width(200)
|
||||
.Height(200)
|
||||
.Width(150)
|
||||
.Height(150)
|
||||
.Background(Colors.Grey.Lighten3)
|
||||
.Padding(10)
|
||||
.Element(element =>
|
||||
{
|
||||
if (turns == 1 || turns == 2)
|
||||
element = element.FlipX();
|
||||
element = element.FlipHorizontal();
|
||||
|
||||
if (turns == 2 || turns == 3)
|
||||
element = element.FlipY();
|
||||
element = element.FlipVertical();
|
||||
|
||||
return element;
|
||||
})
|
||||
.Text($"Flipped.", TextStyle.Default.Size(14));
|
||||
.Box()
|
||||
.Background(Colors.White)
|
||||
.Padding(10)
|
||||
.Text($"Flipped {turns}", TextStyle.Default.Size(16));
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -646,9 +699,11 @@ namespace QuestPDF.Examples
|
||||
RenderingTest
|
||||
.Create()
|
||||
.PageSize(200, 200)
|
||||
.FileName()
|
||||
.Render(container =>
|
||||
{
|
||||
container
|
||||
.Padding(10)
|
||||
.Border(2)
|
||||
.Row(row =>
|
||||
{
|
||||
@@ -663,5 +718,120 @@ namespace QuestPDF.Examples
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Unconstrained()
|
||||
{
|
||||
RenderingTest
|
||||
.Create()
|
||||
.PageSize(400, 350)
|
||||
.FileName()
|
||||
.Render(container =>
|
||||
{
|
||||
container
|
||||
.Padding(25)
|
||||
.PaddingLeft(75)
|
||||
.Stack(stack =>
|
||||
{
|
||||
stack.Item().Width(300).Height(150).Background(Colors.Blue.Lighten4);
|
||||
|
||||
stack
|
||||
.Item()
|
||||
|
||||
// creates an infinite space for its child
|
||||
.Unconstrained()
|
||||
|
||||
// moves the child up and left
|
||||
.TranslateX(-50)
|
||||
.TranslateY(-50)
|
||||
|
||||
// limits the space for the child
|
||||
.Width(100)
|
||||
.Height(100)
|
||||
|
||||
.Background(Colors.Blue.Darken1);
|
||||
|
||||
stack.Item().Width(300).Height(150).Background(Colors.Blue.Lighten3);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
[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));
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.CompilerServices;
|
||||
using QuestPDF.Drawing;
|
||||
using QuestPDF.Elements;
|
||||
using QuestPDF.Fluent;
|
||||
@@ -23,7 +24,7 @@ namespace QuestPDF.Examples.Engine
|
||||
return new RenderingTest();
|
||||
}
|
||||
|
||||
public RenderingTest FileName(string fileName)
|
||||
public RenderingTest FileName([CallerMemberName] string fileName = "test")
|
||||
{
|
||||
FileNamePrefix = fileName;
|
||||
return this;
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace QuestPDF.Examples.Engine
|
||||
container.Page(page =>
|
||||
{
|
||||
page.Size(new PageSize(Size.Width, Size.Height));
|
||||
page.Content().Container().Element(Container as Container);
|
||||
page.Content().Container().Background(Colors.White).Element(Container as Container);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ namespace QuestPDF.Examples
|
||||
RenderingTest
|
||||
.Create()
|
||||
.PageSize(550, 400)
|
||||
.FileName()
|
||||
.Render(container =>
|
||||
{
|
||||
container
|
||||
@@ -39,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.
@@ -36,6 +36,7 @@ namespace QuestPDF.Examples
|
||||
RenderingTest
|
||||
.Create()
|
||||
.PageSize(350, 280)
|
||||
.FileName()
|
||||
.Render(container =>
|
||||
{
|
||||
container
|
||||
|
||||
@@ -13,6 +13,7 @@ namespace QuestPDF.Examples
|
||||
RenderingTest
|
||||
.Create()
|
||||
.PageSize(200, 150)
|
||||
.FileName()
|
||||
.Render(container =>
|
||||
{
|
||||
container
|
||||
@@ -35,6 +36,7 @@ namespace QuestPDF.Examples
|
||||
RenderingTest
|
||||
.Create()
|
||||
.PageSize(200, 150)
|
||||
.FileName()
|
||||
.Render(container =>
|
||||
{
|
||||
container
|
||||
@@ -58,6 +60,7 @@ namespace QuestPDF.Examples
|
||||
RenderingTest
|
||||
.Create()
|
||||
.PageSize(200, 150)
|
||||
.FileName()
|
||||
.Render(container =>
|
||||
{
|
||||
container
|
||||
@@ -108,6 +111,7 @@ namespace QuestPDF.Examples
|
||||
RenderingTest
|
||||
.Create()
|
||||
.PageSize(200, 150)
|
||||
.FileName()
|
||||
.Render(container =>
|
||||
{
|
||||
container
|
||||
|
||||
@@ -16,4 +16,10 @@
|
||||
<ProjectReference Include="..\QuestPDF\QuestPDF.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="LibreBarcode39-Regular.ttf">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -25,17 +25,6 @@ namespace QuestPDF.ReportSample.Layouts
|
||||
public void Compose(IDocumentContainer container)
|
||||
{
|
||||
container
|
||||
// .Page(page =>
|
||||
// {
|
||||
// page.MarginVertical(40);
|
||||
// page.MarginHorizontal(50);
|
||||
//
|
||||
// page.ContinuousSize(PageSizes.A4.Width);
|
||||
//
|
||||
// page.Header().Element(ComposeHeader);
|
||||
// page.Content().Element(ComposeContent);
|
||||
// page.Footer().AlignCenter().PageNumber("Page A {number}");
|
||||
// })
|
||||
.Page(page =>
|
||||
{
|
||||
page.MarginVertical(40);
|
||||
|
||||
@@ -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)
|
||||
@@ -31,7 +31,6 @@ namespace QuestPDF.Drawing
|
||||
public override void BeginPage(Size size)
|
||||
{
|
||||
var scalingFactor = Metadata.RasterDpi / (float) PageSizes.PointsPerInch;
|
||||
|
||||
var imageInfo = new SKImageInfo((int) (size.Width * scalingFactor), (int) (size.Height * scalingFactor));
|
||||
|
||||
Surface = SKSurface.Create(imageInfo);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,57 +1,21 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using QuestPDF.Drawing.SpacePlan;
|
||||
using QuestPDF.Infrastructure;
|
||||
using QuestPDF.Infrastructure;
|
||||
|
||||
namespace QuestPDF.Elements
|
||||
{
|
||||
internal class Rotate : ContainerElement
|
||||
{
|
||||
public int TurnCount { get; set; }
|
||||
public int NormalizedTurnCount => (TurnCount % 4 + 4) % 4;
|
||||
|
||||
internal override ISpacePlan Measure(Size availableSpace)
|
||||
{
|
||||
if (NormalizedTurnCount == 0 || NormalizedTurnCount == 2)
|
||||
return base.Measure(availableSpace);
|
||||
|
||||
availableSpace = new Size(availableSpace.Height, availableSpace.Width);
|
||||
var childSpace = base.Measure(availableSpace) as Size;
|
||||
public float Angle { get; set; } = 0;
|
||||
|
||||
if (childSpace == null)
|
||||
return new Wrap();
|
||||
|
||||
var targetSpace = new Size(childSpace.Height, childSpace.Width);
|
||||
|
||||
if (childSpace is FullRender)
|
||||
return new FullRender(targetSpace);
|
||||
|
||||
if (childSpace is PartialRender)
|
||||
return new PartialRender(targetSpace);
|
||||
|
||||
throw new ArgumentException();
|
||||
}
|
||||
|
||||
internal override void Draw(Size availableSpace)
|
||||
{
|
||||
var skiaCanvas = (Canvas as Drawing.SkiaCanvasBase)?.Canvas;
|
||||
|
||||
if (skiaCanvas == null)
|
||||
return;
|
||||
|
||||
|
||||
var currentMatrix = skiaCanvas.TotalMatrix;
|
||||
|
||||
if (NormalizedTurnCount == 1 || NormalizedTurnCount == 2)
|
||||
skiaCanvas.Translate(availableSpace.Width, 0);
|
||||
|
||||
if (NormalizedTurnCount == 2 || NormalizedTurnCount == 3)
|
||||
skiaCanvas.Translate(0, availableSpace.Height);
|
||||
|
||||
skiaCanvas.RotateRadians(NormalizedTurnCount * (float) Math.PI / 2f);
|
||||
|
||||
if (NormalizedTurnCount == 1 || NormalizedTurnCount == 3)
|
||||
availableSpace = new Size(availableSpace.Height, availableSpace.Width);
|
||||
|
||||
skiaCanvas.RotateDegrees(Angle);
|
||||
Child?.Draw(availableSpace);
|
||||
skiaCanvas.SetMatrix(currentMatrix);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using QuestPDF.Drawing.SpacePlan;
|
||||
using QuestPDF.Infrastructure;
|
||||
|
||||
namespace QuestPDF.Elements
|
||||
{
|
||||
internal class SimpleRotate : ContainerElement
|
||||
{
|
||||
public int TurnCount { get; set; }
|
||||
public int NormalizedTurnCount => (TurnCount % 4 + 4) % 4;
|
||||
|
||||
internal override ISpacePlan Measure(Size availableSpace)
|
||||
{
|
||||
if (NormalizedTurnCount == 0 || NormalizedTurnCount == 2)
|
||||
return base.Measure(availableSpace);
|
||||
|
||||
availableSpace = new Size(availableSpace.Height, availableSpace.Width);
|
||||
var childSpace = base.Measure(availableSpace) as Size;
|
||||
|
||||
if (childSpace == null)
|
||||
return new Wrap();
|
||||
|
||||
var targetSpace = new Size(childSpace.Height, childSpace.Width);
|
||||
|
||||
if (childSpace is FullRender)
|
||||
return new FullRender(targetSpace);
|
||||
|
||||
if (childSpace is PartialRender)
|
||||
return new PartialRender(targetSpace);
|
||||
|
||||
throw new ArgumentException();
|
||||
}
|
||||
|
||||
internal override void Draw(Size availableSpace)
|
||||
{
|
||||
var skiaCanvas = (Canvas as Drawing.SkiaCanvasBase)?.Canvas;
|
||||
|
||||
if (skiaCanvas == null)
|
||||
return;
|
||||
|
||||
var currentMatrix = skiaCanvas.TotalMatrix;
|
||||
|
||||
if (NormalizedTurnCount == 1 || NormalizedTurnCount == 2)
|
||||
skiaCanvas.Translate(availableSpace.Width, 0);
|
||||
|
||||
if (NormalizedTurnCount == 2 || NormalizedTurnCount == 3)
|
||||
skiaCanvas.Translate(0, availableSpace.Height);
|
||||
|
||||
skiaCanvas.RotateDegrees(NormalizedTurnCount * 90);
|
||||
|
||||
if (NormalizedTurnCount == 1 || NormalizedTurnCount == 3)
|
||||
availableSpace = new Size(availableSpace.Height, availableSpace.Width);
|
||||
|
||||
Child?.Draw(availableSpace);
|
||||
skiaCanvas.SetMatrix(currentMatrix);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,8 +5,8 @@ namespace QuestPDF.Elements
|
||||
{
|
||||
internal class Translate : ContainerElement
|
||||
{
|
||||
public float TranslateX { get; set; } = 1;
|
||||
public float TranslateY { get; set; } = 1;
|
||||
public float TranslateX { get; set; } = 0;
|
||||
public float TranslateY { get; set; } = 0;
|
||||
|
||||
internal override void Draw(Size availableSpace)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
using System;
|
||||
using QuestPDF.Drawing.SpacePlan;
|
||||
using QuestPDF.Infrastructure;
|
||||
|
||||
namespace QuestPDF.Elements
|
||||
{
|
||||
internal class Unconstrained : ContainerElement
|
||||
{
|
||||
internal override ISpacePlan Measure(Size availableSpace)
|
||||
{
|
||||
var childSize = Child?.Measure(Size.Max) ?? new FullRender(Size.Zero);
|
||||
|
||||
if (childSize is PartialRender)
|
||||
return new PartialRender(Size.Zero);
|
||||
|
||||
if (childSize is FullRender)
|
||||
return new FullRender(Size.Zero);
|
||||
|
||||
return childSize;
|
||||
}
|
||||
|
||||
internal override void Draw(Size availableSpace)
|
||||
{
|
||||
var measurement = Child?.Measure(Size.Max) as Size;
|
||||
|
||||
if (measurement == null)
|
||||
return;
|
||||
|
||||
Child?.Draw(measurement);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -104,7 +104,7 @@ namespace QuestPDF.Fluent
|
||||
style.Alignment = alignment.Horizontal;
|
||||
}
|
||||
|
||||
element.Element(new Text()
|
||||
element.Element(new Text
|
||||
{
|
||||
Value = text.ToString(),
|
||||
Style = style
|
||||
@@ -162,5 +162,10 @@ namespace QuestPDF.Fluent
|
||||
{
|
||||
return element.Element(new Box());
|
||||
}
|
||||
|
||||
public static IContainer Unconstrained(this IContainer element)
|
||||
{
|
||||
return element.Element(new Unconstrained());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,6 +39,10 @@ namespace QuestPDF.Fluent
|
||||
foreach (var imageData in document.GenerateImages())
|
||||
{
|
||||
var path = filePath(index);
|
||||
|
||||
if (File.Exists(path))
|
||||
File.Delete(path);
|
||||
|
||||
File.WriteAllBytes(path, imageData);
|
||||
index++;
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -6,9 +6,9 @@ namespace QuestPDF.Fluent
|
||||
{
|
||||
public static class RotateExtensions
|
||||
{
|
||||
private static IContainer Rotate(this IContainer element, Action<Rotate> handler)
|
||||
private static IContainer SimpleRotate(this IContainer element, Action<SimpleRotate> handler)
|
||||
{
|
||||
var scale = element as Rotate ?? new Rotate();
|
||||
var scale = element as SimpleRotate ?? new SimpleRotate();
|
||||
handler(scale);
|
||||
|
||||
return element.Element(scale);
|
||||
@@ -16,12 +16,21 @@ namespace QuestPDF.Fluent
|
||||
|
||||
public static IContainer RotateLeft(this IContainer element)
|
||||
{
|
||||
return element.Rotate(x => x.TurnCount--);
|
||||
return element.SimpleRotate(x => x.TurnCount--);
|
||||
}
|
||||
|
||||
public static IContainer RotateRight(this IContainer element)
|
||||
{
|
||||
return element.Rotate(x => x.TurnCount++);
|
||||
return element.SimpleRotate(x => x.TurnCount++);
|
||||
}
|
||||
|
||||
/// <param name="angle">In degrees</param>
|
||||
public static IContainer Rotate(this IContainer element, float angle)
|
||||
{
|
||||
return element.Element(new Rotate
|
||||
{
|
||||
Angle = angle
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,32 +16,32 @@ namespace QuestPDF.Fluent
|
||||
|
||||
public static IContainer Scale(this IContainer element, float value)
|
||||
{
|
||||
return element.ScaleX(value).ScaleY(value);
|
||||
return element.ScaleHorizontal(value).ScaleVertical(value);
|
||||
}
|
||||
|
||||
public static IContainer ScaleX(this IContainer element, float value)
|
||||
public static IContainer ScaleHorizontal(this IContainer element, float value)
|
||||
{
|
||||
return element.Scale(x => x.ScaleX = value);
|
||||
}
|
||||
|
||||
public static IContainer FlipX(this IContainer element)
|
||||
public static IContainer FlipHorizontal(this IContainer element)
|
||||
{
|
||||
return element.ScaleX(-1);
|
||||
return element.ScaleHorizontal(-1);
|
||||
}
|
||||
|
||||
public static IContainer ScaleY(this IContainer element, float value)
|
||||
public static IContainer ScaleVertical(this IContainer element, float value)
|
||||
{
|
||||
return element.Scale(x => x.ScaleY = value);
|
||||
}
|
||||
|
||||
public static IContainer FlipY(this IContainer element)
|
||||
public static IContainer FlipVertical(this IContainer element)
|
||||
{
|
||||
return element.ScaleY(-1);
|
||||
return element.ScaleVertical(-1);
|
||||
}
|
||||
|
||||
public static IContainer FlipOver(this IContainer element)
|
||||
{
|
||||
return element.FlipX().FlipY();
|
||||
return element.FlipHorizontal().FlipVertical();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,12 +13,7 @@ namespace QuestPDF.Fluent
|
||||
|
||||
return element.Element(translate);
|
||||
}
|
||||
|
||||
public static IContainer Translate(this IContainer element, float value)
|
||||
{
|
||||
return element.TranslateX(value).TranslateY(value);
|
||||
}
|
||||
|
||||
|
||||
public static IContainer TranslateX(this IContainer element, float value)
|
||||
{
|
||||
return element.Translate(x => x.TranslateX = value);
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
<Authors>MarcinZiabek</Authors>
|
||||
<Company>CodeFlint</Company>
|
||||
<PackageId>QuestPDF</PackageId>
|
||||
<Version>2021.5.2</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: Box, Grid, Canvas, EnsureSpance and Layers. Redesigned the Debug element. Added material design colors. Added list of basic fonts. Added spacing property to the Row element. Fluent API improvements and increased stability.</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>
|
||||
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
# Security Policy
|
||||
|
||||
## Supported Versions
|
||||
|
||||
| Version | Supported |
|
||||
| ------- | ------------------ |
|
||||
| 2021.5.2 | :white_check_mark: |
|
||||
| Older | :x: |
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
Please report any code vulnerabilities using GitHub Issues. We are trying to respond within 1 day and analyze reported situation as soon as possible.
|
||||
Please collaborate with us to find best solutation available.
|
||||
Once the vulnerability is recognized and fixed, the issue is closed with appropraite message.
|
||||
@@ -16,6 +16,15 @@
|
||||
|
||||
6) **Enjoy fast PDF generation** - QuestPDF is created upon SkiaSharp, a well-known graphical library, and converts your data into PDF documents. It offers a highly optimized layouting engine capable of generating over 1000 PDF files per minute per core. The entire process is thread-safe.
|
||||
|
||||
## Support QuestPDF
|
||||
|
||||
All great frameworks and libraries started from zero. Please help us to make QuestPDF a commonly known library and an obvious choice in case of generating PDF documents. It can be as easy as:
|
||||
- Giving this repository a star ⭐ so more people will know about it,
|
||||
- Observing 🤩 the library to know about each new realease,
|
||||
- Trying our sample project to see how easy it is to create an invoice 📊,
|
||||
- Sharing your thoughts 💬 with us and your colleagues,
|
||||
- Simply using it 👨💻 and suggesting new features,
|
||||
- Creating new features 🆕 for everybody.
|
||||
|
||||
## Installation
|
||||
|
||||
@@ -25,7 +34,6 @@ The library is available as a nuget package. You can install it as any other nug
|
||||
<img src="https://github.com/QuestPDF/example-invoice/raw/main/images/nuget.svg" width="200px">
|
||||
</a>
|
||||
|
||||
|
||||
## Documentation
|
||||
|
||||
1. [Release notes and roadmap](https://www.questpdf.com/documentation/releases.html) - everything that is planned for future library iterations, description of new features and information about potential breaking changes.
|
||||
@@ -46,16 +54,19 @@ For tutorial, documentation and API reference, please visit [the QuestPDF docume
|
||||
Here you can find an example code showing how easy is to write and understand the fluent API:
|
||||
|
||||
```csharp
|
||||
public void Compose(IContainer container)
|
||||
{
|
||||
public void Compose(IDocumentContainer container)
|
||||
{
|
||||
container
|
||||
.PaddingHorizontal(50)
|
||||
.PaddingVertical(50)
|
||||
.Page(page =>
|
||||
{
|
||||
page.Header(ComposeHeader);
|
||||
page.Content(ComposeContent);
|
||||
page.Footer().AlignCenter().PageNumber("Page {number}");
|
||||
page.MarginVertical(60);
|
||||
page.MarginHorizontal(40);
|
||||
|
||||
page.Size(PageSizes.A4);
|
||||
|
||||
page.Header().Element(ComposeHeader);
|
||||
page.Content().Element(ComposeContent);
|
||||
page.Footer().AlignCenter().PageNumber();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -63,11 +74,11 @@ void ComposeHeader(IContainer container)
|
||||
{
|
||||
container.Row(row =>
|
||||
{
|
||||
row.RelativeColumn().Stack(column =>
|
||||
row.RelativeColumn().Stack(stack =>
|
||||
{
|
||||
column.Element().Text($"Invoice #{Model.InvoiceNumber}", TextStyle.Default.Size(20).Bold());
|
||||
column.Element().Text($"Issue date: {Model.IssueDate:d}");
|
||||
column.Element().Text($"Due date: {Model.DueDate:d}");
|
||||
stack.Item().Text($"Invoice #{Model.InvoiceNumber}", TextStyle.Default.Size(20).Bold());
|
||||
stack.Item().Text($"Issue date: {Model.IssueDate:d}");
|
||||
stack.Item().Text($"Due date: {Model.DueDate:d}");
|
||||
});
|
||||
|
||||
row.ConstantColumn(100).Height(50).Placeholder();
|
||||
|
||||
Reference in New Issue
Block a user