Mustafa Can Yücel
blog-post-34

Exporting Excel Charts

The Everlasting Problem: Using Excel Charts in LaTeX

Back in my university days, I was using LaTeX for my reports and theses. One persistent challenge I faced was incorporating high-quality charts from Excel into my LaTeX documents. The default image formats like PNG or JPEG often resulted in pixelated images when scaled, which was far from ideal for professional documents. At that time, the only viable solution I found was to print the chart to a PDF using a virtual PDF printer (in those days Windows was not able to natively print to PDF, so we used third-party software like CutePDF Writer). But this meant printing the chart on a standard, printer-set page with a defined page size (A4, letter, etc) and margins, which was not very flexible. You could set the print area to the chart size, but still, the resulting PDF would have a lot of white space around the chart, which was not ideal. So you had to open the chart in Inkscape, import the PDF, use "Document Properties" > "Resize page to content" to crop the white space, and then export it again as PDF or SVG. This was a tedious process, but it worked. You may of course question why drawing charts in Excel was necessary in the first place, but that is a different topic.

More than a decade later, I found a coworker in a similar situation. He needed to include Excel charts in his LaTeX documents for work reports. Recalling my past struggles, I decided to help him find a better solution. After some research, I discovered that modern versions of Excel (2016 and later) have improved their export capabilities. You can now directly export charts as SVG files, which are vector-based and scale perfectly without losing quality. However, the export functionality is still somewhat hidden in the interface. To make things even worse, you cannot natively use SVG files in LaTeX documents without additional packages or conversions. And these additional packages even do not work by themselves; you need to install Inkscape (hello Inkscape, my old friend!) and configure LaTeX to use it for converting SVG files to PDF during the compilation process. Like, seriously, why is this so complicated?

Converting SVG to PDF for LaTeX

The major challenge in converting an SVG file to PDF for LaTeX is ensuring that the resulting PDF has the correct dimensions and no unwanted margins or white space. When you export a chart from Excel as an SVG, it includes metadata about the chart's size, but when converting to PDF, this information can be lost or misinterpreted, leading to unexpected results. Moreover, common PDF libraries that allow including SVGs in the pdf usually rasterize the image, defeating the purpose of using a vector format in the first place. Therefore, we need a method that preserves the vector quality of the chart while ensuring it fits perfectly within the LaTeX document.

We also need to consider the user experience. If the user is asked to save a file to somewhere, launch additional software, or run command-line tools, it disrupts their workflow and adds unnecessary complexity. The ideal solution should be as seamless and automated as possible, allowing users to export their charts directly from Excel to a LaTeX-compatible PDF format without any extra steps. This means integrating the conversion process into Excel itself as a COM add-in, so users can export their charts with a single click. Thankfully, Visual Studio has a template for creating COM add-ins for Office applications, making it relatively straightforward to develop such a tool. We also do not want user to install any dependency software like Inkscape or Ghostscript. The add-in should handle everything internally.

The Add-In

I am not going to get into the details of the COM add-in development here, but I will outline the key steps involved in creating the add-in that exports Excel charts as LaTeX-compatible PDF files. The result is expected to be a button on the ribbon in Excel, which when clicked, exports the selected chart as a PDF (or SVG, based on user preference) file with the correct dimensions and no unwanted margins. Thankfully we now can use C# for writing add-ins instead of not-so-dev-friendly VBA, which makes the development process much more enjoyable.

As said, we don't want any third party software dependencies, so we will use the the open-source libraries Svg.Skia and SkiaSharp. The Svg.Skia library allows us to load and render SVG files, while SkiaSharp provides the functionality to create and manipulate PDF files using its SKDocument class and PDF backend. By combining these two libraries, we can read the SVG data exported from Excel and convert it directly into a PDF format suitable for LaTeX documents. Note that we are not using a readymade SVG to PDF converter library or PDF tools such as PdfSharp, because most of them rasterize the image during conversion, which we want to avoid.

In the end, the general algorithm for the add-in is as follows:

  1. The user selects a chart and clicks the "Export as PDF" button on the ribbon.
  2. We save the chart to the OS temporary directory as an SVG file, with a temporary name. For this, we directly use the Export function that Excel interop library provides. Note that this export will be exactly as the chart appears in Excel, including any formatting and styles, without any additional margins or padding.
  3. We load the SVG file using Svg.Skia library as an SkSvg.
  4. We get the bounds and dimensions of the chart.
  5. We create a PDF document using SkiaSharp's SKDocument class via SKDocument.CreatePdf(fileStream)
  6. We create a new page in the PDF document with the exact dimensions of the chart.
  7. We render the SVG onto the PDF page using Svg.Skia's rendering capabilities (PdfCanvas.DrawPicture(SvgPicture)).
  8. We close the PDF document to finalize the file.
  9. We delete the temporary SVG file to clean up.

Performance

As expected, rendering a complex SVG chart and converting it to PDF can be computationally intensive, especially for charts with a lot of data points or intricate designs. However, for most typical use cases involving standard charts, the performance is quite acceptable. The conversion process usually takes just a few seconds, which is reasonable for an operation that significantly enhances the quality of the output. Of course, performance may vary depending on the complexity of the chart and the system's capabilities, but overall, users should find the add-in responsive and efficient for their needs. I have tested it with charts having around one million data points, and it took around 3-5 seconds to export on a 13th Gen Intel i9 13900F system. Of course this is not a typical use case, but it shows that the add-in can handle large datasets reasonably well.

Using the PDF Chart in LaTeX

Once you have exported the chart as a PDF file using the add-in, you can easily include it in your LaTeX document using the standard graphicx package. Here is a simple example of how to do this:

\documentclass{article}
\usepackage{graphicx}
\begin{document}
\begin{figure}[h!]
    \centering
    \includegraphics[width=\linewidth]{path/to/your/chart.pdf}
    \caption{Excel Chart Exported as PDF}
\end{figure}
\end{document}
This code snippet demonstrates how to include the exported PDF chart in a LaTeX document. The \includegraphics command is used to insert the PDF file, and you can adjust the width as needed to fit your document layout. The resulting chart will maintain its vector quality, ensuring that it looks sharp and professional in your final document.

Deployment

There are different ways to deploy the add-in to users. The simplest way is to provide the compiled DLL and a manifest file, and instruct users to install it manually via Excel's "Add-ins" menu. However, for a more seamless experience, you can create an installer using tools like One-Click Deployment, Inno Setup or WiX Toolset, which will handle the installation process for the user. Considering the complexity of COM add-in deployment, I chose one-click deployment, as it automatically handles Office COM registration and makes it easy for users to install the add-in with minimal effort. However, this ended up creating additional challenges.

When we build this add-in, the necessary external libraries are compiled as dll files that should be placed in the same directory as the executable. However, since our output is an extension, these dll files are not put into the correct locations during installation by default, and they are not registered in the path. This results in runtime errors when the add-in tries to load these libraries. To solve this, we add some additional code to load the dll files from the add-in directory manually during the add-in's startup. This ensures that all necessary dependencies are available when the add-in is used, preventing any runtime issues related to missing libraries:

private void ExportToSVGRibbon_Load(object sender, RibbonUIEventArgs e)
{
    // Start log at initialization
    ExportLogger.StartNewLog("Add-in Initialization");
    ExportLogger.Log("ChartToSVG loading...");
    RegisterSkiaSharp();
}

private void RegisterSkiaSharp()
{
    if (_isSkiaRegistered)
    {
        ExportLogger.Log("SkiaSharp already registered");
        return;
    }

    ExportLogger.Log("Registering SkiaSharp...");

    try
    {
        var assemblyPath = System.Reflection.Assembly.GetExecutingAssembly().Location;
        var assemblyDirectory = Path.GetDirectoryName(assemblyPath);
        var architecture = Environment.Is64BitProcess ? "x64" : "x86";
        var nativePath = Path.Combine(assemblyDirectory, architecture);

        ExportLogger.Log($"Architecture: {architecture}");
        ExportLogger.Log($"Native DLL path: {nativePath}");

        if (Directory.Exists(nativePath))
        {
            var path = Environment.GetEnvironmentVariable("PATH") ?? String.Empty;
            if (!path.Contains(nativePath))
            {
                Environment.SetEnvironmentVariable("PATH", $"{nativePath};{path}");
                ExportLogger.Log("Added SkiaSharp path to PATH");
            }
            else
            {
                ExportLogger.Log("PATH already includes SkiaSharp");
            }
        }
        else
        {
            ExportLogger.Log("WARNING: Native DLL path not found");
        }

        _isSkiaRegistered = true;
        ExportLogger.Log("✓ SkiaSharp registration complete");
    }
    catch (Exception ex)
    {
        ExportLogger.Log($"✗ Registration failed: {ex.Message}");
        // Don't disrupt Excel startup even if registration fails
    }
}

Conclusions

Developing a COM add-in for Excel that exports charts as LaTeX-compatible PDF files has been a rewarding experience. It addresses a common pain point for users who need high-quality vector graphics in their documents without the hassle of manual conversions and third-party software. By leveraging modern libraries like Svg.Skia and SkiaSharp, we were able to create a solution that is both efficient and user-friendly. The add-in streamlines the workflow for incorporating Excel charts into LaTeX documents, making it easier for users to produce professional-quality reports and presentations. Overall, this project highlights the power of combining existing technologies to solve real-world problems in a seamless manner.

You can find the repository for this add-in on my GitHub. It has few additional features such as a logger that creates a log file under Documents/chart2svg folder to see what is happening during export, and also an option to export as SVG directly. Feel free to check it out, use it, and contribute if you like! It also has the latest installer for easy deployment under Releases.