Feature: added support for shared/global images
This commit is contained in:
@@ -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,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))
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user