|
|
@@ -1,8 +1,10 @@
|
|
|
using System;
|
|
|
using System.Collections.Generic;
|
|
|
+using System.Diagnostics;
|
|
|
using System.IO;
|
|
|
using QuestPDF.Drawing.Exceptions;
|
|
|
using QuestPDF.Drawing.SpacePlan;
|
|
|
+using QuestPDF.Elements;
|
|
|
using QuestPDF.Fluent;
|
|
|
using QuestPDF.Helpers;
|
|
|
using QuestPDF.Infrastructure;
|
|
|
@@ -14,115 +16,130 @@ namespace QuestPDF.Drawing
|
|
|
{
|
|
|
internal static void GeneratePdf(Stream stream, IDocument document)
|
|
|
{
|
|
|
- var content = ElementExtensions.Create(document.Compose);
|
|
|
+ var container = new DocumentContainer();
|
|
|
+ document.Compose(container);
|
|
|
+ var content = container.Compose();
|
|
|
+
|
|
|
var metadata = document.GetMetadata();
|
|
|
+ var pageContext = new PageContext();
|
|
|
+
|
|
|
+ var timer = new Stopwatch();
|
|
|
|
|
|
- using var pdf = SKDocument.CreatePdf(stream, MapMetadata(metadata));
|
|
|
- var totalPages = 1;
|
|
|
+ timer.Start();
|
|
|
+ RenderDocument(pageContext, new FreeCanvas(), content, metadata);
|
|
|
|
|
|
- while(true)
|
|
|
- {
|
|
|
- var spacePlan = content.Measure(metadata.Size);
|
|
|
-
|
|
|
- using var skiaCanvas = pdf.BeginPage(metadata.Size.Width, metadata.Size.Height);
|
|
|
- var canvas = new Canvas(skiaCanvas);
|
|
|
-
|
|
|
- try
|
|
|
- {
|
|
|
- content.Draw(canvas, metadata.Size);
|
|
|
- }
|
|
|
- catch (Exception exception)
|
|
|
- {
|
|
|
- pdf.Close();
|
|
|
- throw new DocumentDrawingException("An exception occured during document drawing.", exception);
|
|
|
- }
|
|
|
-
|
|
|
- pdf.EndPage();
|
|
|
-
|
|
|
- if (totalPages >= metadata.DocumentLayoutExceptionThreshold)
|
|
|
- {
|
|
|
- pdf.Close();
|
|
|
- throw new DocumentLayoutException("Composed layout generates infinite document.");
|
|
|
- }
|
|
|
-
|
|
|
- if (spacePlan is FullRender)
|
|
|
- break;
|
|
|
-
|
|
|
- totalPages++;
|
|
|
- }
|
|
|
+ Console.WriteLine($"First rendering pass: {timer.Elapsed:g}");
|
|
|
+ timer.Restart();
|
|
|
|
|
|
- pdf.Close();
|
|
|
+ var canvas = new PdfCanvas(stream, metadata);
|
|
|
+ RenderDocument(pageContext, canvas, content, metadata);
|
|
|
+
|
|
|
+ Console.WriteLine($"Second rendering pass: {timer.Elapsed:g}");
|
|
|
}
|
|
|
|
|
|
- internal static IEnumerable<byte[]> GenerateImages(IDocument document)
|
|
|
+ private static void RenderDocument<TCanvas>(PageContext pageContext, TCanvas canvas, Container content, DocumentMetadata documentMetadata)
|
|
|
+ where TCanvas : ICanvas, IRenderingCanvas
|
|
|
{
|
|
|
- var content = ElementExtensions.Create(document.Compose);
|
|
|
- var metadata = document.GetMetadata();
|
|
|
-
|
|
|
- var totalPages = 1;
|
|
|
+ content.HandleVisitor(x => x.Initialize(pageContext, canvas));
|
|
|
+ content.HandleVisitor(x => (x as IStateResettable)?.ResetState());
|
|
|
+
|
|
|
+ canvas.BeginDocument();
|
|
|
|
|
|
- while (true)
|
|
|
+ var currentPage = 1;
|
|
|
+
|
|
|
+ while(true)
|
|
|
{
|
|
|
- var spacePlan = content.Measure(metadata.Size);
|
|
|
- byte[] result;
|
|
|
+ pageContext.SetPageNumber(currentPage);
|
|
|
+ var spacePlan = content.Measure(Size.Max) as Size;
|
|
|
+
|
|
|
+ if (spacePlan == null)
|
|
|
+ break;
|
|
|
|
|
|
try
|
|
|
{
|
|
|
- result = RenderPage(content);
|
|
|
+ canvas.BeginPage(spacePlan);
|
|
|
+ content.Draw(spacePlan);
|
|
|
}
|
|
|
catch (Exception exception)
|
|
|
{
|
|
|
+ canvas.EndDocument();
|
|
|
throw new DocumentDrawingException("An exception occured during document drawing.", exception);
|
|
|
}
|
|
|
|
|
|
- yield return result;
|
|
|
+ canvas.EndPage();
|
|
|
|
|
|
- if (totalPages >= metadata.DocumentLayoutExceptionThreshold)
|
|
|
+ if (currentPage >= documentMetadata.DocumentLayoutExceptionThreshold)
|
|
|
{
|
|
|
+ canvas.EndDocument();
|
|
|
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();
|
|
|
+ currentPage++;
|
|
|
}
|
|
|
+
|
|
|
+ canvas.EndDocument();
|
|
|
}
|
|
|
|
|
|
- private static SKDocumentPdfMetadata MapMetadata(DocumentMetadata metadata)
|
|
|
+ internal static IEnumerable<byte[]> GenerateImages(IDocument document)
|
|
|
{
|
|
|
- return new SKDocumentPdfMetadata
|
|
|
- {
|
|
|
- Title = metadata.Title,
|
|
|
- Author = metadata.Author,
|
|
|
- Subject = metadata.Subject,
|
|
|
- Keywords = metadata.Keywords,
|
|
|
- Creator = metadata.Creator,
|
|
|
- Producer = metadata.Producer,
|
|
|
-
|
|
|
- Creation = metadata.CreationDate,
|
|
|
- Modified = metadata.ModifiedDate,
|
|
|
-
|
|
|
- RasterDpi = metadata.RasterDpi,
|
|
|
- EncodingQuality = metadata.ImageQuality,
|
|
|
- PdfA = metadata.PdfA
|
|
|
- };
|
|
|
+ return null;
|
|
|
+
|
|
|
+ // var container = new DocumentContainer();
|
|
|
+ // document.Compose(container);
|
|
|
+ // var content = container.Compose();
|
|
|
+ //
|
|
|
+ // var metadata = document.GetMetadata();
|
|
|
+ //
|
|
|
+ // var currentPage = 1;
|
|
|
+ //
|
|
|
+ // while (true)
|
|
|
+ // {
|
|
|
+ // var spacePlan = content.Measure(null, Size.Max) as Size;
|
|
|
+ // byte[] result;
|
|
|
+ //
|
|
|
+ // if (spacePlan == null)
|
|
|
+ // break;
|
|
|
+ //
|
|
|
+ // try
|
|
|
+ // {
|
|
|
+ // result = RenderPage(spacePlan, content);
|
|
|
+ // }
|
|
|
+ // catch (Exception exception)
|
|
|
+ // {
|
|
|
+ // throw new DocumentDrawingException("An exception occured during document drawing.", exception);
|
|
|
+ // }
|
|
|
+ //
|
|
|
+ // yield return result;
|
|
|
+ //
|
|
|
+ // if (currentPage >= metadata.DocumentLayoutExceptionThreshold)
|
|
|
+ // {
|
|
|
+ // throw new DocumentLayoutException("Composed layout generates infinite document.");
|
|
|
+ // }
|
|
|
+ //
|
|
|
+ // if (spacePlan is FullRender)
|
|
|
+ // break;
|
|
|
+ //
|
|
|
+ // currentPage++;
|
|
|
+ // }
|
|
|
+
|
|
|
+ // byte[] RenderPage(Size size, Element element)
|
|
|
+ // {
|
|
|
+ // // scale the result so it is more readable
|
|
|
+ // var scalingFactor = metadata.RasterDpi / (float) PageSizes.PointsPerInch;
|
|
|
+ //
|
|
|
+ // var imageInfo = new SKImageInfo((int) (size.Width * scalingFactor), (int) (size.Height * scalingFactor));
|
|
|
+ // using var surface = SKSurface.Create(imageInfo);
|
|
|
+ // surface.Canvas.Scale(scalingFactor);
|
|
|
+ //
|
|
|
+ // var canvas = new SkiaCanvasBase(surface.Canvas, new Dictionary<string, int>());
|
|
|
+ // element?.Draw(canvas, size);
|
|
|
+ //
|
|
|
+ // surface.Canvas.Save();
|
|
|
+ // return surface.Snapshot().Encode(SKEncodedImageFormat.Png, 100).ToArray();
|
|
|
+ // }
|
|
|
}
|
|
|
}
|
|
|
}
|