diff --git a/Source/QuestPDF.Examples/ImageExamples.cs b/Source/QuestPDF.Examples/ImageExamples.cs index bd81b65..48d4db1 100644 --- a/Source/QuestPDF.Examples/ImageExamples.cs +++ b/Source/QuestPDF.Examples/ImageExamples.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using System.Linq; using NUnit.Framework; using QuestPDF.Drawing.Exceptions; using QuestPDF.Examples.Engine; @@ -79,11 +80,11 @@ namespace QuestPDF.Examples .ShowResults() .Render(page => { - page.Padding(10).Column(column => + page.Padding(15).Column(column => { - column.Spacing(10); + column.Spacing(15); - column.Item().Image("photo.jpg").WithRasterDpi(16); + column.Item().Image("photo.jpg").WithRasterDpi(16).FitUnproportionally(); column.Item().Image("photo.jpg").WithRasterDpi(72); }); }); @@ -99,9 +100,9 @@ namespace QuestPDF.Examples .ShowResults() .Render(page => { - page.Padding(10).Column(column => + page.Padding(15).Column(column => { - column.Spacing(10); + column.Spacing(15); column.Item().Image("photo.jpg").WithCompressionQuality(ImageCompressionQuality.VeryLow).WithRasterDpi(72); column.Item().Image("photo.jpg").WithCompressionQuality(ImageCompressionQuality.High).WithRasterDpi(72); @@ -109,6 +110,34 @@ namespace QuestPDF.Examples }); } + [Test] + public void ReusingImage_With() + { + RenderingTest + .Create() + .PageSize(400, 600) + .ProduceImages() + .ShowResults() + .Render(page => + { + page.Padding(15).Column(column => + { + column.Spacing(15); + + var image = Image.FromFile("checkbox.png"); + + foreach (var i in Enumerable.Range(0, 5)) + { + column.Item().Row(row => + { + row.AutoItem().Width(24).Image(image); + row.RelativeItem().PaddingLeft(8).AlignMiddle().Text(Placeholders.Label()).FontSize(16); + }); + } + }); + }); + } + [Test] public void Exception() { diff --git a/Source/QuestPDF.Examples/QuestPDF.Examples.csproj b/Source/QuestPDF.Examples/QuestPDF.Examples.csproj index 5f07fa7..4547520 100644 --- a/Source/QuestPDF.Examples/QuestPDF.Examples.csproj +++ b/Source/QuestPDF.Examples/QuestPDF.Examples.csproj @@ -38,6 +38,9 @@ PreserveNewest + + PreserveNewest + diff --git a/Source/QuestPDF.Examples/checkbox.png b/Source/QuestPDF.Examples/checkbox.png new file mode 100644 index 0000000..57422a7 Binary files /dev/null and b/Source/QuestPDF.Examples/checkbox.png differ diff --git a/Source/QuestPDF.UnitTests/ImageTests.cs b/Source/QuestPDF.UnitTests/ImageTests.cs index 3c70a33..5db35d9 100644 --- a/Source/QuestPDF.UnitTests/ImageTests.cs +++ b/Source/QuestPDF.UnitTests/ImageTests.cs @@ -85,7 +85,7 @@ namespace QuestPDF.UnitTests { container.Column(column => { - var sharedImage = DocumentImage.FromBinaryData(photo).DisposeAfterDocumentGeneration(); + var sharedImage = DocumentImage.FromBinaryData(photo); foreach (var i in Enumerable.Range(0, 10)) column.Item().Image(sharedImage); diff --git a/Source/QuestPDF/Fluent/ImageExtensions.cs b/Source/QuestPDF/Fluent/ImageExtensions.cs index 2b64836..c8b4fa7 100644 --- a/Source/QuestPDF/Fluent/ImageExtensions.cs +++ b/Source/QuestPDF/Fluent/ImageExtensions.cs @@ -109,19 +109,19 @@ namespace QuestPDF.Fluent { public static ImageDescriptor Image(this IContainer parent, byte[] imageData) { - var image = Infrastructure.Image.FromBinaryData(imageData).DisposeAfterDocumentGeneration(); + var image = Infrastructure.Image.FromBinaryData(imageData); return parent.Image(image); } public static ImageDescriptor Image(this IContainer parent, string filePath) { - var image = Infrastructure.Image.FromFile(filePath).DisposeAfterDocumentGeneration(); + var image = Infrastructure.Image.FromFile(filePath); return parent.Image(image); } public static ImageDescriptor Image(this IContainer parent, Stream fileStream) { - var image = Infrastructure.Image.FromStream(fileStream).DisposeAfterDocumentGeneration(); + var image = Infrastructure.Image.FromStream(fileStream); return parent.Image(image); } diff --git a/Source/QuestPDF/Infrastructure/Image.cs b/Source/QuestPDF/Infrastructure/Image.cs index 5ed6579..eb1bc73 100644 --- a/Source/QuestPDF/Infrastructure/Image.cs +++ b/Source/QuestPDF/Infrastructure/Image.cs @@ -13,28 +13,29 @@ namespace QuestPDF.Infrastructure internal ImageCompressionQuality CompressionQuality { get; set; } } - public class Image : IDisposable + public class Image { internal SKImage SkImage { get; } internal ImageSize Size { get; } - internal bool IsDocumentScoped { get; set; } + internal bool IsDocumentScoped { get; } internal LinkedList<(GetImageVersionRequest request, SKImage image)> ScaledImageCache { get; } = new(); - private Image(SKImage image) + internal Image(SKImage image, bool isDocumentScoped) { SkImage = image; + IsDocumentScoped = isDocumentScoped; Size = new ImageSize(image.Width, image.Height); } - - public void Dispose() + + internal void Dispose() { SkImage.Dispose(); foreach (var cacheKey in ScaledImageCache) cacheKey.image.Dispose(); } - + #region Scaling Image internal SKImage GetVersionOfSize(GetImageVersionRequest request) @@ -79,15 +80,51 @@ namespace QuestPDF.Infrastructure if (image == null) throw new DocumentComposeException("Cannot load or decode provided image."); - return new Image(image); + return new Image(image, true); } #endregion + } - internal Image DisposeAfterDocumentGeneration() + public class SharedImage : Image, IDisposable + { + internal SharedImage(SKImage image) : base(image, false) { - IsDocumentScoped = true; - return this; + } + + public void Dispose() + { + base.Dispose(); + } + + #region public constructors + + public static new SharedImage FromBinaryData(byte[] imageData) + { + return CreateImage(SKImage.FromEncodedData(imageData)); + } + + public static new SharedImage FromFile(string filePath) + { + return CreateImage(SKImage.FromEncodedData(filePath)); + } + + public static new SharedImage FromStream(Stream fileStream) + { + return CreateImage(SKImage.FromEncodedData(fileStream)); + } + + private static SharedImage CreateImage(SKImage? image) + { + if (image == null) + throw new DocumentComposeException("Cannot load or decode provided image."); + + var result = new SharedImage(image); + + return result; + } + + #endregion } } \ No newline at end of file