Feature: added support for shared/global images

This commit is contained in:
MarcinZiabek
2023-04-17 02:08:04 +02:00
parent 176566801b
commit 1c9bccbeb2
5 changed files with 99 additions and 46 deletions
+19 -31
View File
@@ -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);
var image = Image.FromBinaryData(Placeholders.Image(300, 100)).DisposeAfterDocumentGeneration();
using var file = File.Create(fileName);
file.Write(image);
file.Dispose();
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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
}
}