2021.3.0 Generating images functionality, ShowIf element, fixed mutating TextStyle
This commit is contained in:
@@ -6,6 +6,7 @@ using System.Reflection;
|
||||
using NUnit.Framework;
|
||||
using QuestPDF.Drawing;
|
||||
using QuestPDF.Elements;
|
||||
using QuestPDF.Fluent;
|
||||
using QuestPDF.Infrastructure;
|
||||
using SkiaSharp;
|
||||
|
||||
@@ -60,23 +61,13 @@ namespace QuestPDF.Examples.Engine
|
||||
var container = new Container();
|
||||
methodInfo.Invoke(this, new object[] {container});
|
||||
|
||||
var iteration = 1;
|
||||
Func<int, string> fileNameSchema = i => $"{fileName.ToLower()}-${i}.png";
|
||||
|
||||
while (iteration <= 1)
|
||||
{
|
||||
var imageData = RenderPage(container, size);
|
||||
|
||||
if (imageData == null)
|
||||
return;
|
||||
|
||||
var path = Path.Combine(ResultPath, $"{fileName.ToLower()}-${iteration}.png");
|
||||
File.WriteAllBytes(path, imageData);
|
||||
|
||||
if (showResult)
|
||||
Process.Start("explorer", path);
|
||||
|
||||
iteration++;
|
||||
}
|
||||
var document = new SimpleDocument(container, size);
|
||||
document.GenerateImages(fileNameSchema);
|
||||
|
||||
if (showResult)
|
||||
Process.Start("explorer", fileNameSchema(0));
|
||||
}
|
||||
|
||||
private byte[] RenderPage(Element element, Size size)
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
using QuestPDF.Drawing;
|
||||
using QuestPDF.Fluent;
|
||||
using QuestPDF.Helpers;
|
||||
using QuestPDF.Infrastructure;
|
||||
|
||||
namespace QuestPDF.Examples.Engine
|
||||
{
|
||||
public class SimpleDocument : IDocument
|
||||
{
|
||||
private IContainer Container { get; }
|
||||
private Size Size { get; }
|
||||
|
||||
public SimpleDocument(IContainer container, Size size)
|
||||
{
|
||||
Container = container;
|
||||
Size = size;
|
||||
}
|
||||
|
||||
public DocumentMetadata GetMetadata()
|
||||
{
|
||||
return new DocumentMetadata()
|
||||
{
|
||||
RasterDpi = PageSizes.PointsPerInch * 2,
|
||||
Size = Size
|
||||
};
|
||||
}
|
||||
|
||||
public void Compose(IContainer container)
|
||||
{
|
||||
container.Element(Container.Child);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -19,7 +19,7 @@ namespace QuestPDF.ReportSample
|
||||
|
||||
var path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $"test_result.pdf");
|
||||
using var stream = new FileStream(path, FileMode.Create);
|
||||
report.Generate(stream);
|
||||
report.GeneratePdf(stream);
|
||||
|
||||
Process.Start("explorer.exe", path);
|
||||
}
|
||||
@@ -45,7 +45,7 @@ namespace QuestPDF.ReportSample
|
||||
var sw = new Stopwatch();
|
||||
|
||||
sw.Start();
|
||||
var totalSize = reports.Select(x => x.Generate()).Sum(x => (long)x.Length);
|
||||
var totalSize = reports.Select(x => x.GeneratePdf()).Sum(x => (long)x.Length);
|
||||
sw.Stop();
|
||||
|
||||
// show summary
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using QuestPDF.Drawing.Exceptions;
|
||||
using QuestPDF.Drawing.SpacePlan;
|
||||
using QuestPDF.Elements;
|
||||
using QuestPDF.Fluent;
|
||||
using QuestPDF.Helpers;
|
||||
using QuestPDF.Infrastructure;
|
||||
using SkiaSharp;
|
||||
|
||||
@@ -11,9 +13,7 @@ namespace QuestPDF.Drawing
|
||||
{
|
||||
static class DocumentGenerator
|
||||
{
|
||||
const int DocumentLayoutExceptionThreshold = 250;
|
||||
|
||||
internal static void Generate(Stream stream, IDocument document)
|
||||
internal static void GeneratePdf(Stream stream, IDocument document)
|
||||
{
|
||||
var content = ElementExtensions.Create(document.Compose);
|
||||
var metadata = document.GetMetadata();
|
||||
@@ -42,7 +42,7 @@ namespace QuestPDF.Drawing
|
||||
|
||||
pdf.EndPage();
|
||||
|
||||
if (totalPages >= DocumentLayoutExceptionThreshold)
|
||||
if (totalPages >= metadata.DocumentLayoutExceptionThreshold)
|
||||
{
|
||||
pdf.Close();
|
||||
stream.Close();
|
||||
@@ -60,6 +60,57 @@ namespace QuestPDF.Drawing
|
||||
stream.Dispose();
|
||||
}
|
||||
|
||||
internal static IEnumerable<byte[]> GenerateImages(IDocument document)
|
||||
{
|
||||
var content = ElementExtensions.Create(document.Compose);
|
||||
var metadata = document.GetMetadata();
|
||||
|
||||
var totalPages = 1;
|
||||
|
||||
while (true)
|
||||
{
|
||||
var spacePlan = content.Measure(metadata.Size);
|
||||
byte[] result;
|
||||
|
||||
try
|
||||
{
|
||||
result = RenderPage(content);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
throw new DocumentDrawingException("An exception occured during document drawing.", exception);
|
||||
}
|
||||
|
||||
yield return result;
|
||||
|
||||
if (totalPages >= metadata.DocumentLayoutExceptionThreshold)
|
||||
{
|
||||
throw new DocumentLayoutException("Composed layout generates infinite document.");
|
||||
}
|
||||
|
||||
if (spacePlan is FullRender)
|
||||
break;
|
||||
|
||||
totalPages++;
|
||||
}
|
||||
|
||||
byte[] RenderPage(Element element)
|
||||
{
|
||||
// scale the result so it is more readable
|
||||
var scalingFactor = metadata.RasterDpi / (float) PageSizes.PointsPerInch;
|
||||
|
||||
var imageInfo = new SKImageInfo((int) (metadata.Size.Width * scalingFactor), (int) (metadata.Size.Height * scalingFactor));
|
||||
using var surface = SKSurface.Create(imageInfo);
|
||||
surface.Canvas.Scale(scalingFactor);
|
||||
|
||||
var canvas = new Canvas(surface.Canvas);
|
||||
element?.Draw(canvas, metadata.Size);
|
||||
|
||||
surface.Canvas.Save();
|
||||
return surface.Snapshot().Encode(SKEncodedImageFormat.Png, 100).ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
private static SKDocumentPdfMetadata MapMetadata(DocumentMetadata metadata)
|
||||
{
|
||||
return new SKDocumentPdfMetadata
|
||||
|
||||
@@ -21,6 +21,12 @@ namespace QuestPDF.Drawing
|
||||
public DateTime CreationDate { get; set; } = DateTime.Now;
|
||||
public DateTime ModifiedDate { get; set; } = DateTime.Now;
|
||||
|
||||
/// <summary>
|
||||
/// If the number of generated pages exceeds this threshold
|
||||
/// (likely due to infinite layout), the exception is thrown.
|
||||
/// </summary>
|
||||
public int DocumentLayoutExceptionThreshold { get; set; } = 250;
|
||||
|
||||
public static DocumentMetadata Default => new DocumentMetadata();
|
||||
}
|
||||
}
|
||||
@@ -16,24 +16,6 @@ namespace QuestPDF.Fluent
|
||||
return container;
|
||||
}
|
||||
|
||||
public static byte[] Generate(this IDocument document)
|
||||
{
|
||||
using var stream = new MemoryStream();
|
||||
document.Generate(stream);
|
||||
return stream.ToArray();
|
||||
}
|
||||
|
||||
public static void Generate(this IDocument document, string filePath)
|
||||
{
|
||||
using var stream = new FileStream(filePath, FileMode.Create);
|
||||
document.Generate(stream);
|
||||
}
|
||||
|
||||
public static void Generate(this IDocument document, Stream stream)
|
||||
{
|
||||
DocumentGenerator.Generate(stream, document);
|
||||
}
|
||||
|
||||
public static T Element<T>(this IContainer element, T child) where T : IElement
|
||||
{
|
||||
if (element?.Child != null && element.Child is Empty == false)
|
||||
@@ -158,5 +140,10 @@ namespace QuestPDF.Fluent
|
||||
LocationName = locationName
|
||||
});
|
||||
}
|
||||
|
||||
public static IContainer ShowIf(this IContainer element, bool condition)
|
||||
{
|
||||
return condition ? element : new Container();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using QuestPDF.Drawing;
|
||||
using QuestPDF.Infrastructure;
|
||||
|
||||
namespace QuestPDF.Fluent
|
||||
{
|
||||
public static class GenerateExtensions
|
||||
{
|
||||
public static byte[] GeneratePdf(this IDocument document)
|
||||
{
|
||||
using var stream = new MemoryStream();
|
||||
document.GeneratePdf(stream);
|
||||
return stream.ToArray();
|
||||
}
|
||||
|
||||
public static void GeneratePdf(this IDocument document, string filePath)
|
||||
{
|
||||
using var stream = new FileStream(filePath, FileMode.Create);
|
||||
document.GeneratePdf(stream);
|
||||
}
|
||||
|
||||
public static void GeneratePdf(this IDocument document, Stream stream)
|
||||
{
|
||||
DocumentGenerator.GeneratePdf(stream, document);
|
||||
}
|
||||
|
||||
public static IEnumerable<byte[]> GenerateImages(this IDocument document)
|
||||
{
|
||||
return DocumentGenerator.GenerateImages(document);
|
||||
}
|
||||
|
||||
/// <param name="filePath">Method should return fileName for given index</param>
|
||||
public static void GenerateImages(this IDocument document, Func<int, string> filePath)
|
||||
{
|
||||
var index = 0;
|
||||
|
||||
foreach (var imageData in document.GenerateImages())
|
||||
{
|
||||
var path = filePath(index);
|
||||
File.WriteAllBytes(path, imageData);
|
||||
index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,8 @@ namespace QuestPDF.Fluent
|
||||
{
|
||||
private static TextStyle Mutate(this TextStyle style, Action<TextStyle> handler)
|
||||
{
|
||||
style = style.Clone();
|
||||
|
||||
handler(style);
|
||||
return style;
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@ namespace QuestPDF.Helpers
|
||||
{
|
||||
public static class PageSizes
|
||||
{
|
||||
public const int PointsPerInch = 72;
|
||||
|
||||
public static Size A0 => new Size(2384, 3370);
|
||||
public static Size A1 => new Size(1684, 2384);
|
||||
public static Size A2 => new Size(1190, 1684);
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
namespace QuestPDF.Infrastructure
|
||||
using System;
|
||||
using QuestPDF.Elements;
|
||||
|
||||
namespace QuestPDF.Infrastructure
|
||||
{
|
||||
public class TextStyle
|
||||
{
|
||||
@@ -16,5 +19,7 @@
|
||||
{
|
||||
return $"{Color}|{FontType}|{Size}|{LineHeight}|{Alignment}|{FontWeight}|{IsItalic}";
|
||||
}
|
||||
|
||||
internal TextStyle Clone() => (TextStyle)MemberwiseClone();
|
||||
}
|
||||
}
|
||||
@@ -4,9 +4,9 @@
|
||||
<Authors>MarcinZiabek</Authors>
|
||||
<Company>CodeFlint</Company>
|
||||
<PackageId>QuestPDF</PackageId>
|
||||
<Version>2021.2.0</Version>
|
||||
<Version>2021.3.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>
|
||||
<PackageReleaseNotes>2021.2.0 Internal links, external links, dynamic images, font weights</PackageReleaseNotes>
|
||||
<PackageReleaseNotes>Generating images functionality, ShowIf element, fixed mutating TextStyle</PackageReleaseNotes>
|
||||
<LangVersion>8</LangVersion>
|
||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||
<PackageIcon>Logo.png</PackageIcon>
|
||||
|
||||
Reference in New Issue
Block a user