ImageTests.cs 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. using System;
  2. using System.IO;
  3. using System.Linq;
  4. using System.Net.Mime;
  5. using System.Threading;
  6. using NUnit.Framework;
  7. using QuestPDF.Drawing;
  8. using QuestPDF.Drawing.Exceptions;
  9. using QuestPDF.Elements;
  10. using QuestPDF.Fluent;
  11. using QuestPDF.Helpers;
  12. using QuestPDF.Infrastructure;
  13. using QuestPDF.UnitTests.TestEngine;
  14. using SkiaSharp;
  15. using ImageElement = QuestPDF.Elements.Image;
  16. using DocumentImage = QuestPDF.Infrastructure.Image;
  17. namespace QuestPDF.UnitTests
  18. {
  19. [TestFixture]
  20. public class ImageTests
  21. {
  22. [Test]
  23. public void Measure_TakesMinimalSpaceRegardlessOfSize()
  24. {
  25. TestPlan
  26. .For(x => new ImageElement
  27. {
  28. DocumentImage = GenerateDocumentImage(400, 300)
  29. })
  30. .MeasureElement(new Size(300, 200))
  31. .CheckMeasureResult(SpacePlan.FullRender(0, 0));
  32. }
  33. [Test]
  34. public void Draw_TakesAvailableSpaceRegardlessOfSize()
  35. {
  36. TestPlan
  37. .For(x => new ImageElement
  38. {
  39. CompressionQuality = ImageCompressionQuality.High,
  40. TargetDpi = DocumentSettings.DefaultRasterDpi,
  41. DocumentImage = GenerateDocumentImage(400, 300)
  42. })
  43. .DrawElement(new Size(300, 200))
  44. .ExpectCanvasDrawImage(new Position(0, 0), new Size(300, 200))
  45. .CheckDrawResult();
  46. }
  47. [Test]
  48. public void Fluent_RecognizesImageProportions()
  49. {
  50. var image = GenerateDocumentImage(60, 20);
  51. TestPlan
  52. .For(x =>
  53. {
  54. var container = new Container();
  55. container.Image(image);
  56. return container;
  57. })
  58. .MeasureElement(new Size(300, 200))
  59. .CheckMeasureResult(SpacePlan.FullRender(300, 100));
  60. }
  61. [Test]
  62. public void ImageObject_ThrowsEncodingException_WhenImageDataIsIncorrect()
  63. {
  64. Func<Infrastructure.Image> action = () => Infrastructure.Image.FromBinaryData(new byte[] { 1, 2, 3 });
  65. Assert.That(action, Throws.Exception.TypeOf<DocumentComposeException>().With.Message.EqualTo("Cannot decode the provided image."));
  66. }
  67. [Test]
  68. public void ImageObject_ThrowsEncodingException_WhenStreamIsIncorrect()
  69. {
  70. Func<Infrastructure.Image> action = () =>
  71. {
  72. using var stream = new MemoryStream(new byte[] { 1, 2, 3 });
  73. return Infrastructure.Image.FromStream(stream);
  74. };
  75. Assert.That(action, Throws.Exception.TypeOf<DocumentComposeException>().With.Message.EqualTo("Cannot decode the provided image."));
  76. }
  77. [Test]
  78. public void ImageObject_ThrowsFileNotFoundException_FileIsNotFound()
  79. {
  80. var action = () => Infrastructure.Image.FromFile("non-existing-file.jpg");
  81. Assert.That(action, Throws.Exception.TypeOf<DocumentComposeException>().With.Message.EqualTo("Cannot load an image under the provided relative path, file not found: non-existing-file.jpg"));
  82. }
  83. [Test]
  84. public void UsingSharedImageShouldNotDrasticallyIncreaseDocumentSize()
  85. {
  86. var photo = File.ReadAllBytes("Resources/photo.jpg");
  87. var documentWithSingleImageSize = GetDocumentSize(container =>
  88. {
  89. container.Image(photo);
  90. });
  91. var documentWithMultipleImagesSize = GetDocumentSize(container =>
  92. {
  93. container.Column(column =>
  94. {
  95. foreach (var i in Enumerable.Range(0, 10))
  96. column.Item().Image(photo);
  97. });
  98. });
  99. using var sharedImage = DocumentImage.FromBinaryData(photo);
  100. var documentWithSingleImageUsedMultipleTimesSize = GetDocumentSize(container =>
  101. {
  102. container.Column(column =>
  103. {
  104. foreach (var i in Enumerable.Range(0, 10))
  105. column.Item().Image(sharedImage);
  106. });
  107. });
  108. var documentWithMultipleImagesSizeRatio = (documentWithMultipleImagesSize / (float)documentWithSingleImageSize);
  109. Assert.That(documentWithMultipleImagesSizeRatio, Is.InRange(9.9f, 10));
  110. var documentWithSingleImageUsedMultipleTimesSizeRatio = (documentWithSingleImageUsedMultipleTimesSize / (float)documentWithSingleImageSize);
  111. Assert.That(documentWithSingleImageUsedMultipleTimesSizeRatio, Is.InRange(1f, 1.05f));
  112. }
  113. [Test]
  114. public void ImageCompressionHasImpactOnDocumentSize()
  115. {
  116. var photo = File.ReadAllBytes("Resources/photo.jpg");
  117. var veryLowCompressionSize = GetDocumentSize(container => container.Image(photo).WithCompressionQuality(ImageCompressionQuality.VeryLow));
  118. var bestCompressionSize = GetDocumentSize(container => container.Image(photo).WithCompressionQuality(ImageCompressionQuality.Best));
  119. var compressionSizeRatio = (bestCompressionSize / (float)veryLowCompressionSize);
  120. Assert.That(compressionSizeRatio, Is.GreaterThan(10));
  121. }
  122. [Test]
  123. public void TargetDpiHasImpactOnDocumentSize()
  124. {
  125. var photo = File.ReadAllBytes("Resources/photo.jpg");
  126. var lowDpiSize = GetDocumentSize(container => container.Image(photo).WithRasterDpi(12));
  127. var highDpiSize = GetDocumentSize(container => container.Image(photo).WithRasterDpi(144));
  128. var dpiSizeRatio = (highDpiSize / (float)lowDpiSize);
  129. Assert.That(dpiSizeRatio, Is.GreaterThan(35));
  130. }
  131. private static int GetDocumentSize(Action<IContainer> container)
  132. {
  133. return Document
  134. .Create(document =>
  135. {
  136. document.Page(page =>
  137. {
  138. page.Content().Element(container);
  139. });
  140. })
  141. .GeneratePdf()
  142. .Length;
  143. }
  144. static DocumentImage GenerateDocumentImage(int width, int height)
  145. {
  146. var image = Placeholders.Image(width, height);
  147. var result = DocumentImage.FromBinaryData(image);
  148. result.IsShared = false;
  149. return result;
  150. }
  151. }
  152. }