1313using System . IO ;
1414using System . Runtime . InteropServices ;
1515using System . Runtime . Versioning ;
16+ using System . Threading ;
1617using System . Xml . Linq ;
1718using ImageFileOptimizationContext = DotNetCampus . MediaConverters . Imaging . Optimizations . EnhancedGraphicsMetafileOptimizationContext ;
1819using ImageFileOptimizationResult = DotNetCampus . MediaConverters . Imaging . Optimizations . EnhancedGraphicsMetafileOptimizationResult ;
1920
2021namespace DotNetCampus . MediaConverters . Imaging . Optimizations ;
2122
2223/// <summary>
23- /// 图片文件优化上下文信息
24+ /// 包含用于增强图元(EMF/WMF)优化操作的上下文信息。
2425/// </summary>
2526public readonly record struct EnhancedGraphicsMetafileOptimizationContext ( )
2627{
28+ /// <summary>
29+ /// 跟踪标识符,用于日志定位。
30+ /// </summary>
2731 public string TraceId { get ; init ; } = Guid . NewGuid ( ) . ToString ( "N" ) ;
2832
33+ /// <summary>
34+ /// 要优化的图像文件信息。
35+ /// </summary>
2936 public required FileInfo ImageFile { get ; init ; }
37+
38+ /// <summary>
39+ /// 工作目录,临时输出文件将写入此目录。
40+ /// </summary>
3041 public required DirectoryInfo WorkingFolder { get ; init ; }
42+
43+ /// <summary>
44+ /// 请求的最大图像宽度(像素)。null 表示不限制。
45+ /// </summary>
3146 public required int ? MaxImageWidth { get ; init ; }
47+
48+ /// <summary>
49+ /// 请求的最大图像高度(像素)。null 表示不限制。
50+ /// </summary>
3251 public required int ? MaxImageHeight { get ; init ; } = null ;
3352
53+ /// <summary>
54+ /// 是否将日志输出到控制台。
55+ /// </summary>
3456 public bool ShouldLogToConsole { get ; init ; } = false ;
3557
58+ /// <summary>
59+ /// 是否将日志写入文件。
60+ /// </summary>
3661 public bool ShouldLogToFile { get ; init ; } = false ;
3762
63+ /// <summary>
64+ /// 日志文件名(相对于 <see cref="WorkingFolder"/>)。
65+ /// </summary>
3866 public string LogFileName { get ; init ; } = "Log.txt" ;
3967
68+ /// <summary>
69+ /// 将一条日志消息输出到控制台或工作目录中的日志文件(取决于配置)。
70+ /// </summary>
71+ /// <param name="message">要记录的消息内容。</param>
4072 public void LogMessage ( string message )
4173 {
4274 if ( ! ShouldLogToConsole && ! ShouldLogToFile )
@@ -61,22 +93,35 @@ public void LogMessage(string message)
6193}
6294
6395/// <summary>
64- /// 图片文件优化结果
96+ /// 表示增强图元优化操作的结果。
6597/// </summary>
6698public readonly record struct EnhancedGraphicsMetafileOptimizationResult ( )
6799{
100+ /// <summary>
101+ /// 如果优化过程成功并产生了输出文件,则为 true。
102+ /// </summary>
68103 [ MemberNotNullWhen ( returnValue : true ) ]
69104 public bool IsSuccess => OptimizedImageFile is not null ;
70105
71106 /// <summary>
72- /// 优化后的图片文件
107+ /// 优化后生成的图像文件(如果成功)。
73108 /// </summary>
74109 public FileInfo ? OptimizedImageFile { get ; init ; }
75110
111+ /// <summary>
112+ /// 表示该操作不被支持(例如平台或格式不支持)。
113+ /// </summary>
76114 public bool IsNotSupport { get ; init ; }
77115
116+ /// <summary>
117+ /// 如果发生异常则包含异常对象,否则为 null。
118+ /// </summary>
78119 public Exception ? Exception { get ; init ; }
79120
121+ /// <summary>
122+ /// 创建一个表示不支持的结果实例。
123+ /// </summary>
124+ /// <returns>标识操作不被支持的结果。</returns>
80125 public static ImageFileOptimizationResult NotSupported ( )
81126 {
82127 return new EnhancedGraphicsMetafileOptimizationResult ( )
@@ -85,6 +130,11 @@ public static ImageFileOptimizationResult NotSupported()
85130 } ;
86131 }
87132
133+ /// <summary>
134+ /// 创建一个包含异常信息的失败结果实例。
135+ /// </summary>
136+ /// <param name="exception">导致失败的异常。</param>
137+ /// <returns>包含异常的失败结果。</returns>
88138 public static ImageFileOptimizationResult FailException ( Exception exception )
89139 {
90140 return new EnhancedGraphicsMetafileOptimizationResult ( )
@@ -95,10 +145,16 @@ public static ImageFileOptimizationResult FailException(Exception exception)
95145}
96146
97147/// <summary>
98- /// 增强图元优化方法,用于优化 emf 和 wmf 图片
148+ /// 提供用于将增强型图元(WMF/EMF)转换为 PNG 或 SVG 的工具方法。
149+ /// 此类会根据运行时平台选择合适的实现(Windows 使用 GDI+,Linux 使用 Inkscape/Skia/libwmf 等)。
99150/// </summary>
100151public static class EnhancedGraphicsMetafileOptimization
101152{
153+ /// <summary>
154+ /// 将 WMF 或 EMF 文件转换为 PNG 文件。根据当前运行平台选择合适的转换实现。
155+ /// </summary>
156+ /// <param name="context">包含要转换文件和工作目录等设置的上下文。</param>
157+ /// <returns>转换操作的结果,包含生成的文件或错误信息。</returns>
102158 public static ImageFileOptimizationResult ConvertWmfOrEmfToPngFile ( ImageFileOptimizationContext context )
103159 {
104160 // 在 Windows 上,直接使用 GDI+ 将 WMF 或 EMF 文件转换为 PNG 文件
@@ -207,10 +263,10 @@ ImageFileOptimizationResult ConvertSvgToPngFile(FileInfo svgImageFile)
207263 }
208264
209265 /// <summary>
210- /// 使用自己写的基于 Oxage.Wmf 的 SkiaWmfRenderer 进行转换,可以比较好处理公式内容
266+ /// 使用基于 Oxage.Wmf 的 SkiaWmfRenderer 将 WMF/EMF 转换为 PNG。该方法适用于需要更好文本/公式支持的场景。
211267 /// </summary>
212- /// <param name="context"></param>
213- /// <returns></returns>
268+ /// <param name="context">包含输入文件、输出目录和尺寸限制等信息的上下文。 </param>
269+ /// <returns>如果转换成功则返回包含输出 PNG 文件的结果,否则返回不支持或失败的结果。 </returns>
214270 private static ImageFileOptimizationResult ConvertWithSkiaWmfRenderer ( ImageFileOptimizationContext context )
215271 {
216272 int requestWidth = context . MaxImageWidth ?? 0 ;
@@ -407,62 +463,66 @@ private static ImageFileOptimizationResult ConvertInWindows(ImageFileOptimizatio
407463 }
408464}
409465
466+ /// <summary>
467+ /// 提供 SVG 文件相关的优化与修复方法,例如将 SVG 转换为 PNG,或修复 SVG 中的无效字符。
468+ /// </summary>
410469public static class SvgFileOptimization
411470{
412- /*
413- if (IsExtension(".svg"))
414- {
415- // 如果是 svg 那就直接转换了,因为后续叠加特效等逻辑都不能支持 SVG 格式
416- try
471+ /*
472+ if (IsExtension(".svg"))
417473 {
418- var outputFilePath = ConvertSvgToPngFile(context);
419- if (outputFilePath is null)
474+ // 如果是 svg 那就直接转换了,因为后续叠加特效等逻辑都不能支持 SVG 格式
475+ try
420476 {
421- return new ImageFileOptimizationResult()
477+ var outputFilePath = ConvertSvgToPngFile(context);
478+ if (outputFilePath is null)
422479 {
423- OptimizedImageFile = null,
424- FailureReason = ImageFileOptimizationFailureReason.NotSupported
425- };
480+ return new ImageFileOptimizationResult()
481+ {
482+ OptimizedImageFile = null,
483+ FailureReason = ImageFileOptimizationFailureReason.NotSupported
484+ };
485+ }
486+ else
487+ {
488+ context.LogMessage($"Success ConvertSvgToPngFile. Update current image file to '{outputFilePath.FullName}'");
489+ context = context with
490+ {
491+ ImageFile = outputFilePath
492+ };
493+ }
426494 }
427- else
495+ catch (Exception e)
496+ {
497+ context.LogMessage($"Convert SVG to PNG failed: {e}");
498+
499+ return ImageFileOptimizationResult.FailException(e);
500+ }
501+ }
502+ else if (IsExtension(".wmf") ||
503+ IsExtension(".emf"))
504+ {
505+ var result = EnhancedGraphicsMetafileOptimization.ConvertWmfOrEmfToPngFile(context);
506+ if (result.OptimizedImageFile is not null)
428507 {
429- context.LogMessage($"Success ConvertSvgToPngFile . Update current image file to '{outputFilePath.FullName }'");
508+ context.LogMessage($"Success ConvertWmfOrEmfToPngFile . Update current image file to '{result.OptimizedImageFile }'");
430509 context = context with
431510 {
432- ImageFile = outputFilePath
511+ ImageFile = result.OptimizedImageFile
433512 };
434513 }
435- }
436- catch (Exception e)
437- {
438- context.LogMessage($"Convert SVG to PNG failed: {e}");
439-
440- return ImageFileOptimizationResult.FailException(e);
441- }
442- }
443- else if (IsExtension(".wmf") ||
444- IsExtension(".emf"))
445- {
446- var result = EnhancedGraphicsMetafileOptimization.ConvertWmfOrEmfToPngFile(context);
447- if (result.OptimizedImageFile is not null)
448- {
449- context.LogMessage($"Success ConvertWmfOrEmfToPngFile. Update current image file to '{result.OptimizedImageFile}'");
450- context = context with
514+ else
451515 {
452- ImageFile = result.OptimizedImageFile
453- };
454- }
455- else
456- {
457- return result;
516+ return result;
517+ }
458518 }
459- }
460- */
519+ */
461520
462521 /// <summary>
463- /// 转换 svg 文件为 png 文件
522+ /// 将指定上下文中的 SVG 文件渲染并保存为 PNG 文件。
464523 /// </summary>
465- /// <returns></returns>
524+ /// <param name="context">包含 SVG 文件和工作目录等信息的上下文。</param>
525+ /// <returns>成功时返回生成的 PNG 文件信息;失败时返回 null。</returns>
466526 public static FileInfo ? ConvertSvgToPngFile ( ImageFileOptimizationContext context )
467527 {
468528 var imageFile = context . ImageFile ;
@@ -482,6 +542,12 @@ public static class SvgFileOptimization
482542 return null ;
483543 }
484544
545+ /// <summary>
546+ /// 异步修复 SVG 文件中可能包含的无效字符(例如替换或删除不可见占位符),并在需要时将修复后的文件写入工作目录。
547+ /// </summary>
548+ /// <param name="svgFile">要修复的 SVG 文件。</param>
549+ /// <param name="workingFolder">修复后文件写入的工作目录。</param>
550+ /// <returns>修复后文件的 <see cref="FileInfo"/>;如果未作修改则返回原始文件实例。</returns>
485551 public static async Task < FileInfo > FixSvgInvalidCharacterAsync ( FileInfo svgFile ,
486552 DirectoryInfo workingFolder )
487553 {
@@ -516,6 +582,11 @@ public static async Task<FileInfo> FixSvgInvalidCharacterAsync(FileInfo svgFile,
516582 return svgFile ;
517583 }
518584
585+ /// <summary>
586+ /// 同步修复 SVG 文件中可能包含的无效字符(例如替换或删除不可见占位符),并在需要时将修复后的文件写入工作目录。
587+ /// </summary>
588+ /// <param name="context">包含 SVG 文件和工作目录等信息的上下文。</param>
589+ /// <returns>修复后文件的 <see cref="FileInfo"/>;如果未作修改则返回原始文件实例。</returns>
519590 public static FileInfo FixSvgInvalidCharacter ( ImageFileOptimizationContext context )
520591 {
521592 FileInfo svgFile = context . ImageFile ;
0 commit comments