我正在尝试使用VBA导出SVG格式的Excel图表。
Set objChrt = ActiveChart.Parent
objChrt.Activate
Set curChart = objChrt.Chart
curChart.Export fileName:=fileName, FilterName:="SVG"
如果我将“SVG”替换为“PNG”,导出将完全按预期工作,并生成有效的PNG文件。但是,“SVG”将导致空文件。(手动,Excel 365中有一个另保存为SVG的选项,因此导出过滤器存在)。
根据文档,Filtername是“图形过滤器在注册表中出现时的独立于语言的名称",但我在注册表中找不到类似的名称,无论如何,很难想象SVG filtername被命名为“SVG”以外的任何名称。
有没有办法使用VBA导出SVG格式的图表?
注:还有一个关于Chart.export生成空文件的问题,修复方法是在导出前使用ChartObject.Activate
。这个问题不同,因为代码对“PNG”正确工作,但对“SVG”失败(因此这不是与激活或可见性相关的问题)。建议的修复方法也不起作用。
4条答案
按热度按时间lrpiutwd1#
当你将图表复制到剪贴板时,Excel会添加很多不同的剪贴板格式。从2011版(
Application.Build >= 13426
)开始,这现在包括“image/svg+xml”。所以我们所要做的就是在剪贴板上找到那个格式,然后把它保存到一个文件里。结果证明这相当烦人。
然后只需复制图表并保存svg;
zbwhf8kr2#
如果你不需要.svg,那么.emf是另一种矢量格式。它不能直接从Excel工作,但它可以使用一个“助手”PowerPoint应用程序工作:
您可以像这样使用它:
如果你真的需要.svg,那么不幸的是,该功能没有暴露给VBA,尽管它可以通过保存为图片对话框(右键单击图表形状)在Excel和PowerPoint中手动工作。
简而言之,您无法完全自动将图表导出为.svg文件,除非您使用中间格式(如.emf或.pdf)或通过另保存为图片对话框手动保存为.svg。
2w3kk1z53#
以矢量格式导出:
如果您的主要问题是以某种矢量格式导出图表,我建议您只导出为PDF,因为这非常简单:
PDF现在包含矢量图形形式的图表,并且PDF是广泛支持的格式,可用于进一步处理。
如果你真的需要把图表转换成.svg,你可以从命令行(因此很容易自动化)使用开源软件Inkscape或者我想的那样:/。
转换为SVG:
不幸的是,Inkscape转换似乎对我不起作用,所以我用开源pdf渲染工具包Poppler实现了它。
此库提供命令行实用程序 pdftocairo,将在以下解决方案中使用:
请注意,生成的.svg文件中的文本是不可选择的,并且该文件比手动导出生成的文件大(在我的测试中为241 KB vs. 88 KB)。该文件绝对是无限分辨率的,所以不是偶尔会看到的嵌入在.svg文件中的奇怪位图,但会带来另一个小问题:
不幸的是
ExportAsFixedFormat
方法创建了一个PDF“页面”,其中图形在页面上的位置取决于工作表上的位置。不幸的是,.svg转换保持了这种“页面”格式。我不得不了解,摆脱这个问题并不像我最初想象的那么简单,因为excel不支持自定义页面大小,因此将图表导出为。没有白色边框的pdf看起来几乎是不可能的,看看这个有约束但未解决的question(编辑:我解决了它在下面的部分,也张贴了我的方法作为答案的问题)。我尝试了几种方法,他们甚至没有想到在这个链接的问题,仍然没有设法得到它正确地完成只使用Excel,这可能是可能的,取决于您的打印机驱动程序,但我不会那样做...导出到没有白色条的干净SVG:
最简单的解决方法是使用Word将图表正确导出为.pdf格式:
生成的.pdf和.svg看起来与手动导出的.svg完全相同,只是.pdf具有可选文本。.pdf文件仍保留在文件夹中。如果需要,以后可以通过VBA代码轻松删除它...
如果使用此方法导出大量图表,我强烈建议将其移到一个类中,并让该类保存Word应用程序的一个示例,这样它就不会不断地重新打开和关闭Word。它还有一个额外的好处,即可以使要导出的实际代码非常简洁明了。
导出为干净SVG的基于类的方法:
导出的代码变得非常简单:
名为cShapeExporter的类模块的代码:
安装Poppler实用程序:
我假设你在这里使用的是Windows,在Linux上获得Poppler是微不足道的...
所以在Windows上,我建议使用chocolatey包管理器来安装chocolatey。要安装chocolatey,你可以按照these instructions来安装(需要〈5分钟)。
当你有chocolatey,你可以安装Poppler与简单的命令
现在就可以运行我提出的将.pdf转换为. svg的代码了。
如果您喜欢以不同的方式安装Poppler,here介绍了各种选项,但我想添加一些关于其中一些方法的说明:
1.下载二进制文件对我不起作用,运行该实用程序总是会导致错误。
1.通过Anaconda(
conda install -c conda-forge poppler
)安装对我来说也不起作用,安装失败了。1.通过Windows子系统安装Linux确实有效,实用程序也有效,但是如果你还没有安装wsl,包括一个发行版,你将不得不下载并安装几百MB的ob数据,这可能是矫枉过正。
1.如果你已经安装了MiKTeX,这个实用程序应该是包括在内的(在我的例子中也是如此)。我试着从我的MiKTeX安装中安装这个实用程序,不知何故它不起作用。
6rqinv9w4#
2023更新
这个问题似乎在Excel Version 2302 Build 16.0.16130.20186)64位中得到了修复,它在2021年以来发布的一个版本中得到了修复。不幸的是,我在release notes/archive中找不到提到这个修复的地方。
现在,它按照documentation:
为了便于以后参考,我将保留下面的bug的原始解决方案。但是,即使您正在使用Excel的某个bug版本,我也建议使用this more elegant workaround by Jeremy Lakeman。
旧解决方案
不使用任何外部应用程序仅使用Excel和VBA导出到.SVG
这是一个hacky的烂摊子,但它的工作。至少现在...
首先,我将解释它是如何工作的,存在哪些必须克服的问题,以及它们是如何解决的。如果你对技术细节不感兴趣,你可以跳到简单使用指南一节。
"这是什么意思"
代码尝试只使用手动导出方法。这有几个问题,第一个是
Chart.Export
方法中的另一个bug。Chart.Export Interactive:=True
is supposed to打开了所需的对话框,但这不起作用。通过利用一些快捷方式,可以使用SendKeys "+{F10}"
和SendKeys "g"
非常可靠地打开导出窗口。第一个障碍是,但麻烦才刚刚开始!事实证明,打开一个模态对话框会停止整个应用程序中所有代码的执行。即使在打开对话框之前调用了另一个应用程序示例中的代码,我们如何保持它在那里运行,并返回完成打开对话框?这听起来不可能,因为VBA是严格的单线程...
事实证明,单线程并没有那么严格。解决方案称为
Application.OnTime
,它在未来的预定时间启动一个过程。该过程必须在Excel.Application
的另一个示例中运行,因为Application.OnTime
仅在应用程序处于特定模式时才启动过程(就绪、复制、剪切或查找),并且运行VBA代码或打开模式对话框。因此,在打开对话框之前,需要创建Excel应用程序的后台示例,VBA代码插入其中,并计划在对话框打开后立即在后台示例中开始运行。注意:由于代码是自动插入到后台示例中的,因此需要启用“信任对VBA工程对象模型的访问”。我们现在如何只使用VBA代码来处理Windows对话框呢?我设法通过
EnumChildWindows
获得了对话框的所有窗口和控件句柄,并使用这些信息将文本插入到“FileName”组合框中。由于此输入框也接受路径,剩下的唯一问题是在FileFormat组合框中选择“.svg”,然后单击“保存”按钮。不幸的是,我没有“我们无法避免在这里使用SendKeys
。使用Windows API函数更改组合框中的选择相对容易,但问题是实际上要让它注册更改。它似乎在对话框中更改,但当单击“保存”时,它仍然保存为. png。我花了几个小时在Spy++中监视手动更改期间发送的消息,但我无法用VBA重现它们。正因为如此,必须再次为
SendKeys
,以更改文件格式并按下“保存”。SendKeys
在这个解决方案中被非常小心地使用,包括各种安全检查,并且在每次使用之前将目标窗口拉到前面,但是如果在宏运行的同时与PC交互,那么它从来不是100%安全的。因为这个方法需要一个类似于here和here的后台应用示例,所以我为
ShapeExporter
对象实现了一个类,创建对象会打开后台应用,销毁对象会关闭它。简单使用指南
以下过程将指定工作表中的所有
ChartObjects
导出到保存工作簿的文件夹中。要使代码工作,您必须首先:
1.信任对VBA工程对象模型的访问(有关原因,请参见宏的详细说明)
1.创建一个类模块,将其重命名为“
cShapeExporter
“,并将以下代码粘贴到其中: