LayoutTestOutputVisualization.cs 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. using QuestPDF.Drawing;
  2. using QuestPDF.Fluent;
  3. using QuestPDF.Helpers;
  4. using QuestPDF.Infrastructure;
  5. using SkiaSharp;
  6. namespace QuestPDF.LayoutTests.TestEngine;
  7. internal class LayoutTestResultVisualization
  8. {
  9. // visual settings
  10. private const string DocumentBackgroundColor = Colors.Grey.Lighten1;
  11. private const string PageBackgroundColor = Colors.Grey.Lighten3;
  12. private const string RequiredAreaBackgroundColor = Colors.White;
  13. private const string GridLineColor = Colors.Grey.Lighten1;
  14. private static readonly string[] DefaultElementColors =
  15. {
  16. Colors.Red.Medium,
  17. Colors.Green.Medium,
  18. Colors.Blue.Medium,
  19. Colors.Pink.Medium,
  20. Colors.Orange.Medium,
  21. Colors.Lime.Medium,
  22. Colors.Cyan.Medium,
  23. Colors.Indigo.Medium
  24. };
  25. private const int Padding = 32;
  26. private const int OutputImageScale = 2;
  27. private const float GridSize = 10;
  28. private const float MockBorderThickness = 3;
  29. private const byte MockBackgroundOpacity = 128;
  30. // implementations
  31. public static void Visualize(LayoutTestResult result, Stream stream)
  32. {
  33. // determine output dimenstions
  34. var numberOfPages = Math.Max(result.ActualLayout.Count, result.ExpectedLayout.Count);
  35. var canvasWidth = result.PageSize.Width * 2 + Padding * 4;
  36. var canvasHeight = result.PageSize.Height * numberOfPages + Padding * (numberOfPages + 2);
  37. // create PDF
  38. using var pdf = SKDocument.CreatePdf(stream);
  39. using var canvas = pdf.BeginPage(canvasWidth * OutputImageScale, canvasHeight * OutputImageScale);
  40. canvas.Scale(OutputImageScale, OutputImageScale);
  41. canvas.Clear(SKColor.Parse(DocumentBackgroundColor));
  42. // draw content
  43. var mockColors = AssignColorsToMocks();
  44. canvas.Translate(Padding, Padding);
  45. DrawLayout("ACTUAL", result.ActualLayout);
  46. canvas.Translate(result.PageSize.Width + Padding, 0);
  47. DrawPageNumbers();
  48. canvas.Translate(Padding, 0);
  49. DrawLayout("EXPECTED", result.ActualLayout);
  50. // finish generation
  51. pdf.EndPage();
  52. pdf.Close();
  53. IDictionary<string, string> AssignColorsToMocks()
  54. {
  55. var mocks = Enumerable
  56. .Concat(result.ActualLayout, result.ExpectedLayout)
  57. .SelectMany(x => x.MockPositions)
  58. .Select(x => x.MockId)
  59. .Distinct()
  60. .ToList();
  61. return Enumerable
  62. .Range(0, mocks.Count)
  63. .ToDictionary(i => mocks[i], i => DefaultElementColors[i]);
  64. }
  65. void DrawLayout(string title, ICollection<LayoutTestResult.PageLayoutSnapshot> commands)
  66. {
  67. // draw title
  68. using var titlePaint = TextStyle.LibraryDefault.FontSize(16).Bold().ToPaint().Clone();
  69. titlePaint.TextAlign = SKTextAlign.Center;
  70. var titlePosition = new SKPoint(result.PageSize.Width / 2, titlePaint.TextSize / 2);
  71. canvas.DrawText(title, titlePosition, titlePaint);
  72. // draw pages
  73. canvas.Save();
  74. canvas.Translate(0, Padding);
  75. foreach (var pageDrawingCommand in commands)
  76. {
  77. DrawPage(pageDrawingCommand);
  78. canvas.Translate(0, result.PageSize.Height + Padding);
  79. }
  80. canvas.Restore();
  81. }
  82. void DrawPageNumbers()
  83. {
  84. using var textPaint = TextStyle.LibraryDefault.FontSize(16).Bold().ToPaint().Clone();
  85. textPaint.TextAlign = SKTextAlign.Center;
  86. canvas.Save();
  87. canvas.Translate(0, Padding + textPaint.TextSize);
  88. foreach (var pageNumber in Enumerable.Range(1, numberOfPages))
  89. {
  90. canvas.DrawText(pageNumber.ToString(), 0, 0, textPaint);
  91. canvas.Translate(0, Padding + result.PageSize.Height);
  92. }
  93. canvas.Restore();
  94. }
  95. void DrawPage(LayoutTestResult.PageLayoutSnapshot pageLayout)
  96. {
  97. // draw page
  98. using var availableAreaPaint = new SKPaint
  99. {
  100. Color = SKColor.Parse(PageBackgroundColor)
  101. };
  102. using var requiredAreaPaint = new SKPaint
  103. {
  104. Color = SKColor.Parse(RequiredAreaBackgroundColor)
  105. };
  106. canvas.DrawRect(0, 0, result.PageSize.Width, result.PageSize.Height, availableAreaPaint);
  107. canvas.DrawRect(0, 0, pageLayout.RequiredArea.Width, pageLayout.RequiredArea.Height, requiredAreaPaint);
  108. DrawGridLines();
  109. // draw mocks
  110. foreach (var mock in pageLayout.MockPositions)
  111. {
  112. canvas.Save();
  113. var color = mockColors[mock.MockId];
  114. using var mockBorderPaint = new SKPaint
  115. {
  116. Color = SKColor.Parse(color),
  117. IsStroke = true,
  118. StrokeWidth = MockBorderThickness
  119. };
  120. using var mockAreaPaint = new SKPaint
  121. {
  122. Color = SKColor.Parse(color).WithAlpha(MockBackgroundOpacity)
  123. };
  124. canvas.Translate(mock.Position.X, mock.Position.Y);
  125. canvas.DrawRect(0, 0, mock.Size.Width, mock.Size.Height, mockAreaPaint);
  126. canvas.DrawRect(MockBorderThickness / 2, MockBorderThickness / 2, mock.Size.Width - MockBorderThickness, mock.Size.Height - MockBorderThickness, mockBorderPaint);
  127. canvas.Restore();
  128. }
  129. }
  130. void DrawGridLines()
  131. {
  132. using var paint = new SKPaint
  133. {
  134. Color = SKColor.Parse(GridLineColor),
  135. StrokeWidth = 1
  136. };
  137. var verticalLineCount = (int)Math.Floor(result.PageSize.Width / GridSize);
  138. var horizontalLineCount = (int)Math.Floor(result.PageSize.Height / GridSize);
  139. foreach (var i in Enumerable.Range(1, verticalLineCount))
  140. canvas.DrawLine(new SKPoint(i * GridSize, 0), new SKPoint(i * GridSize, result.PageSize.Height), paint);
  141. foreach (var i in Enumerable.Range(1, horizontalLineCount))
  142. canvas.DrawLine(new SKPoint(0, i * GridSize), new SKPoint(result.PageSize.Width, i * GridSize), paint);
  143. }
  144. }
  145. }