From b74e0327fac8a38a879014ead51d3dbfd1f1c7d0 Mon Sep 17 00:00:00 2001 From: MarcinZiabek Date: Sat, 20 May 2023 01:16:24 +0200 Subject: [PATCH] Improved SharedImage API --- Source/QuestPDF.Examples/ImageExamples.cs | 39 ++++++++++-- .../QuestPDF.Examples.csproj | 3 + Source/QuestPDF.Examples/checkbox.png | Bin 0 -> 3525 bytes Source/QuestPDF.UnitTests/ImageTests.cs | 2 +- Source/QuestPDF/Fluent/ImageExtensions.cs | 6 +- Source/QuestPDF/Infrastructure/Image.cs | 57 +++++++++++++++--- 6 files changed, 88 insertions(+), 19 deletions(-) create mode 100644 Source/QuestPDF.Examples/checkbox.png 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 0000000000000000000000000000000000000000..57422a7a0b52551af918da8724354da15de4c5b6 GIT binary patch literal 3525 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 { - 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