Skip to content

Commit 440dba8

Browse files
authored
feat(Dom2Image): add IDom2ImageService interface (#540)
* chore: 增加 dom2Image 项目 * chore: 增加脚本 * feat: 增加 AddBootstrapBlazorDom2ImageService 服务扩展 * feat: 增加 DownloadAsync 方法 * refactor: 增加 await 关键字 * chore: bump version 9.0.0 * chore: 增加 Dom2Image 项目 * chore: 更新脚本 * chore: 更新文件编码 * chore: bump version 10.0.0
1 parent 91ac117 commit 440dba8

8 files changed

Lines changed: 295 additions & 0 deletions

File tree

BootstrapBlazor.Extensions.slnx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
<Project Path="src/components/BootstrapBlazor.CodeEditor/BootstrapBlazor.CodeEditor.csproj" />
3030
<Project Path="src/components/BootstrapBlazor.Dock/BootstrapBlazor.Dock.csproj" />
3131
<Project Path="src/components/BootstrapBlazor.DockView/BootstrapBlazor.DockView.csproj" />
32+
<Project Path="src/components/BootstrapBlazor.Dom2Image/BootstrapBlazor.Dom2Image.csproj" />
3233
<Project Path="src/components/BootstrapBlazor.DriverJs/BootstrapBlazor.DriverJs.csproj" />
3334
<Project Path="src/components/BootstrapBlazor.ElementIcon/BootstrapBlazor.ElementIcon.csproj" />
3435
<Project Path="src/components/BootstrapBlazor.FileSystem/BootstrapBlazor.FileSystem.csproj" />
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<Project Sdk="Microsoft.NET.Sdk.Razor">
2+
3+
<PropertyGroup>
4+
<Version>10.0.0</Version>
5+
</PropertyGroup>
6+
7+
<PropertyGroup>
8+
<PackageTags>Bootstrap Blazor WebAssembly wasm UI Components Dom Image</PackageTags>
9+
<Description>Bootstrap UI components extensions of DomToImage use snapDom lib</Description>
10+
</PropertyGroup>
11+
12+
<ItemGroup>
13+
<PackageReference Include="BootstrapBlazor" Version="$(BBVersion)" />
14+
</ItemGroup>
15+
16+
</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 BootstrapBlazorDom2ImageServiceExtensions
13+
{
14+
/// <summary>
15+
/// 添加 AzureOpenAIService 服务
16+
/// </summary>
17+
/// <param name="services"></param>
18+
public static IServiceCollection AddBootstrapBlazorDom2ImageService(this IServiceCollection services)
19+
{
20+
services.AddScoped<IDom2ImageService, DefaultDom2ImageService>();
21+
#if NET8_0_OR_GREATER
22+
services.AddKeyedScoped<IDom2ImageService, DefaultDom2ImageService>("BootstrapBlazor.Dom2Image");
23+
#endif
24+
return services;
25+
}
26+
}
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
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.Extensions.Logging;
6+
using Microsoft.JSInterop;
7+
8+
namespace BootstrapBlazor.Components;
9+
10+
/// <summary>
11+
/// 默认 Html to Image 实现
12+
/// <param name="runtime"></param>
13+
/// <param name="logger"></param>
14+
/// </summary>
15+
class DefaultDom2ImageService(IJSRuntime runtime, ILogger<DefaultDom2ImageService> logger) : IDom2ImageService
16+
{
17+
private JSModule? _jsModule;
18+
19+
/// <summary>
20+
/// <inheritdoc/>
21+
/// </summary>
22+
public async Task<string?> GetUrlAsync(string selector, Dom2ImageOptions? options = null, CancellationToken token = default)
23+
{
24+
string? data = null;
25+
try
26+
{
27+
_jsModule ??= await LoadModule();
28+
data = await _jsModule.InvokeAsync<string?>("getUrl", token, selector, options);
29+
}
30+
catch (OperationCanceledException) { }
31+
catch (Exception ex)
32+
{
33+
logger.LogError(ex, "{GetUrlAsync} throw exception: {ex}", nameof(GetUrlAsync), ex.Format());
34+
}
35+
return data;
36+
}
37+
38+
/// <summary>
39+
/// <inheritdoc/>
40+
/// </summary>
41+
public async Task<Stream?> GetStreamAsync(string selector, Dom2ImageOptions? options = null, CancellationToken token = default)
42+
{
43+
Stream? data = null;
44+
try
45+
{
46+
_jsModule ??= await LoadModule();
47+
var streamReference = await _jsModule.InvokeAsync<IJSStreamReference?>("getStream", selector, options);
48+
if (streamReference != null)
49+
{
50+
data = await streamReference.OpenReadStreamAsync(streamReference.Length, token);
51+
}
52+
}
53+
catch (OperationCanceledException) { }
54+
catch (Exception ex)
55+
{
56+
logger.LogError(ex, "{GetStreamAsync} throw exception: {ex}", nameof(GetStreamAsync), ex.Format());
57+
}
58+
return data;
59+
}
60+
61+
/// <summary>
62+
/// <inheritdoc/>
63+
/// </summary>
64+
/// <param name="selector"></param>
65+
/// <param name="fileName"></param>
66+
/// <param name="format"></param>
67+
/// <param name="backgroundColor"></param>
68+
/// <param name="options"></param>
69+
/// <returns></returns>
70+
public async Task DownloadAsync(string selector, string fileName = "capture", string? format = "png", string? backgroundColor = null, Dom2ImageOptions? options = null)
71+
{
72+
try
73+
{
74+
_jsModule ??= await LoadModule();
75+
await _jsModule.InvokeAsync<IJSStreamReference?>("downloadAsync", selector, fileName, format, backgroundColor, options);
76+
}
77+
catch (OperationCanceledException) { }
78+
catch (Exception ex)
79+
{
80+
logger.LogError(ex, "{DownloadAsync} throw exception: {ex}", nameof(DownloadAsync), ex.Format());
81+
}
82+
}
83+
84+
private Task<JSModule> LoadModule() => runtime.LoadModule("./_content/BootstrapBlazor.Dom2Image/dom2image.js");
85+
}
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the Apache 2.0 License
3+
// See the LICENSE file in the project root for more information.
4+
// Maintainer: Argo Zhang(argo@live.ca) Website: https://www.blazor.zone
5+
6+
using System.Text.Json.Serialization;
7+
8+
namespace BootstrapBlazor.Components;
9+
10+
/// <summary>
11+
/// Dom2ImageOptions 选项类
12+
/// </summary>
13+
public class Dom2ImageOptions
14+
{
15+
/// <summary>
16+
/// Removes redundant styles. Default value is true
17+
/// </summary>
18+
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
19+
public bool? Compress { get; set; }
20+
21+
/// <summary>
22+
/// Skips idle delay for faster results. Default value is true
23+
/// </summary>
24+
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
25+
public bool? Fast { get; set; }
26+
27+
/// <summary>
28+
/// Inlines fonts (icon fonts always embedded). Default value is false
29+
/// </summary>
30+
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
31+
public bool? EmbedFonts { get; set; }
32+
33+
/// <summary>
34+
/// Output scale multiplier. Default value is 1
35+
/// </summary>
36+
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
37+
public int? Scale { get; set; }
38+
39+
/// <summary>
40+
/// Device pixel ratio
41+
/// </summary>
42+
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
43+
public int? Dpr { get; set; }
44+
45+
/// <summary>
46+
/// Output specific width size
47+
/// </summary>
48+
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
49+
public int? Width { get; set; }
50+
51+
/// <summary>
52+
/// Output specific height size
53+
/// </summary>
54+
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
55+
public int? Height { get; set; }
56+
57+
/// <summary>
58+
/// Fallback color for JPG/WebP. Default value is #fff
59+
/// </summary>
60+
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
61+
public string? BackgroundColor { get; set; }
62+
63+
/// <summary>
64+
/// Quality for JPG/WebP (0 to 1)
65+
/// </summary>
66+
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
67+
public float? Quality { get; set; }
68+
69+
/// <summary>
70+
/// Select png, jpg, webp Blob type. Default value is svg
71+
/// </summary>
72+
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
73+
public string? Type { get; set; }
74+
75+
/// <summary>
76+
/// CSS selectors for elements to exclude
77+
/// </summary>
78+
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
79+
public string[]? Exclude { get; set; }
80+
81+
/// <summary>
82+
///
83+
/// </summary>
84+
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
85+
public string[]? LocalFonts { get; set; }
86+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
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+
namespace BootstrapBlazor.Components;
6+
7+
/// <summary>
8+
/// IDom2ImageService 接口定义
9+
/// </summary>
10+
public interface IDom2ImageService
11+
{
12+
/// <summary>
13+
/// 通过指定选择器获得 Html 元素返回图片数据
14+
/// </summary>
15+
/// <param name="selector"></param>
16+
/// <param name="options"></param>
17+
/// <param name="token"></param>
18+
/// <returns></returns>
19+
Task<string?> GetUrlAsync(string selector, Dom2ImageOptions? options = null, CancellationToken token = default);
20+
21+
/// <summary>
22+
/// 通过指定选择器获得 Html 元素返回图片数据流
23+
/// </summary>
24+
/// <param name="selector"></param>
25+
/// <param name="options"></param>
26+
/// <param name="token"></param>
27+
/// <returns></returns>
28+
Task<Stream?> GetStreamAsync(string selector, Dom2ImageOptions? options = null, CancellationToken token = default);
29+
30+
/// <summary>
31+
/// 通过指定选择器下载 Html 元素图片
32+
/// </summary>
33+
/// <param name="selector"></param>
34+
/// <param name="fileName"></param>
35+
/// <param name="format"></param>
36+
/// <param name="backgroundColor"></param>
37+
/// <param name="options"></param>
38+
/// <returns></returns>
39+
Task DownloadAsync(string selector, string fileName = "capture", string? format = "png", string? backgroundColor = null, Dom2ImageOptions? options = null);
40+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { snapdom } from './lib/snapdom.min.mjs'
2+
3+
export async function getUrl(selector, options) {
4+
let data = null;
5+
const el = document.querySelector(selector);
6+
if (el) {
7+
const result = await snapdom(el, options || {});
8+
data = result.url;
9+
}
10+
return data;
11+
}
12+
13+
export async function getStream(selector, options) {
14+
let data = null;
15+
const el = document.querySelector(selector);
16+
if (el) {
17+
const result = await snapdom(el, options || {});
18+
data = result.toBlob();
19+
}
20+
return data;
21+
}
22+
23+
export async function downloadAsync(selector, filename, format, backgroundColor, options) {
24+
const el = document.querySelector(selector);
25+
if (el) {
26+
const result = await snapdom(el, options || {});
27+
await result.download({
28+
format,
29+
filename,
30+
backgroundColor
31+
});
32+
}
33+
}

0 commit comments

Comments
 (0)