Skip to content

Commit 05443ea

Browse files
authored
feat(Playwright): add BootstrapBlazor.Html2Pdf.Playwright project (#435)
1 parent fbfb61d commit 05443ea

5 files changed

Lines changed: 182 additions & 0 deletions

File tree

BootstrapBlazor.Extensions.sln

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BootstrapBlazor.Authenticat
184184
EndProject
185185
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BootstrapBlazor.Graph", "src\components\BootstrapBlazor.Graph\BootstrapBlazor.Graph.csproj", "{CED55D86-57CF-CB0D-E880-370C44C0DB1F}"
186186
EndProject
187+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BootstrapBlazor.Html2Pdf.Playwright", "src\components\BootstrapBlazor.Html2Pdf.Playwright\BootstrapBlazor.Html2Pdf.Playwright.csproj", "{F3043A78-1942-4524-BDC4-7E88F56DF3D5}"
188+
EndProject
187189
Global
188190
GlobalSection(SolutionConfigurationPlatforms) = preSolution
189191
Debug|Any CPU = Debug|Any CPU
@@ -498,6 +500,10 @@ Global
498500
{CED55D86-57CF-CB0D-E880-370C44C0DB1F}.Debug|Any CPU.Build.0 = Debug|Any CPU
499501
{CED55D86-57CF-CB0D-E880-370C44C0DB1F}.Release|Any CPU.ActiveCfg = Release|Any CPU
500502
{CED55D86-57CF-CB0D-E880-370C44C0DB1F}.Release|Any CPU.Build.0 = Release|Any CPU
503+
{F3043A78-1942-4524-BDC4-7E88F56DF3D5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
504+
{F3043A78-1942-4524-BDC4-7E88F56DF3D5}.Debug|Any CPU.Build.0 = Debug|Any CPU
505+
{F3043A78-1942-4524-BDC4-7E88F56DF3D5}.Release|Any CPU.ActiveCfg = Release|Any CPU
506+
{F3043A78-1942-4524-BDC4-7E88F56DF3D5}.Release|Any CPU.Build.0 = Release|Any CPU
501507
EndGlobalSection
502508
GlobalSection(SolutionProperties) = preSolution
503509
HideSolutionNode = FALSE
@@ -584,6 +590,7 @@ Global
584590
{2F37FBF4-5C1C-4493-B614-0E8361432621} = {FF1089BE-C704-4374-B629-C57C08E1798F}
585591
{1FDDF0AD-7AB6-4706-A183-26C680817BB4} = {FF1089BE-C704-4374-B629-C57C08E1798F}
586592
{CED55D86-57CF-CB0D-E880-370C44C0DB1F} = {FF1089BE-C704-4374-B629-C57C08E1798F}
593+
{F3043A78-1942-4524-BDC4-7E88F56DF3D5} = {FF1089BE-C704-4374-B629-C57C08E1798F}
587594
EndGlobalSection
588595
GlobalSection(ExtensibilityGlobals) = postSolution
589596
SolutionGuid = {D5EB1960-6F30-4CE1-B375-EAE1F787D6FF}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<Project Sdk="Microsoft.NET.Sdk.Razor">
2+
3+
<PropertyGroup>
4+
<Version>9.0.0</Version>
5+
</PropertyGroup>
6+
7+
<PropertyGroup>
8+
<PackageTags>Bootstrap Blazor WebAssembly wasm UI Components Pdf</PackageTags>
9+
<Description>Bootstrap UI components extensions of Html2Pdf use Playwright lib</Description>
10+
</PropertyGroup>
11+
12+
<ItemGroup>
13+
<PackageReference Include="BootstrapBlazor" Version="$(BBVersion)" />
14+
<PackageReference Include="Microsoft.Playwright" Version="1.52.0" />
15+
</ItemGroup>
16+
17+
</Project>
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
// Website: https://www.blazor.zone or https://argozhang.github.io/
4+
5+
using BootstrapBlazor.Components;
6+
7+
namespace Microsoft.Extensions.DependencyInjection;
8+
9+
/// <summary>
10+
/// BootstrapBlazor 服务扩展类
11+
/// </summary>
12+
public static class BootstrapBlazorHtml2PdfServiceExtensions
13+
{
14+
/// <summary>
15+
/// 添加 AzureOpenAIService 服务
16+
/// </summary>
17+
/// <param name="services"></param>
18+
public static IServiceCollection AddBootstrapBlazorHtml2PdfUsePlaywrightService(this IServiceCollection services)
19+
{
20+
services.AddSingleton<IHtml2Pdf, DefaultPdfService>();
21+
#if NET8_0_OR_GREATER
22+
services.AddKeyedSingleton<IHtml2Pdf, DefaultPdfService>("BootstrapBlazor.Html2Pdf.Playwright");
23+
#endif
24+
return services;
25+
}
26+
}
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
// Website: https://www.blazor.zone or https://argozhang.github.io/
4+
5+
using Microsoft.Playwright;
6+
7+
namespace BootstrapBlazor.Components;
8+
9+
/// <summary>
10+
/// 默认 Html to Pdf 实现
11+
/// </summary>
12+
class DefaultPdfService : IHtml2Pdf
13+
{
14+
/// <summary>
15+
/// <inheritdoc/>
16+
/// </summary>
17+
public Task<byte[]> PdfDataAsync(string url)
18+
{
19+
return GeneratePdfFromUrlAsync(url);
20+
}
21+
22+
/// <summary>
23+
/// <inheritdoc/>
24+
/// </summary>
25+
public async Task<Stream> PdfStreamAsync(string url)
26+
{
27+
var data = await GeneratePdfFromUrlAsync(url);
28+
return new MemoryStream(data);
29+
}
30+
31+
/// <summary>
32+
/// Export method
33+
/// </summary>
34+
/// <param name="html">html raw string</param>
35+
/// <param name="links"></param>
36+
/// <param name="scripts"></param>
37+
public Task<byte[]> PdfDataFromHtmlAsync(string html, IEnumerable<string>? links = null, IEnumerable<string>? scripts = null)
38+
{
39+
return GeneratePdfFromHtmlAsync(html, links, scripts);
40+
}
41+
42+
/// <summary>
43+
/// Export method
44+
/// </summary>
45+
/// <param name="html">html raw string</param>
46+
/// <param name="links"></param>
47+
/// <param name="scripts"></param>
48+
public async Task<Stream> PdfStreamFromHtmlAsync(string html, IEnumerable<string>? links = null, IEnumerable<string>? scripts = null)
49+
{
50+
var data = await PdfDataFromHtmlAsync(html, links, scripts);
51+
return new MemoryStream(data);
52+
}
53+
54+
private static async Task<byte[]> GeneratePdfFromUrlAsync(string url)
55+
{
56+
using var playwright = await Playwright.CreateAsync();
57+
await using var browser = await playwright.Chromium.LaunchAsync(CreateOptions());
58+
59+
await using var context = await browser.NewContextAsync();
60+
var page = await context.NewPageAsync();
61+
62+
await page.GotoAsync(url, new PageGotoOptions { WaitUntil = WaitUntilState.NetworkIdle });
63+
return await page.PdfAsync(new PagePdfOptions
64+
{
65+
Format = "A4",
66+
Landscape = false,
67+
});
68+
}
69+
70+
private static async Task<byte[]> GeneratePdfFromHtmlAsync(string html, IEnumerable<string>? links = null, IEnumerable<string>? scripts = null)
71+
{
72+
using var playwright = await Playwright.CreateAsync();
73+
await using var browser = await playwright.Chromium.LaunchAsync(CreateOptions());
74+
75+
await using var context = await browser.NewContextAsync();
76+
var page = await context.NewPageAsync();
77+
78+
await page.SetContentAsync(html);
79+
await AddStyleTagAsync(page, links);
80+
await AddScriptTagAsync(page, scripts);
81+
82+
return await page.PdfAsync(new PagePdfOptions
83+
{
84+
Format = "A4",
85+
Landscape = false,
86+
});
87+
}
88+
89+
private static BrowserTypeLaunchOptions CreateOptions() => new()
90+
{
91+
Headless = true,
92+
Args = ["--no-sandbox", "--disable-setuid-sandbox", "--disable-web-security"]
93+
};
94+
95+
private static async Task AddStyleTagAsync(IPage page, IEnumerable<string>? links = null)
96+
{
97+
var styles = new List<string>();
98+
99+
if (links != null)
100+
{
101+
styles.AddRange(links);
102+
}
103+
104+
foreach (var link in styles)
105+
{
106+
await page.AddStyleTagAsync(new PageAddStyleTagOptions()
107+
{
108+
Url = link,
109+
});
110+
}
111+
}
112+
113+
private static async Task AddScriptTagAsync(IPage page, IEnumerable<string>? scripts = null)
114+
{
115+
var tags = new List<string>();
116+
117+
if (scripts != null)
118+
{
119+
tags.AddRange(scripts);
120+
}
121+
122+
foreach (var script in tags)
123+
{
124+
await page.AddScriptTagAsync(new PageAddScriptTagOptions()
125+
{
126+
Url = script,
127+
Type = "script"
128+
});
129+
}
130+
}
131+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
@using Microsoft.AspNetCore.Components.Web

0 commit comments

Comments
 (0)