diff --git a/YD_Event.Application/Certificate/CertificateGenerateService.cs b/YD_Event.Application/Certificate/CertificateGenerateService.cs index c96250d..c0c0acb 100644 --- a/YD_Event.Application/Certificate/CertificateGenerateService.cs +++ b/YD_Event.Application/Certificate/CertificateGenerateService.cs @@ -810,7 +810,11 @@ public class CertificateGenerateService : IDynamicApiController, ITransient ExtractPositionOffset(outerXml, paragraphData); } - _logger.LogDebug("最终提取的位置 - X: {X}, Y: {Y}", paragraphData.PositionX, paragraphData.PositionY); + // 方法3: 提取文本框宽度 + ExtractWidthFromDrawing(outerXml, paragraphData); + + _logger.LogDebug("最终提取的位置 - X: {X}, Y: {Y}, Width: {Width}", + paragraphData.PositionX, paragraphData.PositionY, paragraphData.Width); } catch (Exception ex) { @@ -818,6 +822,45 @@ public class CertificateGenerateService : IDynamicApiController, ITransient } } + /// + /// 从 Drawing 对象 XML 中提取宽度信息 + /// + private void ExtractWidthFromDrawing(string xml, ParagraphData paragraphData) + { + try + { + // 方法1: 查找 cx 属性,常见格式 ext cx="3000000" + var cxMatch = System.Text.RegularExpressions.Regex.Match(xml, @"]*?cx=[""'](\d+)[""']"); + if (cxMatch.Success) + { + if (long.TryParse(cxMatch.Groups[1].Value, out long cx)) + { + paragraphData.Width = EmuToPoints(cx); + _logger.LogDebug("提取到宽度 (EMU): {EMU}, (点): {Points}", cx, paragraphData.Width); + return; + } + } + + // 方法2: 查找 extents cx 属性 + var extentsCxMatch = System.Text.RegularExpressions.Regex.Match(xml, @"extents\s*=\s*[\""'](?:\d+)\s*,\s*(\d+)[""']"); + if (extentsCxMatch.Success) + { + if (long.TryParse(extentsCxMatch.Groups[1].Value, out long cx)) + { + paragraphData.Width = EmuToPoints(cx); + _logger.LogDebug("提取到 extents 宽度 (EMU): {EMU}, (点): {Points}", cx, paragraphData.Width); + return; + } + } + + _logger.LogDebug("未找到宽度信息,使用默认值"); + } + catch (Exception ex) + { + _logger.LogError(ex, "提取宽度信息失败"); + } + } + /// /// 从 XML 中提取 simplePos 属性 /// @@ -1070,7 +1113,7 @@ public class CertificateGenerateService : IDynamicApiController, ITransient for (int i = 0; i < documentData.Paragraphs.Count; i++) { var p = documentData.Paragraphs[i]; - _logger.LogInformation($" [{i}] 文本: {p.Text}, X: {p.PositionX}, Y: {p.PositionY}, 字号: {p.FontSize}"); + _logger.LogInformation($" [{i}] 文本: {p.Text}, X: {p.PositionX}, Y: {p.PositionY}, Width: {p.Width}, 字号: {p.FontSize}, 对齐: {p.Alignment}"); } var questDocument = QuestPDF.Fluent.Document.Create(container => @@ -1095,8 +1138,8 @@ public class CertificateGenerateService : IDynamicApiController, ITransient .FitArea(); } - // 最简单且工作的方案:使用正常的 Column 布局 - // 但通过跟踪和补偿累积高度来定位所有文本 + // 解决方案:保持文本框位置不变,在固定宽度容器内对齐 + // 这样文本是在文本框内部对齐,而不是移动文本框位置 float cumulativeHeight = 0; page.Content().Column(column => @@ -1107,35 +1150,58 @@ public class CertificateGenerateService : IDynamicApiController, ITransient { var fontSize = paragraph.FontSize ?? 14; var isBold = paragraph.IsBold; - + var text = paragraph.Text; + // X偏移+80保持不变 // Y坐标减去之前所有文本占用的高度进行补偿 - float x = (float)(paragraph.PositionX ?? 50) + 90; + float baseX = (float)(paragraph.PositionX ?? 50) + 90; float y = (float)(paragraph.PositionY ?? 50) + 75 - cumulativeHeight; + + // 使用从 Word 中提取到的文本框宽度,如未提取到则使用默认值 300 + float textBoxWidth = (float)(paragraph.Width ?? 300); + + _logger.LogInformation($"放置文本框: 文本={text}, baseX={baseX}, Y={y}, width={textBoxWidth}, alignment={paragraph.Alignment}"); - _logger.LogInformation($"放置文本框: 文本={paragraph.Text}, X={x}, Y={y}, cumulativeHeight={cumulativeHeight}"); - - // 正常添加文本,不限制高度 - var element = column.Item() - .TranslateX(x) + // 创建元素并根据对齐方式设置 + var item = column.Item() + .TranslateX(baseX) .TranslateY(y) - .Text(paragraph.Text) + .Width(textBoxWidth); + + // 创建对齐的文本元素 + QuestPDF.Infrastructure.IContainer alignedContainer; + switch (paragraph.Alignment?.ToLower()) + { + case "center": + alignedContainer = item.AlignCenter(); + break; + case "right": + alignedContainer = item.AlignRight(); + break; + case "left": + case "justify": + default: + alignedContainer = item.AlignLeft(); + break; + } + + // 添加文本并设置样式 + var textElement = alignedContainer + .Text(text) .FontSize((float)fontSize) - .FontColor(Colors.Black) - .AlignLeft(); - + .FontColor(Colors.Black); + if (!string.IsNullOrEmpty(selectedFont)) { - element = element.FontFamily(selectedFont); + textElement = textElement.FontFamily(selectedFont); } if (isBold) { - element = element.Bold(); + textElement = textElement.Bold(); } // 估算当前文本行的高度并累积 - // 通常一行文本高度大约是 font-size * 1.5 cumulativeHeight += (float)(fontSize * 1.5f); } }); @@ -1418,6 +1484,7 @@ public class ParagraphData public string Style { get; set; } = "normal"; // normal, heading, subheading public double? PositionX { get; set; } = null; public double? PositionY { get; set; } = null; + public double? Width { get; set; } = null; // 文本框宽度 public double? FontSize { get; set; } = null; public string Alignment { get; set; } = "left"; // left, center, right public bool IsBold { get; set; } = false; diff --git a/YD_Event.Application/YD_Event.Application.xml b/YD_Event.Application/YD_Event.Application.xml index 8c9f53f..65d4518 100644 --- a/YD_Event.Application/YD_Event.Application.xml +++ b/YD_Event.Application/YD_Event.Application.xml @@ -911,6 +911,11 @@ 从 Drawing 对象中提取位置信息 + + + 从 Drawing 对象 XML 中提取宽度信息 + + 从 XML 中提取 simplePos 属性