Browse Source

Feature: added support for shared/global images

MarcinZiabek 2 years ago
parent
commit
1c9bccbeb2

+ 19 - 31
Source/QuestPDF.Examples/ImageExamples.cs

@@ -1,10 +1,12 @@
 using System;
 using System.IO;
+using System.Linq;
 using NUnit.Framework;
 using QuestPDF.Drawing.Exceptions;
 using QuestPDF.Examples.Engine;
 using QuestPDF.Fluent;
 using QuestPDF.Helpers;
+using QuestPDF.Infrastructure;
 
 namespace QuestPDF.Examples
 {
@@ -67,39 +69,25 @@ namespace QuestPDF.Examples
         [Test]
         public void ReusingTheSameImageFileShouldBePossible()
         {
-            var fileName = Path.GetTempFileName() + ".jpg";
-            
-            try
-            {
-                var image = Placeholders.Image(300, 100);
-                
-                using var file = File.Create(fileName);
-                file.Write(image);
-                file.Dispose();
+            var image = Image.FromBinaryData(Placeholders.Image(300, 100)).DisposeAfterDocumentGeneration();
                 
-                RenderingTest
-                    .Create()
-                    .ProducePdf()
-                    .PageSize(PageSizes.A4)
-                    .ShowResults()
-                    .Render(container =>
-                    {
-                        container
-                            .Padding(20)
-                            .Column(column =>
-                            {
-                                column.Spacing(20);
+            RenderingTest
+                .Create()
+                .ProducePdf()
+                .PageSize(PageSizes.A4)
+                .ShowResults()
+                .Render(container =>
+                {
+                    container
+                        .Padding(20)
+                        .Column(column =>
+                        {
+                            column.Spacing(20);
                                 
-                                column.Item().Image(fileName);
-                                column.Item().Image(fileName);
-                                column.Item().Image(fileName);
-                            });
-                    });
-            }
-            finally
-            {
-                File.Delete(fileName);
-            }
+                            foreach (var i in Enumerable.Range(0, 1000))
+                                column.Item().Image(image);
+                        });
+                });
         }
     }
 }

+ 5 - 4
Source/QuestPDF.UnitTests/ImageTests.cs

@@ -5,6 +5,7 @@ using QuestPDF.Fluent;
 using QuestPDF.Infrastructure;
 using QuestPDF.UnitTests.TestEngine;
 using SkiaSharp;
+using Image = QuestPDF.Infrastructure.Image;
 
 namespace QuestPDF.UnitTests
 {
@@ -15,9 +16,9 @@ namespace QuestPDF.UnitTests
         public void Measure_TakesAvailableSpaceRegardlessOfSize()
         {
             TestPlan
-                .For(x => new Image
+                .For(x => new QuestPDF.Elements.Image
                 {
-                    InternalImage = GenerateImage(400, 300)
+                    DocumentImage = Image.FromSkImage(GenerateImage(400, 300))
                 })
                 .MeasureElement(new Size(300, 200))
                 .CheckMeasureResult(SpacePlan.FullRender(300, 200));
@@ -27,9 +28,9 @@ namespace QuestPDF.UnitTests
         public void Draw_TakesAvailableSpaceRegardlessOfSize()
         {
             TestPlan
-                .For(x => new Image
+                .For(x => new QuestPDF.Elements.Image
                 {
-                    InternalImage = GenerateImage(400, 300)
+                    DocumentImage = Image.FromSkImage(GenerateImage(400, 300))
                 })
                 .DrawElement(new Size(300, 200))
                 .ExpectCanvasDrawImage(new Position(0, 0), new Size(300, 200))

+ 5 - 4
Source/QuestPDF/Elements/Image.cs

@@ -7,11 +7,12 @@ namespace QuestPDF.Elements
 {
     internal class Image : Element, ICacheable
     {
-        public SKImage? InternalImage { get; set; }
+        public Infrastructure.Image? DocumentImage { get; set; }
 
         ~Image()
         {
-            InternalImage?.Dispose();
+            if (DocumentImage is { IsDocumentScoped: true })
+                DocumentImage?.Dispose();
         }
         
         internal override SpacePlan Measure(Size availableSpace)
@@ -23,10 +24,10 @@ namespace QuestPDF.Elements
 
         internal override void Draw(Size availableSpace)
         {
-            if (InternalImage == null)
+            if (DocumentImage == null)
                 return;
 
-            Canvas.DrawImage(InternalImage, Position.Zero, availableSpace);
+            Canvas.DrawImage(DocumentImage.SkImage, Position.Zero, availableSpace);
         }
     }
 }

+ 6 - 7
Source/QuestPDF/Fluent/ImageExtensions.cs

@@ -3,7 +3,6 @@ using System.IO;
 using QuestPDF.Drawing.Exceptions;
 using QuestPDF.Elements;
 using QuestPDF.Infrastructure;
-using SkiaSharp;
 
 namespace QuestPDF.Fluent
 {
@@ -11,30 +10,30 @@ namespace QuestPDF.Fluent
     {
         public static void Image(this IContainer parent, byte[] imageData, ImageScaling scaling = ImageScaling.FitWidth)
         {
-            var image = SKImage.FromEncodedData(imageData);
+            var image = Infrastructure.Image.FromBinaryData(imageData).DisposeAfterDocumentGeneration();
             parent.Image(image, scaling);
         }
         
         public static void Image(this IContainer parent, string filePath, ImageScaling scaling = ImageScaling.FitWidth)
         {
-            var image = SKImage.FromEncodedData(filePath);
+            var image = Infrastructure.Image.FromFile(filePath).DisposeAfterDocumentGeneration();
             parent.Image(image, scaling);
         }
         
         public static void Image(this IContainer parent, Stream fileStream, ImageScaling scaling = ImageScaling.FitWidth)
         {
-            var image = SKImage.FromEncodedData(fileStream);
+            var image = Infrastructure.Image.FromStream(fileStream).DisposeAfterDocumentGeneration();
             parent.Image(image, scaling);
         }
         
-        private static void Image(this IContainer parent, SKImage image, ImageScaling scaling = ImageScaling.FitWidth)
+        public static void Image(this IContainer parent, Infrastructure.Image image, ImageScaling scaling = ImageScaling.FitWidth)
         {
             if (image == null)
                 throw new DocumentComposeException("Cannot load or decode provided image.");
             
-            var imageElement = new Image
+            var imageElement = new QuestPDF.Elements.Image
             {
-                InternalImage = image
+                DocumentImage = image
             };
 
             if (scaling != ImageScaling.Resize)

+ 64 - 0
Source/QuestPDF/Infrastructure/Image.cs

@@ -0,0 +1,64 @@
+using System;
+using System.IO;
+using QuestPDF.Drawing.Exceptions;
+using SkiaSharp;
+
+namespace QuestPDF.Infrastructure
+{
+    public class Image : IDisposable
+    {
+        internal SKImage SkImage { get; }
+        internal bool IsDocumentScoped { get; set; }
+        
+        public int Width => SkImage.Width;
+        public int Height => SkImage.Height;
+        
+        private Image(SKImage image)
+        {
+            SkImage = image;
+        }
+
+        public Image DisposeAfterDocumentGeneration()
+        {
+            IsDocumentScoped = true;
+            return this;
+        }
+        
+        public void Dispose()
+        {
+            SkImage.Dispose();
+        }
+
+        #region public constructors
+
+        internal static Image FromSkImage(SKImage image)
+        {
+            return CreateImage(image);
+        }
+        
+        public static Image FromBinaryData(byte[] imageData)
+        {
+            return CreateImage(SKImage.FromEncodedData(imageData));
+        }
+        
+        public static Image FromFile(string filePath)
+        {
+            return CreateImage(SKImage.FromEncodedData(filePath));
+        }
+        
+        public static Image FromStream(Stream fileStream)
+        {
+            return CreateImage(SKImage.FromEncodedData(fileStream));
+        }
+        
+        private static Image CreateImage(SKImage? image)
+        {
+            if (image == null)
+                throw new DocumentComposeException("Cannot load or decode provided image.");
+            
+            return new Image(image);
+        }
+
+        #endregion
+    }
+}