LayoutTestOutputVisualization.cs 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  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. private const string DocumentBackgroundColor = Colors.Grey.Lighten1;
  10. private const string PageBackgroundColor = Colors.Grey.Lighten3;
  11. private const string RequiredAreaBackgroundColor = Colors.White;
  12. private const string GridLineColor = Colors.Grey.Lighten1;
  13. private static readonly string[] DefaultElementColors =
  14. {
  15. Colors.Red.Medium,
  16. Colors.Green.Medium,
  17. Colors.Blue.Medium,
  18. Colors.Pink.Medium,
  19. Colors.Orange.Medium,
  20. Colors.Lime.Medium,
  21. Colors.Cyan.Medium,
  22. Colors.Indigo.Medium
  23. };
  24. public static void Visualize(LayoutTestResult result)
  25. {
  26. var path = "test.pdf";
  27. if (File.Exists(path))
  28. File.Delete(path);
  29. // determine children colors
  30. var mocks = Enumerable
  31. .Concat(result.GeneratedLayout, result.ExpectedLayout)
  32. .SelectMany(x => x.MockPositions)
  33. .Select(x => x.MockId)
  34. .Distinct()
  35. .ToList();
  36. var colors = Enumerable
  37. .Range(0, mocks.Count)
  38. .ToDictionary(i => mocks[i], i => DefaultElementColors[i]);
  39. // create new pdf document output
  40. var matrixHeight = Math.Max(result.GeneratedLayout.Count, result.ExpectedLayout.Count);
  41. const int pagePadding = 25;
  42. var imageInfo = new SKImageInfo((int)result.PageSize.Width * 2 + pagePadding * 4, (int)(result.PageSize.Height * matrixHeight + pagePadding * (matrixHeight + 2)));
  43. const int outputScale = 2;
  44. using var pdf = SKDocument.CreatePdf(path);
  45. using var canvas = pdf.BeginPage(imageInfo.Width * outputScale, imageInfo.Height * outputScale);
  46. canvas.Scale(outputScale, outputScale);
  47. // page background
  48. canvas.Clear(SKColor.Parse(DocumentBackgroundColor));
  49. // chain titles
  50. // available area
  51. using var titlePaint = TextStyle.LibraryDefault.FontSize(16).Bold().ToPaint().Clone();
  52. titlePaint.TextAlign = SKTextAlign.Center;
  53. canvas.Save();
  54. canvas.Translate(pagePadding + result.PageSize.Width / 2f, pagePadding + titlePaint.TextSize / 2);
  55. canvas.DrawText("RESULT", 0, 0, titlePaint);
  56. canvas.Translate(pagePadding * 2 + result.PageSize.Width, 0);
  57. canvas.DrawText("EXPECTED", 0, 0, titlePaint);
  58. canvas.Restore();
  59. // side visualization
  60. canvas.Save();
  61. canvas.Translate(pagePadding, pagePadding * 2);
  62. DrawSide(result.GeneratedLayout);
  63. canvas.Translate(result.PageSize.Width + pagePadding * 2, 0);
  64. DrawSide(result.ExpectedLayout);
  65. canvas.Restore();
  66. // draw page numbers
  67. canvas.Save();
  68. canvas.Translate(pagePadding * 2 + result.PageSize.Width, pagePadding * 2 + titlePaint.TextSize);
  69. foreach (var i in Enumerable.Range(0, matrixHeight))
  70. {
  71. canvas.DrawText((i + 1).ToString(), 0, 0, titlePaint);
  72. canvas.Translate(0, pagePadding + result.PageSize.Height);
  73. }
  74. canvas.Restore();
  75. pdf.EndPage();
  76. pdf.Close();
  77. void DrawSide(ICollection<LayoutTestResult.PageLayoutSnapshot> commands)
  78. {
  79. canvas.Save();
  80. foreach (var pageDrawingCommand in commands)
  81. {
  82. DrawPage(pageDrawingCommand);
  83. canvas.Translate(0, result.PageSize.Height + pagePadding);
  84. }
  85. canvas.Restore();
  86. }
  87. void DrawPageGrid(Size pageSize)
  88. {
  89. using var paint = new SKPaint
  90. {
  91. Color = SKColor.Parse(GridLineColor),
  92. StrokeWidth = 1
  93. };
  94. const float GridSize = 10f;
  95. foreach (var i in Enumerable.Range(1, (int)Math.Floor(pageSize.Width / GridSize)))
  96. {
  97. canvas.DrawLine(new SKPoint(i * GridSize, 0), new SKPoint(i * GridSize, pageSize.Height), paint);
  98. }
  99. foreach (var i in Enumerable.Range(1, (int)Math.Floor(pageSize.Height / GridSize)))
  100. {
  101. canvas.DrawLine(new SKPoint(0, i * GridSize), new SKPoint(pageSize.Width, i * GridSize), paint);
  102. }
  103. }
  104. void DrawPage(LayoutTestResult.PageLayoutSnapshot command)
  105. {
  106. // available area
  107. using var availableAreaPaint = new SKPaint
  108. {
  109. Color = SKColor.Parse(PageBackgroundColor)
  110. };
  111. canvas.DrawRect(0, 0, result.PageSize.Width, result.PageSize.Height, availableAreaPaint);
  112. // taken area
  113. using var takenAreaPaint = new SKPaint
  114. {
  115. Color = SKColor.Parse(RequiredAreaBackgroundColor)
  116. };
  117. canvas.DrawRect(0, 0, command.RequiredArea.Width, command.RequiredArea.Height, takenAreaPaint);
  118. DrawPageGrid(result.PageSize);
  119. // draw children
  120. foreach (var child in command.MockPositions)
  121. {
  122. canvas.Save();
  123. const float strokeWidth = 3f;
  124. var color = colors[child.MockId];
  125. using var childBorderPaint = new SKPaint
  126. {
  127. Color = SKColor.Parse(color),
  128. IsStroke = true,
  129. StrokeWidth = strokeWidth
  130. };
  131. using var childAreaPaint = new SKPaint
  132. {
  133. Color = SKColor.Parse(color).WithAlpha(128)
  134. };
  135. canvas.Translate(child.Position.X, child.Position.Y);
  136. canvas.DrawRect(0, 0, child.Size.Width, child.Size.Height, childAreaPaint);
  137. canvas.DrawRect(strokeWidth / 2, strokeWidth / 2, child.Size.Width - strokeWidth, child.Size.Height - strokeWidth, childBorderPaint);
  138. canvas.Restore();
  139. }
  140. }
  141. // save
  142. GenerateExtensions.OpenFileUsingDefaultProgram(path);
  143. }
  144. }