






















using Aspose.Slides; using Aspose.Slides.Charts; using Aspose.Slides.Export; using Crane.MethodHook; using ScottPlot; using ScottPlot.AxisLimitManagers; using ScottPlot.Colormaps; using ScottPlot.PlotStyles; using ScottPlot.Statistics; using ScottPlot.TickGenerators; using System; using System.Collections; using System.Collections.Generic; using System.Drawing; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Security.Policy; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Xml; using System.Xml.Linq; using Color = System.Drawing.Color; using IAxis = Aspose.Slides.Charts.IAxis; namespace AsposeStackedLineChart { internal class Program { static void Main(string[] args) { try { Crane.MethodHook.MethodHookManager.Instance.AddHook(new MethodHook( typeof(MethodBase).GetMethod("Invoke", BindingFlags.Public | BindingFlags.Instance, null, new[] { typeof(object), typeof(object[]) }, null), typeof(Program).GetMethod(nameof(Program.NewMethodInvoke), BindingFlags.Static | BindingFlags.Public, null, new[] { typeof(MethodBase), typeof(object), typeof(object[]) }, null) )); Crane.MethodHook.MethodHookManager.Instance.AddHook(new MethodHook( typeof(string).GetMethod("Compare", BindingFlags.Static | BindingFlags.Public, null, new[] { typeof(string), typeof(string) }, null), typeof(Program).GetMethod(nameof(Program.NewCompare), BindingFlags.Static | BindingFlags.Public, null, new[] { typeof(string), typeof(string) }, null) )); Crane.MethodHook.MethodHookManager.Instance.StartHook(); new Aspose.Slides.License().SetLicense(new MemoryStream(Convert.FromBase64String("PExpY2Vuc2U+CiAgPERhdGE+CiAgICA8TGljZW5zZWRUbz5TdXpob3UgQXVuYm94IFNvZnR3YXJlIENvLiwgTHRkLjwvTGljZW5zZWRUbz4KICAgIDxFbWFpbFRvPnNhbGVzQGF1bnRlYy5jb208L0VtYWlsVG8+CiAgICA8TGljZW5zZVR5cGU+RGV2ZWxvcGVyIE9FTTwvTGljZW5zZVR5cGU+CiAgICA8TGljZW5zZU5vdGU+TGltaXRlZCB0byAxIGRldmVsb3BlciwgdW5saW1pdGVkIHBoeXNpY2FsIGxvY2F0aW9uczwvTGljZW5zZU5vdGU+CiAgICA8T3JkZXJJRD4yMDA2MDIwMTI2MzM8L09yZGVySUQ+CiAgICA8VXNlcklEPjEzNDk3NjAwNjwvVXNlcklEPgogICAgPE9FTT5UaGlzIGlzIGEgcmVkaXN0cmlidXRhYmxlIGxpY2Vuc2U8L09FTT4KICAgIDxQcm9kdWN0cz4KICAgICAgPFByb2R1Y3Q+QXNwb3NlLlRvdGFsIGZvciAuTkVUPC9Qcm9kdWN0PgogICAgPC9Qcm9kdWN0cz4KICAgIDxFZGl0aW9uVHlwZT5FbnRlcnByaXNlPC9FZGl0aW9uVHlwZT4KICAgIDxTZXJpYWxOdW1iZXI+OTM2ZTVmZDEtODY2Mi00YWJmLTk1YmQtYzhkYzBmNTNhZmE2PC9TZXJpYWxOdW1iZXI+CiAgICA8U3Vic2NyaXB0aW9uRXhwaXJ5PjIwMjEwODI3PC9TdWJzY3JpcHRpb25FeHBpcnk+CiAgICA8TGljZW5zZVZlcnNpb24+My4wPC9MaWNlbnNlVmVyc2lvbj4KICAgIDxMaWNlbnNlSW5zdHJ1Y3Rpb25zPmh0dHBzOi8vcHVyY2hhc2UuYXNwb3NlLmNvbS9wb2xpY2llcy91c2UtbGljZW5zZTwvTGljZW5zZUluc3RydWN0aW9ucz4KICA8L0RhdGE+CiAgPFNpZ25hdHVyZT5wSkpjQndRdnYxV1NxZ1kyOHFJYUFKSysvTFFVWWRrQ2x5THE2RUNLU0xDQ3dMNkEwMkJFTnh5L3JzQ1V3UExXbjV2bTl0TDRQRXE1aFAzY2s0WnhEejFiK1JIWTBuQkh1SEhBY01TL1BSeEJES0NGbWg1QVFZRTlrT0FxSzM5NVBSWmJRSGowOUNGTElVUzBMdnRmVkp5cUhjblJvU3dPQnVqT1oyeDc4WFE9PC9TaWduYXR1cmU+CjwvTGljZW5zZT4="))); Console.WriteLine(CultureInfo.CurrentCulture.Name); Console.WriteLine(CultureInfo.CurrentUICulture.Name); Presentation presentation = new Presentation(); // 设置幻灯片大小为 16:9 格式,宽度为 13.33 英寸,高度为 7.5 英寸 presentation.SlideSize.SetSize(SlideSizeType.Widescreen, SlideSizeScaleType.EnsureFit); // 如果 PPT 没有幻灯片,则添加一张新的空幻灯片 if (presentation.Slides.Count == 0) { presentation.Slides.AddEmptySlide(presentation.LayoutSlides[0]); } ISlide slide = presentation.Slides[0]; //使用第一张幻灯片 float widthfull = presentation.SlideSize.Size.Width; float heightfull = presentation.SlideSize.Size.Height; // 设置图表标题 Test(slide); DrawRiskImprovementIcons(presentation, slide); Console.WriteLine(typeof(Presentation).Assembly.FullName); Console.WriteLine(Aspose.Slides.BuildVersionInfo.Product); Console.WriteLine(Aspose.Slides.BuildVersionInfo.AssemblyVersion); // 保存演示文稿 presentation.Save("ChartExample.pptx", SaveFormat.Pptx); } catch (Exception ex) { throw ex; } } public static object NewMethodInvoke(MethodBase method, object obj, object[] parameters) { if (Assembly.GetCallingAssembly() != null && Assembly.GetCallingAssembly().FullName.StartsWith("Aspose.") && method.Name == "ParseExact" && parameters.Length > 0 && parameters[0].ToString().Contains("0827")) { var ret = DateTime.ParseExact(DATE_CHANGED_TO, "yyyyMMdd", System.Globalization.CultureInfo.InvariantCulture); //ShowLog(method, ret, obj, parameters, true); return ret; } else if (Assembly.GetCallingAssembly() != null && Assembly.GetCallingAssembly().FullName.StartsWith("Aspose.") && method.Name == "ParseExact" && parameters.Length > 0 && System.Text.RegularExpressions.Regex.Match(parameters[0].ToString(), @"^\d{4}\.\d{2}\.\d{2}$").Success) { var ret = DateTime.ParseExact("20200501", "yyyyMMdd", System.Globalization.CultureInfo.InvariantCulture); //ShowLog(method, ret, obj, parameters, true); return ret; } else if (Assembly.GetCallingAssembly() != null && Assembly.GetCallingAssembly().FullName.StartsWith("Aspose.") && method.DeclaringType != null && method.DeclaringType.Name == "String" && method.Name == "Compare") { if (parameters.Length == 2) { if (parameters[0].ToString() == "20200827") { var ret = 1; //ShowLog(method, ret, obj, parameters, true); return ret; } else if (parameters[1].ToString() == "20200827") { var ret = -1; //ShowLog(method, ret, obj, parameters, true); return ret; } } } else if (Assembly.GetCallingAssembly() != null && Assembly.GetCallingAssembly().FullName.StartsWith("Aspose.") && method.Name == "op_GreaterThan" && parameters.Length == 2 && parameters[1] is DateTime && ((DateTime)parameters[1]).ToString("MMdd") == "0827") { //ShowLog(method, false, obj, parameters, true); return false; } else if (Assembly.GetCallingAssembly() != null && Assembly.GetCallingAssembly().FullName.StartsWith("Aspose.") && method.Name == "Split" && System.Text.RegularExpressions.Regex.Match(obj.ToString(), @"^\d{4}\.\d{2}\.\d{2}$").Success && obj != null && obj.ToString().Substring(0, 4) == DateTime.Now.Year.ToString()) { var ret = new string[] { "2019", "08", "27" }; //ShowLog(method, ret, obj, parameters, true); return ret; } var hook = MethodHookManager.Instance.GetHook(System.Reflection.MethodBase.GetCurrentMethod()); var result = hook.InvokeOriginal<object>(method, obj, parameters?.ToArray()); //ShowLog(method, result, obj, parameters); return result; } public static int NewCompare(string s1, string s2) { if (Assembly.GetCallingAssembly() != null && Assembly.GetCallingAssembly().FullName.StartsWith("Aspose.") && s2 == "20200827") { Utils.LogWriteLine($"HOOK SUCCESS: From {Assembly.GetCallingAssembly().GetName().Name} String.Compare({s1},{s2}) return -1;", ConsoleColor.Green); return -1; } else { var hook = MethodHookManager.Instance.GetHook(MethodBase.GetCurrentMethod()); var ret = hook.InvokeOriginal<int>(null, s1, s2); Utils.LogWriteLine($"NOT Aspose Call: From {Assembly.GetCallingAssembly().GetName().Name} String.Compare({s1},{s2}) return {ret};", ConsoleColor.DarkRed); return ret; } } private static readonly string DATE_CHANGED_TO = (DateTime.Today.Year + 1).ToString() + "0827"; public static void Test(ISlide slide) { IChart chart = slide.Shapes.AddChart(ChartType.ClusteredColumn, 20, 20, 500, 300); ChartType chartType = ChartType.ClusteredColumn; // 4. 设置图表标题 chart.HasTitle = true; chart.ChartTitle.AddTextFrameForOverriding("季度销售对比"); chart.ChartTitle.TextFrameForOverriding.TextFrameFormat.CenterText = NullableBool.True; chart.ChartTitle.Height = 20; // 5. 获取图表数据工作簿(默认工作表索引0) int worksheetIndex = 0; IChartDataWorkbook workbook = chart.ChartData.ChartDataWorkbook; // 6. 清空默认系列与类别 chart.ChartData.Series.Clear(); chart.ChartData.Categories.Clear(); // 7. 添加新系列(图例) chart.ChartData.Series.Add(workbook.GetCell(worksheetIndex, 0, 1, "产品A"), chartType); chart.ChartData.Series.Add(workbook.GetCell(worksheetIndex, 0, 2, "产品B"), chartType); // 8. 添加类别(X轴标签) chart.ChartData.Categories.Add(workbook.GetCell(worksheetIndex, 1, 0, "Q1")); chart.ChartData.Categories.Add(workbook.GetCell(worksheetIndex, 2, 0, "Q2")); chart.ChartData.Categories.Add(workbook.GetCell(worksheetIndex, 3, 0, "Q3")); chart.ChartData.Categories.Add(workbook.GetCell(worksheetIndex, 4, 0, "Q4")); // 9. 填充系列数据 // 产品A数据 IChartSeries seriesA = chart.ChartData.Series[0]; seriesA.DataPoints.AddDataPointForBarSeries(workbook.GetCell(worksheetIndex, 1, 1, 120)); seriesA.DataPoints.AddDataPointForBarSeries(workbook.GetCell(worksheetIndex, 2, 1, 150)); seriesA.DataPoints.AddDataPointForBarSeries(workbook.GetCell(worksheetIndex, 3, 1, 180)); seriesA.DataPoints.AddDataPointForBarSeries(workbook.GetCell(worksheetIndex, 4, 1, 210)); // 产品B数据 IChartSeries seriesB = chart.ChartData.Series[1]; seriesB.DataPoints.AddDataPointForBarSeries(workbook.GetCell(worksheetIndex, 1, 2, 90)); seriesB.DataPoints.AddDataPointForBarSeries(workbook.GetCell(worksheetIndex, 2, 2, 110)); seriesB.DataPoints.AddDataPointForBarSeries(workbook.GetCell(worksheetIndex, 3, 2, 140)); seriesB.DataPoints.AddDataPointForBarSeries(workbook.GetCell(worksheetIndex, 4, 2, 170)); // 10. 自定义样式(颜色、数据标签) // 系列A填充色 seriesA.Format.Fill.FillType = FillType.Solid; seriesA.Format.Fill.SolidFillColor.Color = Color.Blue; // 系列B填充色 seriesB.Format.Fill.FillType = FillType.Solid; seriesB.Format.Fill.SolidFillColor.Color = Color.Green; // 显示数据值 seriesA.Labels.DefaultDataLabelFormat.ShowValue = true; seriesB.Labels.DefaultDataLabelFormat.ShowValue = true; } /// <summary> /// 绘制风险改善计划页面的左侧图标与文字(主方法) /// </summary> /// <param name="presentation">PPT演示文稿对象</param> /// <param name="slide">目标幻灯片</param> public static void DrawRiskImprovementIcons(Presentation presentation, ISlide slide) { // ===================== 核心配置区 ===================== float baseX = 80f; // 图标组基准X坐标 float baseY = 180f; // 图标组基准Y坐标 float iconSize = 80f; // 菱形/图标尺寸(宽高一致) float lineSpacing = 90f; // 图标垂直间距 float textOffsetX = 45f; // 文字与图标水平间距 // ===================================================== // 1. 定义图标数据源(替换为你的实际路径+对应文字) var iconItems = new List<(string ImagePath, string Text)> { ("images/risk4501.png", "New Raw Material Introduction\nProcess Control / ICG"), // 云下载图标 ("images/risk4502.png", "Build Alternative & Single\nSource Database"), // 交换箭头图标 ("images/risk4503.png", "Risk 4&5 Audit & Monitor\nAction Plan") // 雨伞图标 }; // 2. 遍历绘制每个图标+文字 for (int i = 0; i < iconItems.Count; i++) { float currentY = baseY + (i * lineSpacing); // 绘制带菱形背景的图标 DrawIconWithDiamondBackground(presentation, slide, iconItems[i].ImagePath, baseX, currentY, iconSize, iconSize); //// 绘制右侧文字 //AddIconDescriptionText(slide, iconItems[i].Text, baseX + textOffsetX, currentY + (iconSize / 2) - 10f); } } /// <summary> /// 绘制带菱形背景的图标(核心修正:匹配AddPictureFrame重载+按文件名判断颜色) /// </summary> /// <param name="presentation">PPT演示文稿</param> /// <param name="slide">目标幻灯片</param> /// <param name="imagePath">图标路径(相对/绝对)</param> /// <param name="x">菱形/图标X坐标</param> /// <param name="y">菱形/图标Y坐标</param> /// <param name="width">菱形/图标宽度</param> /// <param name="height">菱形/图标高度</param> private static void DrawIconWithDiamondBackground(Presentation presentation, ISlide slide, string imagePath, float x, float y, float width, float height) { try { // 1. 处理图片路径(相对路径转绝对路径,避免文件找不到) string fullImagePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, imagePath); if (!File.Exists(fullImagePath)) { throw new FileNotFoundException("图标文件不存在", fullImagePath); } // 2. 加载PNG图标为IPPImage(加入PPT图片池) IPPImage iconImage; using (FileStream fs = new FileStream(fullImagePath, FileMode.Open, FileAccess.Read)) { iconImage = presentation.Images.AddImage(fs); } // 3. 直接添加图片到PPT(无背景,居中显示,保留内边距适配) //float innerPadding = 6f; // 可选:图片与外层框的内边距,不需要可设为0 //float iconDisplayWidth = width - (2 * innerPadding); //float iconDisplayHeight = height - (2 * innerPadding); //IPictureFrame pictureFrame = slide.Shapes.AddPictureFrame( // ShapeType.Rectangle, // 图片框形状(矩形,无样式) // x + innerPadding, // 图片X坐标(可直接用x,取消innerPadding) // y + innerPadding, // 图片Y坐标(可直接用y,取消innerPadding) // iconDisplayWidth, // 图片显示宽度 // iconDisplayHeight, // 图片显示高度 // iconImage // 加载好的图片对象 //); IPictureFrame pictureFrame = slide.Shapes.AddPictureFrame( ShapeType.Rectangle, // 图片框形状(矩形,无样式) x , // 图片X坐标(可直接用x,取消innerPadding) y , // 图片Y坐标(可直接用y,取消innerPadding) width, // 图片显示宽度 height, // 图片显示高度 iconImage // 加载好的图片对象 ); // 4. 优化图片样式(去除边框,保持透明背景) pictureFrame.LineFormat.FillFormat.FillType = FillType.NoFill; // 移除图片边框 // 取消裁剪,确保图片完整显示 pictureFrame.PictureFormat.CropBottom = 0; pictureFrame.PictureFormat.CropTop = 0; pictureFrame.PictureFormat.CropLeft = 0; pictureFrame.PictureFormat.CropRight = 0; } catch (Exception ex) { Console.WriteLine($"绘制图标失败:{ex.Message}"); throw; // 按需调整异常处理,比如返回false或记录日志 } } /// <summary> /// 添加图标右侧的说明文字 /// </summary> /// <param name="slide">目标幻灯片</param> /// <param name="text">文字内容(支持\n换行)</param> /// <param name="x">文字X坐标</param> /// <param name="y">文字Y坐标</param> private static void AddIconDescriptionText(ISlide slide, string text, float x, float y) { IAutoShape textFrame = slide.Shapes.AddAutoShape(ShapeType.Rectangle, x, y, 250f, 40f); // 隐藏文字框背景和边框 textFrame.FillFormat.FillType = FillType.NoFill; textFrame.LineFormat.FillFormat.FillType = FillType.NoFill; // 设置文字内容和样式 textFrame.TextFrame.Text = text; IParagraph paragraph = textFrame.TextFrame.Paragraphs[0]; IPortion portion = paragraph.Portions[0]; portion.PortionFormat.FontHeight = 12f; portion.PortionFormat.LatinFont = new FontData("Arial"); portion.PortionFormat.FillFormat.FillType = FillType.Solid; // 填充为实色 portion.PortionFormat.FillFormat.SolidFillColor.Color = Color.Black; // 文字对齐 textFrame.TextFrame.TextFrameFormat.AnchoringType = TextAnchorType.Top; paragraph.ParagraphFormat.Alignment = TextAlignment.Left; } } }
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。