Skip to content

Commit

Permalink
1. 新增二维码操作 Util.QrCode.IQrCodeService .
Browse files Browse the repository at this point in the history
  2. 新增二维码组件标签 <util-qrcode> .
  3. 新增水印组件标签 <util-water-mark> .
  4. 新增哈希码组件标签 <util-hash-code> .
  5. 新增回到顶部组件标签 <util-back-top> .
  6. Json操作类 Util.Helpers.Json 的 JsonOptions 参数新增 IgnoreEmptyString 属性, 用于忽略空字符串.
  7. 修复表单组件 SpaceItem 属性引起验证指令引用变量作用域错误导致的bug.
  • Loading branch information
UtilCore committed Apr 4, 2024
1 parent cf0f68b commit adaebbb
Show file tree
Hide file tree
Showing 92 changed files with 3,124 additions and 265 deletions.
18 changes: 16 additions & 2 deletions Util.sln
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "05-Util.Security", "src\Uti
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Util.Security.Tests", "test\Util.Security.Tests\Util.Security.Tests.csproj", "{B25D3B7A-AEAA-4EFB-9839-7C6E3F7C24BB}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "07-Images", "07-Images", "{1F5EE147-BD88-4B6D-BA84-35B4F3BE4A4E}"
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "07-Tools", "07-Tools", "{1F5EE147-BD88-4B6D-BA84-35B4F3BE4A4E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "01-Util.Images.ImageSharp", "src\Util.Images.ImageSharp\01-Util.Images.ImageSharp.csproj", "{22305349-51C7-4D80-A538-C7C0F4495895}"
EndProject
Expand All @@ -247,7 +247,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "03-EntityFrameworkCore", "0
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "01-Core", "01-Core", "{2864196E-3044-4FEC-B92A-D1D3C521C567}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "07-Images", "07-Images", "{96DFADC5-FAE8-4860-A57A-93F0534B1B7A}"
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "07-Tools", "07-Tools", "{96DFADC5-FAE8-4860-A57A-93F0534B1B7A}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Util.Images.ImageSharp.Tests.Integration", "test\Util.Images.ImageSharp.Tests.Integration\Util.Images.ImageSharp.Tests.Integration.csproj", "{5921A7FA-8C70-49A9-82E1-BE3FA5B50C33}"
EndProject
Expand Down Expand Up @@ -345,6 +345,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Util.FileStorage.Aliyun.Tes
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "01-Util.FileStorage.Abstractions", "src\Util.FileStorage.Abstractions\01-Util.FileStorage.Abstractions.csproj", "{814E42E9-508E-487F-BCD3-0F07AE7D1492}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "03-Util.QrCode.ZXing", "src\Util.QrCode.ZXing\03-Util.QrCode.ZXing.csproj", "{3F5120A6-9CA4-4B25-9507-86E9E5571DB6}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Util.QrCode.ZXing.Tests.Integration", "test\Util.QrCode.ZXing.Tests.Integration\Util.QrCode.ZXing.Tests.Integration.csproj", "{79A40AC0-A182-49D0-AED9-DF8B6835432A}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -863,6 +867,14 @@ Global
{814E42E9-508E-487F-BCD3-0F07AE7D1492}.Debug|Any CPU.Build.0 = Debug|Any CPU
{814E42E9-508E-487F-BCD3-0F07AE7D1492}.Release|Any CPU.ActiveCfg = Release|Any CPU
{814E42E9-508E-487F-BCD3-0F07AE7D1492}.Release|Any CPU.Build.0 = Release|Any CPU
{3F5120A6-9CA4-4B25-9507-86E9E5571DB6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3F5120A6-9CA4-4B25-9507-86E9E5571DB6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3F5120A6-9CA4-4B25-9507-86E9E5571DB6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3F5120A6-9CA4-4B25-9507-86E9E5571DB6}.Release|Any CPU.Build.0 = Release|Any CPU
{79A40AC0-A182-49D0-AED9-DF8B6835432A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{79A40AC0-A182-49D0-AED9-DF8B6835432A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{79A40AC0-A182-49D0-AED9-DF8B6835432A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{79A40AC0-A182-49D0-AED9-DF8B6835432A}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -1034,6 +1046,8 @@ Global
{4938D59D-CF50-4090-B936-36DB29EBE344} = {E069CEB0-8092-4907-BC9D-C6B8BDE20AD2}
{58C01936-5D8F-4077-8663-EE0E35776D65} = {16175228-03CA-414A-8786-E5BA844110C4}
{814E42E9-508E-487F-BCD3-0F07AE7D1492} = {E069CEB0-8092-4907-BC9D-C6B8BDE20AD2}
{3F5120A6-9CA4-4B25-9507-86E9E5571DB6} = {1F5EE147-BD88-4B6D-BA84-35B4F3BE4A4E}
{79A40AC0-A182-49D0-AED9-DF8B6835432A} = {96DFADC5-FAE8-4860-A57A-93F0534B1B7A}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {94347832-A36D-4C42-9C4D-B848BD4F5DA9}
Expand Down
2 changes: 1 addition & 1 deletion build/version.props
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<PropertyGroup>
<VersionMajor>8</VersionMajor>
<VersionMinor>0</VersionMinor>
<VersionPatch>11</VersionPatch>
<VersionPatch>12</VersionPatch>
<VersionPrefix>$(VersionMajor).$(VersionMinor).$(VersionPatch)</VersionPrefix>
<VersionSuffix></VersionSuffix>
</PropertyGroup>
Expand Down
58 changes: 40 additions & 18 deletions src/Util.Core/Helpers/File.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace Util.Helpers;
namespace Util.Helpers;

/// <summary>
/// 文件流操作
Expand Down Expand Up @@ -33,7 +33,7 @@ public static byte[] ToBytes( string data ) {
/// <param name="encoding">字符编码</param>
public static byte[] ToBytes( string data, Encoding encoding ) {
if ( string.IsNullOrWhiteSpace( data ) )
return new byte[] { };
return Array.Empty<byte>();
return encoding.GetBytes( data );
}

Expand Down Expand Up @@ -136,7 +136,7 @@ public static string ReadToString( string filePath ) {
/// <param name="filePath">文件绝对路径</param>
/// <param name="encoding">字符编码</param>
public static string ReadToString( string filePath, Encoding encoding ) {
if( System.IO.File.Exists( filePath ) == false )
if ( System.IO.File.Exists( filePath ) == false )
return string.Empty;
using var reader = new StreamReader( filePath, encoding );
return reader.ReadToEnd();
Expand Down Expand Up @@ -182,7 +182,7 @@ public static async Task<string> ReadToStringAsync( string filePath ) {
/// <param name="filePath">文件绝对路径</param>
/// <param name="encoding">字符编码</param>
public static async Task<string> ReadToStringAsync( string filePath, Encoding encoding ) {
if( System.IO.File.Exists( filePath ) == false )
if ( System.IO.File.Exists( filePath ) == false )
return string.Empty;
using var reader = new StreamReader( filePath, encoding );
return await reader.ReadToEndAsync();
Expand Down Expand Up @@ -295,18 +295,34 @@ public static byte[] ReadToBytes( Stream stream ) {
/// <param name="filePath">文件绝对路径</param>
/// <param name="content">内容</param>
public static void Write( string filePath, string content ) {
if ( content.IsEmpty() )
return;
Write( filePath, Convert.ToBytes( content ) );
}

/// <summary>
/// 将流写入文件
/// </summary>
/// <param name="filePath">文件绝对路径</param>
/// <param name="content">内容</param>
public static void Write( string filePath, Stream content ) {
if ( content == null )
return;
using ( content ) {
var bytes = ToBytes( content );
Write( filePath, bytes );
}
}

/// <summary>
/// 将字节流写入文件
/// </summary>
/// <param name="filePath">文件绝对路径</param>
/// <param name="content">内容</param>
public static void Write( string filePath, byte[] content ) {
if( string.IsNullOrWhiteSpace( filePath ) )
if ( string.IsNullOrWhiteSpace( filePath ) )
return;
if( content == null )
if ( content == null )
return;
CreateDirectory( filePath );
System.IO.File.WriteAllBytes( filePath, content );
Expand All @@ -323,6 +339,8 @@ public static void Write( string filePath, byte[] content ) {
/// <param name="content">内容</param>
/// <param name="cancellationToken">取消令牌</param>
public static async Task WriteAsync( string filePath, string content, CancellationToken cancellationToken = default ) {
if ( content.IsEmpty() )
return;
await WriteAsync( filePath, Convert.ToBytes( content ), cancellationToken );
}

Expand All @@ -333,8 +351,12 @@ public static void Write( string filePath, byte[] content ) {
/// <param name="content">内容</param>
/// <param name="cancellationToken">取消令牌</param>
public static async Task WriteAsync( string filePath, Stream content, CancellationToken cancellationToken = default ) {
var bytes = await ToBytesAsync( content, cancellationToken );
await WriteAsync( filePath, bytes, cancellationToken );
if ( content == null )
return;
await using ( content ) {
var bytes = await ToBytesAsync( content, cancellationToken );
await WriteAsync( filePath, bytes, cancellationToken );
}
}

/// <summary>
Expand All @@ -344,9 +366,9 @@ public static void Write( string filePath, byte[] content ) {
/// <param name="content">内容</param>
/// <param name="cancellationToken">取消令牌</param>
public static async Task WriteAsync( string filePath, byte[] content, CancellationToken cancellationToken = default ) {
if( string.IsNullOrWhiteSpace( filePath ) )
if ( string.IsNullOrWhiteSpace( filePath ) )
return;
if( content == null )
if ( content == null )
return;
CreateDirectory( filePath );
await System.IO.File.WriteAllBytesAsync( filePath, content, cancellationToken );
Expand All @@ -361,7 +383,7 @@ public static void Write( string filePath, byte[] content ) {
/// </summary>
/// <param name="filePaths">文件绝对路径集合</param>
public static void Delete( IEnumerable<string> filePaths ) {
foreach( var filePath in filePaths )
foreach ( var filePath in filePaths )
Delete( filePath );
}

Expand All @@ -370,9 +392,9 @@ public static void Delete( IEnumerable<string> filePaths ) {
/// </summary>
/// <param name="filePath">文件绝对路径</param>
public static void Delete( string filePath ) {
if( string.IsNullOrWhiteSpace( filePath ) )
if ( string.IsNullOrWhiteSpace( filePath ) )
return;
if( System.IO.File.Exists( filePath ) )
if ( System.IO.File.Exists( filePath ) )
System.IO.File.Delete( filePath );
}

Expand All @@ -385,7 +407,7 @@ public static void Delete( string filePath ) {
/// </summary>
/// <param name="path">目录路径</param>
/// <param name="searchPattern">搜索模式</param>
public static List<FileInfo> GetAllFiles( string path,string searchPattern ) {
public static List<FileInfo> GetAllFiles( string path, string searchPattern ) {
return Directory.GetFiles( path, searchPattern, SearchOption.AllDirectories )
.Select( filePath => new FileInfo( filePath ) ).ToList();
}
Expand All @@ -400,10 +422,10 @@ public static List<FileInfo> GetAllFiles( string path,string searchPattern ) {
/// <param name="sourceFilePath">源文件绝对路径</param>
/// <param name="destinationFilePath">目标文件绝对路径</param>
/// <param name="overwrite">目标文件存在时是否覆盖,默认值: false</param>
public static void Copy( string sourceFilePath,string destinationFilePath, bool overwrite = false ) {
public static void Copy( string sourceFilePath, string destinationFilePath, bool overwrite = false ) {
if ( sourceFilePath.IsEmpty() || destinationFilePath.IsEmpty() )
return;
if( FileExists( sourceFilePath ) == false )
if ( FileExists( sourceFilePath ) == false )
return;
CreateDirectory( destinationFilePath );
System.IO.File.Copy( sourceFilePath, destinationFilePath, overwrite );
Expand All @@ -420,9 +442,9 @@ public static void Copy( string sourceFilePath,string destinationFilePath, bool
/// <param name="destinationFilePath">目标文件绝对路径</param>
/// <param name="overwrite">目标文件存在时是否覆盖,默认值: false</param>
public static void Move( string sourceFilePath, string destinationFilePath, bool overwrite = false ) {
if( sourceFilePath.IsEmpty() || destinationFilePath.IsEmpty() )
if ( sourceFilePath.IsEmpty() || destinationFilePath.IsEmpty() )
return;
if( FileExists( sourceFilePath ) == false )
if ( FileExists( sourceFilePath ) == false )
return;
CreateDirectory( destinationFilePath );
System.IO.File.Move( sourceFilePath, destinationFilePath, overwrite );
Expand Down
28 changes: 23 additions & 5 deletions src/Util.Core/Helpers/Json.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using Util.SystemTextJson;

namespace Util.Helpers;
namespace Util.Helpers;

/// <summary>
/// Json操作
Expand All @@ -23,6 +23,11 @@ public static string ToJson<T>( T value, JsonOptions options ) {
/// </summary>
private static JsonSerializerOptions ToJsonSerializerOptions( JsonOptions options ) {
var jsonSerializerOptions = new JsonSerializerOptions();
if ( options.IgnoreEmptyString ) {
jsonSerializerOptions.TypeInfoResolver = new DefaultJsonTypeInfoResolver {
Modifiers = { IgnoreEmptyString }
};
}
if ( options.IgnoreNullValues )
jsonSerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull;
if ( options.IgnoreCase )
Expand All @@ -37,21 +42,34 @@ private static JsonSerializerOptions ToJsonSerializerOptions( JsonOptions option
return jsonSerializerOptions;
}

/// <summary>
/// 忽略空字符串
/// </summary>
private static void IgnoreEmptyString( JsonTypeInfo jsonTypeInfo ) {
if ( jsonTypeInfo.Kind != JsonTypeInfoKind.Object )
return;
foreach ( JsonPropertyInfo jsonPropertyInfo in jsonTypeInfo.Properties ) {
if ( jsonPropertyInfo.PropertyType == typeof( string ) ) {
jsonPropertyInfo.ShouldSerialize = static ( _, value ) => value.SafeString().IsEmpty() == false;
}
}
}

/// <summary>
/// 将对象转换为Json字符串
/// </summary>
/// <param name="value">目标对象</param>
/// <param name="options">序列化配置</param>
/// <param name="removeQuotationMarks">是否移除双引号</param>
/// <param name="toSingleQuotes">是否将双引号转成单引号</param>
public static string ToJson<T>( T value, JsonSerializerOptions options = null,bool removeQuotationMarks = false, bool toSingleQuotes = false ) {
return ToJson( value, options, removeQuotationMarks, toSingleQuotes,true );
public static string ToJson<T>( T value, JsonSerializerOptions options = null, bool removeQuotationMarks = false, bool toSingleQuotes = false ) {
return ToJson( value, options, removeQuotationMarks, toSingleQuotes, true );
}

/// <summary>
/// 将对象转换为Json字符串
/// </summary>
private static string ToJson<T>( T value, JsonSerializerOptions options, bool removeQuotationMarks, bool toSingleQuotes,bool ignoreInterface ) {
private static string ToJson<T>( T value, JsonSerializerOptions options, bool removeQuotationMarks, bool toSingleQuotes, bool ignoreInterface ) {
if ( value == null )
return string.Empty;
options = GetToJsonOptions( options );
Expand Down Expand Up @@ -87,7 +105,7 @@ private static JsonSerializerOptions GetToJsonOptions( JsonSerializerOptions opt
private static string Serialize<T>( T value, JsonSerializerOptions options, bool ignoreInterface ) {
if ( ignoreInterface ) {
object instance = value;
if( instance != null )
if ( instance != null )
return JsonSerializer.Serialize( instance, options );
}
return JsonSerializer.Serialize( value, options );
Expand Down
5 changes: 5 additions & 0 deletions src/Util.Core/JsonOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ public class JsonOptions {
/// </summary>
public JsonOptions() {
IgnoreNullValues = true;
IgnoreEmptyString = true;
IgnoreCase = true;
IgnoreInterface = true;
}
Expand All @@ -26,6 +27,10 @@ public JsonOptions() {
/// </summary>
public bool IgnoreNullValues { get; set; }
/// <summary>
/// 是否忽略空字符串,默认值: true
/// </summary>
public bool IgnoreEmptyString { get; set; }
/// <summary>
/// 转换为Json时,属性名是否使用驼峰形式
/// </summary>
public bool ToCamelCase { get; set; }
Expand Down
1 change: 1 addition & 0 deletions src/Util.Core/Usings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
global using System.Net.Http;
global using System.Xml;
global using System.Xml.Linq;
global using System.Text.Json.Serialization.Metadata;
global using Microsoft.Extensions.Configuration;
global using Microsoft.Extensions.DependencyInjection;
global using Microsoft.Extensions.Hosting;
Expand Down
69 changes: 69 additions & 0 deletions src/Util.Images.ImageSharp/ImageSharpExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
using SixLabors.ImageSharp.Drawing;

namespace Util.Images;

/// <summary>
/// ImageSharp扩展
/// </summary>
public static class ImageSharpExtensions {
/// <summary>
/// 转换颜色类型
/// </summary>
/// <param name="color">颜色</param>
public static Color ToImageSharpColor( this System.Drawing.Color color ) {
return Color.FromRgba( color.R, color.G, color.B, color.A );
}

/// <summary>
/// 图片缩放
/// </summary>
/// <param name="image">图片</param>
/// <param name="scale">缩放比例</param>
public static Image Zoom( this Image image, double scale ) {
var width = Util.Helpers.Convert.ToInt( image.Width * scale );
var height = Util.Helpers.Convert.ToInt( image.Height * scale );
image.Mutate( t => {
t.Resize( new Size( width, height ) );
} );
return image;
}

/// <summary>
/// 设置圆角
/// </summary>
/// <param name="image">图片</param>
/// <param name="cornerRadius">角度</param>
public static Image RoundCorners( this Image image, int cornerRadius ) {
image.Mutate( context => RoundCorners( context, cornerRadius ) );
return image;
}

/// <summary>
/// 设置圆角
/// </summary>
/// <param name="context">图片处理上下文</param>
/// <param name="cornerRadius">角度</param>
private static void RoundCorners( IImageProcessingContext context, int cornerRadius ) {
var size = context.GetCurrentSize();
var corners = BuildCorners( size.Width, size.Height, cornerRadius );
context.SetGraphicsOptions( new GraphicsOptions { AlphaCompositionMode = PixelAlphaCompositionMode.DestOut } );
context.Fill( Color.Red, corners );
}

/// <summary>
/// 构建圆角
/// </summary>
/// <param name="imageWidth">图片宽度</param>
/// <param name="imageHeight">图片高度</param>
/// <param name="cornerRadius">角度</param>
private static IPathCollection BuildCorners( int imageWidth, int imageHeight, float cornerRadius ) {
var rect = new RectangularPolygon( -0.5f, -0.5f, cornerRadius, cornerRadius );
var cornerTopLeft = rect.Clip( new EllipsePolygon( cornerRadius - 0.5f, cornerRadius - 0.5f, cornerRadius ) );
var rightPos = imageWidth - cornerTopLeft.Bounds.Width + 1;
var bottomPos = imageHeight - cornerTopLeft.Bounds.Height + 1;
var cornerTopRight = cornerTopLeft.RotateDegree( 90 ).Translate( rightPos, 0 );
var cornerBottomLeft = cornerTopLeft.RotateDegree( -90 ).Translate( 0, bottomPos );
var cornerBottomRight = cornerTopLeft.RotateDegree( 180 ).Translate( rightPos, bottomPos );
return new PathCollection( cornerTopLeft, cornerBottomLeft, cornerTopRight, cornerBottomRight );
}
}
Loading

0 comments on commit adaebbb

Please sign in to comment.