Conversion to pdf with SharePoint 2013

On the fly conversion of a Word document is now supported by SharePoint 2013 using the Word Automation Services. Also in SharePoint 2013 you get the new PowerPoint Automation Services, that lets you convert PowerPoint presentations to pdf (or as images in a zip file). Be aware that both these services are running on-premises only and not in Office 365.

Using a few lines of code, you can convert a Word document or a PowerPoint document to a pdf on the fly. This is a great addition to SharePoint 2013, as previously we had to use third-party tools for this. That noted, these third-party tools could convert a lot more file types to pdf. Still having the option to use these Automation Services will be welcomed by many, as it now is quite easy to start using this functionality.

As a little tryout I have created a farm solution (as this is for on-premises use) to add a conversion option to the ECB menu for Word and PowerPoint files. Probably I should have named the option 'Download as PDF' instead of 'Convert to PDF' as that would be the correct description of the functionality.

Screenshot ECB menu

This screenshot contains the ECB menu, the site was created using the Dutch language, but I didn't take the effort to supply multiple language resource files, so I used English as the language for this feature.

To convert a Word document you can use the following code:

public static byte[] GetWordFileAsPdf(SPSite site, SPFile file)
{
    using (Stream read = file.OpenBinaryStream())
    {
        using (MemoryStream write = new MemoryStream())
        {
            var proxy = site.WebApplication.ServiceApplicationProxyGroup.Proxies.Where(p => p is WordServiceApplicationProxy).FirstOrDefault();
            if (proxy == null)
                return null;

            SyncConverter sc = new SyncConverter((WordServiceApplicationProxy)proxy);
            sc.UserToken = site.UserToken;
            sc.Settings.UpdateFields = true;
            sc.Settings.OutputFormat = SaveFormat.PDF;

            ConversionItemInfo info = sc.Convert(read, write);
            if (info.Succeeded)
            {
                return write.ToArray();
            }
        }
    }
    return null;
}
    

To convert a PowerPoint document you need different code:

public static byte[] GetPowerPointFileAsPdf(SPSite site, SPFile file)
{
    using (Stream read = file.OpenBinaryStream())
    {
        using (MemoryStream write = new MemoryStream())
        {
            PdfRequest request = new PdfRequest(read, file.Name.Substring(file.Name.LastIndexOf('.')), write);
            IAsyncResult result = request.BeginConvert(SPServiceContext.GetContext(site), null, null);
            request.EndConvert(result);
            return write.ToArray();
        }
    }
}
    

I have used this code in an application page that returns the document as PDF. To open the file I have used some javascript to add an invisible iframe to open this application page, so the download will not interfere with subsequent javascript calls. To add this to the ECB menu I have added a ScriptLink CustomAction to add the javascript file, and for each supported extension (.doc .docx .ppt .pptx) I have added an EditControlBlock CustomAction like this:

<CustomAction Id="PdfConversion.docx"
              Title="Convert to PDF"
              Location="EditControlBlock"
              RegistrationType="FileType"
              RegistrationId="docx"
              Sequence="100">
    
<UrlAction  Url="javascript:downloadURL('{SiteUrl}/_layouts/15/pdfconversion/convert.aspx?ItemId={ItemId}&amp;ListId={ListId}');"/>
    
</CustomAction>
    

That is all there is to it. You can download the complete solution here. Note that this is just a proof of concept, there is no exception handling, all exception handling is left to SharePoint. As the document is opened using an invisible iframe, no error messages will be displayed. This might not be the most optimal solution, as you could use a script to show a dialog containing information about the encountered issue. For example if the required Automation Service is not available.