2021.2.0 Internal links, external links, dynamic images, font weights
This commit is contained in:
Родитель
8b98c4b1ac
Коммит
35214892ef
|
@ -25,11 +25,11 @@ namespace QuestPDF.ReportSample.Layouts
|
||||||
.PaddingBottom(5)
|
.PaddingBottom(5)
|
||||||
.Text(Model.Title, Typography.Headline);
|
.Text(Model.Title, Typography.Headline);
|
||||||
|
|
||||||
section.Content().PageableStack(column =>
|
section.Content().PageableStack(stack =>
|
||||||
{
|
{
|
||||||
foreach (var part in Model.Parts)
|
foreach (var part in Model.Parts)
|
||||||
{
|
{
|
||||||
column.Element().Row(row =>
|
stack.Element().Row(row =>
|
||||||
{
|
{
|
||||||
row.ConstantColumn(150).DarkCell().Text(part.Label, Typography.Normal);
|
row.ConstantColumn(150).DarkCell().Text(part.Label, Typography.Normal);
|
||||||
var frame = row.RelativeColumn().LightCell();
|
var frame = row.RelativeColumn().LightCell();
|
||||||
|
|
|
@ -71,7 +71,7 @@ namespace QuestPDF.ReportSample.Layouts
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
row.ConstantColumn(150).Image(Model.LogoData);
|
row.ConstantColumn(150).ExternalLink("https://www.questpdf.com").Image(Model.LogoData);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,11 +81,14 @@ namespace QuestPDF.ReportSample.Layouts
|
||||||
{
|
{
|
||||||
stack.Spacing(20);
|
stack.Spacing(20);
|
||||||
|
|
||||||
|
stack.Element().Component(new TableOfContentsTemplate(Model.Sections));
|
||||||
|
|
||||||
foreach (var section in Model.Sections)
|
foreach (var section in Model.Sections)
|
||||||
stack.Element().Component(new SectionTemplate(section));
|
stack.Element().Location(section.Title).Component(new SectionTemplate(section));
|
||||||
|
|
||||||
stack.Element().PageBreak();
|
stack.Element().PageBreak();
|
||||||
|
stack.Element().Location("Photos");
|
||||||
|
|
||||||
foreach (var photo in Model.Photos)
|
foreach (var photo in Model.Photos)
|
||||||
stack.Element().Component(new PhotoTemplate(photo));
|
stack.Element().Component(new PhotoTemplate(photo));
|
||||||
});
|
});
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using QuestPDF.Fluent;
|
||||||
|
using QuestPDF.Infrastructure;
|
||||||
|
|
||||||
|
namespace QuestPDF.ReportSample.Layouts
|
||||||
|
{
|
||||||
|
public class TableOfContentsTemplate : IComponent
|
||||||
|
{
|
||||||
|
private List<ReportSection> Sections { get; }
|
||||||
|
|
||||||
|
public TableOfContentsTemplate(List<ReportSection> sections)
|
||||||
|
{
|
||||||
|
Sections = sections;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Compose(IContainer container)
|
||||||
|
{
|
||||||
|
container
|
||||||
|
.Section(section =>
|
||||||
|
{
|
||||||
|
section
|
||||||
|
.Header()
|
||||||
|
.PaddingBottom(5)
|
||||||
|
.Text("Table of contents", Typography.Headline);
|
||||||
|
|
||||||
|
section.Content().PageableStack(stack =>
|
||||||
|
{
|
||||||
|
stack.Spacing(5);
|
||||||
|
|
||||||
|
for (var i = 0; i < Sections.Count; i++)
|
||||||
|
stack.Element(c => DrawLink(c, i+1, Sections[i].Title));
|
||||||
|
|
||||||
|
stack.Element(c => DrawLink(c, Sections.Count+1, "Photos"));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DrawLink(IContainer container, int number, string locationName)
|
||||||
|
{
|
||||||
|
container
|
||||||
|
.InternalLink(locationName)
|
||||||
|
.Row(row =>
|
||||||
|
{
|
||||||
|
row.ConstantColumn(25).Text($"{number}.", Typography.Normal);
|
||||||
|
row.RelativeColumn().Text(locationName, Typography.Normal);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,7 +5,7 @@ namespace QuestPDF.ReportSample
|
||||||
{
|
{
|
||||||
public static class Typography
|
public static class Typography
|
||||||
{
|
{
|
||||||
public static TextStyle Title => TextStyle.Default.FontType("Helvetica").Color("#000000").Size(20);
|
public static TextStyle Title => TextStyle.Default.FontType("Helvetica").Color("#000000").Size(20).Bold();
|
||||||
public static TextStyle Headline => TextStyle.Default.FontType("Helvetica").Color("#047AED").Size(14);
|
public static TextStyle Headline => TextStyle.Default.FontType("Helvetica").Color("#047AED").Size(14);
|
||||||
public static TextStyle Normal => TextStyle.Default.FontType("Helvetica").Color("#000000").Size(10).LineHeight(1.25f).AlignLeft();
|
public static TextStyle Normal => TextStyle.Default.FontType("Helvetica").Color("#000000").Size(10).LineHeight(1.25f).AlignLeft();
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
using QuestPDF.Drawing.SpacePlan;
|
using QuestPDF.Drawing.SpacePlan;
|
||||||
using QuestPDF.Elements;
|
using QuestPDF.Elements;
|
||||||
using QuestPDF.Infrastructure;
|
using QuestPDF.Infrastructure;
|
||||||
using QuestPDF.UnitTests.MeasureTest;
|
using QuestPDF.UnitTests.TestEngine;
|
||||||
|
|
||||||
namespace QuestPDF.UnitTests
|
namespace QuestPDF.UnitTests
|
||||||
{
|
{
|
||||||
|
|
|
@ -3,7 +3,7 @@ using NUnit.Framework;
|
||||||
using QuestPDF.Drawing.SpacePlan;
|
using QuestPDF.Drawing.SpacePlan;
|
||||||
using QuestPDF.Elements;
|
using QuestPDF.Elements;
|
||||||
using QuestPDF.Infrastructure;
|
using QuestPDF.Infrastructure;
|
||||||
using QuestPDF.UnitTests.MeasureTest;
|
using QuestPDF.UnitTests.TestEngine;
|
||||||
|
|
||||||
namespace QuestPDF.UnitTests
|
namespace QuestPDF.UnitTests
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using QuestPDF.Elements;
|
using QuestPDF.Elements;
|
||||||
using QuestPDF.Infrastructure;
|
using QuestPDF.Infrastructure;
|
||||||
using QuestPDF.UnitTests.MeasureTest;
|
using QuestPDF.UnitTests.TestEngine;
|
||||||
|
|
||||||
namespace QuestPDF.UnitTests
|
namespace QuestPDF.UnitTests
|
||||||
{
|
{
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
using QuestPDF.Drawing.SpacePlan;
|
using QuestPDF.Drawing.SpacePlan;
|
||||||
using QuestPDF.Elements;
|
using QuestPDF.Elements;
|
||||||
using QuestPDF.Infrastructure;
|
using QuestPDF.Infrastructure;
|
||||||
using QuestPDF.UnitTests.MeasureTest;
|
using QuestPDF.UnitTests.TestEngine;
|
||||||
|
|
||||||
namespace QuestPDF.UnitTests
|
namespace QuestPDF.UnitTests
|
||||||
{
|
{
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
using QuestPDF.Drawing.SpacePlan;
|
using QuestPDF.Drawing.SpacePlan;
|
||||||
using QuestPDF.Elements;
|
using QuestPDF.Elements;
|
||||||
using QuestPDF.Infrastructure;
|
using QuestPDF.Infrastructure;
|
||||||
using QuestPDF.UnitTests.MeasureTest;
|
using QuestPDF.UnitTests.TestEngine;
|
||||||
|
|
||||||
namespace QuestPDF.UnitTests
|
namespace QuestPDF.UnitTests
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using QuestPDF.Elements;
|
using QuestPDF.Elements;
|
||||||
using QuestPDF.UnitTests.MeasureTest;
|
using QuestPDF.UnitTests.TestEngine;
|
||||||
|
|
||||||
namespace QuestPDF.UnitTests
|
namespace QuestPDF.UnitTests
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using QuestPDF.Elements;
|
using QuestPDF.Elements;
|
||||||
using QuestPDF.UnitTests.MeasureTest;
|
using QuestPDF.UnitTests.TestEngine;
|
||||||
|
|
||||||
namespace QuestPDF.UnitTests
|
namespace QuestPDF.UnitTests
|
||||||
{
|
{
|
||||||
|
|
|
@ -3,7 +3,7 @@ using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using FluentAssertions;
|
using FluentAssertions;
|
||||||
using QuestPDF.Infrastructure;
|
using QuestPDF.Infrastructure;
|
||||||
using QuestPDF.UnitTests.MeasureTest;
|
using QuestPDF.UnitTests.TestEngine;
|
||||||
|
|
||||||
namespace QuestPDF.UnitTests
|
namespace QuestPDF.UnitTests
|
||||||
{
|
{
|
||||||
|
@ -13,7 +13,7 @@ namespace QuestPDF.UnitTests
|
||||||
|
|
||||||
public static Size RandomSize => new Size(Random.Next(200, 400), Random.Next(100, 200));
|
public static Size RandomSize => new Size(Random.Next(200, 400), Random.Next(100, 200));
|
||||||
|
|
||||||
public static void ShouldEqual(this IEnumerable<Operation> commands, IEnumerable<Operation> expected)
|
public static void ShouldEqual(this IEnumerable<OperationBase> commands, IEnumerable<OperationBase> expected)
|
||||||
{
|
{
|
||||||
commands.Should().HaveSameCount(expected);
|
commands.Should().HaveSameCount(expected);
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ using NUnit.Framework;
|
||||||
using QuestPDF.Drawing.SpacePlan;
|
using QuestPDF.Drawing.SpacePlan;
|
||||||
using QuestPDF.Elements;
|
using QuestPDF.Elements;
|
||||||
using QuestPDF.Infrastructure;
|
using QuestPDF.Infrastructure;
|
||||||
using QuestPDF.UnitTests.MeasureTest;
|
using QuestPDF.UnitTests.TestEngine;
|
||||||
|
|
||||||
namespace QuestPDF.UnitTests
|
namespace QuestPDF.UnitTests
|
||||||
{
|
{
|
||||||
|
|
|
@ -3,7 +3,7 @@ using NUnit.Framework;
|
||||||
using QuestPDF.Drawing.SpacePlan;
|
using QuestPDF.Drawing.SpacePlan;
|
||||||
using QuestPDF.Elements;
|
using QuestPDF.Elements;
|
||||||
using QuestPDF.Infrastructure;
|
using QuestPDF.Infrastructure;
|
||||||
using QuestPDF.UnitTests.MeasureTest;
|
using QuestPDF.UnitTests.TestEngine;
|
||||||
|
|
||||||
namespace QuestPDF.UnitTests
|
namespace QuestPDF.UnitTests
|
||||||
{
|
{
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
using QuestPDF.Drawing.SpacePlan;
|
using QuestPDF.Drawing.SpacePlan;
|
||||||
using QuestPDF.Elements;
|
using QuestPDF.Elements;
|
||||||
using QuestPDF.Infrastructure;
|
using QuestPDF.Infrastructure;
|
||||||
using QuestPDF.UnitTests.MeasureTest;
|
using QuestPDF.UnitTests.TestEngine;
|
||||||
|
|
||||||
namespace QuestPDF.UnitTests
|
namespace QuestPDF.UnitTests
|
||||||
{
|
{
|
||||||
|
@ -220,6 +220,9 @@ namespace QuestPDF.UnitTests
|
||||||
.ExpectCanvasTranslate(0, -250)
|
.ExpectCanvasTranslate(0, -250)
|
||||||
|
|
||||||
.ExpectChildMeasure("c", expectedInput: new Size(500, 400), returns: new FullRender(Size.Zero))
|
.ExpectChildMeasure("c", expectedInput: new Size(500, 400), returns: new FullRender(Size.Zero))
|
||||||
|
.ExpectCanvasTranslate(0, 600)
|
||||||
|
.ExpectChildDraw("c", new Size(500, 0))
|
||||||
|
.ExpectCanvasTranslate(0, -600)
|
||||||
|
|
||||||
.ExpectChildMeasure("d", expectedInput: new Size(500, 400), returns: new FullRender(200, 400))
|
.ExpectChildMeasure("d", expectedInput: new Size(500, 400), returns: new FullRender(200, 400))
|
||||||
.ExpectCanvasTranslate(0, 600)
|
.ExpectCanvasTranslate(0, 600)
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
using System;
|
||||||
|
using QuestPDF.Infrastructure;
|
||||||
|
using SkiaSharp;
|
||||||
|
|
||||||
|
namespace QuestPDF.UnitTests.TestEngine
|
||||||
|
{
|
||||||
|
internal class CanvasMock : ICanvas
|
||||||
|
{
|
||||||
|
public Action<Position> TranslateFunc { get; set; }
|
||||||
|
public Action<SKImage, Position, Size> DrawImageFunc { get; set; }
|
||||||
|
public Action<string, Position, TextStyle> DrawTextFunc { get; set; }
|
||||||
|
public Action<Position, Size, string> DrawRectFunc { get; set; }
|
||||||
|
|
||||||
|
public void Translate(Position vector) => TranslateFunc(vector);
|
||||||
|
public void DrawRectangle(Position vector, Size size, string color) => DrawRectFunc(vector, size, color);
|
||||||
|
public void DrawText(string text, Position position, TextStyle style) => DrawTextFunc(text, position, style);
|
||||||
|
public void DrawImage(SKImage image, Position position, Size size) => DrawImageFunc(image, position, size);
|
||||||
|
public void DrawExternalLink(string url, Size size)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DrawLocationLink(string locationName, Size size)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DrawLocation(string locationName)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DrawLink(string url, Size size)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Size MeasureText(string text, TextStyle style)
|
||||||
|
{
|
||||||
|
return new Size(text.Length * style.Size, style.Size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
using System;
|
||||||
|
using QuestPDF.Drawing.SpacePlan;
|
||||||
|
using QuestPDF.Infrastructure;
|
||||||
|
|
||||||
|
namespace QuestPDF.UnitTests.TestEngine
|
||||||
|
{
|
||||||
|
internal class ElementMock : Element
|
||||||
|
{
|
||||||
|
public string Id { get; set; }
|
||||||
|
public Func<Size, ISpacePlan> MeasureFunc { get; set; }
|
||||||
|
public Action<Size> DrawFunc { get; set; }
|
||||||
|
|
||||||
|
internal override ISpacePlan Measure(Size availableSpace) => MeasureFunc(availableSpace);
|
||||||
|
internal override void Draw(ICanvas canvas, Size availableSpace) => DrawFunc(availableSpace);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
namespace QuestPDF.UnitTests.TestEngine
|
||||||
|
{
|
||||||
|
public abstract class OperationBase
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
using QuestPDF.Infrastructure;
|
||||||
|
|
||||||
|
namespace QuestPDF.UnitTests.TestEngine.Operations
|
||||||
|
{
|
||||||
|
internal class CanvasDrawImageOperationBase : OperationBase
|
||||||
|
{
|
||||||
|
public Position Position { get; }
|
||||||
|
public Size Size { get; }
|
||||||
|
|
||||||
|
public CanvasDrawImageOperationBase(Position position, Size size)
|
||||||
|
{
|
||||||
|
Position = position;
|
||||||
|
Size = size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
using QuestPDF.Infrastructure;
|
||||||
|
|
||||||
|
namespace QuestPDF.UnitTests.TestEngine.Operations
|
||||||
|
{
|
||||||
|
internal class CanvasDrawRectangleOperationBase : OperationBase
|
||||||
|
{
|
||||||
|
public Position Position { get; }
|
||||||
|
public Size Size { get; }
|
||||||
|
public string Color { get; }
|
||||||
|
|
||||||
|
public CanvasDrawRectangleOperationBase(Position position, Size size, string color)
|
||||||
|
{
|
||||||
|
Position = position;
|
||||||
|
Size = size;
|
||||||
|
Color = color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
using QuestPDF.Infrastructure;
|
||||||
|
|
||||||
|
namespace QuestPDF.UnitTests.TestEngine.Operations
|
||||||
|
{
|
||||||
|
internal class CanvasDrawTextOperationBase : OperationBase
|
||||||
|
{
|
||||||
|
public string Text { get; }
|
||||||
|
public Position Position { get; }
|
||||||
|
public TextStyle Style { get; }
|
||||||
|
|
||||||
|
public CanvasDrawTextOperationBase(string text, Position position, TextStyle style)
|
||||||
|
{
|
||||||
|
Text = text;
|
||||||
|
Position = position;
|
||||||
|
Style = style;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
using QuestPDF.Infrastructure;
|
||||||
|
|
||||||
|
namespace QuestPDF.UnitTests.TestEngine.Operations
|
||||||
|
{
|
||||||
|
internal class CanvasTranslateOperationBase : OperationBase
|
||||||
|
{
|
||||||
|
public Position Position { get; }
|
||||||
|
|
||||||
|
public CanvasTranslateOperationBase(Position position)
|
||||||
|
{
|
||||||
|
Position = position;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
using QuestPDF.Infrastructure;
|
||||||
|
|
||||||
|
namespace QuestPDF.UnitTests.TestEngine.Operations
|
||||||
|
{
|
||||||
|
public class ChildDrawOperationBase : OperationBase
|
||||||
|
{
|
||||||
|
public string ChildId { get; }
|
||||||
|
public Size Input { get; }
|
||||||
|
|
||||||
|
public ChildDrawOperationBase(string childId, Size input)
|
||||||
|
{
|
||||||
|
ChildId = childId;
|
||||||
|
Input = input;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
using QuestPDF.Drawing.SpacePlan;
|
||||||
|
using QuestPDF.Infrastructure;
|
||||||
|
|
||||||
|
namespace QuestPDF.UnitTests.TestEngine.Operations
|
||||||
|
{
|
||||||
|
internal class ChildMeasureOperationBase : OperationBase
|
||||||
|
{
|
||||||
|
public string ChildId { get; }
|
||||||
|
public Size Input { get; }
|
||||||
|
public ISpacePlan Output { get; }
|
||||||
|
|
||||||
|
public ChildMeasureOperationBase(string childId, Size input, ISpacePlan output)
|
||||||
|
{
|
||||||
|
ChildId = childId;
|
||||||
|
Input = input;
|
||||||
|
Output = output;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
using QuestPDF.Infrastructure;
|
||||||
|
|
||||||
|
namespace QuestPDF.UnitTests.TestEngine.Operations
|
||||||
|
{
|
||||||
|
public class ElementMeasureOperationBase : OperationBase
|
||||||
|
{
|
||||||
|
public ElementMeasureOperationBase(Size input)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
using FluentAssertions;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using QuestPDF.Drawing.SpacePlan;
|
||||||
|
using QuestPDF.Infrastructure;
|
||||||
|
|
||||||
|
namespace QuestPDF.UnitTests.TestEngine
|
||||||
|
{
|
||||||
|
public static class SingleChildTests
|
||||||
|
{
|
||||||
|
internal static void MeasureWithoutChild<T>(this T element) where T : ContainerElement
|
||||||
|
{
|
||||||
|
element.Child = null;
|
||||||
|
element.Measure(Size.Zero).Should().BeEquivalentTo(new FullRender(Size.Zero));
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void DrawWithoutChild<T>(this T element) where T : ContainerElement
|
||||||
|
{
|
||||||
|
// component does not throw an exception when called with null child
|
||||||
|
Assert.DoesNotThrow(() =>
|
||||||
|
{
|
||||||
|
element.Child = null;
|
||||||
|
|
||||||
|
// component does not perform any canvas operation when called with null child
|
||||||
|
TestPlan
|
||||||
|
.For(x => element)
|
||||||
|
.DrawElement(new Size(200, 100))
|
||||||
|
.CheckDrawResult();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,144 +1,20 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using FluentAssertions;
|
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using QuestPDF.Drawing.SpacePlan;
|
using QuestPDF.Drawing.SpacePlan;
|
||||||
using QuestPDF.Elements;
|
|
||||||
using QuestPDF.Infrastructure;
|
using QuestPDF.Infrastructure;
|
||||||
using SkiaSharp;
|
using QuestPDF.UnitTests.TestEngine.Operations;
|
||||||
|
|
||||||
namespace QuestPDF.UnitTests.MeasureTest
|
namespace QuestPDF.UnitTests.TestEngine
|
||||||
{
|
{
|
||||||
public abstract class Operation
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public class ElementMeasureOperation : Operation
|
|
||||||
{
|
|
||||||
public ElementMeasureOperation(Size input)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal class ChildMeasureOperation : Operation
|
|
||||||
{
|
|
||||||
public string ChildId { get; }
|
|
||||||
public Size Input { get; }
|
|
||||||
public ISpacePlan Output { get; }
|
|
||||||
|
|
||||||
public ChildMeasureOperation(string childId, Size input, ISpacePlan output)
|
|
||||||
{
|
|
||||||
ChildId = childId;
|
|
||||||
Input = input;
|
|
||||||
Output = output;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class ChildDrawOperation : Operation
|
|
||||||
{
|
|
||||||
public string ChildId { get; }
|
|
||||||
public Size Input { get; }
|
|
||||||
|
|
||||||
public ChildDrawOperation(string childId, Size input)
|
|
||||||
{
|
|
||||||
ChildId = childId;
|
|
||||||
Input = input;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal class CanvasTranslateOperation : Operation
|
|
||||||
{
|
|
||||||
public Position Position { get; }
|
|
||||||
|
|
||||||
public CanvasTranslateOperation(Position position)
|
|
||||||
{
|
|
||||||
Position = position;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal class CanvasDrawRectangleOperation : Operation
|
|
||||||
{
|
|
||||||
public Position Position { get; }
|
|
||||||
public Size Size { get; }
|
|
||||||
public string Color { get; }
|
|
||||||
|
|
||||||
public CanvasDrawRectangleOperation(Position position, Size size, string color)
|
|
||||||
{
|
|
||||||
Position = position;
|
|
||||||
Size = size;
|
|
||||||
Color = color;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal class CanvasDrawTextOperation : Operation
|
|
||||||
{
|
|
||||||
public string Text { get; }
|
|
||||||
public Position Position { get; }
|
|
||||||
public TextStyle Style { get; }
|
|
||||||
|
|
||||||
public CanvasDrawTextOperation(string text, Position position, TextStyle style)
|
|
||||||
{
|
|
||||||
Text = text;
|
|
||||||
Position = position;
|
|
||||||
Style = style;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal class CanvasDrawImageOperation : Operation
|
|
||||||
{
|
|
||||||
public Position Position { get; }
|
|
||||||
public Size Size { get; }
|
|
||||||
|
|
||||||
public CanvasDrawImageOperation(Position position, Size size)
|
|
||||||
{
|
|
||||||
Position = position;
|
|
||||||
Size = size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal class ElementMock : Element
|
|
||||||
{
|
|
||||||
public string Id { get; set; }
|
|
||||||
public Func<Size, ISpacePlan> MeasureFunc { get; set; }
|
|
||||||
public Action<Size> DrawFunc { get; set; }
|
|
||||||
|
|
||||||
internal override ISpacePlan Measure(Size availableSpace) => MeasureFunc(availableSpace);
|
|
||||||
internal override void Draw(ICanvas canvas, Size availableSpace) => DrawFunc(availableSpace);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal class CanvasMock : ICanvas
|
|
||||||
{
|
|
||||||
public Action<Position> TranslateFunc { get; set; }
|
|
||||||
public Action<SKImage, Position, Size> DrawImageFunc { get; set; }
|
|
||||||
public Action<string, Position, TextStyle> DrawTextFunc { get; set; }
|
|
||||||
public Action<Position, Size, string> DrawRectFunc { get; set; }
|
|
||||||
|
|
||||||
public void Translate(Position vector) => TranslateFunc(vector);
|
|
||||||
public void DrawRectangle(Position vector, Size size, string color) => DrawRectFunc(vector, size, color);
|
|
||||||
public void DrawText(string text, Position position, TextStyle style) => DrawTextFunc(text, position, style);
|
|
||||||
public void DrawImage(SKImage image, Position position, Size size) => DrawImageFunc(image, position, size);
|
|
||||||
|
|
||||||
public void DrawLink(string url, Size size)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Size MeasureText(string text, TextStyle style)
|
|
||||||
{
|
|
||||||
return new Size(text.Length * style.Size, style.Size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal class TestPlan
|
internal class TestPlan
|
||||||
{
|
{
|
||||||
private Element Element { get; set; }
|
private Element Element { get; set; }
|
||||||
private ICanvas Canvas { get; }
|
private ICanvas Canvas { get; }
|
||||||
|
|
||||||
private Size OperationInput { get; set; }
|
private Size OperationInput { get; set; }
|
||||||
private Queue<Operation> Operations { get; } = new Queue<Operation>();
|
private Queue<OperationBase> Operations { get; } = new Queue<OperationBase>();
|
||||||
|
|
||||||
public TestPlan()
|
public TestPlan()
|
||||||
{
|
{
|
||||||
|
@ -153,7 +29,7 @@ namespace QuestPDF.UnitTests.MeasureTest
|
||||||
return plan;
|
return plan;
|
||||||
}
|
}
|
||||||
|
|
||||||
private T GetExpected<T>() where T : Operation
|
private T GetExpected<T>() where T : OperationBase
|
||||||
{
|
{
|
||||||
if (Operations.TryDequeue(out var value) && value is T result)
|
if (Operations.TryDequeue(out var value) && value is T result)
|
||||||
return result;
|
return result;
|
||||||
|
@ -169,7 +45,7 @@ namespace QuestPDF.UnitTests.MeasureTest
|
||||||
{
|
{
|
||||||
TranslateFunc = position =>
|
TranslateFunc = position =>
|
||||||
{
|
{
|
||||||
var expected = GetExpected<CanvasTranslateOperation>();
|
var expected = GetExpected<CanvasTranslateOperationBase>();
|
||||||
|
|
||||||
Assert.AreEqual(expected.Position.X, position.X);
|
Assert.AreEqual(expected.Position.X, position.X);
|
||||||
Assert.AreEqual(expected.Position.Y, position.Y);
|
Assert.AreEqual(expected.Position.Y, position.Y);
|
||||||
|
@ -178,7 +54,7 @@ namespace QuestPDF.UnitTests.MeasureTest
|
||||||
},
|
},
|
||||||
DrawRectFunc = (position, size, color) =>
|
DrawRectFunc = (position, size, color) =>
|
||||||
{
|
{
|
||||||
var expected = GetExpected<CanvasDrawRectangleOperation>();
|
var expected = GetExpected<CanvasDrawRectangleOperationBase>();
|
||||||
|
|
||||||
Assert.AreEqual(expected.Position.X, position.X);
|
Assert.AreEqual(expected.Position.X, position.X);
|
||||||
Assert.AreEqual(expected.Position.Y, position.Y);
|
Assert.AreEqual(expected.Position.Y, position.Y);
|
||||||
|
@ -194,7 +70,7 @@ namespace QuestPDF.UnitTests.MeasureTest
|
||||||
},
|
},
|
||||||
DrawTextFunc = (text, position, style) =>
|
DrawTextFunc = (text, position, style) =>
|
||||||
{
|
{
|
||||||
var expected = GetExpected<CanvasDrawTextOperation>();
|
var expected = GetExpected<CanvasDrawTextOperationBase>();
|
||||||
|
|
||||||
Assert.AreEqual(expected.Text, text);
|
Assert.AreEqual(expected.Text, text);
|
||||||
|
|
||||||
|
@ -211,7 +87,7 @@ namespace QuestPDF.UnitTests.MeasureTest
|
||||||
},
|
},
|
||||||
DrawImageFunc = (image, position, size) =>
|
DrawImageFunc = (image, position, size) =>
|
||||||
{
|
{
|
||||||
var expected = GetExpected<CanvasDrawImageOperation>();
|
var expected = GetExpected<CanvasDrawImageOperationBase>();
|
||||||
|
|
||||||
Assert.AreEqual(expected.Position.X, position.X);
|
Assert.AreEqual(expected.Position.X, position.X);
|
||||||
Assert.AreEqual(expected.Position.Y, position.Y);
|
Assert.AreEqual(expected.Position.Y, position.Y);
|
||||||
|
@ -232,7 +108,7 @@ namespace QuestPDF.UnitTests.MeasureTest
|
||||||
Id = id,
|
Id = id,
|
||||||
MeasureFunc = availableSpace =>
|
MeasureFunc = availableSpace =>
|
||||||
{
|
{
|
||||||
var expected = GetExpected<ChildMeasureOperation>();
|
var expected = GetExpected<ChildMeasureOperationBase>();
|
||||||
|
|
||||||
Assert.AreEqual(expected.ChildId, id);
|
Assert.AreEqual(expected.ChildId, id);
|
||||||
|
|
||||||
|
@ -246,7 +122,7 @@ namespace QuestPDF.UnitTests.MeasureTest
|
||||||
},
|
},
|
||||||
DrawFunc = availableSpace =>
|
DrawFunc = availableSpace =>
|
||||||
{
|
{
|
||||||
var expected = GetExpected<ChildDrawOperation>();
|
var expected = GetExpected<ChildDrawOperationBase>();
|
||||||
|
|
||||||
Assert.AreEqual(expected.ChildId, id);
|
Assert.AreEqual(expected.ChildId, id);
|
||||||
|
|
||||||
|
@ -271,45 +147,45 @@ namespace QuestPDF.UnitTests.MeasureTest
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
private TestPlan AddOperation(Operation operation)
|
private TestPlan AddOperation(OperationBase operationBase)
|
||||||
{
|
{
|
||||||
Operations.Enqueue(operation);
|
Operations.Enqueue(operationBase);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TestPlan ExpectChildMeasure(string child, Size expectedInput, ISpacePlan returns)
|
public TestPlan ExpectChildMeasure(string child, Size expectedInput, ISpacePlan returns)
|
||||||
{
|
{
|
||||||
return AddOperation(new ChildMeasureOperation(child, expectedInput, returns));
|
return AddOperation(new ChildMeasureOperationBase(child, expectedInput, returns));
|
||||||
}
|
}
|
||||||
|
|
||||||
public TestPlan ExpectChildDraw(string child, Size expectedInput)
|
public TestPlan ExpectChildDraw(string child, Size expectedInput)
|
||||||
{
|
{
|
||||||
return AddOperation(new ChildDrawOperation(child, expectedInput));
|
return AddOperation(new ChildDrawOperationBase(child, expectedInput));
|
||||||
}
|
}
|
||||||
|
|
||||||
public TestPlan ExpectCanvasTranslate(Position position)
|
public TestPlan ExpectCanvasTranslate(Position position)
|
||||||
{
|
{
|
||||||
return AddOperation(new CanvasTranslateOperation(position));
|
return AddOperation(new CanvasTranslateOperationBase(position));
|
||||||
}
|
}
|
||||||
|
|
||||||
public TestPlan ExpectCanvasTranslate(float left, float top)
|
public TestPlan ExpectCanvasTranslate(float left, float top)
|
||||||
{
|
{
|
||||||
return AddOperation(new CanvasTranslateOperation(new Position(left, top)));
|
return AddOperation(new CanvasTranslateOperationBase(new Position(left, top)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public TestPlan ExpectCanvasDrawRectangle(Position position, Size size, string color)
|
public TestPlan ExpectCanvasDrawRectangle(Position position, Size size, string color)
|
||||||
{
|
{
|
||||||
return AddOperation(new CanvasDrawRectangleOperation(position, size, color));
|
return AddOperation(new CanvasDrawRectangleOperationBase(position, size, color));
|
||||||
}
|
}
|
||||||
|
|
||||||
public TestPlan ExpectCanvasDrawText(string text, Position position, TextStyle style)
|
public TestPlan ExpectCanvasDrawText(string text, Position position, TextStyle style)
|
||||||
{
|
{
|
||||||
return AddOperation(new CanvasDrawTextOperation(text, position, style));
|
return AddOperation(new CanvasDrawTextOperationBase(text, position, style));
|
||||||
}
|
}
|
||||||
|
|
||||||
public TestPlan ExpectCanvasDrawImage(Position position, Size size)
|
public TestPlan ExpectCanvasDrawImage(Position position, Size size)
|
||||||
{
|
{
|
||||||
return AddOperation(new CanvasDrawImageOperation(position, size));
|
return AddOperation(new CanvasDrawImageOperationBase(position, size));
|
||||||
}
|
}
|
||||||
|
|
||||||
public TestPlan CheckMeasureResult(ISpacePlan expected)
|
public TestPlan CheckMeasureResult(ISpacePlan expected)
|
||||||
|
@ -336,70 +212,4 @@ namespace QuestPDF.UnitTests.MeasureTest
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class SingleChildTests
|
|
||||||
{
|
|
||||||
internal static void MeasureWithoutChild<T>(this T element) where T : ContainerElement
|
|
||||||
{
|
|
||||||
element.Child = null;
|
|
||||||
element.Measure(Size.Zero).Should().BeEquivalentTo(new FullRender(Size.Zero));
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static void DrawWithoutChild<T>(this T element) where T : ContainerElement
|
|
||||||
{
|
|
||||||
// component does not throw an exception when called with null child
|
|
||||||
Assert.DoesNotThrow(() =>
|
|
||||||
{
|
|
||||||
element.Child = null;
|
|
||||||
|
|
||||||
// component does not perform any canvas operation when called with null child
|
|
||||||
TestPlan
|
|
||||||
.For(x => element)
|
|
||||||
.DrawElement(new Size(200, 100))
|
|
||||||
.CheckDrawResult();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestFixture]
|
|
||||||
public class LetsTest
|
|
||||||
{
|
|
||||||
[Test]
|
|
||||||
public void TestExample()
|
|
||||||
{
|
|
||||||
TestPlan
|
|
||||||
.For(x => new Padding
|
|
||||||
{
|
|
||||||
Top = 5,
|
|
||||||
Right = 10,
|
|
||||||
Bottom = 15,
|
|
||||||
Left = 20,
|
|
||||||
|
|
||||||
Child = x.CreateChild("child")
|
|
||||||
})
|
|
||||||
.MeasureElement(new Size(200, 100))
|
|
||||||
.ExpectChildMeasure("child", expectedInput: new Size(170, 80), returns: new FullRender(new Size(100, 50)))
|
|
||||||
.CheckMeasureResult(new FullRender(130, 70));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void TestExample2()
|
|
||||||
{
|
|
||||||
TestPlan
|
|
||||||
.For(x => new Padding
|
|
||||||
{
|
|
||||||
Top = 5,
|
|
||||||
Right = 10,
|
|
||||||
Bottom = 15,
|
|
||||||
Left = 20,
|
|
||||||
|
|
||||||
Child = x.CreateChild("child")
|
|
||||||
})
|
|
||||||
.DrawElement(new Size(200, 100))
|
|
||||||
.ExpectCanvasTranslate(new Position(20, 5))
|
|
||||||
.ExpectChildDraw("child", expectedInput: new Size(170, 80))
|
|
||||||
.ExpectCanvasTranslate(new Position(-20, -5))
|
|
||||||
.CheckDrawResult();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -41,9 +41,19 @@ namespace QuestPDF.Drawing
|
||||||
SkiaCanvas.DrawImage(image, new SKRect(vector.X, vector.Y, size.Width, size.Height));
|
SkiaCanvas.DrawImage(image, new SKRect(vector.X, vector.Y, size.Width, size.Height));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void DrawLink(string url, Size size)
|
public void DrawExternalLink(string url, Size size)
|
||||||
{
|
{
|
||||||
SkiaCanvas.DrawUrlAnnotation(new SKRect(0, 0, size.Width, size.Height), url);
|
SkiaCanvas.DrawUrlAnnotation(new SKRect(0, 0, size.Width, size.Height), url);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void DrawLocationLink(string locationName, Size size)
|
||||||
|
{
|
||||||
|
SkiaCanvas.DrawLinkDestinationAnnotation(new SKRect(0, 0, size.Width, size.Height), locationName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DrawLocation(string locationName)
|
||||||
|
{
|
||||||
|
SkiaCanvas.DrawNamedDestinationAnnotation(new SKPoint(0, 0), locationName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -30,13 +30,15 @@ namespace QuestPDF.Drawing
|
||||||
|
|
||||||
static SKPaint Convert(TextStyle style)
|
static SKPaint Convert(TextStyle style)
|
||||||
{
|
{
|
||||||
|
var slant = style.IsItalic ? SKFontStyleSlant.Italic : SKFontStyleSlant.Upright;
|
||||||
|
|
||||||
return new SKPaint
|
return new SKPaint
|
||||||
{
|
{
|
||||||
Color = SKColor.Parse(style.Color),
|
Color = SKColor.Parse(style.Color),
|
||||||
Typeface = Fonts.GetOrAdd(style.FontType, SKTypeface.FromFamilyName),
|
Typeface = SKTypeface.FromFamilyName(style.FontType, (int)style.FontWeight, (int)SKFontStyleWidth.Normal, slant),
|
||||||
TextSize = style.Size,
|
TextSize = style.Size,
|
||||||
IsLinearText = true,
|
TextEncoding = SKTextEncoding.Utf32,
|
||||||
|
|
||||||
TextAlign = style.Alignment switch
|
TextAlign = style.Alignment switch
|
||||||
{
|
{
|
||||||
HorizontalAlignment.Left => SKTextAlign.Left,
|
HorizontalAlignment.Left => SKTextAlign.Left,
|
||||||
|
|
|
@ -12,7 +12,6 @@ namespace QuestPDF.Drawing
|
||||||
static class DocumentGenerator
|
static class DocumentGenerator
|
||||||
{
|
{
|
||||||
const int DocumentLayoutExceptionThreshold = 250;
|
const int DocumentLayoutExceptionThreshold = 250;
|
||||||
private static readonly Watermark Watermark = new Watermark();
|
|
||||||
|
|
||||||
internal static void Generate(Stream stream, IDocument document)
|
internal static void Generate(Stream stream, IDocument document)
|
||||||
{
|
{
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
using QuestPDF.Drawing.SpacePlan;
|
||||||
|
using QuestPDF.Infrastructure;
|
||||||
|
|
||||||
|
namespace QuestPDF.Elements
|
||||||
|
{
|
||||||
|
internal class ExternalLink : ContainerElement
|
||||||
|
{
|
||||||
|
public string Url { get; set; } = "https://www.questpdf.com";
|
||||||
|
|
||||||
|
internal override void Draw(ICanvas canvas, Size availableSpace)
|
||||||
|
{
|
||||||
|
var targetSize = Child?.Measure(availableSpace) as Size;
|
||||||
|
|
||||||
|
if (targetSize == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
canvas.DrawExternalLink(Url, targetSize);
|
||||||
|
Child?.Draw(canvas, availableSpace);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
using QuestPDF.Drawing.SpacePlan;
|
||||||
|
using QuestPDF.Infrastructure;
|
||||||
|
|
||||||
|
namespace QuestPDF.Elements
|
||||||
|
{
|
||||||
|
internal class InternalLink : ContainerElement
|
||||||
|
{
|
||||||
|
public string LocationName { get; set; }
|
||||||
|
|
||||||
|
internal override void Draw(ICanvas canvas, Size availableSpace)
|
||||||
|
{
|
||||||
|
var targetSize = Child?.Measure(availableSpace) as Size;
|
||||||
|
|
||||||
|
if (targetSize == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
canvas.DrawLocationLink(LocationName, targetSize);
|
||||||
|
Child?.Draw(canvas, availableSpace);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
using System;
|
||||||
|
using QuestPDF.Drawing.SpacePlan;
|
||||||
|
using QuestPDF.Infrastructure;
|
||||||
|
|
||||||
|
namespace QuestPDF.Elements
|
||||||
|
{
|
||||||
|
internal class InternalLocation : ContainerElement
|
||||||
|
{
|
||||||
|
public string LocationName { get; set; }
|
||||||
|
|
||||||
|
internal override void Draw(ICanvas canvas, Size availableSpace)
|
||||||
|
{
|
||||||
|
canvas.DrawLocation(LocationName);
|
||||||
|
Child?.Draw(canvas, availableSpace);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -47,10 +47,8 @@ namespace QuestPDF.Elements
|
||||||
|
|
||||||
var size = space as Size;
|
var size = space as Size;
|
||||||
|
|
||||||
if (size.Height < Size.Epsilon)
|
if (size.Height > Size.Epsilon)
|
||||||
continue;
|
heightOnCurrentPage += size.Height + Spacing;
|
||||||
|
|
||||||
heightOnCurrentPage += size.Height + Spacing;
|
|
||||||
|
|
||||||
if (space is PartialRender)
|
if (space is PartialRender)
|
||||||
{
|
{
|
||||||
|
@ -81,18 +79,13 @@ namespace QuestPDF.Elements
|
||||||
break;
|
break;
|
||||||
|
|
||||||
var size = space as Size;
|
var size = space as Size;
|
||||||
|
|
||||||
if (size.Height < Size.Epsilon)
|
|
||||||
{
|
|
||||||
ChildrenQueue.Dequeue();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
canvas.Translate(new Position(0, topOffset));
|
canvas.Translate(new Position(0, topOffset));
|
||||||
child.Draw(canvas, new Size(availableSpace.Width, size.Height));
|
child.Draw(canvas, new Size(availableSpace.Width, size.Height));
|
||||||
canvas.Translate(new Position(0, -topOffset));
|
canvas.Translate(new Position(0, -topOffset));
|
||||||
|
|
||||||
topOffset += size.Height + Spacing;
|
if (size.Height > Size.Epsilon)
|
||||||
|
topOffset += size.Height + Spacing;
|
||||||
|
|
||||||
if (space is PartialRender)
|
if (space is PartialRender)
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -1,62 +0,0 @@
|
||||||
using QuestPDF.Drawing.SpacePlan;
|
|
||||||
using QuestPDF.Infrastructure;
|
|
||||||
|
|
||||||
namespace QuestPDF.Elements
|
|
||||||
{
|
|
||||||
internal class Watermark : Element
|
|
||||||
{
|
|
||||||
private Position Offset { get; set; } = new Position(36, 36);
|
|
||||||
private const float ImageHeight = 28;
|
|
||||||
private const string TargetUrl = "https://www.questpdf.com";
|
|
||||||
|
|
||||||
private Image Image { get; set; }
|
|
||||||
private static readonly byte[] ImageData;
|
|
||||||
|
|
||||||
static Watermark()
|
|
||||||
{
|
|
||||||
ImageData = Helpers.Helpers.LoadEmbeddedResource("QuestPDF.Resources.Watermark.png");
|
|
||||||
}
|
|
||||||
|
|
||||||
public Watermark()
|
|
||||||
{
|
|
||||||
Image = new Image()
|
|
||||||
{
|
|
||||||
Data = ImageData
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void AdjustPosition(Element? element)
|
|
||||||
{
|
|
||||||
while (element != null)
|
|
||||||
{
|
|
||||||
if (element is Padding padding)
|
|
||||||
{
|
|
||||||
if (padding.Left > 0 && padding.Bottom > 0)
|
|
||||||
Offset = new Position(padding.Left, padding.Bottom);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
element = (element as ContainerElement)?.Child;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal override ISpacePlan Measure(Size availableSpace)
|
|
||||||
{
|
|
||||||
return Image.Measure(availableSpace);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal override void Draw(ICanvas canvas, Size availableSpace)
|
|
||||||
{
|
|
||||||
var offset = new Position(Offset.X, availableSpace.Height - Offset.Y - ImageHeight);
|
|
||||||
canvas.Translate(offset);
|
|
||||||
|
|
||||||
availableSpace = new Size(availableSpace.Width, ImageHeight);
|
|
||||||
var targetSize = Image.Measure(availableSpace) as FullRender;
|
|
||||||
Image.Draw(canvas, targetSize);
|
|
||||||
canvas.DrawLink(TargetUrl, targetSize);
|
|
||||||
|
|
||||||
canvas.Translate(offset.Reverse());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -66,6 +66,14 @@ namespace QuestPDF.Fluent
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void DynamicImage(this IContainer element, Func<Size, byte[]> imageSource)
|
||||||
|
{
|
||||||
|
element.Element(new DynamicImage
|
||||||
|
{
|
||||||
|
Source = imageSource
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public static void PageNumber(this IContainer element, string textFormat = "{number}", TextStyle? style = null)
|
public static void PageNumber(this IContainer element, string textFormat = "{number}", TextStyle? style = null)
|
||||||
{
|
{
|
||||||
element.Element(new PageNumber
|
element.Element(new PageNumber
|
||||||
|
@ -127,11 +135,27 @@ namespace QuestPDF.Fluent
|
||||||
return element.Element(new Container());
|
return element.Element(new Container());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void DynamicImage(this IContainer element, Func<Size, byte[]> handler)
|
public static IContainer ExternalLink(this IContainer element, string url)
|
||||||
{
|
{
|
||||||
element.Element(new DynamicImage()
|
return element.Element(new ExternalLink
|
||||||
{
|
{
|
||||||
Source = handler
|
Url = url
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IContainer Location(this IContainer element, string locationName)
|
||||||
|
{
|
||||||
|
return element.Element(new InternalLocation
|
||||||
|
{
|
||||||
|
LocationName = locationName
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IContainer InternalLink(this IContainer element, string locationName)
|
||||||
|
{
|
||||||
|
return element.Element(new InternalLink
|
||||||
|
{
|
||||||
|
LocationName = locationName
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,13 @@ namespace QuestPDF.Fluent
|
||||||
return style.Mutate(x => x.LineHeight = value);
|
return style.Mutate(x => x.LineHeight = value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static TextStyle Italic(this TextStyle style, bool value = true)
|
||||||
|
{
|
||||||
|
return style.Mutate(x => x.IsItalic = value);
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Alignmnet
|
||||||
|
|
||||||
public static TextStyle Alignment(this TextStyle style, HorizontalAlignment value)
|
public static TextStyle Alignment(this TextStyle style, HorizontalAlignment value)
|
||||||
{
|
{
|
||||||
return style.Mutate(x => x.Alignment = value);
|
return style.Mutate(x => x.Alignment = value);
|
||||||
|
@ -38,17 +45,78 @@ namespace QuestPDF.Fluent
|
||||||
|
|
||||||
public static TextStyle AlignLeft(this TextStyle style)
|
public static TextStyle AlignLeft(this TextStyle style)
|
||||||
{
|
{
|
||||||
return style.Mutate(x => x.Alignment = HorizontalAlignment.Left);
|
return style.Alignment(HorizontalAlignment.Left);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static TextStyle AlignCenter(this TextStyle style)
|
public static TextStyle AlignCenter(this TextStyle style)
|
||||||
{
|
{
|
||||||
return style.Mutate(x => x.Alignment = HorizontalAlignment.Center);
|
return style.Alignment(HorizontalAlignment.Center);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static TextStyle AlignRight(this TextStyle style)
|
public static TextStyle AlignRight(this TextStyle style)
|
||||||
{
|
{
|
||||||
return style.Mutate(x => x.Alignment = HorizontalAlignment.Right);
|
return style.Alignment(HorizontalAlignment.Right);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Weight
|
||||||
|
|
||||||
|
public static TextStyle Weight(this TextStyle style, FontWeight weight)
|
||||||
|
{
|
||||||
|
return style.Mutate(x => x.FontWeight = weight);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TextStyle Thin(this TextStyle style)
|
||||||
|
{
|
||||||
|
return style.Weight(FontWeight.Thin);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TextStyle ExtraLight(this TextStyle style)
|
||||||
|
{
|
||||||
|
return style.Weight(FontWeight.ExtraLight);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TextStyle Light(this TextStyle style)
|
||||||
|
{
|
||||||
|
return style.Weight(FontWeight.Light);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TextStyle NormalWeight(this TextStyle style)
|
||||||
|
{
|
||||||
|
return style.Weight(FontWeight.Normal);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TextStyle Medium(this TextStyle style)
|
||||||
|
{
|
||||||
|
return style.Weight(FontWeight.Medium);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TextStyle SemiBold(this TextStyle style)
|
||||||
|
{
|
||||||
|
return style.Weight(FontWeight.SemiBold);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TextStyle Bold(this TextStyle style)
|
||||||
|
{
|
||||||
|
return style.Weight(FontWeight.Bold);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TextStyle ExtraBold(this TextStyle style)
|
||||||
|
{
|
||||||
|
return style.Weight(FontWeight.ExtraBold);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TextStyle Black(this TextStyle style)
|
||||||
|
{
|
||||||
|
return style.Weight(FontWeight.Black);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TextStyle ExtraBlack(this TextStyle style)
|
||||||
|
{
|
||||||
|
return style.Weight(FontWeight.ExtraBlack);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
namespace QuestPDF.Infrastructure
|
||||||
|
{
|
||||||
|
public enum FontWeight
|
||||||
|
{
|
||||||
|
Thin = 100,
|
||||||
|
ExtraLight = 200,
|
||||||
|
Light = 300,
|
||||||
|
Normal = 400,
|
||||||
|
Medium = 500,
|
||||||
|
SemiBold = 600,
|
||||||
|
Bold = 700,
|
||||||
|
ExtraBold = 800,
|
||||||
|
Black = 900,
|
||||||
|
ExtraBlack = 1000
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,6 +10,8 @@ namespace QuestPDF.Infrastructure
|
||||||
void DrawText(string text, Position position, TextStyle style);
|
void DrawText(string text, Position position, TextStyle style);
|
||||||
void DrawImage(SKImage image, Position position, Size size);
|
void DrawImage(SKImage image, Position position, Size size);
|
||||||
|
|
||||||
void DrawLink(string url, Size size);
|
void DrawExternalLink(string url, Size size);
|
||||||
|
void DrawLocationLink(string locationName, Size size);
|
||||||
|
void DrawLocation(string locationName);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -2,17 +2,19 @@
|
||||||
{
|
{
|
||||||
public class TextStyle
|
public class TextStyle
|
||||||
{
|
{
|
||||||
public string Color { get; set; } = "#000000";
|
internal string Color { get; set; } = "#000000";
|
||||||
public string FontType { get; set; } = "Helvetica";
|
internal string FontType { get; set; } = "Helvetica";
|
||||||
public float Size { get; set; } = 12;
|
internal float Size { get; set; } = 12;
|
||||||
public float LineHeight { get; set; } = 1.2f;
|
internal float LineHeight { get; set; } = 1.2f;
|
||||||
public HorizontalAlignment Alignment { get; set; } = HorizontalAlignment.Left;
|
internal HorizontalAlignment Alignment { get; set; } = HorizontalAlignment.Left;
|
||||||
|
internal FontWeight FontWeight { get; set; } = FontWeight.Normal;
|
||||||
|
internal bool IsItalic { get; set; } = false;
|
||||||
|
|
||||||
public static TextStyle Default => new TextStyle();
|
public static TextStyle Default => new TextStyle();
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
return $"{Color}|{FontType}|{Size}|{LineHeight}|{Alignment}";
|
return $"{Color}|{FontType}|{Size}|{LineHeight}|{Alignment}|{FontWeight}|{IsItalic}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -4,9 +4,9 @@
|
||||||
<Authors>MarcinZiabek</Authors>
|
<Authors>MarcinZiabek</Authors>
|
||||||
<Company>CodeFlint</Company>
|
<Company>CodeFlint</Company>
|
||||||
<PackageId>QuestPDF</PackageId>
|
<PackageId>QuestPDF</PackageId>
|
||||||
<Version>2021.1.0</Version>
|
<Version>2021.2.0</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>
|
<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>The library is open-source and totally free now. Removed watermak.</PackageReleaseNotes>
|
<PackageReleaseNotes>2021.2.0 Internal links, external links, dynamic images, font weights</PackageReleaseNotes>
|
||||||
<LangVersion>8</LangVersion>
|
<LangVersion>8</LangVersion>
|
||||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||||
<PackageIcon>Logo.png</PackageIcon>
|
<PackageIcon>Logo.png</PackageIcon>
|
||||||
|
|
Загрузка…
Ссылка в новой задаче