Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/BootstrapBlazor.Server/BootstrapBlazor.Server.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
<PackageReference Include="BootstrapBlazor.Gantt" Version="9.0.2" />
<PackageReference Include="BootstrapBlazor.Holiday" Version="9.0.1" />
<PackageReference Include="BootstrapBlazor.Html2Image" Version="9.0.2" />
<PackageReference Include="BootstrapBlazor.Html2Pdf" Version="9.0.6-beta01" />
<PackageReference Include="BootstrapBlazor.Html2Pdf" Version="10.0.0-rc.2.1.2" />
<PackageReference Include="BootstrapBlazor.IconPark" Version="9.0.3" />
<PackageReference Include="BootstrapBlazor.ImageCropper" Version="9.0.3" />
<PackageReference Include="BootstrapBlazor.IP2Region" Version="9.0.4" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,10 @@ private async Task OnExportAsync()
""";

// 增加网页所需样式表文件
using var stream = await Html2PdfService.PdfStreamFromHtmlAsync(htmlString, [$"{NavigationManager.BaseUri}_content/BootstrapBlazor/css/bootstrap.blazor.bundle.min.css"]);
using var stream = await Html2PdfService.PdfStreamFromHtmlAsync(htmlString, [$"{NavigationManager.BaseUri}_content/BootstrapBlazor/css/bootstrap.blazor.bundle.min.css"], options: new PdfOptions()
{
Format = PaperFormat.A4
});

// 下载 Pdf 文件
await DownloadService.DownloadFromStreamAsync($"table-{DateTime.Now:HHmmss}.pdf", stream);
Expand Down
4 changes: 2 additions & 2 deletions src/BootstrapBlazor/BootstrapBlazor.csproj
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk.Razor">

<PropertyGroup Condition="'$(VisualStudioVersion)' == '17.0'">
<Version>9.11.5-beta10</Version>
<Version>9.11.5-beta11</Version>
</PropertyGroup>

<PropertyGroup Condition="'$(VisualStudioVersion)' == '18.0'">
<Version>10.0.0-rc.2.1.9</Version>
<Version>10.0.0-rc.2.1.10</Version>
</PropertyGroup>

<ItemGroup>
Expand Down
33 changes: 33 additions & 0 deletions src/BootstrapBlazor/Options/MarginOptions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the Apache 2.0 License
// See the LICENSE file in the project root for more information.
// Maintainer: Argo Zhang([email protected]) Website: https://www.blazor.zone

namespace BootstrapBlazor.Components;

/// <summary>
/// 页面边距选项
/// </summary>
[ExcludeFromCodeCoverage]
public record MarginOptions
{
/// <summary>
/// Top margin, accepts values labeled with units.
/// </summary>
public object? Top { get; set; }

/// <summary>
/// Left margin, accepts values labeled with units.
/// </summary>
public object? Left { get; set; }

/// <summary>
/// Bottom margin, accepts values labeled with units.
/// </summary>
public object? Bottom { get; set; }

/// <summary>
/// Right margin, accepts values labeled with units.
/// </summary>
public object? Right { get; set; }
Comment on lines +14 to +32
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: Using object? for margin properties may reduce type safety.

Consider specifying a more precise type for margin properties to prevent runtime issues and make the code clearer.

Suggested change
/// <summary>
/// Top margin, accepts values labeled with units.
/// </summary>
public object? Top { get; set; }
/// <summary>
/// Left margin, accepts values labeled with units.
/// </summary>
public object? Left { get; set; }
/// <summary>
/// Bottom margin, accepts values labeled with units.
/// </summary>
public object? Bottom { get; set; }
/// <summary>
/// Right margin, accepts values labeled with units.
/// </summary>
public object? Right { get; set; }
/// <summary>
/// Top margin, accepts values labeled with units (e.g., "10px", "2em", "5%").
/// </summary>
public string? Top { get; set; }
/// <summary>
/// Left margin, accepts values labeled with units (e.g., "10px", "2em", "5%").
/// </summary>
public string? Left { get; set; }
/// <summary>
/// Bottom margin, accepts values labeled with units (e.g., "10px", "2em", "5%").
/// </summary>
public string? Bottom { get; set; }
/// <summary>
/// Right margin, accepts values labeled with units (e.g., "10px", "2em", "5%").
/// </summary>
public string? Right { get; set; }

}
89 changes: 89 additions & 0 deletions src/BootstrapBlazor/Options/PaperFormat.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the Apache 2.0 License
// See the LICENSE file in the project root for more information.
// Maintainer: Argo Zhang([email protected]) Website: https://www.blazor.zone

namespace BootstrapBlazor.Components;

/// <summary>
/// 纸张规格配置类
/// </summary>
[ExcludeFromCodeCoverage]
public record PaperFormat
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: Consider making PaperFormat immutable for thread safety and consistency.

Width and Height should be init-only or readonly to prevent changes after creation, ensuring immutability for this value object.

{
/// <summary>
///
/// </summary>
public static PaperFormat Letter => new(8.5m, 11m);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (complexity): Consider using a centralized mapping for paper formats to avoid repetitive instantiation in each static property.

Consider centralizing the size-to-dimension mapping (once) instead of repeating new(…,…) in every static prop. For example, define an enum and either a switch factory or a single Dictionary:

public enum StandardPaperFormat
{
    Letter, Legal, Tabloid, Ledger,
    A0, A1, A2, A3, A4, A5, A6
}

public record PaperFormat(decimal Width, decimal Height)
{
    private static readonly IReadOnlyDictionary<StandardPaperFormat, PaperFormat> _map
        = new Dictionary<StandardPaperFormat, PaperFormat>
    {
        [StandardPaperFormat.Letter]  = new(8.5m, 11m),
        [StandardPaperFormat.Legal]   = new(8.5m, 14m),
        [StandardPaperFormat.Tabloid] = new(11m, 17m),
        [StandardPaperFormat.Ledger]  = new(17m, 11m),
        [StandardPaperFormat.A0]      = new(33.1102m, 46.811m),
        [StandardPaperFormat.A1]      = new(23.3858m, 33.1102m),
        // …
    };

    public static PaperFormat Create(StandardPaperFormat format)
        => _map.TryGetValue(format, out var pf)
           ? pf
           : throw new ArgumentOutOfRangeException(nameof(format), format, null);
}

If you still want named properties for discoverability, point them at the dictionary:

public static PaperFormat Letter  => Create(StandardPaperFormat.Letter);
public static PaperFormat Legal   => Create(StandardPaperFormat.Legal);
// …


/// <summary>
///
/// </summary>
public static PaperFormat Legal => new(8.5m, 14m);

/// <summary>
///
/// </summary>
public static PaperFormat Tabloid => new(11m, 17m);

/// <summary>
///
/// </summary>
public static PaperFormat Ledger => new(17m, 11m);

/// <summary>
///
/// </summary>
public static PaperFormat A0 => new(33.1102m, 46.811m);

/// <summary>
///
/// </summary>
public static PaperFormat A1 => new(23.3858m, 33.1102m);

/// <summary>
///
/// </summary>
public static PaperFormat A2 => new(16.5354m, 23.3858m);

/// <summary>
///
/// </summary>
public static PaperFormat A3 => new(11.6929m, 16.5354m);

/// <summary>
///
/// </summary>
public static PaperFormat A4 => new(8.2677m, 11.6929m);

/// <summary>
///
/// </summary>
public static PaperFormat A5 => new(5.8268m, 8.2677m);

/// <summary>
///
/// </summary>
public static PaperFormat A6 => new(4.1339m, 5.8268m);

/// <summary>
///
/// </summary>
public decimal Width { get; set; }

/// <summary>
///
/// </summary>
public decimal Height { get; set; }

/// <summary>
///
/// </summary>
/// <param name="width"></param>
/// <param name="height"></param>
public PaperFormat(decimal width, decimal height)
{
Width = width;
Height = height;
}
}
25 changes: 25 additions & 0 deletions src/BootstrapBlazor/Options/PdfOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,29 @@ public class PdfOptions
/// 获得/设置 是否横向打印 默认 false
/// </summary>
public bool Landscape { get; set; }

/// <summary>
/// 获得/设置 是否打印背景色 默认 false
/// </summary>
public bool PrintBackground { get; set; }

/// <summary>
/// 获得/设置 纸张格式 默认 A4
/// </summary>
public PaperFormat Format { get; set; } = PaperFormat.A4;

/// <summary>
/// 获得/设置 是否显示页眉页脚 默认 false
/// </summary>
public bool DisplayHeaderFooter { get; set; }

/// <summary>
/// 获得/设置 放大比例 默认 1 取值 0.1 到 2 之间
/// </summary>
public decimal Scale { get; set; } = 1;
Copy link

Copilot AI Oct 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The documentation states the valid range is 0.1 to 2, but there is no validation enforcing this constraint. Consider adding validation in a setter or validation method to ensure the Scale value remains within the documented range.

Suggested change
public decimal Scale { get; set; } = 1;
private decimal _scale = 1;
/// <summary>
/// 获得/设置 放大比例 默认 1 取值 0.1 到 2 之间
/// </summary>
public decimal Scale
{
get => _scale;
set
{
if (value < 0.1m || value > 2m)
{
throw new ArgumentOutOfRangeException(nameof(Scale), "Scale must be between 0.1 and 2.");
}
_scale = value;
}
}

Copilot uses AI. Check for mistakes.

/// <summary>
/// 获得/设置 页面边距 默认 none
/// </summary>
public MarginOptions MarginOptions { get; set; } = new();
}
38 changes: 38 additions & 0 deletions test/UnitTest/Options/PdfOptionsTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the Apache 2.0 License
// See the LICENSE file in the project root for more information.
// Maintainer: Argo Zhang([email protected]) Website: https://www.blazor.zone

namespace UnitTest.Options;

public class PdfOptionsTest
{
[Fact]
public void Test_PdfOptions_Ok()
{
var options = new PdfOptions()
{
Scale = 1.0m,
DisplayHeaderFooter = true,
PrintBackground = true,
Landscape = true,
Format = PaperFormat.A1,
MarginOptions = new MarginOptions()
{
Top = "10mm",
Bottom = "10mm",
Left = "10mm",
Right = "10mm"
}
};
Assert.Equal(1.0m, options.Scale);
Assert.True(options.DisplayHeaderFooter);
Assert.True(options.PrintBackground);
Assert.True(options.Landscape);
Assert.Equal(PaperFormat.A1, options.Format);
Assert.Equal("10mm", options.MarginOptions.Top);
Assert.Equal("10mm", options.MarginOptions.Bottom);
Assert.Equal("10mm", options.MarginOptions.Left);
Assert.Equal("10mm", options.MarginOptions.Right);
}
}
Loading