diff --git a/.github/workflows/build-action.yml b/.github/workflows/build-action.yml
index 47d345a3a..3767c37c2 100644
--- a/.github/workflows/build-action.yml
+++ b/.github/workflows/build-action.yml
@@ -17,7 +17,7 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v2
with:
- dotnet-version: 7.0.x
+ dotnet-version: 8.0.x
- name: Restore dependencies
run: dotnet restore Source/HtmlRenderer.sln
diff --git a/.github/workflows/release-action.yml b/.github/workflows/release-action.yml
index dd99688b0..e396f0d4d 100644
--- a/.github/workflows/release-action.yml
+++ b/.github/workflows/release-action.yml
@@ -31,7 +31,7 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v2
with:
- dotnet-version: 7.0.x
+ dotnet-version: 8.0.x
- name: Restore dependencies
run: dotnet restore Source/HtmlRenderer.sln
diff --git a/Source/Demos/HtmlRenderer.Demo.Common/HtmlRenderer.Demo.Common.csproj b/Source/Demos/HtmlRenderer.Demo.Common/HtmlRenderer.Demo.Common.csproj
index 12bf0c0e8..6b0f65ab3 100644
--- a/Source/Demos/HtmlRenderer.Demo.Common/HtmlRenderer.Demo.Common.csproj
+++ b/Source/Demos/HtmlRenderer.Demo.Common/HtmlRenderer.Demo.Common.csproj
@@ -1,300 +1,35 @@
+
+ net7.0
+ enable
+ disable
+
-
- net7.0
- enable
- disable
-
+
+
+
-
-
-
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
+
+
+
+
-
-
-
-
-
-
-
-
+
+
+
diff --git a/Source/Demos/HtmlRenderer.Demo.Console/SampleConverterBase.cs b/Source/Demos/HtmlRenderer.Demo.Common/SampleConverterBase.cs
similarity index 87%
rename from Source/Demos/HtmlRenderer.Demo.Console/SampleConverterBase.cs
rename to Source/Demos/HtmlRenderer.Demo.Common/SampleConverterBase.cs
index 8c1e4b2cb..ed5370c0d 100644
--- a/Source/Demos/HtmlRenderer.Demo.Console/SampleConverterBase.cs
+++ b/Source/Demos/HtmlRenderer.Demo.Common/SampleConverterBase.cs
@@ -10,33 +10,18 @@
using TheArtOfDev.HtmlRenderer.Core.Entities;
using TheArtOfDev.HtmlRenderer.Demo.Common;
-namespace HtmlRenderer.Demo.Console
+namespace HtmlRenderer.Demo.Common
{
public class SampleConverterBase
{
- private string _sampleRunIdentifier;
- private string _thisTypeName;
- private string _basePath;
-
- public SampleConverterBase(string sampleRunIdentifier, string basePath)
+ public SampleConverterBase()
{
- _sampleRunIdentifier = sampleRunIdentifier;
- _basePath = basePath;
- _thisTypeName = this.GetType().Name;
-
this.OnImageLoaded += ImageLoad;
this.OnStyleLoaded += StylesheetLoad;
}
public CssData CssData => null;
- protected string GetSamplePath(HtmlSample sample)
- {
- var path = Path.Combine(_basePath, _sampleRunIdentifier);
- Directory.CreateDirectory(path);
- return Path.Combine(path, sample.FullName + _thisTypeName + "_" + ".pdf");
- }
-
protected EventHandler OnImageLoaded;
protected EventHandler OnStyleLoaded;
@@ -56,4 +41,25 @@ internal void StylesheetLoad(object? sender, HtmlStylesheetLoadEventArgs e)
throw new NotImplementedException();
}
}
+
+ public class SampleConverterFileBase : SampleConverterBase
+ {
+ private string _sampleRunIdentifier;
+ private string _thisTypeName;
+ private string _basePath;
+
+ public SampleConverterFileBase(string sampleRunIdentifier, string basePath) : base()
+ {
+ _sampleRunIdentifier = sampleRunIdentifier;
+ _basePath = basePath;
+ _thisTypeName = this.GetType().Name;
+ }
+
+ protected string GetSamplePath(HtmlSample sample)
+ {
+ var path = Path.Combine(_basePath, _sampleRunIdentifier);
+ Directory.CreateDirectory(path);
+ return Path.Combine(path, sample.FullName + _thisTypeName + "_" + ".pdf");
+ }
+ }
}
diff --git a/Source/Demos/HtmlRenderer.Demo.Console/PdfSharpCoreConverter.cs b/Source/Demos/HtmlRenderer.Demo.Console/PdfSharpCoreConverter.cs
index 983c888e8..b18d81cab 100644
--- a/Source/Demos/HtmlRenderer.Demo.Console/PdfSharpCoreConverter.cs
+++ b/Source/Demos/HtmlRenderer.Demo.Console/PdfSharpCoreConverter.cs
@@ -1,4 +1,5 @@
-using System;
+using HtmlRenderer.Demo.Common;
+using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
@@ -8,7 +9,7 @@
namespace HtmlRenderer.Demo.Console
{
- public class PdfSharpCoreConverter : SampleConverterBase
+ public class PdfSharpCoreConverter : SampleConverterFileBase
{
public PdfSharpCoreConverter(string sampleRunIdentifier, string basePath) : base(sampleRunIdentifier, basePath)
{
diff --git a/Source/Demos/HtmlRenderer.Demo.Console/Program.cs b/Source/Demos/HtmlRenderer.Demo.Console/Program.cs
index 328899812..186bc09a2 100644
--- a/Source/Demos/HtmlRenderer.Demo.Console/Program.cs
+++ b/Source/Demos/HtmlRenderer.Demo.Console/Program.cs
@@ -11,7 +11,7 @@
}
//Probably won't be running a suite of tests more than once a second, so this will do.
-string runIdentifier = DateTime.Now.ToString("yyyyMMdd-hhmmss");
+var runIdentifier = DateTime.Now.ToString("yyyyMMdd-hhmmss");
var skia = new SkiaConverter(runIdentifier, basePath);
var pdfSharp = new PdfSharpCoreConverter(runIdentifier, basePath);
@@ -23,10 +23,10 @@
foreach (var htmlSample in samples)
{
////Just doing one test here. Comment this for all of them.
- if (!htmlSample.FullName.Contains("02", StringComparison.OrdinalIgnoreCase)) continue;
+ //if (!htmlSample.FullName.Contains("16", StringComparison.OrdinalIgnoreCase)) continue;
await skia.GenerateSampleAsync(htmlSample);
- //await pdfSharp.GenerateSampleAsync(htmlSample);
+ await pdfSharp.GenerateSampleAsync(htmlSample);
}
diff --git a/Source/Demos/HtmlRenderer.Demo.Console/SkiaConverter.cs b/Source/Demos/HtmlRenderer.Demo.Console/SkiaConverter.cs
index 93a749b38..5cfa068a4 100644
--- a/Source/Demos/HtmlRenderer.Demo.Console/SkiaConverter.cs
+++ b/Source/Demos/HtmlRenderer.Demo.Console/SkiaConverter.cs
@@ -1,4 +1,5 @@
-using System;
+using HtmlRenderer.Demo.Common;
+using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
@@ -8,7 +9,7 @@
namespace HtmlRenderer.Demo.Console
{
- public class SkiaConverter : SampleConverterBase
+ public class SkiaConverter : SampleConverterFileBase
{
public SkiaConverter(string sampleRunIdentifier, string basePath) : base(sampleRunIdentifier, basePath)
{
diff --git a/Source/HtmlRenderer.Demo.Web.Api/Controllers/PrinterController.cs b/Source/HtmlRenderer.Demo.Web.Api/Controllers/PrinterController.cs
new file mode 100644
index 000000000..20128c5d5
--- /dev/null
+++ b/Source/HtmlRenderer.Demo.Web.Api/Controllers/PrinterController.cs
@@ -0,0 +1,66 @@
+using Microsoft.AspNetCore.Mvc;
+using TheArtOfDev.HtmlRenderer.SkiaSharp;
+using TheArtOfDev.HtmlRenderer.Demo.Common;
+
+namespace HtmlRenderer.Demo.Web.Api.Controllers
+{
+ [ApiController]
+ [Route("[controller]")]
+ public class PrinterController(ILogger logger) : ControllerBase
+ {
+ private readonly ILogger _logger = logger;
+
+
+ [HttpGet("SampleNames")]
+ public IEnumerable GetSampleNames()
+ {
+ return SamplesLoader
+ .TestSamples
+ .Select(s => s.Name);
+ }
+
+ [HttpGet("Print")]
+ public async Task PrintSkia(string name)
+ {
+ var sample = GetSample(name);
+ if (sample == null)
+ {
+ return NotFound();
+ }
+
+ var converter = new SkiaConverter();
+ return await PrintPdf(converter, sample);
+ }
+
+
+ [HttpGet("PrintLegacy")]
+ public async Task PrintLegacy(string name)
+ {
+ var sample = GetSample(name);
+ if (sample == null)
+ {
+ return NotFound();
+ }
+
+ var converter = new PdfSharpCoreConverter();
+ return await PrintPdf(converter, sample);
+ }
+
+ private HtmlSample? GetSample(string name)
+ {
+ var sample = SamplesLoader.TestSamples
+ .Where(s => s.FullName.Contains(name, StringComparison.InvariantCultureIgnoreCase))
+ .FirstOrDefault();
+
+ return sample;
+ }
+
+ private async Task PrintPdf(IStreamPdfGenerator converter, HtmlSample sample)
+ {
+ var stream = await converter.GenerateSampleAsync(sample);
+ var filename = $"{sample.Name}-{DateTime.Now:yyyyMMdd-hhmmss}";
+
+ return File(stream, "application/pdf", filename);
+ }
+ }
+}
diff --git a/Source/HtmlRenderer.Demo.Web.Api/HtmlRenderer.Demo.Web.Api.csproj b/Source/HtmlRenderer.Demo.Web.Api/HtmlRenderer.Demo.Web.Api.csproj
new file mode 100644
index 000000000..5ce26f230
--- /dev/null
+++ b/Source/HtmlRenderer.Demo.Web.Api/HtmlRenderer.Demo.Web.Api.csproj
@@ -0,0 +1,21 @@
+
+
+
+ net8.0
+ enable
+ enable
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Source/HtmlRenderer.Demo.Web.Api/HtmlRenderer.Demo.Web.Api.http b/Source/HtmlRenderer.Demo.Web.Api/HtmlRenderer.Demo.Web.Api.http
new file mode 100644
index 000000000..a90271bb6
--- /dev/null
+++ b/Source/HtmlRenderer.Demo.Web.Api/HtmlRenderer.Demo.Web.Api.http
@@ -0,0 +1,16 @@
+@HtmlRenderer.Demo.Web.Api_HostAddress = http://localhost:5181
+
+GET {{HtmlRenderer.Demo.Web.Api_HostAddress}}/Printer/Samplenames
+Accept: application/json
+
+###
+
+GET {{HtmlRenderer.Demo.Web.Api_HostAddress}}/Printer/Print?name=Header
+Accept: application/pdf
+
+###
+
+GET {{HtmlRenderer.Demo.Web.Api_HostAddress}}/Printer/PrintLegacy?name=Header
+Accept: application/pdf
+
+###
\ No newline at end of file
diff --git a/Source/HtmlRenderer.Demo.Web.Api/IStreamPdfGenerator.cs b/Source/HtmlRenderer.Demo.Web.Api/IStreamPdfGenerator.cs
new file mode 100644
index 000000000..d5821c67f
--- /dev/null
+++ b/Source/HtmlRenderer.Demo.Web.Api/IStreamPdfGenerator.cs
@@ -0,0 +1,9 @@
+using TheArtOfDev.HtmlRenderer.Demo.Common;
+
+namespace HtmlRenderer.Demo.Web.Api
+{
+ public interface IStreamPdfGenerator
+ {
+ Task GenerateSampleAsync(HtmlSample sample);
+ }
+}
diff --git a/Source/HtmlRenderer.Demo.Web.Api/PdfConverter.cs b/Source/HtmlRenderer.Demo.Web.Api/PdfConverter.cs
new file mode 100644
index 000000000..424f8cd64
--- /dev/null
+++ b/Source/HtmlRenderer.Demo.Web.Api/PdfConverter.cs
@@ -0,0 +1,31 @@
+using HtmlRenderer.Demo.Common;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using TheArtOfDev.HtmlRenderer.Demo.Common;
+using TheArtOfDev.HtmlRenderer.PdfSharp;
+
+namespace HtmlRenderer.Demo.Web.Api
+{
+ public class PdfSharpCoreConverter : SampleConverterBase, IStreamPdfGenerator
+ {
+ public async Task GenerateSampleAsync(HtmlSample sample)
+ {
+ var config = new PdfGenerateConfig();
+
+ config.PageSize = PdfSharpCore.PageSize.A4;
+ config.MarginLeft = 0;
+ config.MarginRight = 0;
+ config.MarginTop = 0;
+ config.MarginBottom = 0;
+
+ var pdf = await PdfGenerator.GeneratePdfAsync(sample.Html, config, imageLoad: OnImageLoaded);
+ var stream = new MemoryStream();
+ pdf.Save(stream);
+ stream.Seek(0, SeekOrigin.Begin);
+ return stream;
+ }
+ }
+}
diff --git a/Source/HtmlRenderer.Demo.Web.Api/Program.cs b/Source/HtmlRenderer.Demo.Web.Api/Program.cs
new file mode 100644
index 000000000..d84c78ffc
--- /dev/null
+++ b/Source/HtmlRenderer.Demo.Web.Api/Program.cs
@@ -0,0 +1,26 @@
+using TheArtOfDev.HtmlRenderer.Demo.Common;
+
+var builder = WebApplication.CreateBuilder(args);
+
+// Add services to the container.
+
+builder.Services.AddControllers();
+// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
+builder.Services.AddEndpointsApiExplorer();
+builder.Services.AddSwaggerGen();
+
+var app = builder.Build();
+
+// Configure the HTTP request pipeline.
+app.UseSwagger();
+app.UseSwaggerUI();
+
+app.UseHttpsRedirection();
+
+app.UseAuthorization();
+
+app.MapControllers();
+
+SamplesLoader.Init("Console", typeof(Program).Assembly.GetName().Version!.ToString());
+
+app.Run();
diff --git a/Source/HtmlRenderer.Demo.Web.Api/Properties/launchSettings.json b/Source/HtmlRenderer.Demo.Web.Api/Properties/launchSettings.json
new file mode 100644
index 000000000..2890a2afd
--- /dev/null
+++ b/Source/HtmlRenderer.Demo.Web.Api/Properties/launchSettings.json
@@ -0,0 +1,41 @@
+{
+ "$schema": "http://json.schemastore.org/launchsettings.json",
+ "iisSettings": {
+ "windowsAuthentication": false,
+ "anonymousAuthentication": true,
+ "iisExpress": {
+ "applicationUrl": "http://localhost:12837",
+ "sslPort": 44340
+ }
+ },
+ "profiles": {
+ "http": {
+ "commandName": "Project",
+ "dotnetRunMessages": true,
+ "launchBrowser": true,
+ "launchUrl": "swagger",
+ "applicationUrl": "http://localhost:5181",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ },
+ "https": {
+ "commandName": "Project",
+ "dotnetRunMessages": true,
+ "launchBrowser": true,
+ "launchUrl": "swagger",
+ "applicationUrl": "https://localhost:7289;http://localhost:5181",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ },
+ "IIS Express": {
+ "commandName": "IISExpress",
+ "launchBrowser": true,
+ "launchUrl": "swagger",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ }
+ }
+}
diff --git a/Source/HtmlRenderer.Demo.Web.Api/SkiaConverter.cs b/Source/HtmlRenderer.Demo.Web.Api/SkiaConverter.cs
new file mode 100644
index 000000000..54443d952
--- /dev/null
+++ b/Source/HtmlRenderer.Demo.Web.Api/SkiaConverter.cs
@@ -0,0 +1,32 @@
+using HtmlRenderer.Demo.Common;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using TheArtOfDev.HtmlRenderer.Demo.Common;
+using TheArtOfDev.HtmlRenderer.SkiaSharp;
+
+namespace HtmlRenderer.Demo.Web.Api
+{
+ public class SkiaConverter : SampleConverterBase, IStreamPdfGenerator
+ {
+ public async Task GenerateSampleAsync(HtmlSample sample)
+ {
+ var config = new PdfGenerateConfig();
+
+ config.PageSize = PageSize.A4;
+
+ config.MarginLeft = 0;
+ config.MarginRight = 0;
+ config.MarginTop = 0;
+ config.MarginBottom = 0;
+
+ var stream = new MemoryStream();
+ await PdfGenerator.GeneratePdfAsync(sample.Html, stream, config, imageLoad: OnImageLoaded);
+ stream.Seek(0, SeekOrigin.Begin);
+
+ return stream;
+ }
+ }
+}
diff --git a/Source/HtmlRenderer.Demo.Web.Api/appsettings.Development.json b/Source/HtmlRenderer.Demo.Web.Api/appsettings.Development.json
new file mode 100644
index 000000000..0c208ae91
--- /dev/null
+++ b/Source/HtmlRenderer.Demo.Web.Api/appsettings.Development.json
@@ -0,0 +1,8 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft.AspNetCore": "Warning"
+ }
+ }
+}
diff --git a/Source/HtmlRenderer.Demo.Web.Api/appsettings.json b/Source/HtmlRenderer.Demo.Web.Api/appsettings.json
new file mode 100644
index 000000000..10f68b8c8
--- /dev/null
+++ b/Source/HtmlRenderer.Demo.Web.Api/appsettings.json
@@ -0,0 +1,9 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft.AspNetCore": "Warning"
+ }
+ },
+ "AllowedHosts": "*"
+}
diff --git a/Source/HtmlRenderer.sln b/Source/HtmlRenderer.sln
index ff45b31b1..440428e60 100644
--- a/Source/HtmlRenderer.sln
+++ b/Source/HtmlRenderer.sln
@@ -25,6 +25,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HtmlRenderer.Demo.SkiaSharp
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HtmlRenderer.Demo.Console", "Demos\HtmlRenderer.Demo.Console\HtmlRenderer.Demo.Console.csproj", "{7E5B30E9-34C6-4123-B8A6-B50AC078DA53}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HtmlRenderer.Demo.Web.Api", "HtmlRenderer.Demo.Web.Api\HtmlRenderer.Demo.Web.Api.csproj", "{59590969-0677-4DC7-95B1-6D1442B71586}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -63,6 +65,10 @@ Global
{7E5B30E9-34C6-4123-B8A6-B50AC078DA53}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7E5B30E9-34C6-4123-B8A6-B50AC078DA53}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7E5B30E9-34C6-4123-B8A6-B50AC078DA53}.Release|Any CPU.Build.0 = Release|Any CPU
+ {59590969-0677-4DC7-95B1-6D1442B71586}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {59590969-0677-4DC7-95B1-6D1442B71586}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {59590969-0677-4DC7-95B1-6D1442B71586}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {59590969-0677-4DC7-95B1-6D1442B71586}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -73,6 +79,7 @@ Global
{46175F41-83B5-4E4E-BA90-775BA6AC144A} = {CF4F888A-71EE-4EDC-99BA-8A02B4B841F0}
{5E5E2495-4F7A-4C36-B7DF-3EBE71A5108A} = {CF4F888A-71EE-4EDC-99BA-8A02B4B841F0}
{7E5B30E9-34C6-4123-B8A6-B50AC078DA53} = {CF4F888A-71EE-4EDC-99BA-8A02B4B841F0}
+ {59590969-0677-4DC7-95B1-6D1442B71586} = {CF4F888A-71EE-4EDC-99BA-8A02B4B841F0}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {B4ABBC6A-EFE0-46EB-BEED-7C8017BA004C}